Как получить IP-адрес узла докера из контейнера докера


358

Как видно из названия. Мне нужно иметь возможность получить IP-адрес хоста докера и сопоставления портов от хоста к контейнеру, и делать это внутри контейнера.


Не могли бы вы рассказать, как бы вы хотели использовать эту информацию? Вы сказали «хосты Docker» - вы запускаете Docker на нескольких хостах? Как только ваш контейнер узнает IP-адрес хоста и карт портов, что он будет делать?
Энди

Самый простой способ передать IP-адреса хоста докера в контейнер докера, я думаю, что вы должны сделать вызов внутри контейнера, используя 'docker container exec'. Предположим, что вы хотите пропинговать хост из контейнера busybox, например: $ IP = '8.8.8.8' && docker container busybox ping $ IP 'Способ узнать IP хоста, используйте то, что вам больше нравится.
SauloAlessandre

Ответы:


315
/sbin/ip route|awk '/default/ { print $3 }'

Как заметил @MichaelNeale, нет смысла использовать этот метод Dockerfile(кроме случаев, когда нам нужен этот IP только во время сборки), потому что этот IP будет жестко задан во время сборки.


49
Когда вы используете Docker Bridge (по умолчанию) для контейнеров, это выведет IP-адрес мостов, например, 172.17.42.1, а не IP-адрес хоста, такой как 192.168.1.x (я предполагаю, что ваш хост находится на домашнем NAT). Ответ @Magno Torres - это, вероятно, то, чего хотят люди в таких ситуациях, если вам нужен адрес 192.168.1.x.
Programster

2
этот RUN не будет работать так, как вы ожидаете - он будет только вычислять IP во время сборки - и будет всегда статическим и бесполезным. Это будет IP хоста сборки.
Майкл Нил

7
@ Programster, я могу предположить, что людям нужна связь между хостом докера и контейнером, это то, что может дать вам IP-мост (конечно, в стандартной «домашней» установке). Зачем кому-то нужен «реальный» IP-адрес хоста, если он может быть даже за пределами докерского моста и может быть недоступен? Это решение для всех людей, которые только что установили докер и хотят поиграть с ним в скором времени.
Спинус

1
@MichaelNeale, как и раньше, я бы предположил, что большинству людей, начинающих с докера, нужна связь между их хостом и контейнером, вот и все. Если кто-то делает «правильное» развертывание, возможно, он в любом случае не использует Docker Bridge, он использует настраиваемую сеть, и, возможно, он знает обо всех сетевых особенностях или у них настроен DNS (или любое другое обнаружение).
Спинус

1
@ spinus - но это будет допустимо только в том случае, если он работает на хосте, на котором он был создан - в этом случае - вы можете просто жестко его кодировать - или посмотреть его - я думаю, что это не полезный ответ и будет вводить в заблуждение много людей - рекомендую удалить его. (Бег RUN)
Майкл Нил

183

Начиная с версии 18.03, вы можете использовать host.docker.internalв качестве IP- адреса хоста.

Работает в Docker для Mac , Docker для Windows и, возможно, на других платформах.

Это обновление для Mac docker.for.mac.localhost, доступное с версии 17.06 и docker.for.mac.host.internalдоступное с версии 17.12, которое также может работать на этой платформе.

Обратите внимание, как и в документации для Mac и Windows , это только для целей разработки.

Например, на моем хосте установлены переменные окружения:

MONGO_SERVER=host.docker.internal

В моем docker-compose.ymlфайле у меня есть это:

version: '3'

services:
  api:
    build: ./api
    volumes:
      - ./api:/usr/src/app:ro
    ports:
      - "8000"
    environment:
      - MONGO_SERVER
    command: /usr/local/bin/gunicorn -c /usr/src/app/gunicorn_config.py -w 1 -b :8000 wsgi

2
@allanberry, к сожалению, люди Docker предпочитают не предоставлять нам независимый от платформы способ сделать это, потому что они предпочитают не использовать непреднамеренные варианты использования (например, доступ к любому сервису на локальном компьютере из контейнера Docker)
Энди

21
Я познакомился с Docker'ом как Build it однажды, запускаю его везде. Но это на самом деле неверно, так как вы всегда должны настраивать и хост-систему. Так что docker.for.mac..это бесполезно , так как в большинстве случаев не имеют среды linux- или Mac-только в вашей компании. Это смешанно, у вас есть разработчики, использующие Linux, Mac и Windows. Этот домен не имеет смысла, так как на 99% это смешанная среда хост-ОС. Я не разрабатываю контейнер под macOS и не развертываю его на сервере macOS. Я развернул его в Linux. Это то, что все делают. Так в чем же смысл docker.for.mac..?
TheFox

1
@allanberry docker.for.mac.host.internalне имеет значения, используете ли вы Docker с или без docker-compose. Я хочу использовать фиксированный хост в файлах конфигурации. IDK, например, docker.host.internalкоторый всегда указывает на IP-адрес хоста. Независимо от того, какую хост-систему я использую. В этом весь смысл использования Docker: я хочу быть автономным. Я понимаю, что это еще сложнее в macOS, потому что у вас есть другой слой между хост-системой и контейнером. Но в любом случае, на мой взгляд docker.for.mac.host.internal, бесполезно, если вы можете использовать его только для macOS.
TheFox

1
host.docker.internal действительно работает на Docker для Windows , по крайней мере, во время написания этого комментария.
Джоанлоф

1
это работает отлично, у меня есть dockerCe для окон и запуска jenkins в одном из контейнеров. Я хотел запустить команду docker в jenkins, но docker не смог подключиться на этапе добавления облака, я использовал этот tcp: //host.docker.internal: 2375 и включил «выставить демон на localhost: 2375», и он работает. сэкономил много времени. Спасибо!
Викаш

84

Обновление: в Docker для Mac , начиная с версии 18.03, вы можете использовать host.docker.internal в качестве IP- адреса хоста. Смотрите ответ Алланберри . Для предыдущих версий Docker для Mac все еще может быть полезен следующий ответ:

В Docker для Mac docker0мост не существует, поэтому другие ответы здесь могут не работать. Однако весь исходящий трафик направляется через ваш родительский хост, поэтому до тех пор, пока вы пытаетесь подключиться к IP-адресу, который он распознает как сам по себе (а док-контейнер не считает себя таким), вы должны иметь возможность подключиться. Например, если вы запускаете это с родительского компьютера, запустите:

ipconfig getifaddr en0

Это должно показать вам IP вашего Mac в его текущей сети, и ваш док-контейнер должен также иметь возможность подключиться к этому адресу. Это, конечно, неприятно, если этот IP-адрес когда-либо изменится, но вы можете добавить свой петлевой IP-адрес к вашему Mac, который контейнер не считает самим, выполнив что-то вроде этого на родительской машине:

sudo ifconfig lo0 alias 192.168.46.49

Затем вы можете проверить соединение из контейнера Docker с помощью telnet. В моем случае я хотел подключиться к удаленному серверу xdebug:

telnet 192.168.46.49 9000

Теперь, когда трафик поступает на ваш Mac с адресом 192.168.46.49 (и весь трафик, выходящий из вашего контейнера, проходит через ваш Mac), ваш Mac будет считать, что IP сам по себе. Когда вы закончите использовать этот IP-адрес, вы можете удалить псевдоним петли следующим образом:

sudo ifconfig lo0 -alias 192.168.46.49

Одна вещь, о которой следует быть осторожным, заключается в том, что док-контейнер не будет отправлять трафик на родительский хост, если он думает, что адресат трафика сам по себе. Поэтому проверьте интерфейс обратной связи внутри контейнера, если у вас возникли проблемы:

sudo ip addr show lo

В моем случае это показало, inet 127.0.0.1/8что означает, что я не мог использовать любые IP-адреса в 127.*диапазоне. Вот почему я использовал 192.168.*в приведенном выше примере. Убедитесь, что используемый вами IP-адрес не конфликтует с чем-то в вашей сети.


это очистит эти настройки обратной петли после перезагрузки системы?
Robbo_UK

@Robbo_UK Да, псевдоним петли исчезнет после перезагрузки вашего Mac.
Код командира

1
Использование этого имени хоста не имеет смысла, так как оно не работает в Docker для Linux. Почему они не добавили его и для Linux?
TheFox

Они изучают это в данный момент @TheFox: github.com/docker/libnetwork/pull/2348
Иво Перейра

46

Для тех, кто использует Docker в AWS, метаданные экземпляра для хоста по-прежнему доступны внутри контейнера.

curl http://169.254.169.254/latest/meta-data/local-ipv4

Например:

$ docker run alpine /bin/sh -c "apk update ; apk add curl ; curl -s http://169.254.169.254/latest/meta-data/local-ipv4 ; echo"
fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/community/x86_64/APKINDEX.tar.gz
v3.3.1-119-gb247c0a [http://dl-cdn.alpinelinux.org/alpine/v3.3/main]
v3.3.1-59-g48b0368 [http://dl-cdn.alpinelinux.org/alpine/v3.3/community]
OK: 5855 distinct packages available
(1/4) Installing openssl (1.0.2g-r0)
(2/4) Installing ca-certificates (20160104-r2)
(3/4) Installing libssh2 (1.6.0-r1)
(4/4) Installing curl (7.47.0-r0)
Executing busybox-1.24.1-r7.trigger
Executing ca-certificates-20160104-r2.trigger
OK: 7 MiB in 15 packages
172.31.27.238

$ ifconfig eth0 | grep -oP 'inet addr:\K\S+'
172.31.27.238

Это очень удобный метод для тех, кто использует AWS. Я использую это для настройки клиента агентов Консул и адресов привязки. Это идеальный вариант, когда вы не можете использовать хост-сеть (например, развертывание контейнеров в Elastic Beanstalk и ECS).
Ричард Клейтон

Это спасатель, спасибо. У меня были проблемы с выяснением, как обрабатывать связь между контейнерами в моем кластере ECS.
Бреннан

На Phusion Basimage (на основе Ubuntu) мне пришлось немного изменить вашу команду:ifconfig eth0 | grep -oP 'inet \K\S+'
Meuoi

25

Единственный способ - передать информацию о хосте в качестве среды при создании контейнера.

run --env <key>=<value>

19
Более конкретно, IP-адрес моста может быть передан с использованием параметра командной строки, например: -e "DOCKER_HOST=$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+')"(используя принятый ответ от unix.stackexchange.com/questions/87468/… )
ncoghlan

7
Я думаю, что это не работает в Docker для Mac / Windows. (IP-адрес моста)
zx1986

22

Это --add-hostможет быть более чистое решение (но без части порта, только хост может быть обработан с этим решением). Итак, в вашей docker runкоманде сделайте что-то вроде:

docker run --add-host dockerhost:`/sbin/ip route|awk '/default/ { print  $3}'` [my container]

https://stackoverflow.com/a/26864854/127400 )


Я сказал «сделано для этого», когда кто-то еще хотел получить запись в / etc / hosts; в этом вопросе это не совсем так. Также OP запросил «host and portmaps», и вы охватили только хост.
Брайан

Хорошо. Я был немного смущен, так как принятое решение охватывает также и основную часть. И я думаю, что ваше решение превосходит решение Spinus.
Аугунрик

это не работает, если вы хотите использовать dind - docker-in-docker. Внутренний докер будет иметь другой ip
шумный

12

Стандартные рекомендации для большинства приложений, которые хотят сделать это автоматически: нет . Вместо этого человек, выполняющий контейнер, вводит внешнее имя хоста / IP-адрес в качестве конфигурации, например, в качестве переменной среды или файла конфигурации. Позволяя пользователю вводить это дает вам наиболее портативный дизайн.

Почему это так сложно? Поскольку контейнеры по своей природе изолируют приложение от среды хоста. По умолчанию пространство сети относится именно к этому контейнеру, а сведения о хосте защищены от процесса, выполняющегося внутри контейнера, которому нельзя доверять полностью.


Существуют различные варианты в зависимости от вашей конкретной ситуации:

Если ваш контейнер работает с сетью хоста, то вы можете посмотреть таблицу маршрутизации на хосте напрямую, чтобы увидеть маршрут по умолчанию. Из этого вопроса у меня работает следующее, например:

ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p'

Пример, показывающий это с хост-сетью в контейнере, выглядит следующим образом:

docker run --rm --net host busybox /bin/sh -c \
  "ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p'"

В некоторых версиях Docker Desktop они внедрили запись DNS во встроенную виртуальную машину:

getent hosts host.docker.internal | awk '{print $1}'

Если вы работаете в облачной среде, вы можете проверить сервис метаданных у облачного провайдера, например AWS:

curl http://169.254.169.254/latest/meta-data/local-ipv4

Если вам нужен ваш внешний / интернет-адрес, вы можете запросить удаленный сервис, например:

curl ifconfig.co

Каждый из них имеет ограничения и работает только в определенных сценариях. Наиболее переносимым вариантом по-прежнему является запуск вашего контейнера с IP-адресом, введенным в качестве конфигурации, например, вот вариант, который запускал предыдущую ipкоманду на хосте и вставлял ее как переменную среды:

export HOST_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
docker run --rm -e HOST_IP busybox printenv HOST_IP

Действительно полезная curl ifconfig.coкоманда .. Спасибо :)
MadAboutProgramming

8

Если вы хотите, чтобы действительный IPадрес (не мост IP) Windowsбыл включен, и у вас есть докер 18.03(или более поздняя версия), сделайте следующее:

Запустите bash для контейнера с хоста, на котором находится имя образа nginx(работает Alpine Linux distribution):

 docker run -it nginx /bin/ash

Затем запустите внутри контейнера

/ # nslookup host.docker.internal

Name:      host.docker.internal
Address 1: 192.168.65.2

192.168.65.2это IP-адрес хоста, а не IP-адрес моста, как в spinusпринятом ответе.

Я использую здесь host.docker.internal :

Хост имеет изменяющийся IP-адрес (или не имеет, если у вас нет доступа к сети). Начиная с 18.03, мы рекомендуем подключаться к специальному DNS-имени host.docker.internal, который разрешает внутренний IP-адрес, используемый хостом. Это для целей разработки и не будет работать в производственной среде за пределами Docker для Windows.


2
Я попробовал вам решение, и кажется, что команда nslookup не может быть найдена
Sergey

@ Сергей основан на вашем изображении Alpine Linux? Если нет, то проверьте эквивалент для вашего конкретного linux distribution.
Камиль Витковски

Нет, я использую именно вашу команду - Docker запускает -it nginx / bin / ash
Сергей

Хорошо - если вы находитесь в Windows, то я переключился на linux containersи я не использую. windows containersВы можете сделать это, щелкнув правой кнопкой мыши docker iconи выбрав Switch to Linux containers. Я думаю, что это может быть важно, когда вы загружаете изображение. Если вы windows containerпроверили, удалив ли старое nginxизображение и загрузите его снова, вы получите другой контейнер. Если это все еще не работает для вас - чем вы можете попробовать установить nslookupв ash.
Камил Витковски

Если вы не можете выполнить nslookup, просто выполните команду ping. Это покажет разрешенный IP. Для меня этот ответ работает, и я просто использую это имя хоста ( host.docker.internal) из контейнера
Дмитрий Минковский

7

TLDR для Mac и Windows

docker run -it --rm alpine nslookup host.docker.internal

... печатает IP-адрес хоста ...

nslookup: can't resolve '(null)': Name does not resolve

Name:      host.docker.internal
Address 1: 192.168.65.2

подробности

На Mac и Windows вы можете использовать специальное DNS-имя host.docker.internal.

Хост имеет изменяющийся IP-адрес (или не имеет, если у вас нет доступа к сети). Начиная с 18.03, мы рекомендуем подключаться к специальному DNS-имени host.docker.internal, который разрешает внутренний IP-адрес, используемый хостом. Это для целей разработки и не будет работать в производственной среде за пределами Docker Desktop для Mac.


1
Пожалуйста, не добавляйте один и тот же ответ на несколько вопросов . Ответьте лучшим и отметьте остальных как дубликаты, как только вы заработаете достаточно репутации. Если это не дубликат, адаптируйте сообщение к вопросу и отметьте его как удаленное.
Бхаргав Рао

6

Docker для Mac Я хочу подключиться из контейнера к службе на хосте

Хост имеет изменяющийся IP-адрес (или не имеет, если у вас нет доступа к сети). Начиная с 18.03, мы рекомендуем подключаться к специальному DNS-имени host.docker.internal, который разрешает внутренний IP-адрес, используемый хостом.

Шлюз также доступен как gateway.docker.internal. https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds


5

Если вы включили удаленный API докера ( например, через ) и знаете имя хоста или IP-адрес хост-машины, это можно сделать с помощью большого количества команд bash.-Htcp://0.0.0.0:4243

Внутри пользователя моего контейнера bashrc:

export hostIP=$(ip r | awk '/default/{print $3}')
export containerID=$(awk -F/ '/docker/{print $NF;exit;}' /proc/self/cgroup)
export proxyPort=$(
  curl -s http://$hostIP:4243/containers/$containerID/json |
  node -pe 'JSON.parse(require("fs").readFileSync("/dev/stdin").toString()).NetworkSettings.Ports["DESIRED_PORT/tcp"][0].HostPort'
)

Вторая строка берет идентификатор контейнера из вашего локального /proc/self/cgroupфайла.

Третья строка выводится на хост-машину (если вы используете 4243 в качестве порта докера), а затем использует узел для анализа возвращенного JSON для DESIRED_PORT.


Это применимо только при использовании переадресации портов. Действительно HostPortможет быть полезной информацией здесь, к сожалению, HostIpможет быть0.0.0.0
Арно Энгелен

4

У меня Ubuntu 16.03. Для меня

docker run --add-host dockerhost:`/sbin/ip route|awk '/default/ { print  $3}'` [image]

это НЕ работает (неправильно внутрибрюшинно генерировала)

Мое рабочее решение было таким:

docker run --add-host dockerhost:`docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' bridge` [image]

3

Вот еще один вариант для тех, кто работает в Docker в AWS. Эта опция позволяет избежать использования apk для добавления пакета curl и экономит драгоценные 7 МБ пространства. Используйте встроенный wget (часть монолитного двоичного файла BusyBox):

wget -q -O - http://169.254.169.254/latest/meta-data/local-ipv4

3

AFAIK, в случае Docker для Linux (стандартный дистрибутив), IP-адрес хоста всегда будет 172.17.0.1 .

Самый простой способ получить его - через ifconfig(интерфейс docker0) с хоста:

ifconfig

Из докера, следующая команда из докера: ip -4 route show default | cut -d" " -f3

Вы можете быстро запустить его в докере с помощью следующей командной строки:

# 1. Run an ubuntu docker
# 2. Updates dependencies (quietly)
# 3. Install ip package   (quietly)
# 4. Shows (nicely) the ip of the host
# 5. Removes the docker (thanks to `--rm` arg)
docker run -it --rm ubuntu:19.10 bash -c "apt-get update && apt-get install iproute2 -y && ip -4 route show default | cut -d' ' -f3"

Я надеюсь, что это помогает.


2

В Linux вы можете запустить

HOST_IP=`hostname -I | awk '{print $1}'`

В macOS ваш хост-компьютер не является хостом Docker. Docker установит свою ОС в VirtualBox.

HOST_IP=`docker run busybox ping -c 1 docker.for.mac.localhost | awk 'FNR==2 {print $4}' | sed s'/.$//'`

1
Первый блок кода захватит IP-адрес контейнера, а не IP-адрес хоста
Ari

Мандок hostname -Iпредупреждает, чтобы «не делать никаких предположений о порядке вывода».
заимствовано

1

Это минималистичная реализация в Node.js для того, кто запускает хост на экземплярах AWS EC2 , используя вышеупомянутый экземпляр метаданных EC2.

const cp = require('child_process');
const ec2 = function (callback) {
    const URL = 'http://169.254.169.254/latest/meta-data/local-ipv4';
    // we make it silent and timeout to 1 sec
    const args = [URL, '-s', '--max-time', '1'];
    const opts = {};
    cp.execFile('curl', args, opts, (error, stdout) => {
        if (error) return callback(new Error('ec2 ip error'));
        else return callback(null, stdout);
    })
        .on('error', (error) => callback(new Error('ec2 ip error')));
}//ec2

и используется как

ec2(function(err, ip) {
        if(err) console.log(err)
        else console.log(ip);
    })


0

Вот как я это делаю. В этом случае он добавляет запись hosts в / etc / hosts в образе докера, указывающую taurus-host на IP-адрес моей локальной машины:

TAURUS_HOST=`ipconfig getifaddr en0`
docker run -it --rm -e MY_ENVIRONMENT='local' --add-host "taurus-host:${TAURUS_HOST}" ...

Затем из контейнера Docker сценарий может использовать имя хоста taurus-host, чтобы выйти на мою локальную машину, на которой размещен контейнер Docker.



0

Решение, которое я использую, основано на «сервере», который возвращает внешний адрес хоста Docker, когда он получает запрос http.

На «сервере»:

1) Запустите jwilder / nginx-прокси

# docker run -d -p <external server port>:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy

2) Запустить ipify контейнер

# docker run -e VIRTUAL_HOST=<external server name/address> --detach --name ipify osixia/ipify-api:0.1.0

Теперь, когда контейнер отправляет запрос http на сервер, например

# curl http://<external server name/address>:<external server port>

IP-адрес хоста Docker возвращается через ipify через заголовок http «X-Forwarded-For»

Пример (сервер ipify имеет имя «ipify.example.com» и работает на порту 80, хост докера имеет IP 10.20.30.40):

# docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
# docker run -e VIRTUAL_HOST=ipify.example.com --detach --name ipify osixia/ipify-api:0.1.0

Внутри контейнера теперь можно звонить:

# curl http://ipify.example.com
10.20.30.40


-2

В Ubuntu hostnameкоманду можно использовать со следующими параметрами:

  • -i, --ip-address адреса для имени хоста
  • -I, --all-ip-addressesвсе адреса для хоста

Например:

$ hostname -i
172.17.0.2

Для присвоения переменной можно использовать следующую однострочную строку:

IP=$(hostname -i)

Это даст вам IP-адрес контейнера Docker, а не хоста
Mario Camou

-7

С помощью https://docs.docker.com/machine/install-machine/

а) $ docker-machine ip

б) Получить IP-адрес одной или нескольких машин.

  $ docker-machine ip host_name

  $ docker-machine ip host_name1 host_name2

10
При этом извлекается IP-адрес виртуальной машины, на которой выполняются контейнеры док-станции, а не IP-адрес хоста, на котором работают контейнеры.
Спенсер Уильямс,

2
Это относится только к докеру, работающему на докер-машине. Новый Docker для Mac не работает на Docker-машине.
thomas.han
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.