#docker #docker-compose
#docker #docker-compose
Вопрос:
Рассмотрим часть некоторого базового docker-compose.yml
файла:
services:
foo:
image: bar
network_mode: host
.
.
.
Затем рассмотрите docker-compose.prod.yml
файл, который переопределит сетевой режим базового файла, а также установит порты:
services:
foo:
ports:
- 'xxxx:yyyy'
network_mode: ?
Я ищу такое значение ?
, которое network_mode
считается отключенным. Другими словами, установка для него значения none
или bridge
, похоже, не работает, поэтому я хочу, чтобы оно просто исчезло или использовало значение с таким эффектом (я не думаю, что есть значение по умолчанию).
Альтернативным решением этой проблемы является определение трех файлов docker-compose: docker-compose.yml
, docker-compose.prod.yml
, и docker-compose.dev.yml
(или что-то эквивалентное, не имеет значения). Это работает нормально (см. Ниже), но я бы предпочел иметь только 2 файла и переопределить файл dev файлом prod, а не наоборот (так кажется более естественным).
Рабочая версия, использующая три файла:
docker-compose.yml
services:
foo:
image: bar
.
.
.
docker-compose.dev.yml
services:
foo:
network_mode: host
docker-compose.prod.yml
services:
foo:
ports:
- 'xxxx:yyyy'
Примечания:
- Все файлы используют версию docker-compose
3
. - Конкретная настройка, которая в моем случае не работает с
bridge
сетевым режимом, представляет собой набор из трех служб: одна для запуска веб-материалов (общедоступных), одна для работников сельдерея (внутренняя) и одна для Redis (внутренняя). Использованиеbridge
в web и / или celery приводит к невозможности подключения к службе Redis.
Ответ №1:
Я не знаю, как удалить параметр из предыдущего docker-compose.yaml
, но bridge
он действительно работает, возможно, вам потребуется двойное подтверждение.
Если мы посмотрим на сеть docker по умолчанию, вы bridge
действительно можете увидеть там, если мы не установим --net
, docker по умолчанию будет использовать bridge
:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
32a9a31082ae bridge bridge local
dcb12f4cc711 host host local
16c73acab8c9 none null local
Я привожу небольшой пример, чтобы доказать это:
docker-compose.yaml:
version: "3"
services:
web:
image: python:3.7
network_mode: host
command: python -m http.server 9000
docker-compose.prod.yaml:
version: "3"
services:
web:
ports:
- 10000:9000
network_mode: bridge
- docker-compose up
С помощью этой команды мы фактически просто будем использовать
docker-compose.yaml
, в то время, если мы откроем браузер, который мы можем увидеть, может успешно посетить, например:http://$ip:9000
, это потому, что сеть естьhost
. - docker-compose -f docker-compose.yaml -f docker-compose.prod.yaml вверх
С помощью этой команды мы будем использовать 2 файла compose, последний переопределит дублирующую опцию в первом.
Если вы откроете браузер, вы обнаружите, что не можете зайти
http://$ip/9000
сейчас, вы могли бы просто зайтиhttp://$ip/10000
. Это может доказать, чтоhost
эффект потери иbridge
переопределениеhost
успешно.(ПРИМЕЧАНИЕ: после вам нужно будет убедиться
docker-compose.prod.yaml
docker-compose.yaml
, что порядок последовательности важен.)
ОБНОВЛЕНИЕ 20211017 на основе ваших новых комментариев:
Если вы хотите дополнительно посетить другой контейнер в вашем compose, вам нужно будет определить network_mode в этой целевой службе, чтобы использовать ту же сеть исходной службы network_mode: service:web
, см. Раздел Сетевой режим:
docker-compose.yaml:
version: "3"
services:
web:
image: python:3.7-alpine3.13
command: python -m http.server 9000
network_mode: host
db:
image: python:3.7-alpine3.13
command: python -m http.server 8000
network_mode: service:web
docker-compose.yaml:
version: "3"
services:
web:
ports:
- 10000:9000
network_mode: bridge
Затем, после up, вы можете использовать что-то вроде next, чтобы напрямую перейти к сервису в db:
docker-compose exec web wget http://localhost:8000 -O -
ПРИМЕЧАНИЕ:
- при
network_mode: bridge
использовании inweb
web
контейнер больше не использует сеть по умолчанию, которую compose настроил для вас. В результате вы не получите выгоды от автоматической настройки dns с помощью compose, что означаетweb
, что вы не сможете получить доступdb
к контейнеру, используя имя службыdb
. - чтобы решить эту проблему, теперь вы можете разрешить
db
контейнеруweb
явно использовать сеть сnetwork_mode: service:web
помощью . Это означает, что 2 контейнера теперь используют одно и то же сетевое пространство имен, тогда вам не нужно посещатьdb
с именем службы, но использоватьlocalhost
. Теперьweb
вы можете получить доступdb
к порту 8000 только сhttp://localhost:8000
помощью .
Комментарии:
1. Спасибо за подробное описание. К сожалению,
bridge
у меня не работает, я проверил еще раз. У меня есть три службы: web stuff, celery stuff и Redis. Если я используюbridge
on web и / или celery, я не могу подключиться к Redis внутренне, но если я ничего не использую, все подключается просто отлично (и порты из веб-материалов действительно доступны для общественности). Я обновил вопрос с помощью этой информации.2. Я также пытался явно настроить
bridge
службу Redis, но без хороших результатов.3. Поскольку мы указываем network_mode, мы не сможем извлечь выгоду из автоматического dns для docker-compose, поэтому вы не сможете посетить другой контейнер с именем службы. В качестве поправки вы можете разрешить контейнерам использовать одно и то же сетевое пространство имен, подробности см. В разделе Обновление в ответе.
4. Уверяю вас, я рассмотрю отредактированное решение, потому что оно выглядит очень многообещающим, просто нужно немного времени: (
5. Спасибо за ваше обновление. К сожалению, кажется, что я не могу публиковать порты и одновременно использовать ваше предложение :
Cannot create container for service ...: conflicting options: port publishing and the container type network mode
. Кроме того, кажется, что если я включаюdepends_on: B
в службу A, но включаюnetwork_mode: service:A
в службу B, я также получаю циклическое предупреждение о зависимости.
Ответ №2:
TL; DR
docker-compose.prod.yml
services:
foo:
network_mode: unset # Can be any string other than 'host'.
networks: [ default ]
ports: [ 80:80 ]
Docker Compose Сеть по умолчанию
Это поведение по умолчанию: если networks:
для службы не определено и не network_mode:
определено, то она подключена к default
сети.
К сожалению, пустая строка игнорируется синтаксическим анализатором YAML, поэтому мы не можем переопределить network_mode:
обратно ''
, что мы можем сделать, это установить networks: [ default ]
, но это не будет работать с network_mode: host
так что мы можем установить network_mode:
?
network_mode:
эквивалентно Docker --network
, если мы установим для него сетевое имя networks:
, оно переопределит его, поэтому мы можем использовать любое значение, отличное от host
того, которое, по-видимому, вызывает какое-то особое поведение. Вероятно, хорошей идеей будет установить для него значение, которое не будет работать без networks:
и избегать default
bridge
или none
.
Чтобы восстановить поведение по умолчанию, нам нужно добавить default
к networks:
и установить network_mode:
что-то другое, чем host
.
Обратите внимание, что network_mode: default
это эквивалентно --network default
или --network bridge
который использует сеть Docker по умолчанию: bridge
, а не по умолчанию для всего проекта Compose network: projectName_default
.
Комментарии:
1. Это выглядит многообещающе, я посмотрю, когда у меня будет такая возможность
2. Привет, извините — мне потребовалось некоторое время, чтобы попробовать это, поскольку я некоторое время не работал с docker. Не уверен, было ли какое-либо обновление за это время, но я получаю следующее:
Cannot start service foo: network unset not found
а также'network_mode' and 'networks' cannot be combined
3. Но, похоже, я могу использовать
network_mode: ""
(пустую строку) просто отлично. Мне потребуется некоторое время, чтобы убедиться, что все службы доступны, как и ожидалось, в этом сетевом режиме, но я думаю, что это будет хорошим результатом.