python

Как получить доступ из одного докер-контейнера в другой докер-контейнер

  • четверг, 6 мая 2021 г. в 00:38:05
https://habr.com/ru/post/554190/
  • Python
  • Программирование
  • Микросервисы


Изображение от Mike Wheatley
Изображение от Mike Wheatley

Цель этой статьи — показать как мы можем сконфигурировать два и более контейнера, чтобы они могли взаимодействовать друг с другом. В этой статье мы сделаем следующее:

  • Создадим образ Docker используя простой веб-сервис с использованием Python и Flask.

  • Запустим два отдельных контейнера

  • Создадим сеть в Docker

  • Объединим контейнеры используя созданную сеть

Подготовка

Чтобы пойти дальше вы должны обладать средними знаниями в программировании и API. Также понадобится докер инсталлированный локально на вашей машине.

Руководство об основах работы с контейнерами можно найти здесь:

Идея

Для этой статьи мы будем использовать два простых веб-сервиса, каждый со своим эндпойнтом. Давайте назовём первый сервис "ping", второй — "pong", а нашим замыслом будет отправка запроса сервисом "ping" к сервису "pong" так, чтобы они могли играть в пинг-понг.

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

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

Фото от https://unsplash.com/@ellenqin
Фото от https://unsplash.com/@ellenqin

Сервис "ping"

Наши сервисы - очень простые flask-приложения. В app.py будут наши эндпойнты.

В нашем случае сервис "ping" будет иметь эндпойнт "/ping", который будет отправлять запросы к сервису "pong" в эндпойнт "/pong". Если сервис "pong" недоступен, то он просто вернёт "Ping …”. В противном случае сервис вернёт “Ping … Pong”.

В requirements.txt перечислены все модули, которые мы будем использовать, а в Dockerfile перечислены все шаги, которые помогут нам собрать образ.

Source: https://www.metricfire.com/blog/how-to-build-optimal-docker-images/

Сейчас у нас есть два python-сервиса с их Dockerfile. Давайте соберём образы Docker для них.

cd ping-service
docker build -t ping-service .

и

cd pong-service
docker build -t pong-service .

После того как выполним команду docker images мы должны увидеть два образа:

REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
pong-service        latest              968a682344de        7 seconds ago        124MB
ping-service        latest              6e079525fd69        About a minute ago   128MB
python              3.8-slim-buster     b281745b6df9        8 days ago           114MB

Запуск контейнеров

Теперь у нас есть образы, давайте создадим из них контейнеры и запустим их.

cd ping-service
docker run --name ping-service-container -p 5000:5000 ping-service

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

 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 761-609-740

Если мы выполним команду curl http://0.0.0.0:5000 мы должны получить вывод сообщения Hello, I am ping service!

Теперь давайте запустим контейнер для сервиса "pong":

cd pong-service
docker run --name pong-service-container -p 5001:5001 pong-service

А сейчас давайте выполним docker container ls, чтобы посмотреть на созданный контейнеры:

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
d7eb5ee014fb        pong-service        "python app.py"     13 seconds ago      Up 11 seconds       0.0.0.0:5001->5001/tcp   pong-service-container
d2331893e5b9        ping-service        "python app.py"     3 minutes ago       Up 3 minutes        0.0.0.0:5000->5000/tcp   ping-service-container

Мы видим, что у нас теперь есть два контейнера с именами pong-service-containerиping-service-container.

Настраиваем сеть в Docker

Без сети наши контейнеры не смогут взаимодействовать друг с другом. Или другими словами, "ping-service-container" не сможет отправить запрос в эндпойнт "/pong" контейнера "pong-service-container".

Мы можем сделать доступным взаимодействие через сеть в Docker посредством следующих шагов:

  • Создаём сеть

  • Добавляем контейнеры в сеть

И таким образом всем контейнеры в одной докер-сети могут взаимодействовать между собой через имя контейнера или IP-адрес.

Давайте выполним эти вышеуказанные шаги.

Создаём сеть в Docker

Давайте создадим сеть с именем ping-pong-network

docker network create ping-pong-network

и когда мы выполним команду docker network inspect ping-pong-network, мы получим:

TheDarkSide:pong-service raf$ docker network inspect ping-pong-network
[
    {
        "Name": "ping-pong-network",
        "Id": "b496b144d72d9d02795eb0472351b093d6b4f1d0015a37e1525d4d163e7ec532",
        "Created": "2021-04-18T22:16:25.2399196Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.25.0.0/16",
                    "Gateway": "172.25.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

И как говорилось выше, это сеть без контейнеров и мы можем пойти дальше и добавить запущенные контейнеры в эту сеть, используя следующие команды:

docker network connect ping-pong-network ping-service-container
docker network connect ping-pong-network pong-service-container

И если теперь запустим инспектирование сети(docker network inspect ping-pong-network), то в секции Containers мы увидим наши контейнеры:

"Containers": {
            "d2331893e5b9dad95a2691b81c256a9f07d4bf62c10601115483d45f8d7b8e2a": {
                "Name": "ping-service-container",
                "EndpointID": "3a9e8eea9802602652719461681d3ad4bc7c603697bc1c1b027e35876fdddad7",
                "MacAddress": "02:42:ac:19:00:02",
                "IPv4Address": "172.25.0.2/16",
                "IPv6Address": ""
            },
            "d7eb5ee014fbdb850a19ebb216a56f8b7ebd10db62af197d2d17f5be30ee0210": {
                "Name": "pong-service-container",
                "EndpointID": "901ba7f76df59498bd662742536ee31a56a26cc4eedd35d4bd681c9788be5291",
                "MacAddress": "02:42:ac:19:00:03",
                "IPv4Address": "172.25.0.3/16",
                "IPv6Address": ""
            }
        }

И как было сказано выше, контейнеры могут взаимодействовать друг с другом используя имя контейнера или IPv4 адрес.

Проверяем взаимодействие контейнеров

Когда оба сервиса — "ping" и "pong" будут объединены общей сетью, то запрос к эндпойнту "/ping" сервиса "ping":

TheDarkSide:pong-service raf$ curl http://0.0.0.0:5000/ping

нам вернёт:

Ping ... Pong

Для тестирования остановим один из контейнеров и затем проведём инспекцию сети. Мы должны будем увидеть только один контейнер.

Видеоруководство

Кому лень читать, кто больше любит видео и сюда пролистал "по диагонали", может посмотреть это руководство в формате видео.

Заключение

Контейнеры в одной докер-сети могут взаимодействовать используя свой IP адрес или имя контейнера.

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