В чем разница между "выставлять" и "публиковать" в Docker?

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

Все обучающие программы, которые я видел сначала, включают команду EXPOSE в файле Docker:

...
EXPOSE 8080
...

Затем они создают изображение из этого файла Docker:

$ docker build -t an_image - < Dockerfile

Затем опубликуйте тот же порт, что и при работе с изображением:

$ docker run -d -p 8080 an_image

или опубликовать все порты, используя

$ docker run -d -P an_image

Какой смысл выставлять порт в файле Docker, если он будет опубликован в любом случае? Может ли когда-нибудь возникнуть необходимость открыть порт первым, а не опубликовать его позже? Фактически, я хотел бы указать все порты, которые я буду использовать в Dockerfile при создании изображения, а затем не беспокоиться о них снова, запуская их просто с помощью

$ docker run -d an_image

Возможно ли это?

Ответ 1

По сути, у вас есть три варианта:

  1. Ни укажите EXPOSE, ни -p
  2. Укажите только EXPOSE
  3. Укажите EXPOSE и -p

1) Если вы не укажете ни EXPOSE, ни -p, служба в контейнере будет доступна только изнутри самого контейнера.

2) Если вы EXPOSE порт, служба в контейнере не доступна снаружи Docker, но из других контейнеров Docker. Так что это хорошо для межконтейнерной коммуникации.

3) Если у вас EXPOSE и -p порт, служба в контейнере доступна из любого места, даже за пределами Docker.

Причина, по которой оба разделены, ИМХО, потому что:

  • выбор порта хоста зависит от хоста и, следовательно, не принадлежит Dockerfile (иначе это будет зависеть от хоста),
  • и часто этого достаточно, если услуга в контейнере доступна из других контейнеров.

В документации documentation прямо говорится:

Инструкция EXPOSE предоставляет порты для использования в ссылках.

В нем также указывается, как связывать контейнеры, что по сути является межконтейнерной связью, о которой я говорил.

PS: Если вы делаете -p, но не EXPOSE, Docker делает неявное EXPOSE. Это связано с тем, что если порт открыт для общего доступа, он автоматически также открывается для других контейнеров Docker. Следовательно, -p включает в себя EXPOSE. Вот почему я не перечислил это как четвертый случай.

Ответ 2

Краткий ответ:

  • EXPOSE - это способ документирования
  • --publish (или -p) - это способ сопоставления порта хоста с портом работающего контейнера

Обратите внимание, что ниже:

  • EXPOSE относится к Dockerfiles (документирование)
  • --publish относится к docker run ... (выполнение/время выполнения)

Разоблачение и публикация портов

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

  • Вы открываете порты, используя ключевое слово EXPOSE в Dockerfile или флаг --expose для запуска Docker. Предоставление портов - это способ документировать, какие порты используются, , но фактически не отображает и не открывает какие-либо порты. Предоставление портов не является обязательным.

  • Вы публикуете порты, используя флаг --publish или --publish-all для docker run. Это сообщает Docker, какие порты открывать в сетевом интерфейсе контейнеров. Когда порт публикуется, он сопоставляется с доступным портом высокого порядка (выше, чем 30000) на хост-компьютере, если только вы не укажете порт, который будет отображаться на хост-компьютере во время выполнения. Вы не можете указать порт для сопоставления на хост-машине при создании образа (в Dockerfile), потому что нет способа гарантировать, что порт будет доступен на хост-машине, на которой вы запускаете образ.

from: Docker container networking

Обновление за октябрь 2019 г.: вышеуказанный фрагмент текста больше не находится в документах, но есть заархивированная версия: docs.docker.com/v17.09/engine/userguide/networking/#exposing- и-издательских порты

Может быть, текущая документация приведена ниже:

  Опубликованные порты

     По умолчанию при создании контейнера он не публикует свои порты во внешнем мире. Чтобы сделать порт доступным для служб вне Docker или для контейнеров Docker, которые не подключены к сети контейнеров, используйте флаг --publish или -p. Это создает правило брандмауэра, которое сопоставляет порт контейнера с портом на хосте Docker.

and can be found here: docs.docker.com/config/containers/container-networking/#published-ports

Кроме того,

ПОДВЕРГАТЬ

... Инструкция EXPOSE фактически не публикует порт. Он функционирует как документация между человеком, который создает образ, и человеком, который запускает контейнер, о том, какие порты предназначены для публикации.

from: Dockerfile reference






Доступ к сервису, когда EXPOSE/--publish не определены:

На @Golo Roden указано, что ::

"Если вы не укажете ни один из них, служба в контейнере не будет доступна нигде, кроме как внутри самого контейнера".

Возможно, так было во время написания ответа, но теперь кажется, что даже если вы не используете EXPOSE или --publish, host и другие containers той же сети смогут получить доступ к услуге, которую вы можете запустить внутри этого контейнера.

Как это проверить:

Я использовал следующее Dockerfile. По сути, я начинаю с Ubuntu и устанавливаю крошечный веб-сервер:

FROM ubuntu
RUN apt-get update && apt-get install -y mini-httpd

Я build изображение как "testexpose" и run новый контейнер с:

docker run --rm -it testexpose bash

Внутри контейнера я запускаю несколько экземпляров mini-httpd:

[email protected]:/# mini_httpd -p 80
[email protected]:/# mini_httpd -p 8080
[email protected]:/# mini_httpd -p 8090

Затем я могу использовать curl с хоста или других контейнеров, чтобы получить домашнюю страницу mini-httpd.

Ответ 3

EXPOSE позволяет вам определять частные (контейнерные) и общедоступные (хост-порты) порты, чтобы выставлять их во время сборки изображения при запуске контейнера. Публичный порт является необязательным, если не указывается публичный порт, случайный порт будет выбран на хосте докере, чтобы открыть указанный контейнерный порт в файле Docker.

Хорошая оценка не указывает общий порт, поскольку он ограничивает только один контейнер для каждого хоста (второй контейнер будет использовать порт, который уже используется).

Вы можете использовать -p в docker run, чтобы контролировать, какой открытый порт могут быть подключены открытые порты контейнера.

В любом случае, если вы не используете EXPOSE и -p, порты не будут открыты.

Если вы всегда используете -p в docker run, вам не нужен EXPOSE, но если вы используете EXPOSE, ваша команда docker run может быть более простой, EXPOSE может быть полезна, если вам все равно какой порт будет отображаться на хосте, или если вы уверены, что будет загружен только один контейнер.

Ответ 4

Вы открываете порты, используя ключевое слово EXPOSE в файле Docker или - флаг флага для запуска докеров. Экспозиция портов - это способ документирования порты, но фактически не отображают или не открывают какие-либо порты. Развертывание портов необязательно.

Источник: github commit

Ответ 5

Большинство людей используют докер в сетях. В документации говорится:

Сетевая функция Docker поддерживает создание сетей без необходимости открывать порты в сети, для получения подробной информации см. обзор этой функции).

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

Ответ 6

Dockerfile EXPOSE против публикации

ПОДВЕРГАТЬ

При записи ваших файлов Docker инструкция EXPOSE сообщает Docker, что работающий контейнер прослушивает определенные сетевые порты. Это действует как документация по отображению портов, которую можно использовать при публикации портов.

ЭКСПОЗИЦИЯ [/...]

Вы также можете указать это в команде запуска Docker, например:

запуск докера --expose = 1234 my_app

Но EXPOSE не разрешит связь через определенные порты с контейнерами вне той же сети или с хост-машиной. Чтобы это произошло, вам нужно опубликовать порты.

Опубликовать порты и сопоставить их с хостом

При использовании команды docker run можно использовать несколько флагов для публикации портов контейнеров вне сети контейнеров и сопоставления их с портами хост-машин. Это флаги -p и -p, и они различаются в зависимости от того, хотите ли вы опубликовать один или все порты.

Чтобы действительно опубликовать порт при запуске контейнера, используйте флаг -p в окне запуска Docker, чтобы опубликовать и сопоставить один или несколько портов, или флаг -p, чтобы опубликовать все открытые порты и сопоставить их с портами высокого порядка. - Докер документы: ЭКСПОЗИЦИЯ

запуск докера -p 80: 80/tcp -p 80: 80/udp my_app

В приведенном выше примере первое число после флага -p является портом хоста, а второе - портом контейнера.

Чтобы опубликовать все порты, которые вы определили в своем Dockerfile с помощью EXPOSE, и связать их с хост-машиной, вы можете использовать флаг -p.

запуск докера -p my_app

Ответ 7

EXPOSE используется для сопоставления локального порта с контейнерным портом То есть: если вы укажете expose в файле Docker, например,

EXPOSE 8090

Что он сделает, это отобразит локальный хост-порт 8090 на контейнерный порт 8090