Estou aprendendo o Docker. Neste artigo, quero compartilhar um pequeno experimento que eu fiz. Eu sei que o código parece mais complicado do que o necessário, mas é apenas uma desculpa para construir algo com o docker e contêineres. Deixe-me explicar um pouco.
A ideia é construir um relógio no navegador. Algo assim:

Sim, eu sei. Podemos fazê-lo apenas com js, css e html, mas quero trabalhar um pouco mais. A ideia é criar:
- Uma interface em Silex/PHP
- Um servidor WebSocket com socket.io/node
- Um script Python para obter a hora atual
O servidor WebSocket abrirá 2 ports: um para servir os webSockets (socket.io) e outro como um servidor http (express). O script Python receberá a hora atual e a enviará para o servidor webSocket. Finalmente, uma interface (silex) estará ouvindo o evento do WebSocket e renderizará a hora atual.
Esse é o servidor WebSocket (com socket.io e express)
var
express = require('express'),
expressApp = express(),
server = require('http').Server(expressApp),
io = require('socket.io')(server, {origins: 'localhost:*'})
;
expressApp.get('/tic', function (req, res) {
io.sockets.emit('time', req.query.time);
res.json('OK');
});
expressApp.listen(6400, '0.0.0.0');
server.listen(8080);
Este é o nosso script Python
from time import gmtime, strftime, sleep
import httplib2
h = httplib2.Http()
while True:
(resp, content) = h.request("http://node:6400/tic?time=" + strftime("%H:%M:%S", gmtime()))
sleep(1)
E a nossa interface Silex
use Silex\Application;
use Silex\Provider\TwigServiceProvider;
$app = new Application(['debug' => true]);
$app->register(new TwigServiceProvider(), [
'twig.path' => __DIR__ . '/../views',
]);
$app->get("/", function (Application $app) {
return $app['twig']->render('index.twig', []);
});
$app->run();
Usando este template twig
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Docker example</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link href="css/app.css" rel="stylesheet">
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
</head>
<body>
<div class="site-wrapper">
<div class="site-wrapper-inner">
<div class="cover-container">
<div class="inner cover">
<h1 class="cover-heading">
<div id="display">
display
</div>
</h1>
</div>
</div>
</div>
</div>
<script src="//localhost:8080/socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
var socket = io.connect('//localhost:8080');
$(function () {
socket.on('time', function (data) {
$('#display').html(data);
});
});
</script>
</body>
</html>
A ideia é usar um contêiner Docker para cada processo. Eu gosto de ter todo o código em um só lugar para que todos os contêineres compartilhem o mesmo volume com o código-fonte.
Primeiro, o contêiner de node (servidor WebSocket)
FROM node:argon RUN mkdir -p /mnt/src WORKDIR /mnt/src/node EXPOSE 8080 6400
Agora o contêiner python
FROM python:2 RUN pip install httplib2 RUN mkdir -p /mnt/src WORKDIR /mnt/src/python
E, finalmente, o container Frontend (apache2 com Ubuntu 16.04)
FROM ubuntu:16.04 RUN locale-gen es_ES.UTF-8 RUN update-locale LANG=es_ES.UTF-8 ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update -y RUN apt-get install --no-install-recommends -y apache2 php libapache2-mod-php RUN apt-get clean -y COPY ./apache2/sites-available/000-default.conf /etc/apache2/sites-available/000-default.conf RUN mkdir -p /mnt/src RUN a2enmod rewrite RUN a2enmod proxy RUN a2enmod mpm_prefork RUN chown -R www-data:www-data /mnt/src ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_LOG_DIR /var/log/apache2 ENV APACHE_LOCK_DIR /var/lock/apache2 ENV APACHE_PID_FILE /var/run/apache2/apache2.pid ENV APACHE_SERVERADMIN admin@localhost ENV APACHE_SERVERNAME localhost EXPOSE 80
Agora temos os três contêineres, mas queremos usar todos juntos. Usaremos um arquivo docker-compose.yml. O contêiner da web expõe a porta 80 e o contêiner node a 8080. O contêiner node também abre a 6400, mas essa é uma porta interna. Nós não precisamos acessar essa porta fora. Somente o contêiner Python precisa acessar essa porta, porquea 6400 não está mapeada para nenhuma porta em docker-compose
version: '2'
services:
web:
image: gonzalo123/example_web
container_name: example_web
ports:
- "80:80"
restart: always
depends_on:
- node
build:
context: ./images/php
dockerfile: Dockerfile
entrypoint:
- /usr/sbin/apache2
- -D
- FOREGROUND
volumes:
- ./src:/mnt/src
node:
image: gonzalo123/example_node
container_name: example_node
ports:
- "8080:8080"
restart: always
build:
context: ./images/node
dockerfile: Dockerfile
entrypoint:
- npm
- start
volumes:
- ./src:/mnt/src
python:
image: gonzalo123/example_python
container_name: example_python
restart: always
depends_on:
- node
build:
context: ./images/python
dockerfile: Dockerfile
entrypoint:
- python
- tic.py
volumes:
- ./src:/mnt/src
E isso é tudo. Só precisamos iniciar nossos contêineres
docker-compose up --build -d
e abrir o nosso navegador em: http: // localhost para ver o nosso relógio.
Código-fonte completo disponível na minha conta no github.
***
Gonzalo Ayuso faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://gonzalo123.com/2017/01/02/playing-with-docker-silex-python-node-and-websockets/




