Ya hemos hablado, en anteriores capítulos, de que podemos tener centenares de contenedores funcionando a la vez. Si, por ejemplo, son servidores web, ocurriría que cada uno de ellos tendría corriendo un servicio web, como Apache o Nginx. Sabemos que los puertos por defecto para estos servicios son el 80 o bien el 443 si usa una conexión web cifrada y utiliza el protocolo https. ¿Cómo hacemos para llegar a todos estos servidores web si solo tenemos su dirección privada?

La solución es la exposición de puertos, que consiste en reservar un puerto en el servidor Docker con el fin de redirigir las peticiones a un puerto específico.

Por ejemplo, podemos indicar que el puerto 80 del contenedor sea redirigido al puerto 23250 del servidor anfitrión.

Para realizar dicha tarea utilizaremos las opciones –p o –P, más los puertos indicados.

  • -P o –publish-all, selecciona un puerto libre aleatorio del servidor anfitrión donde se van a escuchar las peticiones.
  • -p o –publish-value, se debe especificar un puerto de manera manual donde deseamos realizar la escucha. Si ese puerto está en uso el contenedor fallará.

En el caso de la opción –P, Docker revisará los puertos que se han configurado en la imagen para ser expuestos y, por cada uno de ellos, generará otro aleatorio.

Veamos un ejemplo:

[root@centos7 /]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@centos7 /]# docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
fanfoni/teampass        latest              59c69279adb4        6 days ago          383MB
httpd                   latest              7239615c0645        6 days ago          177MB
teampass/teampass       latest              30e63d67f3bf        6 days ago          280MB
nickistre/centos-lamp   latest              3d8b86c3bd87        2 weeks ago         538MB
hello-world             latest              f2a91732366c        3 weeks ago         1.85kB
debian                  latest              6d83de432e98        6 weeks ago         100MB
driket54/glpi           latest              9a17476d3cbe        15 months ago       267MB
[root@centos7 /]# docker run -dti --name web1 -P 3d8b86c3bd87
07a38e60bcc2e6b786f30a6a9ee0309443b5f32a01a9d5274350e2837cb4e37e
[root@centos7 /]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                                                                  NAMES
07a38e60bcc2        3d8b86c3bd87        "supervisord -n"    4 seconds ago       Up 3 seconds        0.0.0.0:32777->22/tcp, 0.0.0.0:32776->80/tcp, 0.0.0.0:32775->443/tcp   web1
[root@centos7 /]#

Al principio no teníamos ningún contenedor funcionando. Hemos listado las imágenes disponibles y escogido “nickistre/centos-lamp”, que es una imagen de un servidor web LAMP. Generamos el contenedor, utilizando la opción “-P”, que redirecciona los puertos indicados en el contenedor a puertos aleatorios. En este caso, el contenedor tiene el puerto 80 redirigido al 32776 en el host anfitrión.

Un imagen de ejemplo del funcionamiento de la exposición de puertos:

Vamos a crear unos cuantos contenedores más pero, esta vez, indicamos el puerto que queremos utilizar de manera manual de la siguiente manera:

[root@centos7 /]# docker run -dti --name web2 -p 22140:80 -p 22141:22 -p 22143:443 3d8b86c3bd87
64e19c4957c1353190b2d2fa43e7202012913dae35e2fa43787b356dad0c42e2

Podemos ver ambos contenedores funcionando:

[root@centos7 /]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                                                                  NAMES
64e19c4957c1        3d8b86c3bd87        "supervisord -n"    4 seconds ago       Up 2 seconds        0.0.0.0:22141->22/tcp, 0.0.0.0:22140->80/tcp, 0.0.0.0:22143->443/tcp   web2
07a38e60bcc2        3d8b86c3bd87        "supervisord -n"    5 minutes ago       Up 5 minutes        0.0.0.0:32777->22/tcp, 0.0.0.0:32776->80/tcp, 0.0.0.0:32775->443/tcp   web1

A nivel de sistema operativo podemos ver que cada uno de estos contenedores tienen su propio número de proceso (pid):

[root@centos7 /]# ps -ef | grep -i docker
root     15985     1  0 12:21 ?        00:00:03 /usr/bin/dockerd
root     15990 15985  0 12:21 ?        00:00:01 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc
root     26119 15985  0 12:54 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 32775 -container-ip 172.17.0.2 -container-port 443
root     26129 15985  0 12:54 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 32776 -container-ip 172.17.0.2 -container-port 80
root     26139 15985  0 12:54 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 32777 -container-ip 172.17.0.2 -container-port 22
root     26143 15990  0 12:54 ?        00:00:00 docker-containerd-shim 07a38e60bcc2e6b786f30a6a9ee0309443b5f32a01a9d5274350e2837cb4e37e /var/run/docker/libcontainerd/07a38e60bcc2e6b786f30a6a9ee0309443b5f32a01a9d5274350e2837cb4e37e docker-runc
root     26313 15985  0 12:59 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 22143 -container-ip 172.17.0.3 -container-port 443
root     26323 15985  0 12:59 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 22140 -container-ip 172.17.0.3 -container-port 80
root     26333 15985  0 12:59 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 22141 -container-ip 172.17.0.3 -container-port 22
root     26337 15990  0 12:59 ?        00:00:00 docker-containerd-shim 64e19c4957c1353190b2d2fa43e7202012913dae35e2fa43787b356dad0c42e2 /var/run/docker/libcontainerd/64e19c4957c1353190b2d2fa43e7202012913dae35e2fa43787b356dad0c42e2 docker-runc
root     26495 25325  0 13:02 pts/0    00:00:00 grep --color=auto -i docker

Se observa también cómo el servicio “docker-proxy” se encarga de redirigir los puertos entre la IP privada del contenedor a la IP pública del servidor, con su correspondiente puerto.

Si utilizamos la herramienta “netstat” vemos los puertos de Docker que están escuchando, en este momento, en el servidor anfitrión:

[root@centos7 /]# netstat -putnoea | grep -i docker
tcp6       0      0 :::22140                :::*                    LISTEN      0          83848      26323/docker-proxy   off (0.00/0/0)
tcp6       0      0 :::22141                :::*                    LISTEN      0          83887      26333/docker-proxy   off (0.00/0/0)
tcp6       0      0 :::22143                :::*                    LISTEN      0          83809      26313/docker-proxy   off (0.00/0/0)
tcp6       0      0 :::32775                :::*                    LISTEN      0          82304      26119/docker-proxy   off (0.00/0/0)
tcp6       0      0 :::32776                :::*                    LISTEN      0          82343      26129/docker-proxy   off (0.00/0/0)
tcp6       0      0 :::32777                :::*                    LISTEN      0          82382      26139/docker-proxy   off (0.00/0/0)

Un comando muy útil, para saber que puertos utilizará un contenedor tras generarlo desde una imagen, es : “docker inspect”

[root@centos7 /]# docker inspect 30e63d67f3bf | grep -i tcp
                "443/tcp": {},
                "80/tcp": {},
                "9000/tcp": {}

No hace falta que diga que cada uno de los puertos que expongamos de los contenedores deben estar accesibles en el cortafuegos. Para ellos, si utilizamos CentOS 7, utilizando el servicio “firewalld”, sería:

[root@centos7 /]# firewall-cmd --permanent --add-port=22140/tcp
success
[root@centos7 /]# firewall-cmd --reload
success
[root@centos7 /]#

Lo dejamos por hoy. Sé que este apartado es muy técnico, pero es esencial conocerlo. En el siguiente capítulo hablaremos de cómo realizar las copias de seguridad de los contenedores. Cualquier duda u observación la podéis dejar en los comentarios.


La imagen de portada ha sido extraída de Flickr y tiene derechos de Public Domain

4.5 4 votos
Article Rating
Subscribe
Notificarme de
guest

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

8 Comments
más antiguo
más nuevo más votado
Reacciones en línea
Ver todos los comentarios
Marcelo

Hola, muchas gracias por estos artículos sobre Docker.

Si pudieras hablar sobre la persistencia de datos y compartirlos entre varios contenedores, he leído la documentación pero aún no consigo que funcione como espero.

De cualquier forma muchas gracias por su labor.

carlos

Qué tal?
Hay alguna manera de abrir puertos una vez creado y corriendo el contenedor?