Primeros pasos con Kubernetes (I): Docker


Para los primeros ejemplos hemos creado una aplicación NodeJS que únicamente arranca un servidor por el puerto 8080 y responde con un mensaje de texto.


var http = require('http');
var handleRequest = function(request, response) {
  console.log('Received request for URL: ' + request.url);
  response.writeHead(200);
  response.end('Hello World!');
};
var www = http.createServer(handleRequest);
www.listen(8080);


Para verificar su funcionamiento, arrancaremos el servidor y lanzaremos una petición para verificar que devuelve el mensaje de “Hello World!”.


$ nodejs ./apps/hello/v1/server.js &
[2] 20227

$ curl http://localhost:8080
Received request for URL: /
Hello World!

$ kill 20227
[2]-  Exit 143                nodejs server.js

Ahora que tenemos una aplicación que funciona, estamos preparados para ponerlo dentro de un Docker Container. Para ello deberemos escribir nuestro fichero Dockerfile.


FROM node:4.4
COPY server.js .
CMD node server.js 

Antes de crear nuestro Container, verificamos los Containers que tenemos en nuestro Docker Repositories local.


$ sudo docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE



Podemos comprobar que no tenemos todavía ningún Container en nuestro repositorio local. Vamos a crear nuestro Container de la siguiente manera:


$ sudo docker build –f ./apps/hello/v1/Dockerfile -t hello ./apps/hello/v1/

Sending build context to Docker daemon 3.072 kB
Step 1 : FROM node:4.4
 ---> 93b396996a16
Step 2 : COPY server.js .
 ---> 8c7386f8eb24
Removing intermediate container d8e1d8b25b14
Step 3 : CMD node server.js
 ---> Running in d01acd103abe
 ---> d441bcd0d3ee
Removing intermediate container d01acd103abe
Successfully built d441bcd0d3ee

$ sudo docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello               latest              d441bcd0d3ee        3 seconds ago       647.5 MB
node                4.4                 93b396996a16        6 weeks ago         647.5 MB


Ahora que vemos que se ha creado el Container, procedemos a ejecutarlo y lanzar otra petición.


$ sudo docker run -d --name=hello hello

81bc525278dd4d04c3ccc6c2af77b2426754c05760d19e14dad7447cd2c3fb0a

$ curl http://localhost:8080

curl: (7) Failed to connect to localhost port 8080: Connection refused

$ sudo docker stop hello

Hello

$ sudo docker rm hello

hello


Vemos que la llamada que hemos realizado ha fallado al intentar realizar una conexión por el puerto 8080. Para entender este problema daremos unas nociones sobre el networking en Docker.

Para simplificar, todos los Containers de Docker internamente tienen su propio adaptador de red, es decir, tienen su propia IP y espacio de puertos dentro de una red virtual que monta Docker. Esta IP solo es accesible dentro del Container y por lo tanto el espacio de puertos también.

Entonces, como es posible que desde fuera del Container, podamos realizar una petición a la aplicación que se encuentra escuchando peticiones por el puerto 8080 dentro del Container? Solo podemos realizar peticiones desde dentro del Container?

Docker proporciona un mecanismo para abrir un túnel entre la red de la máquina donde está corriendo el Container (máquina Host) y la red interna del Container. Este mecanismo llamado Docker Bridge funciona básicamente indicando el puerto que se expone dentro del Container e indicando en que puerto, del espacio de puertos de la máquina Host, queremos exponer el servicio. Docker Bridge realizará un túnel que redireccionará todas las peticiones recibidas en la IP Host por el puerto que expondremos y las redireccionará al puerto que se expone dentro del Container.




Dado que puede ser un poco confuso entender esto, mejor lo vemos con un ejemplo. Ahora arrancaremos el contenedor y expondremos en la máquina host el puerto 9090 y lo mapearemos contra el 8080 del Container.


$ sudo docker run -d -p 9090:8080 --name=hello hello

c3c5dcf61109d2783fc41e792104c03942001f809da6d97b70d6edb73df1f54e

$ curl http://localhost:9090

Hello World!

$ sudo docker stop hello

hello

$ sudo docker rm hello

hello


Podemos ver que ahora sin ningún problema podemos acceder.


En algunos casos, podría interesar que el Container no tenga una red interna y use directamente la interface de red de la máquina Host, por lo que el concepto del bridge desaparecería y el Container trabajaría directamente sobre la IP y espacio de puertos de la máquina Host. Para este escenario, Docker proporciona un mecanismo para ignorar el Bridge y que el Container trabaje directamente sobre la interface de red de la máquina Host, como veremos en el siguiente ejemplo:



$ sudo docker run -d –-net=host --name=hello hello

c3c5dcf61109d2783fc41e792104c03942001f809da6d97b70d6edb73df1f54e

$ curl http://localhost:8080

Hello World!

$ sudo docker stop hello

hello

$ sudo docker rm hello

hello



Tras indicar el parámetro “--net=host” en el arranque del Container, este le indica a Docker que no use un Bridge y se trabaje directamente sobre la interface de red de la máquina Host. Una vez arrancado podemos ver que llamando directamente sobre el 8080 tenemos visibilidad.


A pesar que esta característica pueda parecer demasiado detallista para un ejemplo de los primeros pasos con Docker, se ha querido explicar, dado que Kubernetes arranca los Container sin Bridge. Estas características de la integración de Kubernetes con Docker las veremos en posteriores ejemplos, pero es importante que se entienda estos conceptos de networking.

A continuación mostramos los comandos para limpiar todo lo que hemos realizado.



$ sudo docker rmi –f hello

Untagged: hello:latest
Deleted: sha256:c613533d961b29252c0afa447b5473360d432266fa2ac712a895c8ac34d60132
Deleted: sha256:6e68b75e65eb85dffb49d6435426857ce000745d9b78b8cf50003902051d560b

$ sudo docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
node                4.4                 93b396996a16        6 weeks ago         647.5 MB

$ sudo docker rmi -f node:4.4

Untagged: node:4.4
Untagged: node@sha256:e720e944ce6994a461cd2a9e0ae34c4bc45c0f9ee7b3f48052933182fc5f0bf1
Deleted: sha256:93b396996a16fb7b0fe1a4163e8088aaec32c7061b06c9dcc2070afd656ddf7f 

$ sudo docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

No hay comentarios