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
Publicar un comentario