Estoy tratando de crear un contenedor Docker que actúe como una máquina virtual completa. Sé que puedo usar la instrucción EXPOSE dentro de un Dockerfile para exponer un puerto, y puedo usar la -p
bandera con docker run
para asignar puertos, pero una vez que un contenedor se está ejecutando, ¿hay un comando para abrir / asignar puertos adicionales en vivo?
Por ejemplo, supongamos que tengo un contenedor Docker que ejecuta sshd. Alguien más está usando el contenedor ssh's e instala httpd. ¿Hay alguna manera de exponer el puerto 80 en el contenedor y asignarlo al puerto 8080 en el host, para que las personas puedan visitar el servidor web que se ejecuta en el contenedor, sin reiniciarlo?
Respuestas:
No puede hacer esto a través de Docker, pero puede acceder al puerto no expuesto del contenedor desde la máquina host.
si tiene un contenedor que tiene algo ejecutándose en su puerto 8000, puede ejecutar
Para obtener la dirección IP del contenedor, ejecute los 2 comandos:
Internamente, Docker se abre para llamar a iptables cuando ejecuta una imagen, por lo que tal vez alguna variación al respecto funcione.
para exponer el puerto 8000 del contenedor en su puerto localhosts 8001:
Una forma de resolver esto es configurar otro contenedor con el mapeo de puertos que desee y comparar la salida del comando iptables-save (aunque tuve que eliminar algunas de las otras opciones que obligan al tráfico a pasar por la ventana acoplable apoderado).
NOTA: esto está subvirtiendo la ventana acoplable, por lo que debe hacerse con la conciencia de que bien puede crear humo azul
O
Otra alternativa es buscar la opción (nueva? Post 0.6.6?) -P, que utilizará puertos de host aleatorios y luego los conectará.
O
con 0.6.5, podría usar la función LINKs para abrir un nuevo contenedor que se comunique con el existente, con alguna transmisión adicional a las banderas -p de ese contenedor. (Todavía no he usado LINKs)
O
con docker 0.11? puede usar
docker run --net host ..
para adjuntar su contenedor directamente a las interfaces de red del host (es decir, net no está espaciado de nombres) y, por lo tanto, todos los puertos que abre en el contenedor están expuestos.fuente
CONTAINER_IP=$(docker inspect container_name | jq .[0].NetworkSettings.IPAddress | sed -r 's/\"([^\"]+)\"/\1/''])'); iptables -t nat -A DOCKER -p tcp --dport 8001 -j DNAT --to-destination ${CONTAINER_IP}:8000
jq
ysed
puede usar la-f
opción dedocker inspect
:CONTAINER_IP=$(docker inspect -f '{{ .NetworkSettings.IPAddress }}' container_name)
jshon -e 0 -e NetworkSettings -e Networks -e bridge -e IPAddress -u
Esto es lo que haría:
fuente
sudo docker
y no solodocker
?docker commit
, estaba listo para probar la aplicación nuevamente en lugar de pasar horas para reinstalar todo.Si bien no puede exponer un nuevo puerto de un contenedor existente , puede iniciar un nuevo contenedor en la misma red de Docker y hacer que reenvíe el tráfico al contenedor original.
Ejemplo trabajado
Inicie un servicio web que escuche en el puerto 80, pero no exponga su puerto interno 80 (¡Uy!):
Encuentra su IP de red Docker:
Inicie
verb/socat
con el puerto 8080 expuesto y haga que reenvíe el tráfico TCP al puerto 80 de esa IP:Ahora puede acceder a pastebin en http: // localhost: 8080 / , y sus solicitudes van a
socat:1234
donde lo reenvíapastebin:80
, y la respuesta recorre la misma ruta en reversa.fuente
verb/socat:alpine
, ya que su imagen tiene el 5% de la huella (a menos que se encuentre con incompatibilidades de libc o DNS ).alpine/socat
--net myfoldername_default
a miverb/socat
comando de lanzamiento desde que comencé el contenedor no expuesto en una composición acoplable que crea una red.Los hacks de IPtables no funcionan, al menos en Docker 1.4.1.
La mejor manera sería ejecutar otro contenedor con el puerto expuesto y retransmitir con socat. Esto es lo que he hecho para conectarme (temporalmente) a la base de datos con SQLPlus:
Dockerfile:
fuente
FROM
imagen base que su contenedor de base de datos, para un uso eficiente de los recursos.Aquí hay otra idea. Use SSH para hacer el reenvío de puertos; Esto tiene la ventaja de trabajar también en OS X (y probablemente en Windows) cuando su host Docker es una VM.
fuente
Tuve que lidiar con este mismo problema y pude resolverlo sin detener ninguno de mis contenedores en ejecución. Esta es una solución actualizada a partir de febrero de 2016, utilizando Docker 1.9.1. De todos modos, esta respuesta es una versión detallada de la respuesta de @ ricardo-branco, pero en mayor profundidad para los nuevos usuarios.
En mi caso, quería conectarme temporalmente a MySQL que se ejecuta en un contenedor, y dado que otros contenedores de aplicaciones están vinculados a él, detener, reconfigurar y volver a ejecutar el contenedor de la base de datos no fue un iniciador.
Como me gustaría acceder a la base de datos MySQL externamente (desde Sequel Pro a través de túneles SSH), voy a usar el puerto
33306
en la máquina host. (No3306
, solo en caso de que se esté ejecutando una instancia externa de MySQL).Aproximadamente una hora de ajuste de iptables resultó infructuoso, aunque:
Paso a paso, esto es lo que hice:
Editar
dockerfile
, colocando esto dentro:Luego construye la imagen:
Luego ejecútelo, vinculándolo a su contenedor en ejecución. (Use en
-d
lugar de-rm
mantenerlo en segundo plano hasta que se detenga y elimine explícitamente. Solo quiero que se ejecute temporalmente en este caso).fuente
Para agregar a la solución de respuesta aceptada
iptables
, tuve que ejecutar dos comandos más en el host para abrirlo al mundo exterior.Nota: Estaba abriendo el puerto https (443), mi IP interna de Docker era
172.17.0.2
Nota 2: Estas reglas son temporales y solo durarán hasta que se reinicie el contenedor
fuente
Puede usar SSH para crear un túnel y exponer su contenedor en su host.
Puede hacerlo de ambas maneras, de contenedor a host y de host a contenedor. Pero necesita una herramienta SSH como OpenSSH en ambos (cliente en uno y servidor en otro).
Por ejemplo, en el contenedor, puedes hacer
Puede encontrar la dirección IP del contenedor desde esta línea (en el contenedor):
Luego, en el host, puedes hacer:
fuente
En caso de que ninguna respuesta funcione para alguien, verifique si su contenedor de destino ya se está ejecutando en la red de acopladores:
Guárdelo para más adelante en la variable
$NET_NAME
:En caso afirmativo, debe ejecutar el contenedor proxy en la misma red.
A continuación, busque el alias del contenedor:
Guárdelo para más adelante en la variable
$ALIAS
:Ahora ejecute
socat
en un contenedor en la red$NET_NAME
para conectar al$ALIAS
puerto expuesto (pero no publicado) del contenedor ed:fuente
Puede usar una red superpuesta como Weave Net , que asignará una dirección IP única a cada contenedor y expondrá implícitamente todos los puertos a cada parte del contenedor de la red.
Weave también proporciona integración de red de host . Está deshabilitado de forma predeterminada, pero si desea acceder también a las direcciones IP del contenedor (y todos sus puertos) desde el host, puede ejecutar simplemente ejecutar
weave expose
.Divulgación completa: trabajo en Weaveworks.
fuente
Hay un práctico envoltorio HAProxy.
Esto crea un HAProxy para el contenedor de destino. pan comido.
fuente
Aquí hay algunas soluciones:
https://forums.docker.com/t/how-to-expose-port-on-running-container/3252/12
fuente
Lea primero la respuesta de Ricardo . Esto funcionó para mí.
Sin embargo, existe un escenario en el que esto no funcionará si el contenedor en ejecución se inició utilizando docker-compose. Esto se debe a que docker-compose (estoy ejecutando docker 1.17) crea una nueva red. La forma de abordar este escenario sería
docker network ls
Luego agregue lo siguiente
docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus --net network_name
fuente
No es posible hacer un mapeo de puertos en vivo, pero hay varias maneras en que puede darle a un contenedor Docker lo que equivale a una interfaz real como lo haría una máquina virtual.
Interfaces Macvlan
Docker ahora incluye un controlador de red Macvlan . Esto conecta una red Docker a una interfaz del "mundo real" y le permite asignar las direcciones de esas redes directamente al contenedor (como un modo puenteado de máquinas virtuales).
pipework
También puede asignar una interfaz real a un contenedor o configurar una interfaz secundaria en versiones anteriores de Docker.IP de enrutamiento
Si tiene control de la red, puede enrutar redes adicionales a su host Docker para usar en los contenedores.
Luego asigna esa red a los contenedores y configura su host Docker para enrutar los paquetes a través de la red docker.
Interfaz de host compartida
La
--net host
opción permite que la interfaz del host se comparta en un contenedor, pero probablemente no sea una buena configuración para ejecutar varios contenedores en un host debido a la naturaleza compartida.fuente