web-dev-qa-db-fra.com

Comment définir une adresse IP statique dans un conteneur Docker?

Je suis parfaitement satisfait de la plage d'adresses IP que docker me fournit par défaut 176.17.x.x, je n'ai donc pas besoin de créer un nouveau pont, je veux simplement donner à mes conteneurs une adresse statique entre cette plage afin que je puisse pointer directement les navigateurs clients sur celle-ci. J'ai essayé d'utiliser

RUN echo "auto eth0" >> /etc/network/interfaces
RUN echo "iface eth0 inet static" >> /etc/network/interfaces
RUN echo "address 176.17.0.250" >> /etc/network/interfaces
RUN echo "netmask 255.255.0.0" >> /etc/network/interfaces
RUN ifdown eth0
RUN ifup eth0

à partir d'un fichier Docker, et il a correctement rempli le fichier d'interface, mais l'interface elle-même n'a pas changé. En fait, exécuter ifup eth0 dans le conteneur génère cette erreur:

RTNETLINK répond: Opération non autorisée Échec de l'affichage de eth0

41
dlanced

J'ai déjà répondu à cette question ici https://stackoverflow.com/a/35359185/4094678 mais je vois maintenant que cette question est en fait plus ancienne que celle susmentionnée, je vais donc copier la réponse également :

Facile avec Docker version 1.10.1, build 9e83765.

Vous devez d’abord créer votre propre réseau de dockers (mynet123)

docker network create --subnet=172.18.0.0/16 mynet123

que simplement lancer l'image (je prends Ubuntu comme exemple)

docker run --net mynet123 --ip 172.18.0.22 -it ubuntu bash

puis dans Ubuntu Shell

ip addr

En outre, vous pouvez utiliser
--hostname pour spécifier un nom d'hôte
--add-Host pour ajouter plus d'entrées à /etc/hosts

Docs (et pourquoi vous devez créer un réseau) sur https://docs.docker.com/engine/reference/commandline/network_create/

29
cantSleepNow

J'utilise la méthode écrite ici de la documentation officielle de Docker et j'ai confirmé que cela fonctionne:

# At one Shell, start a container and
# leave its Shell idle and running

$ Sudo docker run -i -t --rm --net=none base /bin/bash
root@63f36fc01b5f:/#

# At another Shell, learn the container process ID
# and create its namespace entry in /var/run/netns/
# for the "ip netns" command we will be using below

$ Sudo docker inspect -f '{{.State.Pid}}' 63f36fc01b5f
2778
$ pid=2778
$ Sudo mkdir -p /var/run/netns
$ Sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid

# Check the bridge's IP address and netmask

$ ip addr show docker0
21: docker0: ...
inet 172.17.42.1/16 scope global docker0
...

# Create a pair of "peer" interfaces A and B,
# bind the A end to the bridge, and bring it up

$ Sudo ip link add A type veth peer name B
$ Sudo brctl addif docker0 A
$ Sudo ip link set A up

# Place B inside the container's network namespace,
# rename to eth0, and activate it with a free IP

$ Sudo ip link set B netns $pid
$ Sudo ip netns exec $pid ip link set dev B name eth0
$ Sudo ip netns exec $pid ip link set eth0 up
$ Sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0
$ Sudo ip netns exec $pid ip route add default via 172.17.42.1

En utilisant cette approche, je lance toujours mes conteneurs avec net = none et définit les adresses IP avec un script externe.

13
unlink

En fait, malgré mon échec initial, la réponse de @ MarkO'Connor était correcte. J'ai créé une nouvelle interface (docker0) dans mon fichier d'hôte/etc/network/interfaces, j'ai lancé Sudo ifup docker0 sur l'hôte et then a exécuté

docker run --net=Host -i -t ... 

qui a ramassé l’adresse IP statique et l’a attribué à docker0 dans le conteneur.

Merci!

6
dlanced

Les conteneurs Docker par défaut ne disposent pas des privilèges suffisants pour manipuler la pile réseau. Vous pouvez essayer d'ajouter --cap-add=NET_ADMIN à la commande run pour autoriser cette capacité spécifique. Ou vous pouvez essayer --privileged=true (accorde tous les droits) pour le test.

Une autre option consiste à utiliser tuyauterie à partir de l'hôte.

4
user2105103

Cela a fonctionné pour moi:

docker run --cap-add=NET_ADMIN -d -it myimages/image1  /bin/sh -c "/sbin/ip addr add 172.17.0.8 dev eth0;  bash"

A expliqué:

  • --cap-add=NET_ADMIN ont le droit d’administrer le réseau (c.-à-d. pour le /sbin/ip commande)

  • myimages/image1 image pour le conteneur

  • /bin/sh -c "/sbin/ip addr add 172.17.0.8 dev eth0 ; bash" À l'intérieur du conteneur, exécutez ip addr add 172.17.0.8 dev eth0 pour ajouter une nouvelle adresse ip 172.17.0.8 à ce conteneur (attention: utilisez une adresse ip libre maintenant et à l'avenir ). Ensuite, lancez bash, juste pour que le conteneur ne soit pas arrêté automatiquement.

Bonus:

Ma scène cible: configurer une application distribuée avec des conteneurs jouant différents rôles dans l'application dist. Un "conteneur de conducteur" est capable d'exécuter des commandes docker lui-même (à l'intérieur) afin de démarrer et d'arrêter les conteneurs selon les besoins. Chaque conteneur est configuré pour savoir où se connecter pour accéder à un rôle/conteneur particulier dans l'application dist (ainsi, l'ensemble des adresses IP de chaque rôle doit être connu de chaque partenaire).

Pour faire ça:

  1. "conteneur de conducteur"

image créée avec ce Dockerfile

FROM pin3da/docker-zeromq-node
MAINTAINER Foobar

# install docker software  
RUN apt-get -yqq update && apt-get -yqq install docker.io 

# export /var/run/docker.sock  so we can connect it in the Host
VOLUME /var/run/docker.sock

commande de construction d'image:

docker build --tag=myimages/conductor --file=Dockerfile .

commande d'exécution du conteneur:

docker run -v /var/run/docker.sock:/var/run/docker.sock --name=conductor1 -d -it myimages/conductor  bash
  1. Exécuter des conteneurs avec des rôles différents.

D'abord (pas absolument nécessaire) ajoutez des entrées à /etc/hosts pour localiser les partenaires par ip ou par nom (option --add-Host)

Second (évidemment requis) attribuer une adresse IP au conteneur en cours d’exécution (utilisez /sbin/ip dedans)

docker run --cap-add=NET_ADMIN --add-Host worker1:172.17.0.8 --add-Host worker2:172.17.0.9 --name=worker1 -h worker1.example.com -d -it myimages/image1  /bin/sh -c "/sbin/ip addr add 172.17.0.8 dev eth0;  bash"
3
cibercitizen1

& avec tuyauterie (192.168.1.1 ci-dessous étant le default gateway adresse IP):

pipework br0 container-name 192.168.1.10/[email protected]

Edit: ne commence pas par --net=none: ceci ferme les ports de conteneur.

Voir notes complémentaires

3
Stuart Cardall

pipework est également très bien, mais si vous pouvez utiliser un nom d’hôte autre que ip, vous pouvez essayer ce script

#!/bin/bash
# This function will list all ip of running containers
function listip {
    for vm in `docker ps|tail -n +2|awk '{print $NF}'`; 
        do
            ip=`docker inspect --format '{{ .NetworkSettings.IPAddress }}' $vm`;
            echo "$ip  $vm";
        done    
}

# This function will copy hosts file to all running container /etc/hosts
function updateip {
        for vm in `docker ps|tail -n +2|awk '{print $NF}'`;
                do
                        echo "copy hosts file to  $vm";
                        docker exec -i $vm sh -c 'cat > /etc/hosts' < /tmp/hosts
                done
}

listip > /tmp/hosts
updateip

Vous devez juste exécuter cette commande chaque fois que vous démarrez vos laboratoires de docker. Vous pouvez trouver mes scripts avec une fonction supplémentaire ici dockerip

2
Phan Dolphy

J'ai cru comprendre que vous ne cherchiez pas à mettre en réseau plusieurs conteneurs de conteneurs à ce stade, mais je pense que vous en aurez probablement besoin bientôt. Weave vous permettrait de définir d’abord plusieurs réseaux de conteneurs sur un hôte, puis de déplacer éventuellement certains conteneurs vers un autre hôte sans perdre l’adresse IP statique que vous lui avez attribuée.

2
errordeveloper

J'ai découvert que --net=Host _ n'est peut-être pas toujours la meilleure option car cela pourrait permettre aux utilisateurs d'arrêter l'hôte à partir du conteneur! Quoi qu’il en soit, il s’est avéré que la raison pour laquelle je ne pouvais pas le faire correctement de l’intérieur était parce que la configuration du réseau avait été conçue pour être limitée aux sessions commençant par le --privileged=true argument.

1
dlanced

Pour être complet, une autre méthode est proposée sur les forums Docker. (Edit: et mentionné en passant par la réponse de Андрей Сердюк).

Ajoutez l’adresse IP statique sur le système hôte, puis publiez les ports sur cette adresse IP, par exemple. docker run -p 192.0.2.1:80:80 -d mywebserver.

Bien sûr, cette syntaxe ne fonctionnera pas pour IPv6 et la documentation ne le mentionne pas ...

Cela me semble faux: le caractère générique habituel se lie (*: 80) sur l'hôte, est théoriquement en conflit avec le conteneur. En pratique, le port Docker a la priorité et n’entre pas en conflit, en raison de la façon dont il est implémenté avec iptables. Mais votre IP de conteneur public répondra toujours sur tous les non - ports en conflit, par exemple. ssh.

1
sourcejedi

Vous pouvez configurer SkyDns avec l'outil de découverte de service - https://github.com/crosbymichael/skydock

Ou: Créez simplement une interface réseau et publiez des ports de conteneur docker comme ici https://Gist.github.com/andreyserdjuk/bd92b5beba2719054dfe