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 SilexApplication; use SilexProviderTwigServiceProvider; $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/
Powered by WPeMatico