Перейти к содержимому

Docker compose links для чего

  • автор:

Мультиконтейнерное приложение и Docker Compose

Как собирать целые системы на основе докер контейнеров.

Время чтения: 11 мин

Открыть/закрыть навигацию по статье

  1. Кратко
  2. Как начать
  3. Как понять
  4. Как пишется
    1. Services
    2. Networks
    3. Volumes
    1. Игорь Коровченко советует
    1. Опишите жизненный цикл контейнера Docker

    Обновлено 20 декабря 2021

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

    Кратко

    Скопировать ссылку «Кратко» Скопировано

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

    Как начать

    Скопировать ссылку «Как начать» Скопировано

    Если вы работаете на операционных системах Mac или Windows и установили Docker Desktop, то Docker Compose уже установлен автоматически. Если вы работаете на операционной системе семейства Linux, вам необходимо его установить, предварительно скачав последний релиз из репозитория. До установки убедитесь, что Docker Engine на Linux уже установлен и готов к работе (подробнее в статье «Что такое Docker?»). Процесс установки описан в официальной документации Docker.

    Как понять

    Скопировать ссылку «Как понять» Скопировано

    Рассмотрим мультиконтейнерное приложение на примере WordPress.

    Можно создать один образ с установленной базой данных, веб-сервером, интерпретатором PHP и движком WordPress на борту. А можно сделать иначе.

    Способы организации сайта на движке WordPress с помощью Docker

    Веб-приложение — это, как правило, сложная система взаимодействующих частей, которые называют сервисами. Команда разработчиков Docker рекомендует подход: один сервис — один контейнер. Этот подход позволяет легче отлавливать ошибки, проще модернизировать сервисы, избегать работы над всем приложением сразу. При большой нагрузке на отдельные сервисы такой подход упрощает масштабирование с помощью перераспределения сетевых запросов (маршрутизатор можно поместить в отдельный контейнер). Реализовать мониторинг и сформировать поток ошибок также можно с помощью отдельного сервиса, запущенного в контейнере. Совокупность описанных сервисов называется мультиконтейнерным приложением.

    Вернёмся к примеру. Что нужно для запуска сайта на WordPress? В самом простом случае такое веб-приложение состоит из двух сервисов:

    — веб-сервер с WordPress;
    — база данных.

    Оба контейнера должны работать совместно. Мы можем написать Dockerfile для каждого из них и настроить взаимодействие друг с другом через виртуальную сеть Docker Network. Но такой ручной подход не очень удобен. Docker Compose — это инструмент, который помогает конфигурировать запуск сразу нескольких контейнеров и указывать им, как работать совместно.

    Docker Compose поддерживает файлы конфигурации в формате YAML. Имя файла конфигурации по умолчанию — compose.yaml. Для нашего примера такой файл мог бы выглядеть следующим образом (в качестве базы данных будем использовать MySQL):

    Конфигурация мультиконтейнерного приложения для сайта на движке WordPress

    version: "3.9" services: db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: goodpassword MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: depends_on: - db image: wordpress:latest ports: - "8000:80" restart: always environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpress volumes: db_data: <>

    В первой строчке этого файла конфигурации содержится информация о версии формата описания. С каждой новой версией функциональность Docker Compose расширяется. Если раньше этот параметр был обязательным, то сейчас его можно не указывать, если не нужно поддерживать старую версию Docker Engine, смотрите таблицу соответствия версий формата описания и движка Docker.

    В разделе services содержится описание всех контейнеров, запуск которых нужно настроить. Отдельно работающие приложения или службы в терминах Docker Compose называются сервисами.

    В подразделе image необходимо указать имя образа, который должен присутствовать локально на компьютере или в реестре. Можно установить и переменные окружения в подразделе environment , порты для подключения к сервису (например, со стороны браузера) в подразделе ports , пути для монтирования томов в подразделе volumes и прочие параметры.

    В различных базах данных, не только в MySQL, как у нас, существует возможность хранить данные в отдельном файле или папке. Логично было бы положить в отдельные файлы и данные нашего сайта на WordPress. Для таких задач используются тома (Docker Volumes). На самом деле — это отдельные образы дисков. Для приложения в контейнере они видны как примонтированные папки. Следовательно, когда используется том db_data, при остановке или перезапуске контейнера с MySQL все данные сохранятся. Ну а с контейнером с самим движком данные вообще никак не связаны.

    Файл конфигурации готов, и можно «поднять» все контейнеры всего одной командой:

     docker-compose up docker-compose up     

    Когда все образы будут загружены, тома включены, переменные окружения установлены, сайт на WordPress окажется доступным по адресу http : / / localhost : 8000 . В настройках compose . yaml указано, что если один из контейнеров упадёт, то Docker Compose должен перезапустить его автоматически ( restart : always ). Вы сможете начать с того же места. Появляется ещё одна возможность — можно обновить базу данных, и при следующем перезапуске запустится уже новая версия. То же самое можно делать и с веб-сервером, и движком.

    Выключить оба контейнера так же просто, как и включить:

     docker-compose down docker-compose down     

    Вы можете подробнее посмотреть все команды Docker Compose CLI в официальной документации.

    Как пишется

    Скопировать ссылку «Как пишется» Скопировано

    Поскольку Docker Compose работает с несколькими типами объектов Docker (образами, контейнерами, томами), то логично представить их настройки в виде дерева в формате YAML, который очень часто используется в файлах конфигурации.

    Если вы когда-нибудь писали на языке Python, YAML покажется вам очень понятным. Каждый новый блок отделяется отступами. Блоки могут быть вложенными, что очень удобно, и зрительно воспринимается намного легче, чем, скажем, JSON. Несомненным плюсом является популярность YAML среди специалистов по инфраструктуре.

    Предпочтительное расположение файла compose.yaml — корневая папка проекта, которая может содержать подпапки с сервисами мультиконтейнерного приложения. Для обеспечения обратной совместимости поддерживаются файлы с именами docker-compose.yaml и docker-compose.yml.

    В файле compose.yaml могут быть следующие элементы верхнего уровня:

    — version (скоро исключат): информация о версии формата файла конфигурации;
    — services (обязательный): список всех контейнеров, которые нужно будет запустить;
    — networks: список подсетей Docker Network, которые объединяют группы контейнеров в виртуальную локальную сеть (она может быть доступна из внешнего мира);
    — volumes: список томов, которые будут доступны контейнерам, описанным в файле конфигурации;
    — configs: список параметров, которые позволяют запускать контейнеры в различных режимах, не собирая их заново;
    — secrets: список чувствительных с точки зрения безопасности параметров (то же, что и configs , но специального назначения).

    Services

    Скопировать ссылку «Services» Скопировано

    Мультиконтейнерное приложение — система взаимодействующих сервисов. Как правило, один сервис обеспечивает какую-то одну функцию системы. Например, веб-сервер только отдаёт статический сайт (HTML, CSS и JS) браузеру, API служит для обмена данными. Сервисы — это самостоятельные (атомарные) микроприложения или службы, работающие независимо в отдельных контейнерах.

    Docker Compose — это инструмент, который не только автоматически запускает или останавливает контейнеры, но и поддерживает их жизненный цикл, обеспечивает совместное использование ресурсов.

    Разрабатывая мультиконтейнерное приложение, в голове нужно держать мысль о перспективах его масштабирования и поддержки. Например, один веб-сервер со статическим сайтом может обеспечить тысячу пользователей одновременно. А что, если пользователей больше? Docker Compose в этом случае будет автоматически использовать дополнительные экземпляры сервиса, перенаправляя запросы к ним.

    Например, мы запускаем два сервиса, frontend и backend:

     services: frontend: image: awesome/webapp build: ./webapp deploy: mode: replicated replicas: 6 backend: image: awesome/database build: context: backend dockerfile: ../backend.Dockerfile deploy: resources: limits: cpus: '0.50' memory: 50M reservations: cpus: '0.25' memory: 20M services: frontend: image: awesome/webapp build: ./webapp deploy: mode: replicated replicas: 6 backend: image: awesome/database build: context: backend dockerfile: ../backend.Dockerfile deploy: resources: limits: cpus: '0.50' memory: 50M reservations: cpus: '0.25' memory: 20M     

    Скажем, нам нужно обеспечить до шести экземпляров сервиса frontend, ресурсы для которого будут расходоваться, пока они будут доступны. Тогда мы указываем это явно, как сделано в примере выше, с помощью настроек mode и replicas для элемента deploy . Настроек для развёртывания сервиса (запуска, использования ресурсов процессора, памяти и прочее) очень много.

    Сборка сервиса frontend описывается отдельно от параметров развёртывания. В нашем случае она будет производиться из папки ./webapp с помощью файла с именем по умолчанию Dockerfile.

    Для backend — другие настройки. Нам нужно собрать образ перед тем, как мы будем использовать приложение. Настройка context будет содержать относительный путь к папке сервиса. Вариантов сборки образа несколько, но наш будет описываться в файле backend.Dockerfile. А ещё будут требования к ресурсам, которые использует приложение. Docker Compose:

    • будет использовать процессор не более чем на 50% в штатном режиме, и не более 75% в пиковых нагрузках;
    • сервис будет использовать не более чем 50 МБ оперативной памяти и 70 МБ в пике.

    Подробнее про настройки сборки вы можете почитать в спецификации здесь, а про настройки развёртывания контейнеров здесь.

    Networks

    Скопировать ссылку «Networks» Скопировано

    Параметры, описанные в элементе networks , позволяют настроить виртуальную сеть Docker Network для совместной работы нескольких контейнеров. Например, можно указать две подсети, одна из которых, back-tier, будет обеспечивать прямую связь между frontend и backend, в то время как другая, front-tier, будет связывать frontend с внешним миром. В файле конфигурации это можно записать так:

     services: frontend: image: awesome/webapp networks: - front-tier - back-tier backend: image: awesome/database networks: - back-tier networks: front-tier: external: true name: host back-tier: services: frontend: image: awesome/webapp networks: - front-tier - back-tier backend: image: awesome/database networks: - back-tier networks: front-tier: external: true name: host back-tier:      

    Volumes

    Скопировать ссылку «Volumes» Скопировано

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

     services: backend: image: awesome/database volumes: - db-data:/etc/data volumes: db-data: services: backend: image: awesome/database volumes: - db-data:/etc/data volumes: db-data:      

    Подробная спецификация элементов описана в отдельном репозитории.

    На практике

    Скопировать ссылку «На практике» Скопировано

    Игорь Коровченко советует

    Скопировать ссылку «Игорь Коровченко советует» Скопировано

    �� Вы можете поискать подходящие образы на GitHub. Есть, например, целый каталог наиболее удачных: Awesome Compose.

    Использование терминальных команд

    Скопировать ссылку «Использование терминальных команд» Скопировано

    На этапе сборки образа можно передать аргументы командной строки, а также выполнить произвольные команды по окончании сборки. Иногда это бывает крайне полезно. Например, вы хотите после сборки образа сделать паузу, в течение которой можно будет подождать какой-то процесс или посмотреть вывод в терминал результатов работы программы. В этом случае можно использовать элемент command :

     version: "3.9"services: phys-website: env_file: ./.env command: /bin/sh -c "while sleep 1000; do :; done" build: context: ./ args: USER_NAME: $ USER_EMAIL: $ version: "3.9" services: phys-website: env_file: ./.env command: /bin/sh -c "while sleep 1000; do :; done" build: context: ./ args: USER_NAME: $NAME> USER_EMAIL: $EMAIL>      

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

     docker-compose build --build-arg NAME="John Doe" --build-arg EMAIL=john@light.org docker-compose build --build-arg NAME="John Doe" --build-arg EMAIL=john@light.org     

    Приложение на стеке MERN

    Скопировать ссылку «Приложение на стеке MERN» Скопировано

    MERN — это аббревиатура от MongoDB, Express, React, Node.js. С помощью Docker Compose можно легко реализовать фулстек-приложение. MERN является одним из популярных решений. Оно объединяет веб-сервер, базу данных и фреймворки для бэкенда и фронтенда.

    Обычно структура папок MERN-проекта выглядит следующим образом:

    . ├── backend │ ├── Dockerfile │ . ├── compose.yaml ├── frontend │ ├── . │ └── Dockerfile └── README.md

    Файл конфигурации compose.yaml можно сделать так:

     services: frontend: build: frontend ports: - 3000:3000 stdin_open: true volumes: - ./frontend:/usr/src/app - /usr/src/app/node_modules container_name: frontend restart: always networks: - react-express depends_on: - backend backend: container_name: backend restart: always build: backend volumes: - ./backend:/usr/src/app - /usr/src/app/node_modules depends_on: - mongo networks: - express-mongo - react-express mongo: container_name: mongo restart: always image: mongo:4.2.0 volumes: - ./data:/data/db networks: - express-mongo networks: react-express: express-mongo: services: frontend: build: frontend ports: - 3000:3000 stdin_open: true volumes: - ./frontend:/usr/src/app - /usr/src/app/node_modules container_name: frontend restart: always networks: - react-express depends_on: - backend backend: container_name: backend restart: always build: backend volumes: - ./backend:/usr/src/app - /usr/src/app/node_modules depends_on: - mongo networks: - express-mongo - react-express mongo: container_name: mongo restart: always image: mongo:4.2.0 volumes: - ./data:/data/db networks: - express-mongo networks: react-express: express-mongo:      

    + Развернуть

    На собеседовании

    Скопировать ссылку «На собеседовании» Скопировано

    Docker-compose: идеальное рабочее окружение

    Здрасте!
    В последнее время все чаще задумываюсь об оптимальности рабочего процесса и хотелось бы поделиться своими изысканиями в данном вопросе.

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

    Описывать все я буду почти на пальцах, поэтому если вы до этого ни разу не слышали про docker (что странно), ни разу с ним не работали и хотите в нем разобраться, то прошу под кат.

    Предисловие

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

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

    Те, кто считают иначе — это ваше полное право, но только не нужно навязывать свою точку зрения.
    Спасибо!

    Docker

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

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

    Docker-compose

    Пакетный менеджер (по аналогии с composer и npm, только у docker — контейнеры), позволяющий описывать необходимую структуру в одном файле (конфиге).
    Подробнее также можно узнать из ссылок в конце статьи.

    Docker-hub

    Репозиторий контейнеров (по аналогии с packagist и npm).
    Важное замечание: внимательно читайте описание к образу, 70-80% тупых вопросов там описано, не тратьте время на гугление.

    Установка

    Переписывать документацию docker я не стану, поэтому просто кину ссылки:

    Установка обычного программного обеспечения (ПО), проблем возникнут не должно.
    Если все же возникнут, то дальше можете не читать, вероятно вы случайно наткнулись на эту статью и разработку в целом.

    Если вы устанавливали docker под Windows, то работать нужно через специальную консоль Docker Quickstart Terminal. После установки, на рабочем столе должен появиться соответствующий ярлык.

    Структура проекта

    Для начала определимся со структурой проектов:

    • project 1
    • project 2
    • project N
      • src
      • container 1
      • container 2
      • container N
      • docker-compose.yml

      Каждый проект в обязательном порядке имеет docker-compose.yml и директорию src.
      Также для каждого контейнера должна быть своя директория (совпадающая с названием контейнера), где будет храниться вся информация, необходимая для работы контейнера (конфиги, данные, . ).

      CMD / Terminal

      Для работы с docker и compose мы будем использовать всего несколько команд:

      • docker ps – просмотр всех контейнеров (подробнее),
      • docker-compose up —build – сборка проекта. Параметр build используется для того, чтобы заставить compose пересоздавать контейнеры. (подробнее).

      Описание прочих команд, можно найти на официальном сайте.
      Перейдем непосредственно к делу.

      apache

      Начнем, пожалуй, с самого популярного сервера — Apache.
      Создадим директорию проекта:

      Конфиг будет выглядеть таким образом:

      docker-compose.yml

      version: '3' services: apache: image: httpd:2.4 ports: - 80:80 volumes: - ./src:/usr/local/apache2/htdocs

      Что здесь происходит:

      • image: httpd:2.4 — указываем какой образ нам нужно и его версию (список доступных версий и модификаций можно посмотреть в соответствующем docker-hub).
      • ports: 80:80 — пробрасываем порты между docker и нашей машиной, т.е. все запросы которые будут идти на 80 порт нашей машины, будут транслироваться на 80 порт docker.
      • volumes: ./src:/usr/local/apache2/htdocs — линкуем директорию на нашей машине, с рабочей директорий apache, т.е. все файлы находящиеся в директории src, будут доступны для apache, как будто они лежат в директории htdocs (обратное тоже работает, все что создано в docker «копируется» на локальную машину).

      Создадим файл src/index.html в рабочей директории с содержимым:

      Hi, I'am Apache

      Запускаем наш проект:

      docker-compose up --build

      Переходим в браузер по адресу ПК и наблюдаем приветствие нашего сервера.
      Чтобы уничтожить контейнеры нашего проекта, достаточно в консоле выполнить Ctrl+C.

      Если докер работает через VirtualBox, то нужно заходить по IP виртуалки. При любом раскладе, если вы работаете через Docker Quickstart Terminal, то адрес выведется при запуске консоли.

      Работа в фоновом режиме

      Если вам необходимо запустить docker и далее работать в консоле, то можно запустить проект в фоном режиме:

      docker-compose up --build -d

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

      docker ps

      В моем случае получился такой вывод:

      CONTAINER ID IMAGE . 988e27da7bdf httpd:2.4 . 

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

      docker stop 988e27da7bdf docker rm 988e27da7bdf

      Либо можно поступить грубо и сразу удалить:

      docker rm -f 988e27da7bdf

      nginx

      Конфиг nginx строиться по той же самой схеме, что и apache: образ, порты, рабочая директория. Выглядит файл таким образом:

      docker-compose.yml

      version: '3' services: nginx: image: nginx:1.13 ports: - 80:80 volumes: - ./src:/usr/share/nginx/html

      Создаем файл src/index.html в рабочей директории с содержимым:

      Hi, I'am Nginx

      Заходим в браузер, и видим приветствие очередного сервера.

      php + apache

      Если говорить про связку PHP и Apache, то для нее уже есть готовый образ, поэтому про линковку контейнеров будем говорить далее. А сейчас просто конфиг:

      docker-compose.yml

      version: '3' services: web: image: php:7.2-apache ports: - 80:80 volumes: - ./src:/var/www/html

      Создаем файл src/index.php в рабочей директории с содержимым:

      Проверяем его работу в браузере.

      php + nginx

      В данной связке php будет в формате fpm. Схематично это выглядит таким образом:

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

      docker-compose.yml

      version: '3' services: nginx: image: nginx:1.13 ports: - 80:80 volumes: - ./src:/usr/share/nginx/html - ./nginx/nginx.conf:/etc/nginx/nginx.conf depends_on: - php php: image: php:7.2-fpm volumes: - ./src:/usr/share/nginx/html
      • volumes: ./nginx/nginx.conf:/etc/nginx/nginx.conf — линкуем файл конфига nginx;
      • depends_on: php — указываем зависимость nginx от php, т.е. по сути, это гарантия того что контейнер php запуститься раньше nginx.

      Если мы не укажем depends_on, то можем словить подобную ошибку:

      nginx_1 | 2018/01/05 08:56:42 [emerg] 1#1: host not found in upstream "php" in /etc/nginx/nginx.conf:23 nginx_1 | nginx: [emerg] host not found in upstream "php" in /etc/nginx/nginx.conf:23

      Создаем файл /nginx/nginx.conf в директории нашего проекта. Сам конфиг выглядит таким образом:

      nginx.conf

      worker_processes 1; events < worker_connections 1024; >http < include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server < root /usr/share/nginx/html; listen 80; server_name localhost; location / < index index.html index.htm; >location ~ \.php$ < fastcgi_pass php:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; >> >

      Все стандартное, главное, чтобы директива root совпадала с docker-compose.yml.
      Глядя на конфиг, прошу обратить внимание на директиву fastcgi_pass, а именно на значение php:9000 .
      Обычно, когда настраивается локальный сервер указывается localhost:9000 , НО т.к. php у нас находится в другом контейнере, то обращаться мы должны именно к нему (docker сам «подставит» нужный IP контейнера, по сути вся магия скрыта в простом дописывании файла hosts).
      Чтобы это стало возможным, в наш docker-compose нужно добавить директиву links (хотя по факту не надо, подробнее).

      После всех действий, директория нашего проекта выглядит таким образом:

      Запускаем, проверяем, радуемся!

      php + apache + nginx

      Наверное, самая популярная связка для веб-проектов. Схематично это выглядит так:

      • php используется как php-fpm, потому что быстрее и моднее;
      • apache используется, потому что популярен и htaccess.

      Для того чтобы все настроить нам нужно будет также слинковать конфиг apache, и таким образом docker-compose будет выглядеть так:

      docker-compose.yml

      version: '3' services: apache: image: httpd:2.4 volumes: - ./src:/var/www/html - ./httpd/httpd.conf:/usr/local/apache2/conf/httpd.conf depends_on: - php nginx: image: nginx:1.13 ports: - 80:80 volumes: - ./src:/var/www/html - ./nginx/nginx.conf:/etc/nginx/nginx.conf depends_on: - apache php: image: php:7.2-fpm volumes: - ./src:/var/www/html

      Так как на просторах интернета я не нашел нормальный конфиг (оке, я просто не искал), а под рукой как раз docker, то решено было вытаскивать его из стандартного контейнера.
      Уложилось все в 3 команды:

      docker run -d httpd:2.4 docker ps docker cp [ID контейнера]:/usr/local/apache2/conf/httpd.conf ./httpd.conf

      После выполнения данных команд, в текущей директории появится файл httpd.conf, который мы и будем использовать в качестве основы.
      По сути, это простое копирование из запущенного контейнера.
      Создаем файл /httpd/httpd.conf в рабочей директории, который после правок выглядит так:

      httpd.conf

      ServerRoot "/usr/local/apache2" Listen 80 LoadModule authn_file_module modules/mod_authn_file.so LoadModule authn_core_module modules/mod_authn_core.so LoadModule authz_host_module modules/mod_authz_host.so LoadModule authz_groupfile_module modules/mod_authz_groupfile.so LoadModule authz_user_module modules/mod_authz_user.so LoadModule authz_core_module modules/mod_authz_core.so LoadModule access_compat_module modules/mod_access_compat.so LoadModule auth_basic_module modules/mod_auth_basic.so LoadModule reqtimeout_module modules/mod_reqtimeout.so LoadModule filter_module modules/mod_filter.so LoadModule mime_module modules/mod_mime.so LoadModule log_config_module modules/mod_log_config.so LoadModule env_module modules/mod_env.so LoadModule headers_module modules/mod_headers.so LoadModule setenvif_module modules/mod_setenvif.so LoadModule version_module modules/mod_version.so LoadModule unixd_module modules/mod_unixd.so LoadModule status_module modules/mod_status.so LoadModule autoindex_module modules/mod_autoindex.so LoadModule dir_module modules/mod_dir.so LoadModule alias_module modules/mod_alias.so # additional LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so ServerAdmin you@example.com AllowOverride none Require all denied DocumentRoot "/var/www/html" Options Indexes FollowSymLinks Includes ExecCGI AllowOverride All Require all granted User daemon Group daemon DirectoryIndex index.php index.pl index.cgi index.asp index.shtml index.html index.htm \ default.php default.pl default.cgi default.asp default.shtml default.html default.htm \ home.php home.pl home.cgi home.asp home.shtml home.html home.htm Require all denied LogFormat "%h %l %u %t \"%r\" %>s %b \"%i\" \"%i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common LogFormat "%h %l %u %t \"%r\" %>s %b \"%i\" \"%i\" %I %O" combinedio  ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/" AllowOverride All Options None Require all granted RequestHeader unset Proxy early TypesConfig conf/mime.types AddType application/x-compress .Z AddType application/x-gzip .gz .tgz AddType text/html .shtml AddHandler cgi-script .cgi .pl .asp AddOutputFilter INCLUDES .shtml # # Настройка FPM #  SetHandler "proxy:fcgi://php:9000"  

      Создаем файл /nginx/nginx.conf в рабочей директории со следующим содержимым:

      nginx.conf

      worker_processes 1; events < worker_connections 1024; >http < include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server < listen 80; server_name localhost; location ~ \.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js)$ < root /var/www/html; >location ~ /\.ht < deny all; >location / < proxy_pass http://apache; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_connect_timeout 120; proxy_send_timeout 120; proxy_read_timeout 180; >> >

      В строке proxy_pass http://apache мы опять указываем не IP адрес, а название контейнера (вспоминаем про магию с hosts).

      Для тестинга, нам нужно будет проверить, работает ли PHP и работает ли Apache.
      Сформируем такую структуру проекта:

      Содержимое .htaccess:

      Deny from all

      Содержимое index.php:

      Содержимое index.html:

      Apache not working :-(

      Если все настроено корректно, то картина должна быть следующей:

      • /index.php — откроется информация о php
      • /protected/index.html — откроется 403 ошибка apache
      • /protected/.htaccess — откроется 403 ошибка nginx (визуально они отличаются)

      mariadb + phpmyadmin

      Поговорим про базы данных.
      Конфиг для подключения выглядит следующим образом:

      docker-compose.yml

      version: '3' services: mariadb: image: mariadb:10.3 restart: always volumes: - ./mariadb:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: qwerty phpmyadmin: image: phpmyadmin/phpmyadmin links: - mariadb:db ports: - 8765:80 environment: MYSQL_ROOT_PASSWORD: qwerty depends_on: - mariadb

      Для mariadb и phpmyadmin мы указали директиву environment, которая содержит специфические для конкретного контейнера переменные (подробности можно посмотреть в репозиториях самих контейнеров).
      В данном случае, это пароль для пользователя root.

      Для phpmyadmin мы вручную указали директиву links:

      links: - mariadb:db

      Сделать это необходимо для того, чтобы phpmyadmin знал с какой базой соединятся.
      Если бы контейнер mariadb назывался db, то указывать эту директорию было бы не нужно.

      Для mariadb мы слинковали директорию с данными:

      volumes: - ./mariadb:/var/lib/mysql

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

      Если вы работаете не на linux машине, то у вас возникнут проблемы с размещением данных базы на локальной машине.
      Эти непреодолимое обстоятельство, к сожалению, на данный момент не преодолено.
      У кого есть решение просьба поделиться.
      Однако по умолчанию (даже после уничтожения контейнера), данные базы сохраняются и вы можете пересоздавать контейнер сколько угодно раз — данные сохранятся в недрах локальной машины.

      php + apache + nginx + mariadb + phpmyadmin

      Ну, а теперь совмещаем наши конфиги, и получаем неплохое веб-окружение:

      docker-compose.yml

      version: '3' services: apache: image: httpd:2.4 volumes: - ./src:/var/www/html - ./httpd/httpd.conf:/usr/local/apache2/conf/httpd.conf depends_on: - php nginx: image: nginx:1.13 ports: - 80:80 volumes: - ./src:/var/www/html - ./nginx/nginx.conf:/etc/nginx/nginx.conf depends_on: - apache php: build: ./php volumes: - ./src:/var/www/html - ./php/php.ini:/usr/local/etc/php/php.ini depends_on: - mariadb mariadb: image: mariadb:10.3 volumes: - ./mariadb:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: qwerty phpmyadmin: image: phpmyadmin/phpmyadmin links: - mariadb:db ports: - 8765:80 environment: MYSQL_ROOT_PASSWORD: qwerty depends_on: - mariadb

      Для php мы добавили директиву build (подробнее), в которой указали директорию php, где хранится Dockerfile со следующим содержанием:

      FROM php:7.2-apache RUN apt-get update RUN docker-php-ext-install pdo pdo_mysql mysqli

      В данном файле мы обновляем репозитории и устанавливаем php модули (подробнее про docker-php-ext-install).
      Также мы слинковали конфиг php, чтобы можно было его настроить нужным нам образом.
      Содержимое php.ini можно взять, например, здесь.

      Запускаем, проверяем, радуемся!
      Если все сделано правильно, то index.php отработает без ошибок, а в директории project/mysql появятся служебные файлы базы.

      Docker production

      По данному вопросу к сожалению я ничего сказать не могу, зато может сказать официальная документация.
      Если у вас есть опыт использования docker на боевых проектах, то просьба поделиться своим опытом в комментариях: стоит ли, какие трудности и подводные камни у вас возникли и др. полезную информацию для молодых и неопытных.

      Заключение

      Вот собственно и все, чем я хотел поделиться.
      Как видите необязательно знать принцип работы docker, чтобы успешно с ним работать.
      Да, конечно, для тонкой настройки или сложных задач, необходимо уже углубляться в дебри docker, но в средне-статистическом случае — это не нужно.
      Если у вас есть что добавить, или вы заметили какой-то косяк, или вы с чем-то не согласны, то прошу в комментарии, обсудим 😉

      Полезные ссылки (a.k.a список используемой литературы)

      P.S.

      Если честно, я не понимаю откуда столько негатива.
      Судя по комментариям, основные претензии к формулировкам и терминологии, и это с учетом того, что в предисловии я написал что умышленно упрощаю многие моменты.
      Цель статьи — показать, как просто работать с docker-compose, как вместо того, чтобы разворачивать 100500 окружений и ПО для каждого своего проекта, можно использовать docker-compose и быть довольным.
      Тут нет речи про prodUction (одного абзаца хватит), про deploy, про миграцию между dev и prod средой.
      Нет, статья не об этом.

      P.P.S.

      Большое спасибо krocos Caravus Vershnik Fesor за дельные комментарии.

      Difference between links and depends_on in docker_compose.yml

      I don’t understand the purpose of linking to other containers so the difference between two options still seems quite difficult for me.

      It would be much easier if there is an example, but I can’t find any.

      I noticed, when I link container B with container A then container B will be «pingable» inside container A’s shell.

      I ran ping B inside container A’s bash and got result like this (just for reference, image from the Internet)

      enter image description here

      20.2k 19 19 gold badges 104 104 silver badges 191 191 bronze badges
      asked Mar 6, 2016 at 20:24
      4,719 3 3 gold badges 13 13 silver badges 12 12 bronze badges

      The —link flag is now a deprecated legacy feature of Docker and the documentation suggests «It may eventually be removed» Docker: Legacy container links. It is suggested not to use the Docker networks feature or the docker compose method. I figured this would be helpful to anyone here learning about this feature.

      Sep 30, 2017 at 15:39

      4 Answers 4

      The post needs an update after the links option is deprecated.

      Basically, links is no longer needed because its main purpose, making container reachable by another by adding environment variable, is included implicitly with network . When containers are placed in the same network, they are reachable by each other using their container name and other alias as host.

      For docker run , —link is also deprecated and should be replaced by a custom network.

      docker network create mynet docker run -d --net mynet --name container1 my_image docker run -it --net mynet --name container1 another_image 

      depends_on expresses start order (and implicitly image pulling order), which was a good side effect of links .

      answered Jan 18, 2019 at 9:51
      11.4k 4 4 gold badges 44 44 silver badges 56 56 bronze badges

      How to do the same thing in docker-compose? I think that with docker compose all services are in the same network already and there is no need to add anything. Still linking between the containers doesn’t work if one of the containers is trying to connect to container that is not in the Ready state.

      Mar 27, 2019 at 8:44

      I can’t see information about links being deprecated in docker-compose version 3 docs: docs.docker.com/compose/compose-file/#links . I don’t see the option too useful, since we have shared networks and depends_on, but it is not deprecated if I read the docs correctly (they only mention —link flag on docker container).

      Jul 2, 2019 at 10:29

      Note: containers (actually services) in the same network are accessible by service name, not container name. Official documentation: docs.docker.com/compose/networking/#links

      Dec 23, 2019 at 13:47

      @makkasi you can use the depends_on setting in a compose file to change how containers are span up. At worst, you can add a wait script to your image to only let it run the up command when a certain criteria is met. Such as, only starting the server once a script that checks if the database is up and running has finished executing.

      Jan 12, 2022 at 6:52

      This answer is for docker-compose version 2 and it also works on version 3

      You can still access the data when you use depends_on.

      If you look at docker docs Docker Compose and Django, you still can access the database like this:

      version: '2' services: db: image: postgres web: build: . command: python manage.py runserver 0.0.0.0:8000 volumes: - .:/code ports: - "8000:8000" depends_on: - db 

      What is the difference between links and depends_on?

      links:

      When you create a container for a database, for example:

      docker run -d --name=test-mysql --env="MYSQL_ROOT_PASSWORD=mypassword" -P mysql docker inspect d54cf8a0fb98 |grep HostPort 

      And you may find

      "HostPort": "32777" 

      This means you can connect the database from your localhost port 32777 (3306 in container) but this port will change every time you restart or remove the container. So you can use links to make sure you will always connect to the database and don’t have to know which port it is.

      web: links: - db 

      depends_on:

      I found a nice blog from Giorgio Ferraris Docker-compose.yml: from V1 to V2

      When docker-compose executes V2 files, it will automatically build a network between all of the containers defined in the file, and every container will be immediately able to refer to the others just using the names defined in the docker-compose.yml file.

      So we don’t need links anymore; links were used to start a network communication between our db container and our web-server container, but this is already done by docker-compose

      Update

      depends_on

      Express dependency between services, which has two effects:

      • docker-compose up will start services in dependency order. In the following example, db and redis will be started before web.
      • docker-compose up SERVICE will automatically include SERVICE’s dependencies. In the following example, docker-compose up web will also create and start db and redis.
      version: '2' services: web: build: . depends_on: - db - redis redis: image: redis db: image: postgres 

      Note: depends_on will not wait for db and redis to be “ready” before starting web — only until they have been started. If you need to wait for a service to be ready, see Controlling startup order for more on this problem and strategies for solving it.

      1 1 1 silver badge
      answered Sep 23, 2016 at 10:19
      6,922 4 4 gold badges 31 31 silver badges 50 50 bronze badges
      I’ve updated my answer to clarify that the answer was intended for compose file v1.
      Sep 23, 2016 at 13:36
      Is this still valid for version 3?
      Mar 20, 2017 at 0:03
      Yes, you may have a look at https://docs.docker.com/compose/compose-file/compose-versioning/
      Mar 20, 2017 at 2:36

      «This means you can connect the database from your localhost port 32777(3306 in container) But this port will change every time you restart or remove the container» not if you specify the port binding in the docker-compose-file, it will not. And since this question is specifically about docker-compose, I feel that the example with docker run here is completely irrelevant, that’s not how the container will be run anyway. What am I missing?

      May 10, 2017 at 5:34

      Yes, you are right if you specify the port. My docker run example wanna point out why we need to use depends_on or links instead of hard-code a port number.just because if you not specify it, it change every time. I think this will let people understand more about depends_on or links.

      May 10, 2017 at 8:01

      [Update Sep 2016]: This answer was intended for docker compose file v1 (as shown by the sample compose file below). For v2, see the other answer by @Windsooon.

      It is pretty clear in the documentation. depends_on decides the dependency and the order of container creation and links not only does these, but also

      Containers for the linked service will be reachable at a hostname identical to the alias, or the service name if no alias was specified.

      For example, assuming the following docker-compose.yml file:

      web: image: example/my_web_app:latest links: - db - cache db: image: postgres:latest cache: image: redis:latest 

      With links , code inside web will be able to access the database using db:5432 , assuming port 5432 is exposed in the db image. If depends_on were used, this wouldn’t be possible, but the startup order of the containers would be correct.

      answered Mar 6, 2016 at 20:46
      Xiongbing Jin Xiongbing Jin
      11.9k 3 3 gold badges 49 49 silver badges 41 41 bronze badges

      Can you give me an example? Because that part is what I’m still unclear about. Maybe there are other compose-file options that may make it more specific. Please provide further details. Thanks!

      Mar 6, 2016 at 21:13

      Thank you very much! I got it. One final question, please. So, in my particular case, i’m deploying my rails app, should i use links or depends_on or either of them is ok? My current docker-compose.yml uses depends_on and things seem to work fine. 🙂

      Mar 7, 2016 at 8:36
      If you don’t need to directly access the other container via name:port then depends_on is ok.
      Mar 7, 2016 at 15:09
      name:port works even without linking when you use expose:
      Aug 21, 2016 at 13:32

      «If depends_on were used, this wouldn’t be possible, but the startup order of the containers would be correct.». This is not correct. It would work if you just use depends_on. You can still access your db in the web using databases hostname.

      Sep 22, 2016 at 4:08

      I think that the answers for this question need updating based on the new Docker compose specification introduced first in v1.27.0, which now allows for a long-form of depends_on :

      In this long form, you can specify that you want to wait for a service to be either started, healthy, or completed successfully.

      Docker compose knows that a service is healthy if you produce a health_check on that service:

      I’d recommend to read the examples in the documentation for more details, see links above!

      For a quick example, this is what I used in a compose file for integration tests:

      services: cloud-broker: image: my.docker.registry/activemq-artemis:latest healthcheck: test: ["CMD-SHELL", "wget http://localhost:8161/ --delete-after --tries=3 2> /dev/null"] interval: 10s timeout: 5s retries: 5 postgresql: image: postgres healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 10s timeout: 5s retries: 5 environment: POSTGRES_PASSWORD: "" POSTGRES_USER: "postgres" POSTGRES_DB: "postgres" # This service calls a script to create an empty database and the service-user postgresql-setup: image: postgres depends_on: postgresql: condition: service_healthy restart: "no" volumes: - "./scripts:/scripts" environment: PGPASSWORD: "" entrypoint: "psql -U postgres -d postgres -h postgresql -f /scripts/create-db.sql" my-business-service: image: my.docker.registry/my-business-service:latest depends_on: cloud-broker: condition: service_healthy postgresql-setup: condition: service_completed_successfully 

      Сети в Docker Compose¶

      По умолчанию Compose создает единую сеть для приложения. Каждый контейнер сервиса подключается к сети по-умолчанию и доступен другим контейнерам в этой сети, имея хостнейм идентичный имени контейнера.

      Сеть приложения имеет имя по названию директории в которой находится файл описания Compose, однако его можно задать флагом —project-name или переменной окружения COMPOSE_PROJECT_NAME .

      В качестве примера представим, что приложение находится в директории myapp , а docker-compose.yml выглядит следующим образом:

      version: "3" services: web: build: . ports: - "8000:8000" db: image: postgres ports: - "8001:5432"

      После выполнения docker-compose up произойдет следующее:

      1. Создается сеть myapp_default ;
      2. Контейнер, использующий конфигурацию web имеет DNS имя web внутри сети myapp_default ;
      3. Контейнер, использующий конфигурацию db имеет DNS имя db внутри сети myapp_default .

      Надо так же учитывать, что начиная с версии 2.1 Compose файла overlay сети по умолчанию имеют параметр attachable и свойство attachable можно задать на false , начиная с версии 3.0 Compose файла.

      При изменении параметров контейнера в Docker Compose файлах, обновить параметры приложения можно выполнив docker-compose up . Контейнеры будут пересозданы с другими IP адресами, если они не заданы статически в пользовательских сетях для контейнеров.

      Настройка сети по-умолчанию¶

      Вместо описания своих сетей можно настроить стандартную сеть для контейнера. Для этого необходимо изменять запись default внутри записи networks .

      version: "3" services: web: build: . ports: - "8000:8000" db: image: postgres networks: default: # Use a custom driver driver: overlay attachable: true ipam: driver: default config: - subnet: 172.28.0.0/16

      Использование существующей сети¶

      Если сеть уже создана (например, через Docker CLI), то подключиться к ней можно с использованием опции external :

      networks: default: external: name: my-pre-existing-network

      Таким образом вместо создания сети [projectname]_default , Compose подключит приложение к сети my-pre-existing-network .

      Создание сети¶

      Конечно же можно создать свою сеть в Docker Compose. Вначале приведем docker-compose.yml для представление как можно описать сети и поясним что происходит:

      version: '2.3' #network_mode: "bridge" services: nginx: image: nginx ports: - "80:80" networks: back: ipv4_address: 172.16.238.2 ipv6_address: 2001:3984:3989::2 default: wetty: build: context: ./wetty dockerfile: Dockerfilealt image: wetty:latest ports: - "3000:3000" networks: back: ipv4_address: 172.16.238.3 ipv6_address: 2001:3984:3989::3 codiad: build: ./docker-codiad image: docker-codiad:latest volumes: - ./code:/code - /etc/localtime:/etc/localtime:ro ports: - "5000:5000" - "8080:8080" networks: back: ipv4_address: 172.16.238.4 ipv6_address: 2001:3984:3989::4 default: networks: #Internal-only network for proper nginx proxying and ssh back: driver: bridge enable_ipv6: true internal: true ipam: driver: default config: - subnet: 172.16.238.0/24 - subnet: 2001:3984:3989::/64 #External network actually default: driver: bridge

      В файле описывается внутренняя bridge сеть с своей подсетью ( back ), а так же внешняя сеть, основанная на стандартной ( default ). У некоторых контейнеров заданы статические IP-адреса.

      Необходимо отметить, что в Dockerfile 2 версии в целом больше настраиваемых параметров вроде IPv6 адресации, а в Dockerfile 3 версии таких параметров нет, так как их пока не поддерживает Docker Swarm (сделано было для удобства).

      Наглядная иерархия параметров в Docker Compose¶

      Стоит учитывать, что многие параметры в представленном ниже описании конфликтуют, но они были описаны вместе для удоства и понимания иерархии параметров.

      networks: # Имя default для реконфигурации стандартной сети для Compose имясети: # Типы драйверов: bridge, overlay driver: overlay # attachable работает только в Compose 3.2+ attachable: true # параметры драйвера (см. документацию драйвера) driver_opts: foo: "bar" baz: 1 # Поддержка IPv6 не доступна в Compose 3, только 2. enable_ipv6: true # Настройка IPAM конфигурации ipam: # драйвер IPAM заместо default если нужно driver: default # Конфигурация с 0 и больше блоков, содержащая ключ subnet: config: - subnet: 172.28.0.0/16 - subnet: 192.168.10.0/24 # Делает сеть изолированной internal: true # Использование сети, созданной вне Compose. # Если параметр external имеет флаг true, то это указывает Compose, что сеть была создана извне. docker-compose up ее не создаст и если не найдет, то выкинет ошибку. # external не может быть использован с другими ключами конфигурации (driver, driver_opts, ipam, internal) external: true # Для external можно задать имя для использования в Compose файле начиная с версии 3.5: external: name: actual-name-of-network # Так же с версии 3.5 можно задать имя сети даже с спецсимволами: network1: # Использование файла external так же работает в купе с заданным именем сети external: true name: my-app-net # Метаданные для контейнера могут быть созданы с помощью Docker labels: это массив или словарь. labels: com.example.description: "Financial transaction network" com.example.department: "Finance" com.example.label-with-empty-value: ""

      Версия без комментариев:

      networks: networkname: driver: overlay attachable: true driver_opts: foo: "bar" baz: 1 enable_ipv6: true ipam: config: - subnet: 172.28.0.0/16 - subnet: 192.168.10.0/24 internal: true external: true external: name: actual-name-of-network network1: external: true name: my-app-net labels: com.example.description: "Financial transaction network" com.example.department: "Finance" com.example.label-with-empty-value: ""

      Описание host и none режимов сети¶

      host и none режимы отличаются в описании по сравнению с bridge и overlay . Для них и не требуются какие-либо еще параметры.

      # Host services: web: . networks: hostnet: <> networks: hostnet: external: name: host
      # None services: web: . networks: nonet: <> networks: nonet: external: name: none

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *