Як отримати IP-адресу докерного хоста зсередини докерного контейнера


358

Як говориться в назві. Мені потрібно мати можливість отримати IP-адресу хостів докера та порт-карти від хоста до контейнера і робити це всередині контейнера.


Чи можете ви детальніше розказати, як ви хочете використовувати цю інформацію? Ви сказали, що "хокери докера" - ви керуєте Docker на кількох хостах? Як тільки ваш контейнер дізнається IP-адресу хоста та порт-карти, що це зробить?
Енді

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

Відповіді:


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

Як зауважив @MichaelNeale, немає сенсу використовувати цей метод у Dockerfile(за винятком випадків, коли нам потрібен цей IP лише під час збирання), оскільки цей IP буде жорстко кодований протягом часу збирання.


49
Коли ви використовуєте докерний міст (за замовчуванням) для контейнерів, це виведе 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, як і раніше, я вважаю, що більшість людей, які починають з докера, потребують зв'язку між своїм хостом і контейнером, ось і все. Якщо хтось робить "належні" розгортання, ймовірно, він все одно не використовує докерний міст, він використовує власну мережу, і, мабуть, він знає про всі мережеві химерності або у них встановлено DNS (або будь-яке відкриття).
спінус

1
@spinus - але це буде дійсно лише в тому випадку, якщо він працює на хості, на якому він був побудований - у такому випадку - ви можете просто жорстко кодувати його - або шукати - я думаю, що це не корисна відповідь і введе в оману багато людей - рекомендую видалити його. (Біт RUN)
Майкл Ніл

182

З версії 18.03 ви можете використовувати host.docker.internalIP-адресу хоста.

Працює в 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, на жаль, люди з Докера воліють не давати нам незалежно від платформи робити це, оскільки вони воліють не приймати випадки випадкового використання (як-от доступ до будь-якої служби на локальній машині з док-контейнера)
Енді

21
Мене познайомили з Docker, як Build it Once, запускайте його скрізь. Але це гостро помилково, оскільки завжди потрібно також налаштувати хост-систему. Це docker.for.mac..марно, оскільки у більшості випадків у вашій компанії немає середовища лише для Linux або Mac. Це неоднозначно, у вас є розробники, які використовують Linux та Mac та Windows. Цей домен не має сенсу, оскільки в 99% це змішане середовище Host OS. Я не розробляю контейнер під macOS і розгортаю його на сервері macOS. Я розгортаю його в Linux. Це те, що роблять усі. Тож у чому навіть вся суть docker.for.mac..?
TheFox

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

1
host.docker.internal також працює над Docker для Windows , принаймні під час написання цього коментаря.
joanlofe

1
це прекрасно працює, у мене є докерСе для вікон та запущених джинкінів в одному з контейнерів. Я хотів запустити команду docker в межах jenkins, але докер не зміг підключитися на етапі додавання хмари, я використав цей 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-адреса коли-небудь змінюється, але ви можете додати на свій Mac спеціальний IP-адрес із зворотним циклом, що контейнер не вважає собою, зробивши щось подібне на батьківській машині:

sudo ifconfig lo0 alias 192.168.46.49

Потім ви можете перевірити з'єднання всередині контейнера докера з 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 Так, псевдонім циклу не буде вимкнено після перезавантаження комп'ютера.
Командир коду

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; в цьому питанні це насправді не так. Також ОП попросив "хост і порт-карти", і ви лише покрили хост.
Браян

Добре. Я трохи розгубився, оскільки прийняте рішення охоплює також лише частину хоста. І я думаю, що ваше рішення перевершує рішення спінуса.
Аугунрік

це не працює, якщо ви хочете використовувати 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 у вбудований VM:

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.2IP-адреса хоста - не IP-місток мосту, як у spinusприйнятій відповіді.

Я використовую тут host.docker.internal :

Хост має зміну IP-адреси (або її немає, якщо у вас немає доступу до мережі). Починаючи з 18.03, наша рекомендація полягає в підключенні до спеціального імені DNS host.docker.internal, яке визначає внутрішню IP-адресу, яку використовує хост. Це призначено для розробки і не працюватиме у виробничих умовах поза Docker для Windows.


2
Я спробував вам рішення, і здається, що команду nslookup не вдалося знайти
Сергій

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

Ні, я використовую саме вашу команду - docker run -it nginx / bin / ash
Сергій

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

Якщо ви не можете зробити nslookup, просто зробіть пінг. Він покаже вирішений 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
Не додайте однакову відповідь на кілька запитань . Дайте відповідь найкращому та позначте решта як дублікати, як тільки ви заробите достатню репутацію. Якщо це не дублікат, пристосуйте публікацію до питання та позначте його на невизначення.
Bhargav Rao

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 API докера ( наприклад, наприклад) і знаєте ім'я хоста або IP-адресу хост-машини, це можна зробити з великою сумою.-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 та економить дорогоцінні 7mb місця. Використовуйте вбудований 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
Арі

mandoc 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

Ось як я це роблю. У цьому випадку він додає запис хостів у / etc / hosts в межах зображення докера, що вказує host-taurus до моєї 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

Можливо, контейнер, який я створив, корисний також https://github.com/qoomon/docker-host

Ви можете просто використовувати ім’я контейнера dns для доступу до хост-системи, наприклад curl http: // dockerhost: 9200 , тому не потрібно мати клопоту з будь-якою IP-адресою.


0

Я використовую рішення засноване на "сервері", який повертає зовнішню адресу хокера Docker, коли він отримує http-запит.

На "сервері":

1) Запустіть jwilder / nginx-proxy

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

a) $ docker-machine ip

b) Отримайте IP-адресу однієї або декількох машин.

  $ docker-machine ip host_name

  $ docker-machine ip host_name1 host_name2

10
Це витягує IP-адресу віртуальної машини, яка працює докер-контейнерами, а не IP-хоста, в якому працюють контейнери.
Спенсер Вільямс

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