Как контейнер Docker получает доступ к внешней сети и как работает сопоставление портов?
Как контейнер Docker получает доступ к внешней сети и как работает сопоставление портов?

напиши впереди

  • аккуратный контейнер DockerКак получить доступ к внешнему сетевому порту и принципу сопоставления портов для простого обмена
  • Если вы недостаточно понимаете, пожалуйста, помогите мне исправить это.

Не слишком запутывайтесь в настоящем и не беспокойтесь слишком сильно о будущем. Когда вы что-то испытываете, пейзаж перед вами уже не тот, что раньше. —— Харуки Мураками

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

По умолчанию, когда ничего не настроено, докер будет использоваться для каждого созданного контейнера Bridge Network тип сети, в то время как docker Используется по умолчанию bridge сетевой драйвер

Это можно проверить с помощью следующей команды

Язык кода:javascript
копировать
liruilonger@cloudshell:~$ docker network inspect bridge --format='{{.Driver}}'
bridge
liruilonger@cloudshell:~$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "cd77486c39955f3d2369fe32e1f5b9b65d81c1a07bb677b085cec72b8fb52440",
        "Created": "2024-03-26T13:03:43.742084591Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1460"
        },
        "Labels": {}
    }
]
liruilonger@cloudshell:~$
liruilonger@cloudshell:~$ docker info | grep -i network
  Network: bridge host ipvlan macvlan null overlay

Теперь запускаем контейнер nginx

Язык кода:javascript
копировать
liruilonger@cloudshell:~$ docker run -d -p 2024:80 --name mynginxs nginx
704b4427a24d56e6a2cc999fcf95125c73e665cb90029b191febc405f90a789a
liruilonger@cloudshell:~$

Доступ к маппинг-порту нормальный

В то же время доступ к внешним веб-сайтам внутри контейнера является нормальным.

Язык кода:javascript
копировать
liruilonger@cloudshell:~$ docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                  NAMES
704b4427a24d   nginx     "/docker-entrypoint.…"   2 minutes ago   Up 2 minutes   0.0.0.0:2024->80/tcp   mynginxs
liruilonger@cloudshell:~$ docker exec -it 704b4427a24d bash
root@704b4427a24d:/# curl baidu.com
<html>
<meta http-equiv="refresh" content="0;url=http://www.baidu.com/">
</html>
root@704b4427a24d:/#

Теперь давайте посмотрим на доступ к контейнеру. baidu.com Как это произошло? Перед этим мне нужно взглянуть на конфигурацию сети текущего контейнера.

Язык кода:javascript
копировать
liruilonger@cloudshell:~$ docker inspect 704b4427a24d

Чтобы иметь доступ к внешней сети, необходима следующая конфигурация:

Язык кода:javascript
копировать
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "29735aa89eefbbbc03beb8f120aab0d0898de7b46959cf560739748458a1f8ca",
            "SandboxKey": "/var/run/docker/netns/29735aa89eef",
            "Ports": {
                "80/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "2024"
                    }
                ]
            },
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "c8e13b9e448504121192937ac4e4619c3dbdcc58fd26b89a601f3bba61dd9f21",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:11:00:02",
                    "NetworkID": "cd77486c39955f3d2369fe32e1f5b9b65d81c1a07bb677b085cec72b8fb52440",
                    "EndpointID": "c8e13b9e448504121192937ac4e4619c3dbdcc58fd26b89a601f3bba61dd9f21",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DriverOpts": null,
                    "DNSNames": null
                }
            }
        }

В приведенной выше информации о конфигурации вы можете найти полезную информацию.

IP-адрес: «IPAddress»: «172.17.0.2», шлюз: «Шлюз»: «172.17.0.1».

Кратко подытожим процесс:

  1. Сначала начните разговор внутри контейнера baidu.com запрос доступа
  2. Запрос первыйконтейнерсерединапространство имен сети(/var/run/docker/netns/29735aa89eef)Соответствующийсетьстек получать
  3. Сетевой стек внутри контейнера проверит, находится ли целевой адрес да в диапазоне подсети контейнерсеть. потому что baidu.com Не внутри контейнерсеть, стек сети определил, что запрос необходимо отправить во внешнюю сеть контейнера.
  4. Итак контейнер ищет шлюз 172.17.0.1 Отправьте запрос. Адрес шлюза здесь на самом деле является местом установки. docker да Устройство виртуального подключения моста, созданное по умолчанию docker0

Мы можем увидеть с помощью следующей команды

Язык кода:javascript
копировать
liruilonger@cloudshell:~$ ifconfig  docker0
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1460
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:87:21:0a:8b  txqueuelen 0  (Ethernet)
        RX packets 23  bytes 2710 (2.6 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 23  bytes 4437 (4.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

liruilonger@cloudshell:~$

Фактически, после создания контейнера докер по умолчанию сделает за нас некоторые вещи.

  • Соответствующий контейнер будет создан. Linux пространство имен сети
  • Создать пару veth pair,Воля Чтосередина Порт, подключенный к корневому пространству именсерединамостdocker0начальство,Другой порт размещается в пространстве имен контейнера.
  • существоватьконтейнерпространство именсередина Конфигурация IP адрес (172.17.0.2) и активируйте устройство.
  • Включено в корневом пространстве имен IP Функция переадресации (через настройки net.ipv4.ip_forward=1),Также в пространстве имен контейнера Конфигурация по умолчанию используется шлюз (172.17.0.1).
  • Конфигурация NAT правило SNAT,Воляконтейнерпространство имен сетисерединатрафик ВпередизИсходный IP-адрес преобразуется в IP-адрес в корневом пространстве имен.

может пройти sudo iptables -t nat -nL команда найденаPOSTROUTING настроен в цепочке SNAT правило

Язык кода:javascript
копировать
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0

Он устанавливает исходный адрес как 172.17.0.0/16 (подсеть сети Docker Bridge)Исходный адрес всех пакетов изменяется наIP-адрес хоста,и Воля Цельадресустановлен на 0.0.0.0/0,Представляет любой адрес назначения. Это правило разрешено располагать в Docker Контейнеры в мостовой сети получают доступ к внешней сети и ресурсам Интернета.

  • Трафик в целевом пространстве имен будет перенаправляться в корневое пространство имен через IP-адрес шлюзового моста по умолчанию и подключаться к Интернету через сетевое устройство в корневом пространстве имен.
  1. Итак, когда вы доберетесь до адреса, соответствующего шлюзу Linux мостовое устройство docker0 После этого, поскольку он включен по умолчанию ipv4 Вперед,То есть это можно просто понимать как обращение с хостом как свыключатель, docker0 трафик будет перенаправляться напрямую во внешнюю сеть
Язык кода:javascript
копировать
liruilonger@cloudshell:~$ ip route
default via 10.88.0.1 dev eth0 
10.88.0.0/16 dev eth0 proto kernel scope link src 10.88.0.4 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
liruilonger@cloudshell:~$
  1. Docker После того, как сетевой стек хоста получит запрос, устанавливается конфигурация сети хоста. SNAT,это ВоляКонвертироватьконтейнервнутренний источник IP Адрес соответствует адресу хост-машины IP адрес,Сетевой стек на хосте будет основан на собственной таблице маршрутизации.,Переслать запрос во внешнюю сеть,В то же время, чтобы ответ мог прийти корректно при возврате
  2. Последующие запросы будут направлены на хост-компьютер и в общедоступную сеть.,Здесь не так много описаний

Итак, как правило, для доступа контейнера к внешней сети необходимы два фактора:

  • ip_forward(включать IPV4 Вперед)
  • SNAT/MASQUERADE(Конфигурация SNAT/MASQUERADE)

Поэтому, если вы обнаружите, что не можете получить доступ к внешней сети внутри контейнера,Вам необходимо подтвердить системуip_forwardда Нет, открыто。или проверьтеdocker daemonпри запуске--ip-forwardпараметрда Нетдаустановлено наfalseПонятно,Если да,Вам нужно установить--ip-forward=trueПерезапуск Docker,Docker Открою хост ip forward。

То есть доступ к пакетам внешней сети из контейнерного сегмента сети.,Придется сделать это один разMASQUERADE,То есть все исходящие пакеты используют адрес хоста.Исходный адрес замены IP-адреса

Ниже приведены все цепочки на текущем хосте контейнера. nat столбрандмауэрправило

Язык кода:javascript
копировать
liruilonger@cloudshell:~$ sudo iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DNAT       tcp  --  0.0.0.0/0            169.254.169.254      tcp dpt:80 to:127.0.0.1:900
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DNAT       tcp  --  0.0.0.0/0            169.254.169.254      tcp dpt:80 to:127.0.0.1:900
DNAT       tcp  --  0.0.0.0/0            169.254.169.254      tcp dpt:8080 to:169.254.169.254:80
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0
MASQUERADE  tcp  --  172.17.0.2           172.17.0.2           tcp dpt:80

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:2024 to:172.17.0.2:80
liruilonger@cloudshell:~$

Здесь мы рассмотрим принцип сопоставления контейнерных портов. На самом деле он в основном заключается в. DOCKER Эта пользовательская цепочка настроена с DNAT

Язык кода:javascript
копировать
Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:2024 to:172.17.0.2:80
liruilonger@cloudshell:~$

второйправилода Целевой источникадресдля0.0.0.0/0,Цельадресдля0.0.0.0/0,TCP-пакет с портом назначения 2024. Это правило изменяет адрес назначения пакета на 172.17.0.2:80.,То есть перенаправить пакет на порт 80 172.17.0.2.

Здесь фактически выполняется сопоставление портов, и именно здесь возникает DNAT. Он имеет две ссылки.

соответственнодаPREROUTINGцепь иOUTPUTцепь,Это означает, что он отправляется на локальную машину извне, и локальный процесс обращается к локальной машине (посредством iptables соответствоватьправилоADDRTYPE match dst-type LOCALобозначение)из 2024 Адрес назначения пакета порта будет изменен на 172.17.0.2:80。

о docker отображение портов, удалять Понятноиспользоватьdocker psкоманда данаконтейнервзаимосвязь сопоставления портов,Также доступенdocker portПредставление командконтейнериз端口существовать Хозяинначальствоиз映射

Вот краткий обзор некоторых знаний о DNAT и SNAT.

Осведомленность о SNAT/DNAT

DNAT

ДНКАТ в соответствии с заданными условиями Измените IP-адрес назначения и порт назначения пакета. 。DNAT Принцип аналогичен принципу переадресации портов, который мы обсуждали выше. Разница в том, что переадресация портов не изменяет IP-адрес. Типичный пример использования iptables для преобразования адресов назначения выглядит следующим образом:

Язык кода:javascript
копировать
iptables -t nat -A PREROUTING -d 1.2.3.4  -p tcp -dport 80 -j DNAT  --to-destination 10.20.30.40:8080 
  • -j DNAT указывает на преобразование адреса назначения.
  • -d 1.2.3.4 -p tcp --dport 80 указывает совпадающие пакеты, условие — TCP-пакеты с адресом назначения и портом 1.2.3.4:80
  • --to-destination Указывает на изменение адреса назначения и порта пакета на 10.20.30.40:8080。

Аналогично, DNAT не изменяет протокол. Если вы хотите сопоставить сетевую карту, вы можете использовать -i eth0 Укажите сетевую карту, получившую пакет (т. да input аббревиатура). На что следует обратить внимание, ДНКАТ происходит только в таблица НАТ PREROUTING цепь и OUTPUT,Это также причина, по которой нам нужно указать сетевую карту, которая получает пакет, а не сетевую карту, которая отправляет пакет.

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

Язык кода:javascript
копировать
echo 1 > /proc/sys/net/ipv4/ip_forward

Подмена SNAT/сетевого адреса

Таинственный подмена сетевого Адрес на самом деле является разновидностью даSNAT. СНАТ Измените исходный IP-адрес пакета данных в соответствии с указанными условиями, то есть DNAT обратная операция. и DNAT Ограничения аналогичны SNAT. Стратегии могут возникать только в nat стол POSTROUTING цепь и INPUT цепь。

Язык кода:javascript
копировать
ipttables -t nat -A POSTROUTING -s 192.168.26.12 -o eth0 -j SNAT -to-source 10.127.16.1 
  • -j SNAT указывает на преобразование адреса источника
  • -s 192.168.1.12 Указывает соответствующий адрес источника пакета. 192.168.1.12,
  • --to-source означает изменение исходного адреса пакета на 10.172.16.1. Похоже на: ДНКАТ
  • -o eth0 (аббревиатура odaoutput) соответствует сетевой карте, которая отправляет пакет.

Что касается камуфляжа сетевых адресов,Подобно SNAT, это на самом деле специальная трансляция адреса источника.,Замените исходный адрес сообщения IP-адресом сетевой карты, с которой пришло сообщение.,Какой конкретно использовать?IPадрес Определяется ядром。Следующийправилозначениеда:источникадресда 10.8.0.0/16 Сделайте это один раз для каждого сообщения Masq

Язык кода:javascript
копировать
iptable -t nat -A POSTROUTING -s 10.8.0.0/16 -j MASQUERADE

Ссылка на часть сообщения в блоге

© Авторские права на справочный контент в этой статье принадлежат оригинальному автору. Пожалуйста, сообщите нам, если есть какие-либо нарушения. :)

© liruilonger@gmail.com, 2018–2024. Все права сохранены. Attribution-NonCommercial-ShareAlike (CC BY-NC-SA 4.0).

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose