Как установить статический IP-адрес в контейнере Docker?

Я вполне доволен диапазоном IP, который докер предоставляет мне по умолчанию (176.17.xx), поэтому мне не нужно создавать новый мост, я просто хочу предоставить своим контейнерам статический адрес в этом диапазоне поэтому я могу напрямую указать на него клиентские браузеры. Я попытался использовать

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

из файла Docker, и он правильно заполнил файл интерфейсов, но сам интерфейс не изменился. Фактически, запуск ifup eth0 внутри контейнера получает эту ошибку:

RTNETLINK ответы: операция не разрешена

     

Не удалось вызвать eth0

Ответ 1

Я уже ответил на это здесь fooobar.com/questions/66399/... но теперь я вижу, что этот вопрос на самом деле старше, чем предыдущий, поэтому я также скопирую ответ:

Простая версия Docker версии 1.10.1, постройте 9e83765.

Сначала вам нужно создать свою собственную докерную сеть (mynet123)

docker network create --subnet=172.18.0.0/16 mynet123

чем просто запустить изображение (я возьму ubuntu в качестве примера)

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

то в оболочке ubuntu

ip addr

Кроме того, вы можете использовать --hostname, чтобы указать имя хоста
--add-host, чтобы добавить дополнительные записи в /etc/hosts

Документы (и почему вам нужно создать сеть) на https://docs.docker.com/engine/reference/commandline/network_create/

Ответ 2

Я использую метод, написанный здесь из официальной документации Docker, и я подтвердил, что он работает:

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

$ sudo docker run -i -t --rm --net=none base /bin/bash
[email protected]:/#

# 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 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 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

Используя этот подход, я запускаю свои контейнеры всегда с net = none и устанавливаю IP-адреса с помощью внешнего script.

Ответ 3

На самом деле, несмотря на мой первоначальный сбой, ответ @MarkO'Connor был прав. Я создал новый интерфейс (docker0) в файле моего хоста /etc/network/interfaces, запустил sudo ifup docker0 на хосте, а затем запустил

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

который взял статический IP-адрес и назначил его docker0 в контейнере.

Спасибо!

Ответ 4

Контейнеры-докеры по умолчанию не имеют достаточных привилегий для управления сетевым стеком. Вы можете попробовать добавить -cap-add = NET_ADMIN в команду run, чтобы разрешить эту конкретную возможность. Или вы можете попробовать --privileged = true (предоставляет все права) для тестирования.

Другой вариант - использовать pipework с хоста.

Ответ 6

Это сработало для меня:

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

Разъяснения:

  • --cap-add=NET_ADMIN имеют права на администрирование сети (т.е. для команды /sbin/ip)

  • myimages/image1 изображение для контейнера

  • /bin/sh -c "/sbin/ip addr add 172.17.0.8 dev eth0 ; bash" Внутри контейнера запустите ip addr add 172.17.0.8 dev eth0, чтобы добавить новый ip-адрес 172.17.0.8 в этот контейнер (предостережение: используйте бесплатный ip-адрес сейчас и в будущем). Затем запустите bash, просто чтобы контейнер не был автоматически остановлен.

Bonus

Моя целевая сцена: настройте распределенное приложение с контейнерами, играющими разные роли в dist-app. "Контейнер-проводник" может самостоятельно выполнять команды докеров (внутри), чтобы при необходимости запускать и останавливать контейнеры. Каждый контейнер сконфигурирован для того, чтобы знать, где подключиться для доступа к определенной роли/контейнеру в dist-приложении (поэтому набор ip для каждой роли должен быть известен каждому партнеру).

Для этого:

  • "контейнер-проводник

изображение, созданное с помощью этого файла 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

команда сборки изображения:

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

команда запуска контейнера:

docker run -v /var/run/docker.sock:/var/run/docker.sock --name=conductor1 -d -it myimages/conductor  bash
  1. Запуск контейнеров с разными ролями.

Сначала (не обязательно) добавьте записи в /etc/hosts, чтобы найти партнеров по ip или имени (опция --add-host)

Второй (очевидно, необходимый) присваивает ip запущенному контейнеру (используйте /sbin/ip в нем)

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"

Ответ 7

Я понял, что на данном этапе вы не смотрите на создание сетей с несколькими узлами, но я считаю, что вам, скорее всего, понадобится это в ближайшее время. Weave позволит вам сначала определить несколько контейнерных сетей на одном хосте, а затем потенциально переместить некоторые контейнеры на другой хост без потери статического IP-адреса присвоили ему.

Ответ 8

pipework также отлично, но если вы можете использовать имя хоста, отличное от ip, тогда вы можете попробовать этот 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

Вам просто нужно запускать эту команду каждый раз, когда вы загружаете свои докерные лаборатории Здесь вы можете найти мои скрипты с дополнительной функцией dockerip

Ответ 9

Я обнаружил, что --net = host не всегда может быть лучшим вариантом, так как это может позволить пользователям отключить хост из контейнера! В любом случае выясняется, что причина, по которой я не мог правильно сделать это изнутри, состояла в том, что конфигурация сети была предназначена для ограничения сеансов, начинающихся с аргумента --privileged = true.

Ответ 10

Для полноты: существует другой метод, предложенный на форумах Docker. (Редактировать: и упоминается попутно по ответу от Андрея Сердюк).

Добавить статический IP-адрес в хост-системе, а затем опубликовать порты для этого ip, например. docker run -p 192.0.2.1:80:80 -d mywebserver.

Конечно, этот синтаксис не будет работать для IPv6, и в документации не упоминается, что...

Это звучит неправильно для меня: обычные групповые привязки (*: 80) на хосте теоретически конфликтуют с контейнером. На практике порт Docker имеет приоритет и не конфликтует, поскольку он реализован с использованием iptables. Но ваш публичный контейнерный IP-адрес будет по-прежнему отвечать на все не конфликтующие порты, например. SSH.