В чем разница между "выставлять" и "публиковать" в 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
По сути, у вас есть три варианта:
- Ни укажите
EXPOSE
, ни -p
- Укажите только
EXPOSE
- Укажите
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