Docker compose. быстрый старт.

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

Введение.

Предположим что Docker у Вас установлен и я не буду уделять вниманию как его установить. Вместе с Docker ставится плагин compose, есть отдельное приложение Docker-compose, но его мы устанавливать не будем поскольку compase есть в Docker и обе программы одинаково создают контейнеры, например для запуска контейнера используя конфигурационный файл docker-compose.yaml файла в Docker команда будет выглядеть так:

docker compose up -d

для Docker compose так

docker-compose up -d

кроме этого контейнер можно запустить в командной строке, тогда конфигурация берется не из файла а пишется в командной строке, так же можно контейнеры запустить в web интерфейсе Portainer

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

Старт

Очень удобный инструмент Portainer, рекомендую его установить. Для этого создаем папку и в ней файл docker-compose.yaml

mkdir portainer
cd portainer
nano docker-compose.yaml

и вставляем туда следующее содержимое.

services:
  portainer:
    image: portainer/portainer-ce:latest
    container_name: portainer
    environment:
      - TZ=Europe/Luxembourg
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/data
    ports:
      - "9443:9443"
    restart: always

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

docker compose up -d

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

Вообще все дальнейшие конфигурации можно делать внутри Portainer, так выглядит вэб интерфейс Portainer

local — это наш сервер, бесплатная версия поддерживает до 3-х серверов. Войдя на сервер мы увидим структуру контернизации

Нас интересуют:

Staks — это сборки, может содержать один или несколько контейнеров

Containers — это контейнеры, которые работают на основании образа (Images), проще говоря это образ (Images) в котором имеются какие то изменения

Images — это образы, они неизменны, на их основе работают контейнеры.

Networks — это сети

Volumes — это подключенные к контейнеру внешние диски.

В основном используются два вида запуска контейнеров в сети, это в режиме Host и в режиме Bridge

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

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

На снимке экрана 2 контейнера, один в режиме Host (контейнер pritunl) второй в режиме Bridge (контейнер wg-easy) как видно у контейнера wg-easy есть айпи адрес и доступ возможен по айпи адресу или имени контейнера, так же можно получить доступ к портам контейнера по имени локального хоста на котором стоит Docker если перенаправления портов указаны в Published Ports или контейнер работает в режиме Host.

Например у меня развернут вэб сервер с отдельными контейнерами nginx, php-fpm, mariadb, phpmyadmin

и доступ к вэб странице web сервера возможен как по адресу хоста (у хоста ip адрес 192.168.178.20) http://localhost так и по айпи адресу контейнера http://172.100.0.2, по имени из браузера не получиться подключиться поскольку нужны DNS имена, а наша локальная машина не имеет DNS имени контейнера, а вот из контейнеров можно обращаться по имени, например вот в конфиге nginx сделано перенаправление на phpmyadmin по его имени

server { server_name pma.localhost;
location / { proxy_pass http://phpmyadmin:80;
include /etc/nginx/conf/redirect.conf; }
}

и мы можем получить доступ к phpmyadmin по адресу http://pma.localhost
так же в mysql настройки сайта мы указываем имя контейнера, вот например строка настройки majordomo или тоже самое на сайте WordPress в файле wp-config.php

Define('DB_HOST', 'mariadb');

где mariadb это имя контейнера и настройки fastcgi для работы сайта на php в nginx

fastcgi_pass php82fpm:9000;

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

Define('DB_HOST', 'localhost');

Так же к phpmyadmin можно получить доступ по айпи адресу http://172.100.0.5, а доступ по имени хоста (http://pma.localhost) обеспечивает nginx перенаправляя имя на контейнер с phpmyadmin, мы может открыть порт в Published Ports, однако надо учесть что у не могут быть открыты одинаковые порты у разных контейнеров а так же этот порт не должен быть занят на локальной машине и в контейнерах работающих в режиме host. У нас 80-й порт уже занят nginx по этому для phpmyadmin мы делаем Published Ports 85:80 что означает что при обращении к порту 85 хост машины перенаправление будет на 80-й порт контейнера.

В данном примере мы получим одинаковый результат на адрес http://localhost:85 и адрес http://172.110.0.5 (80-й порт писать не обязательно, по умолчанию протокол http работает на 80-м порту)

Однако не все контейнеры могут работать таким образом с помощью перенаправления портов в Published Ports, например web интерфейс EreePBX не работает на другом порту кроме как на 80-м и по этому либо использовать 80-й порт либо делать перенаправление доменного имени на 80-й порт через nginx

server { server_name freepbx.localhost;
location / { proxy_pass http://freepbx:80;
include /etc/nginx/conf/redirect.conf; }
}

Про сети

В самом начале статьи есть конфигурационный файл запуска в контейнере Portainer, по умолчанию если сетевой режим не указан то контейнер запускается в режиме Bridge, мы видим что у Portainer сделаны перенаправления портов из хоста в контейнер и по этому мы заходим в вэб интерфейс Portainer заходим не по ip адресу Portainer, а по адресу локальной машины localhost.

Как видно из скриншота выше айпи адрес Portainer в другой подсети чем другие, дело в том, что Portainet запущен без настроек сети и Docket сам создал сеть с рандомным айпи адресом (вообще не совсем рандомным, выдается в определенном порядке), а сеть 172.110.0 создана мною.

Я рассмотрю 4 варианта работы сетей, вернее первые 2 я уже рассмотрел, это режим Host и режим автоматический Bridge (если в конфиге не указать параметры сети).

необходимо добавить, что Docker создает и сетевые интерфейсы с именами типа br-8de41b7dcd6b, br-6758ee04a617 что не очень то красиво и если надо будет например добавить маршруты в iptables то не очень удобно запоминать имя этого сетевого интерфейса, по этому я рекомендую задать параметры сети Bridge с понятными названиями и не случайными ip адресами.

для создания сети в конфигурационный файл надо добавить (в любое место, можно в конец):

networks:
 netlemp:
   name: netlemp
   driver: bridge
   driver_opts:
    com.docker.network.bridge.name: br_web
   ipam:
    config:
     - subnet: 172.100.0.0/24
       gateway: 172.100.0.1

где br-web это имя нашего сетевого интерфейса которое мы видим например введя команду ifconfig, красивее выглядит чем br-6758ee04a617, остальные параметры надеюсь понятны, для ссылки в конфиге контейнера мы используем netlemp

  networks: 
   netlemp:

полностью конфиг для запуска portainer и сети будет выглядеть так:

services:
  portainer:
    image: portainer/portainer-ce:latest
    container_name: portainer
    environment:
      - TZ=Europe/Luxembourg
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/data
    ports:
      #- "8000:8000"
      - "9443:9443"
    restart: always
    networks: 
      netlemp:
        ipv4_address: 172.100.0.2

# создание сети
networks:
 netlemp:
   name: netlemp
   driver: bridge
   driver_opts:
    com.docker.network.bridge.name: br_web
   ipam:
    config:
     - subnet: 172.100.0.0/24
       gateway: 172.100.0.1

если не задать строку ipv4_address: 172.100.0.2 то ip адрес выдаст автоматически.
сюда можно добавить хоть сколько контейнеров и одной командой все запустить, например у меня конфиг установки системы умного дома MajorDoMo (самая лучшая и гибкая система, до недавнего времени единственной проблемой была сложность установки, но Docker решил эту проблему), в конфиге создается сеть и запускаются контейнеры nginx, mariadb, php-fpm, supervisor

Но что делать если надо к существующей сети добавить контейнер? есть для этой цели 2 варианта: добавить конфигурацию контейнера в существующий конфиг и остановить контейнеры командой

docker compose down

и запустить командой

docker compose up -d

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

networks:
 netlemp:
  external:
   name: mylan

и например запуск контейнера nginx с подключением к существующей сети выглядит так:

# подключение к существующей сети mylan
networks:
 netlemp:
  external:
   name: mylan
# создание контейнеров
services:
# web сервер NGINX
 nginx:
  container_name: nginx
  image: nginx:latest
  restart: always
  privileged: true
  networks: 
   netlemp:
    ipv4_address: 172.100.0.3
  hostname: nginx
  ports:
  - 80:80

обратите внимание, что ссылка на сеть в контейнере не на имя сети, а на идентификатор конфигурации netlemp

Переменные в конфигурации

У меня в конфигурации в одном файле несколько контейнеров и например чтобы заменить номера портов или айпи адреса не очень удобно рыскать по всей конфигурации, для того чтобы менять параметры в одном месте в папке с файлом docker-compose.yaml создадим файл .env в который мы зададим переменные

HTTP_PORT=80
IPV4_NETWORK=172.100.0

и переменную в конфиге используем так:

${IPV4_NETWORK}

наш код будет выглядеть так

version: '3'
# подключение к существующей сети mylan
networks:
 netlemp:
  external:
   name: mylan
# создание контейнеров
services:
# web сервер NGINX
 nginx:
  container_name: nginx
  image: nginx:latest
  restart: always
  privileged: true
  networks: 
   netlemp:
    ipv4_address: ${IPV4_NETWORK:-172.100.0}.3
  hostname: nginx
  ports:
  - ${HTTP_PORT:-80}:80

я добавил значение по умолчанию если в файле .env нет такой переменной. Теперь можно все переменные задавать в файле .env

 

Docker compose. быстрый старт.

Навигация по записям