El mapeo de puertos es esencial para acceder a servicios dentro de contenedores Docker desde el host externo. Este artículo detalla varios métodos y consideraciones clave.
Consideraciones iniciales
- Un puerto del host solo puede mapearse a un único puerto interno del contenedor. Por ejemplo, al configurar 9000->80, no se puede usar simultáneaemnte 9000->81.
- Un puerto interno del contenedor puede recibir mapeos desde múltiples puertos del host, como 9000->80 y 9010->80.
Método 1: Mapeo durante la creación del contenedor
La opción -p permite especificar un puerto concreto del host, mientras que -P asigna un puerto aleatorio. Generalmente se prefiere -p para control explícito.
Método 2: Vinculación a una IP específica del host
Es posible restringir el acceso al mapeo a una dirección IP del host, por ejemplo, usando la IP de una interfaz de red particular.
Vincular a la IP del host
sudo docker run -d --name servidor-web2 -p 192.168.1.100:9010:80 nginx:latest
sudo docker ps
Salida muestra los mapeos: 127.0.0.1:9000->80/tcp para servidor-web1 y 192.168.1.100:9010->80/tcp para servidor-web2
Acceder a `http://127.0.0.1:9000` funcionará para servidor-web1, pero intentar `http://192.168.1.100:9000` será rechazado. Análogamente, para servidor-web2 solo se permite acceso vía `http://192.168.1.100:9010`.
</div>### Método 3: Especificación del protocolo de comunicación
Se puede indicar el protocolo (tcp o udp) al realizar el mapeo.
<div>```
# Mapeo TCP explícito
sudo docker run -d --name servicio-tcp -p 9020:80/tcp nginx:latest
# Mapeo UDP
sudo docker run -d --name servicio-udp -p 192.168.1.100:9030:80/udp nginx:latest
sudo docker ps
# servicio-tcp muestra 0.0.0.0:9020->80/tcp
# servicio-udp muestra 192.168.1.100:9030->80/udp
Nota: Un servicio diseñado para TCP (como Nginx) no será accesible mediante un mapeo UDP.
Para inspeccionar los mapeos configurados y la dirección IP interna del contenedor:
Obtener la IP interna del contenedor
sudo docker inspect servicio-tcp | grep IPAddress
Salida incluye "IPAddress": "172.17.0.3" (valor puede variar)
</div>### Método 5: Reenvío NAT con iptables para contenedores sin mapeo inicial
Cuando un contenedor se inicia sin mapeo de puertos, se puede usar iptablse en el host para redirigir tráfico.
<div>```
# Iniciar contenedor sin mapeo
sudo docker run -d --name app-interna nginx:latest
# Obtener su IP interna (ej: 172.17.0.4)
sudo docker inspect app-interna | grep IPAddress
# Configurar iptables para redirigir el puerto 9040 del host al puerto 80 del contenedor
sudo iptables -t nat -A PREROUTING -p tcp --dport 9040 -j DNAT --to-destination 172.17.0.4:80
sudo iptables -t nat -A POSTROUTING -d 172.17.0.4/32 -p tcp --sport 80 -j SNAT --to-source 192.168.1.100
sudo iptables -A INPUT -p tcp --dport 9040 -j ACCEPT
# Persistir las reglas (en sistemas basados en systemd)
sudo sh -c "iptables-save > /etc/iptables.rules"
# Reiniciar iptables o recargar reglas según el sistema
sudo systemctl restart iptables
Importante: En algunas distribuciones, asegurarse de que las reglas de rechazo ICMP en la cadena INPUT estén comentadas para evitar conflictos.
Si al iniciar un contenedor con mapeo se produce un error relacionaod con iptables (por ejemplo, "No chain/target/match by that name"), se puede solucionar reiniciando el servicio Docker y luego los contenedores.
Reiniciar todos los contenedores existentes
sudo docker start $(sudo docker ps -a -q)
Esto restablece la configuración de red de Docker y permite que los mapeos se establezcan correctamente.
</div>