Exposer un port sur un conteneur Docker en direct

J’essaie de créer un conteneur Docker qui agit comme une machine virtuelle complète. Je sais que je peux utiliser l’instruction EXPOSE dans un fichier Dockerfile pour exposer un port, et je peux utiliser l’ -p avec l’ docker run pour atsortingbuer des ports, mais une fois qu’un conteneur est en cours d’exécution, existe-t-il une commande pour ouvrir / mapper des ports supplémentaires? ?

Par exemple, disons que j’ai un conteneur Docker qui exécute sshd. Quelqu’un d’autre utilisant le conteneur ssh est installé et installe httpd. Existe-t-il un moyen d’exposer le port 80 sur le conteneur et de le mapper sur le port 8080 de l’hôte afin que les utilisateurs puissent visiter le serveur Web exécuté dans le conteneur sans le redémarrer?

Vous ne pouvez pas le faire via Docker, mais vous pouvez accéder au port non exposé du conteneur depuis la machine hôte.

si vous avez un conteneur avec quelque chose qui tourne sur son port 8000, vous pouvez exécuter

 wget http://container_ip:8000 

Pour obtenir l’adresse IP du conteneur, exécutez les 2 commandes:

 docker ps docker inspect container_name | grep IPAddress 

En interne, Docker tente d’appeler iptables lorsque vous exécutez une image.

exposer le port 8000 du conteneur sur votre port localhosts 8001:

  iptables -t nat -A DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.19:8000 

Une façon de résoudre ce problème consiste à configurer un autre conteneur avec le mappage de port souhaité et à comparer la sortie de la commande iptables-save (cependant, j’ai dû supprimer certaines des autres options qui obligent le trafic à passer par le menu fixe). Procuration).

NOTE: ceci est un subverting docker, donc devrait être fait avec la conscience qu’il peut bien créer de la fumée bleue

OU

Une autre alternative consiste à regarder l’option (nouvelle? Post 0.6.6?) -P – qui utilisera des ports hôtes aléatoires, puis les reliera.

OU

avec 0.6.5, vous pouvez utiliser la fonctionnalité LINKs pour afficher un nouveau conteneur qui communique avec l’existant, avec quelques relais supplémentaires vers les options -p de ce conteneur? (Je n’ai pas encore utilisé LINK)

OU

avec docker 0.11? Vous pouvez utiliser docker run --net host .. pour connecter votre conteneur directement aux interfaces réseau de l’hôte (par exemple, net n’est pas espacé par un nom) et ainsi tous les ports que vous ouvrez dans le conteneur sont exposés.

Voici ce que je ferais:

  • Validez le conteneur en direct.
  • Exécutez à nouveau le conteneur avec la nouvelle image, avec les ports ouverts (je vous recommande de monter un volume partagé et d’ouvrir également le port ssh)
 sudo docker ps sudo docker commit   sudo docker run -i -p 22 -p 8000:80 -m /data:/data -t  /bin/bash 

Voici une autre idée. Utilisez SSH pour effectuer le transfert de port; Cela présente l’avantage de fonctionner également sous OS X (et probablement Windows) lorsque votre hôte Docker est une machine virtuelle.

 docker exec -it  ssh -R5432:localhost:5432 @ 

Les hacks IPtables ne fonctionnent pas, au moins sur Docker 1.4.1.

Le meilleur moyen serait de lancer un autre conteneur avec le port exposé et de relayer avec socat. C’est ce que j’ai fait pour (temporairement) me connecter à la firebase database avec SQLPlus:

 docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus 

Dockerfile:

 FROM debian:7 RUN apt-get update && \ apt-get -y install socat && \ apt-get clean USER nobody CMD socat -dddd TCP-LISTEN:1521,reuseaddr,fork TCP:db:1521 

Bien que vous ne puissiez pas exposer un nouveau port d’un conteneur existant , vous pouvez démarrer un nouveau conteneur sur le même réseau Docker et le faire transférer le trafic vers le conteneur d’origine.

 # docker run \ --rm \ -p $PORT:1234 \ verb/socat \ TCP-LISTEN:1234,fork \ TCP-CONNECT:$TARGET_CONTAINER_IP:$TARGET_CONTAINER_PORT 

Exemple travaillé

Lancez un service Web qui écoute sur le port 80, mais n’exposez pas son port interne 80 (oops!):

 # docker run -ti mkodockx/docker-pastebin # Forgot to expose PORT 80! 

Trouver son réseau IP Docker:

 # docker inspect 63256f72142a | grep IPAddress "IPAddress": "172.17.0.2", 

Lancez verb/socat avec le port 8080 exposé, et verb/socat à transférer le trafic TCP vers le port 80 de cet IP:

 # docker run --rm -p 8080:1234 verb/socat TCP-LISTEN:1234,fork TCP-CONNECT:172.17.0.2:80 

Vous pouvez maintenant accéder à pastebin sur http: // localhost: 8080 / et vos demandes vont à socat:1234 qui le transmet à pastebin:80 , et la réponse parcourt le même chemin en sens inverse.

J’ai dû faire face à ce problème et j’ai pu résoudre le problème sans arrêter aucun de mes conteneurs en cours d’exécution. Il s’agit d’une solution à jour en date de février 2016, utilisant Docker 1.9.1. Quoi qu’il en soit, cette réponse est une version détaillée de la réponse de @ricardo-branco, mais plus approfondie pour les nouveaux utilisateurs.

Dans mon scénario, je souhaitais me connecter temporairement à MySQL en cours d’exécution dans un conteneur et, étant donné que d’autres conteneurs d’applications y sont liés, l’arrêt, la reconfiguration et la ré-exécution du conteneur de firebase database n’était pas un début.

Comme je voudrais accéder à la firebase database MySQL en externe (à partir de Sequel Pro via tunneling SSH), je vais utiliser le port 33306 sur la machine hôte. (Pas 3306 , juste au cas où une instance externe de MySQL serait en cours d’exécution.)

Environ une heure de réglage d’ iptables s’est avérée infructueuse, même si:

Pas à pas, voici ce que j’ai fait:

 mkdir db-expose-33306 cd db-expose-33306 vim Dockerfile 

Modifiez dockerfile en le plaçant à l’intérieur:

 # Exposes port 3306 on linked "db" container, to be accessible at host:33306 FROM ubuntu:latest # (Recommended to use the same base as the DB container) RUN apt-get update && \ apt-get -y install socat && \ apt-get clean USER nobody EXPOSE 33306 CMD socat -dddd TCP-LISTEN:33306,reuseaddr,fork TCP:db:3306 

Ensuite, construisez l’image:

 docker build -t your-namespace/db-expose-33306 . 

Ensuite, lancez-le, en vous connectant à votre conteneur en cours d’exécution. (Utilisez -d place de -rm pour le garder en arrière-plan jusqu’à ce qu’il soit explicitement arrêté et supprimé. Je ne le souhaite que temporairement dans ce cas.)

 docker run -it --rm --name=db-33306 --link the_live_db_container:db -p 33306:33306 your-namespace/db-expose-33306 

Pour append à la solution de réponse iptables acceptée , j’ai dû exécuter deux commandes supplémentaires sur l’hôte pour l’ouvrir au monde extérieur.

 HOST> iptables -t nat -A DOCKER -p tcp --dport 443 -j DNAT --to-destination 172.17.0.2:443 HOST> iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source 172.17.0.2 --destination 172.17.0.2 --dport https HOST> iptables -A DOCKER -j ACCEPT -p tcp --destination 172.17.0.2 --dport https 

Remarque: 172.17.0.2 port https (443), mon adresse IP interne du 172.17.0.2 était 172.17.0.2

Note 2: Ces règles et temporelles ne dureront que lorsque le conteneur sera redémarré

Vous pouvez utiliser SSH pour créer un tunnel et exposer votre conteneur sur votre hôte.

Vous pouvez le faire dans les deux sens, du conteneur à l’hôte et de l’hôte au conteneur. Mais vous avez besoin d’un outil SSH comme OpenSSH dans les deux (client dans l’un et serveur dans un autre).

Par exemple, dans le conteneur, vous pouvez faire

 $ yum install -y openssh openssh-server.x86_64 service sshd restart Stopping sshd: [FAILED] Generating SSH2 RSA host key: [ OK ] Generating SSH1 RSA host key: [ OK ] Generating SSH2 DSA host key: [ OK ] Starting sshd: [ OK ] $ passwd # You need to set a root password.. 

Vous pouvez trouver l’adresse IP du conteneur à partir de cette ligne (dans le conteneur):

 $ ifconfig eth0 | grep "inet addr" | sed 's/^[^:]*:\([^ ]*\).*/\1/g' 172.17.0.2 

Ensuite, dans l’hôte, vous pouvez simplement faire:

 sudo ssh -NfL 80:0.0.0.0:80 [email protected] 

Vous pouvez utiliser un réseau superposé tel que Weave Net , qui atsortingbuera une adresse IP unique à chaque conteneur et exposera implicitement tous les ports à chaque conteneur du réseau.

Weave fournit également une intégration réseau hôte . Il est désactivé par défaut mais, si vous souhaitez également accéder aux adresses IP du conteneur (et à tous ses ports) depuis l’hôte, vous pouvez exécuter simplement exécuter weave expose .

Divulgation complète: je travaille chez Weaveworks.

Il existe un wrapper HAProxy très pratique.

 docker run -it -p LOCALPORT:PROXYPORT --rm --link TARGET_CONTAINER:EZNAME -e "BACKEND_HOST=EZNAME" -e "BACKEND_PORT=PROXYPORT" demandbase/docker-tcp-proxy 

Cela crée un HAProxy dans le conteneur cible. peasy facile.

Lisez d’abord la réponse de Ricardo . Cela a fonctionné pour moi.

Cependant, il existe un scénario où cela ne fonctionnera pas si le conteneur en cours d’exécution a été lancé à l’aide de docker-compose. Cela est dû au fait que docker-compose (j’utilise docker 1.17) crée un nouveau réseau. La façon de traiter ce scénario serait

docker network ls

Ajoutez ensuite le docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus --net network_name suivant, docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus --net network_name

Il n’est pas possible de faire un mappage de port en direct, mais il existe de nombreuses manières de donner à un conteneur Docker une interface réelle comme une machine virtuelle.

Interfaces Macvlan

Docker inclut désormais un pilote réseau Macvlan . Cela attache un réseau Docker à une interface “réelle” et vous permet d’atsortingbuer les adresses de réseaux directement au conteneur (comme un mode pont de machines virtuelles).

 docker network create \ -d macvlan \ --subnet=172.16.86.0/24 \ --gateway=172.16.86.1 \ -o parent=eth0 pub_net 

pipework peut également mapper une interface réelle dans un conteneur ou configurer une sous-interface dans les anciennes versions de Docker.

IP de routage

Si vous contrôlez le réseau, vous pouvez acheminer des réseaux supplémentaires vers votre hôte Docker pour les utiliser dans les conteneurs.

Ensuite, vous affectez ce réseau aux conteneurs et configurez votre hôte Docker pour acheminer les paquets via le réseau Docker.

Interface hôte partagé

L’option --net host permet à l’interface hôte d’être partagée dans un conteneur, mais ce n’est probablement pas une bonne configuration pour exécuter plusieurs conteneurs sur un hôte en raison de la nature partagée.

Si aucune réponse ne fonctionne pour quelqu’un, vérifiez si votre conteneur cible est déjà en cours d’exécution dans le réseau docker:

 docker inspect my-target-container | grep NetworkMode "NetworkMode": "my-network-name", 

Si oui, vous devez exécuter le conteneur proxy sur le même réseau.

 docker inspect my-target-container | grep -A2 Aliases "Aliases": [ "my-alias", "23ea4ea42e34a" 

Commande finale:

 docker run --net my-network-name --name my-new-proxy \ -d -p 8080:1234 alpine/socat TCP-LISTEN:1234,fork TCP-CONNECT:my-alias:80 

Pour moi, le meilleur moyen consiste à modifier directement le fichier de configuration du conteneur, voir Comment atsortingbuer un mappage de port à un conteneur Docker existant? , appuyez sur Ctrl + F et trouvez “json” .

Utilisez la commande suivante pour lancer votre conteneur:

 docker run -d -p : -t  
  • est votre numéro de port localhost.
  • est le numéro de port exposé dans le fichier Docker pour ce conteneur.

Il y a aussi l’indicateur -P qui est assez récent et indique à Docker de mapper tous les ports réseau requirejs dans notre conteneur à notre hôte. Cela peut vous aider à visualiser votre application Web du monde extérieur.

Lorsque vous vous connectez à un port, Docker le redirige pour vous. En utilisant la commande du port Docker, vous verrez quelque chose comme ceci:

 docker port 5019f8e8f902 5000/tcp -> 0.0.0.0:49162 5555/tcp -> 0.0.0.0:49163 8080/tcp -> 0.0.0.0:49164