Погружение в сетевое взаимодействие Docker

DockerBeginner
Практиковаться сейчас

Введение

В ходе этой практической работы мы изучим продвинутые концепции сетевого взаимодействия в Docker, опираясь на базовые знания о сетях. Мы подробно разберем три основных сетевых режима: Bridge (мост), Host (хост) и None (отсутствие сети). Вы также научитесь создавать пользовательские сети, подключать контейнеры к нескольким сетям одновременно и поймете, как каждый режим влияет на коммуникацию и изоляцию контейнеров. Этот практический опыт заложит прочный фундамент для работы с сетевой инфраструктурой Docker.

Пользовательские мостовые сети

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

  1. Для начала просмотрим текущий список сетей Docker:
docker network ls

Вы должны увидеть примерно следующее:

NETWORK ID     NAME      DRIVER    SCOPE
296d1b460b17   bridge    bridge    local
91199fc6ad2e   host      host      local
1078d2c781b6   none      null      local
  1. Теперь создадим пользовательскую мостовую сеть:
docker network create my-custom-bridge
  1. Снова выведите список всех сетей Docker, чтобы подтвердить создание:
docker network ls

Теперь в выводе должна появиться сеть my-custom-bridge:

NETWORK ID     NAME               DRIVER    SCOPE
296d1b460b17   bridge             bridge    local
91199fc6ad2e   host               host      local
7215f99d0080   my-custom-bridge   bridge    local
1078d2c781b6   none               null      local
  1. Запустите два контейнера в этой пользовательской сети и установите утилиту ping:
docker run --network=my-custom-bridge --name container1 -d nginx
docker run --network=my-custom-bridge --name container2 -d nginx

Теперь установим утилиту ping в оба контейнера. Это необходимо, так как стандартный образ Nginx не содержит ping:

docker exec container1 apt-get update && docker exec container1 apt-get install -y iputils-ping
docker exec container2 apt-get update && docker exec container2 apt-get install -y iputils-ping
  1. Проверьте связь между контейнерами:
docker exec container1 ping -c 4 container2

Вы должны увидеть успешные ответы на запросы ping. Это доказывает, что контейнеры в одной пользовательской мостовой сети могут взаимодействовать друг с другом, используя имена контейнеров. Это возможно благодаря встроенному DNS-серверу Docker, который сопоставляет имена контейнеров с их IP-адресами внутри одной сети.

Если ping не проходит, убедитесь, что оба контейнера запущены (docker ps) и утилита ping была установлена без ошибок.

Соединение контейнеров между разными сетями

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

  1. Сначала создадим вторую пользовательскую мостовую сеть:
docker network create my-second-bridge
  1. Проверьте создание сети:
docker network ls

Теперь вы должны увидеть обе пользовательские сети:

NETWORK ID     NAME               DRIVER    SCOPE
296d1b460b17   bridge             bridge    local
91199fc6ad2e   host               host      local
7215f99d0080   my-custom-bridge   bridge    local
8a15f99d0081   my-second-bridge   bridge    local
1078d2c781b6   none               null      local
  1. Подключите container2 к новой сети:
docker network connect my-second-bridge container2

Эта команда добавляет container2 в сеть my-second-bridge, при этом он остается подключенным и к my-custom-bridge.

  1. Создайте новый контейнер во второй сети:
docker run --network=my-second-bridge --name container3 -d nginx
docker exec container3 apt-get update && docker exec container3 apt-get install -y iputils-ping
  1. Проверьте связь между всеми контейнерами:
docker exec container1 ping -c 2 container2
docker exec container1 ping -c 2 container3
docker exec container2 ping -c 2 container3

Обратите внимание на результаты:

  • container1 может связаться с container2 (они в одной сети).
  • container1 не может связаться с container3 (они в разных сетях).
  • container2 может связаться и с container1, и с container3 (он подключен к обеим сетям).

Если бы container1 смог пропинговать container3, это означало бы нарушение логики изоляции сети.

Сетевой режим Host

Режим Host убирает сетевую изоляцию между контейнером и хост-системой Docker, позволяя контейнеру использовать сетевой стек хоста напрямую. Это полезно для достижения максимальной производительности, но несет риски для безопасности, так как снижается уровень изоляции.

  1. Создайте контейнер, используя сетевой режим host:
docker run --network host --name host-container -d nginx
  1. Проверьте текущий список сетей:
docker network ls

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

  1. Убедитесь, что контейнер действительно использует сеть хоста:
docker inspect --format '{{.HostConfig.NetworkMode}}' host-container

Команда должна вывести host.

  1. Попробуйте получить доступ к странице Nginx по умолчанию с вашей хост-машины:
curl localhost:80

Вы должны увидеть приветственную страницу Nginx. Это работает, потому что контейнер использует сеть хоста, и Nginx слушает порт 80 непосредственно на сетевом интерфейсе хоста.

Примечание: Если на вашей хост-машине уже запущен какой-либо сервис на порту 80, этот шаг может завершиться ошибкой. В таком случае сначала необходимо остановить существующий сервис.

Сетевой режим None

Режим 'none' создает контейнеры без сетевого интерфейса, полностью изолируя их от любой сети. Это применяется для обеспечения максимальной безопасности и изоляции, однако такой контейнер не сможет передавать или принимать данные по сети.

  1. Создайте контейнер без сети:
docker run --network none --name isolated-container -d alpine sleep infinity
  1. Проверьте список сетей:
docker network ls

Для этого контейнера не будет создано новой сети, так как он ни к чему не подключен.

  1. Убедитесь, что у контейнера нет сетевых интерфейсов:
docker exec isolated-container ip addr

Вы должны увидеть только локальный интерфейс (lo). Интерфейсы eth0 или другие сетевые адаптеры будут отсутствовать.

  1. Попробуйте выполнить ping Google из изолированного контейнера:
docker exec isolated-container ping -c 2 google.com

Команда должна завершиться ошибкой "Network is unreachable" (Сеть недоступна), так как у контейнера нет доступа к сети.

Сетевые псевдонимы и обнаружение сервисов

Сети Docker поддерживают обнаружение сервисов (service discovery) с помощью сетевых псевдонимов (aliases), что крайне полезно для создания отказоустойчивых и масштабируемых приложений. Эта функция позволяет нескольким контейнерам отвечать на одно и то же DNS-имя, реализуя базовую балансировку нагрузки.

  1. Создайте новую мостовую сеть для этого упражнения:
docker network create service-network
  1. Проверьте создание сети:
docker network ls

Вы должны увидеть service-network в списке.

  1. Создайте два контейнера с одинаковым сетевым псевдонимом:
docker run -d --network service-network --network-alias myservice --name service1 nginx
docker run -d --network service-network --network-alias myservice --name service2 nginx
  1. Создайте клиентский контейнер и используйте nslookup для разрешения имени сервиса:
docker run --rm --network service-network appropriate/curl nslookup myservice

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

  1. Проверьте доступ к сервису несколько раз:
for i in {1..4}; do docker run --rm --network service-network appropriate/curl ping -c 1 myservice; done

Вы увидите ответы от обоих контейнеров, что подтверждает работу базовой балансировки нагрузки. DNS-сервер Docker будет чередовать IP-адреса при разрешении имени myservice.

PING myservice (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.106 ms

--- myservice ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.106/0.106/0.106 ms
PING myservice (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.119 ms

--- myservice ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.119/0.119/0.119 ms
PING myservice (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.097 ms

--- myservice ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.097/0.097/0.097 ms
PING myservice (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.140 ms

--- myservice ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.140/0.140/0.140 ms

Резюме

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

  1. Пользовательские мостовые сети для улучшения изоляции и взаимодействия контейнеров.
  2. Подключение контейнеров к нескольким сетям одновременно.
  3. Сетевой режим Host для прямого доступа к сетевому стеку хоста.
  4. Сетевой режим None для полной сетевой изоляции.
  5. Сетевые псевдонимы и обнаружение сервисов для построения масштабируемых приложений.

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

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

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