Docker Compose overview
Important
From the end of June 2023 Compose V1 won’t be supported anymore and will be removed from all Docker Desktop versions.
Make sure you switch to Compose V2 with the docker compose CLI plugin or by activating the Use Docker Compose V2 setting in Docker Desktop. For more information, see the Evolution of Compose
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.
Compose works in all environments: production, staging, development, testing, as well as CI workflows. It also has commands for managing the whole lifecycle of your application:
- Start, stop, and rebuild services
- View the status of running services
- Stream the log output of running services
- Run a one-off command on a service
The key features of Compose that make it effective are:
Install Compose
Follow the instructions on how to install Docker Compose.
Try Compose
Learn the key concepts of Docker Compose whilst building a simple Python web application.
View the release notes
Find out about the latest enhancements and bug fixes.
Understand key features of Compose
Understand its key features and explore common use cases.
Explore the Compose file reference
Find information on defining services, networks, and volumes for a Docker application.
Руководство по Docker Compose для начинающих
Автор статьи, перевод которой мы сегодня публикуем, говорит, что она предназначена для тех разработчиков, которые хотят изучить Docker Compose и идут к тому, чтобы создать своё первое клиент-серверное приложение с использованием Docker. Предполагается, что читатель этого материала знаком с основами Docker. Если это не так — можете взглянуть на эту серию материалов, на эту публикацию, где основы Docker рассмотрены вместе с основами Kubernetes, и на эту статью для начинающих.
Что такое Docker Compose?
Docker Compose — это инструментальное средство, входящее в состав Docker. Оно предназначено для решения задач, связанных с развёртыванием проектов.
Изучая основы Docker, вы могли столкнуться с созданием простейших приложений, работающих автономно, не зависящих, например, от внешних источников данных или от неких сервисов. На практике же подобные приложения — редкость. Реальные проекты обычно включают в себя целый набор совместно работающих приложений.
Как узнать, нужно ли вам, при развёртывании некоего проекта, воспользоваться Docker Compose? На самом деле — очень просто. Если для обеспечения функционирования этого проекта используется несколько сервисов, то Docker Compose может вам пригодиться. Например, в ситуации, когда создают веб-сайт, которому, для выполнения аутентификации пользователей, нужно подключиться к базе данных. Подобный проект может состоять из двух сервисов — того, что обеспечивает работу сайта, и того, который отвечает за поддержку базы данных.
Технология Docker Compose, если описывать её упрощённо, позволяет, с помощью одной команды, запускать множество сервисов.
Разница между Docker и Docker Compose
Docker применяется для управления отдельными контейнерами (сервисами), из которых состоит приложение.
Docker Compose используется для одновременного управления несколькими контейнерами, входящими в состав приложения. Этот инструмент предлагает те же возможности, что и Docker, но позволяет работать с более сложными приложениями.

Docker (отдельный контейнер) и Docker Compose (несколько контейнеров)
Типичный сценарий использования Docker Compose
Docker Compose — это, в умелых руках, весьма мощный инструмент, позволяющий очень быстро развёртывать приложения, отличающиеся сложной архитектурой. Сейчас мы рассмотрим пример практического использования Docker Compose, разбор которого позволит вам оценить те преимущества, которые даст вам использование Docker Compose.
Представьте себе, что вы являетесь разработчиком некоего веб-проекта. В этот проект входит два веб-сайта. Первый позволяет людям, занимающимся бизнесом, создавать, всего в несколько щелчков мышью, интернет-магазины. Второй нацелен на поддержку клиентов. Эти два сайта взаимодействуют с одной и той же базой данных.
Ваш проект становится всё популярнее, и оказывается, что мощности сервера, на котором он работает, уже недостаточно. В результате вы решаете перевести весь проект на другую машину.
К сожалению, нечто вроде Docker Compose вы не использовали. Поэтому вам придётся переносить и перенастраивать сервисы по одному, надеясь на то, что вы, в процессе этой работы, ничего не забудете.
Если же вы используете Docker Compose, то перенос вашего проекта на новый сервер — это вопрос, который решается выполнением нескольких команд. Для того чтобы завершить перенос проекта на новое место, вам нужно лишь выполнить кое-какие настройки и загрузить на новый сервер резервную копию базы данных.
Разработка клиент-серверного приложения с использованием Docker Compose
Теперь, когда вы знаете о том, для чего мы собираемся использовать Docker Compose, пришло время создать ваше первое клиент-серверное приложение с использованием этого инструмента. А именно, речь идёт о разработке небольшого веб-сайта (сервера) на Python, который умеет выдавать файл с фрагментом текста. Этот файл у сервера запрашивает программа (клиент), тоже написанная на Python. После получения файла с сервера программа выводит текст, хранящийся в нём, на экран.
Обратите внимание на то, что мы рассчитываем на то, что вы владеете основами Docker, и на то, что у вас уже установлена платформа Docker.
Приступим к работе над проектом.
▍1. Создание проекта
Для того чтобы построить ваше первое клиент-серверное приложение, предлагаю начать с создания папки проекта. Она должна содержать следующие файлы и папки:
- Файл docker-compose.yml . Это файл Docker Compose, который будет содержать инструкции, необходимые для запуска и настройки сервисов.
- Папка server . Она будет содержать файлы, необходимые для обеспечения работы сервера.
- Папка client . Здесь будут находиться файлы клиентского приложения.
▍2. Создание сервера
Тут мы, в процессе создания сервера, затронем некоторые базовые вещи, касающиеся Docker.
2a. Создание файлов
Перейдите в папку server и создайте в ней следующие файлы:
- Файл server.py . В нём будет находиться код сервера.
- Файл index.html . В этом файле будет находиться фрагмент текста, который должно вывести клиентское приложение.
- Файл Dockerfile . Это — файл Docker, который будет содержать инструкции, необходимые для создания окружения сервера.
2b. Редактирование Python-файла.
Добавим в файл server.py следующий код:
Этот код позволяет создать простой веб-сервер. Он будет отдавать клиентам файл index.html , содержимое которого позже будет выводиться на веб-странице.
2c. Редактирование HTML-файла
В файл index.html добавим следующий текст:
Этот текст будет передаваться клиенту.
2d. Редактирование файла Dockerfile
Сейчас мы создадим простой файл Dockerfile , который будет отвечать за организацию среды выполнения для Python-сервера. В качестве основы создаваемого образа воспользуемся официальным образом, предназначенным для выполнения программ, написанных на Python. Вот содержимое Dockerfile:
Теперь займёмся работой над клиентом.
▍3. Создание клиента
Создавая клиентскую часть нашего проекта, мы попутно вспомним некоторые основы Docker.
3a. Создание файлов
Перейдите в папку вашего проекта client и создайте в ней следующие файлы:
- Файл client.py . Тут будет находиться код клиента.
- Файл Dockerfile . Этот файл играет ту же роль, что и аналогичный файл в папке сервера. А именно, он содержит инструкцию, описывающую создание среды для выполнения клиентского кода.
3b. Редактирование Python-файла
Добавим в файл client.py следующий код:
Благодаря этому коду клиентское приложение может загрузить данные с сервера и вывести их на экран.
3c. Редактирование файла Dockerfile
Как и в случае с сервером, мы создаём для клиента простой Dockerfile , ответственный за формирование среды, в которой будет работать клиентское Python-приложение. Вот код клиентского Dockerfile :
▍4. Docker Compose
Как вы могли заметить, мы создали два разных проекта: сервер и клиент. У каждого из них имеется собственный файл Dockerfile . До сих пор всё происходящее не выходит за рамки основ работы с Docker. Теперь же мы приступаем к работе с Docker Compose. Для этого обратимся к файлу docker-compose.yml , расположенному в корневой папке проекта.
Обратите внимание на то, что тут мы не стремимся рассмотреть абсолютно все команды, которые можно использовать в docker-compose.yml . Наша главная цель — разобрать практический пример, дающий вам базовые знания по Docker Compose.
Вот код, который нужно поместить в файл docker-compose.yml :
▍5. Сборка проекта
После того, как в docker-compose.yml внесены все необходимые инструкции, проект нужно собрать. Этот шаг нашей работы напоминает использование команды docker build , но соответствующая команда имеет отношение к нескольким сервисам:
▍6. Запуск проекта
Теперь, когда проект собран, пришло время его запустить. Этот шаг нашей работы соответствует шагу, на котором, при работе с отдельными контейнерами, выполняется команда docker run :
После выполнения этой команды в терминале должен появиться текст, загруженный клиентом с сервера: Docker-Compose is magic! .
Как уже было сказано, сервер использует порт компьютера 1234 для обслуживания запросов клиента. Поэтому, если перейти в браузере по адресу http://localhost:1234/, в нём будет отображена страница с текстом Docker-Compose is magic! .
Полезные команды
Рассмотрим некоторые команды, которые могут вам пригодиться при работе с Docker Compose.
Эта команда позволяет останавливать и удалять контейнеры и другие ресурсы, созданные командой docker-compose up :
Эта команда выводит журналы сервисов:
Например, в нашем проекте её можно использовать в таком виде: $ docker-compose logs -f [service name] .
С помощью такой команды можно вывести список контейнеров:
Данная команда позволяет выполнить команду в выполняющемся контейнере:
Например, она может выглядеть так: docker-compose exec server ls .
Такая команда позволяет вывести список образов:
Итоги
Мы рассмотрели основы работы с технологией Docker Compose, знание которых позволит вам пользоваться этой технологией и, при желании, приступить к её более глубокому изучению. Вот репозиторий с кодом проекта, который мы здесь рассматривали.
Уважаемые читатели! Пользуетесь ли вы Docker Compose в своих проектах?
Гайд по Docker: что это такое, зачем его использовать и как с ним работать

Давайте представим себе разработчика, который приходит на работу в новую компанию. На онбординге тимлид дает ему первое шуточное задание: изучить сайт организации и найти на нем страницу с фотографиями котиков.
Разработчик узнаёт, что сайт компании работает с помощью веб-сервера Nginx, менеджера процессов PHP-FPM и системы управления базами данных Postgres. Теперь программист ищет нужную страницу. Поиск выглядит так:
- Разработчик вводит в браузере адрес сайта
- Браузер запрашивает HTML-страницу с котиками по указанному адресу
- HTTP-сервер Nginx принимает запрос и делегирует создание страницы PHP-FPM
- PHP-FPM запрашивает данные о котиках из базы Postgres, строит HTML-страницу и отдает обратно его серверу Nginx, а тот — клиенту-браузеру
- Разработчик видит страницу с котиками.

Свое первое задание разработчик выполняет на компьютере тимлида, где уже установлен Nginx, PHP-FPM и Postgres. На следующий день ему выдают новый компьютер, на котором этих программ нет.
Чтобы начать работать над сайтом вместе с коллегами, разработчик разворачивает проект, то есть устанавливает и настраивает все необходимое для работы. Он делает это последовательно:
- Устанавливает Nginx
- Устанавливает PHP-FPM и все нужные расширения
- Настраивает совместную работу Nginx и PHP-FPM
- Устанавливает Postgres, создает пользователей, нужные базы и схемы.
Установка идет долго: приходится ждать, пока сначала установится одна программа, потом другая. Сложности добавляет и то, что вся его команда работает над проектом на разных операционных системах: одни на macOS, а другие на Ubuntu или Windows.
Чтобы не терять время, устанавливая программу за программой, разработчик мог бы автоматизировать свои действия с помощью программы Docker. Она разворачивает проект программиста за считанные минуты.
Что такое Docker
Docker — это популярная программа, в основе которой лежит технология контейнеризации. Docker позволяет запускать Docker-контейнеры с приложениями из заранее заготовленных шаблонов — Docker-образов (или по-другому Docker images).
Контейнеризация — это технология, которая помогает запускать приложения изолированно от операционной системы. Приложение как бы упаковывается в специальную оболочку — контейнер, внутри которого находится среда, необходимая для работы.
Простыми словами контейнер — это некая изолированная песочница для запуска ваших приложений.

На картинке видно, что приложение 1 и приложение 2 изолированы как друг от друга, так и от операционной системы.
Что еще может делать Docker:
- Управлять изолированными приложениями
- Ускорять и автоматизировать развертывание приложений
- Доставлять приложения до серверов
- Масштабировать приложения
- Запускать на одном компьютере разные версии одной программы.
Как работает Docker
Концепцию программы легче понять на практике. Сначала установим на компьютер Docker и запустим HTTP-сервер Nginx. Для этого введем следующую команду:
docker run -p 8080:80 nginx:latest
Далее откроем браузер и забьем в адресную строку: 127.0.0.1:8080 . Откроется страница приветствия Nginx.

Теперь разберемся подробнее, что происходит, когда мы вводим команду docker run -p 8080:80 nginx:latest . Она выполняет следующее:
- Скачивает docker-образ — шаблон для создания Docker-контейнера — nginx:latest из публичного репозитория Docker Hub (если его не скачивали ранее). Docker-образ содержит все необходимое для запуска приложения: код, среду выполнения, библиотеки, переменные окружения и файлы конфигурации. На странице Nginx в Docker Hub можно найти Docker-образ nginx:latest, где latest — это тег (метка, снимок), который ссылается на самый свежий docker-образ и описывает его.
- Запускает Docker-контейнер с помощью Docker-образа
- Пробрасывает порт. Ранее мы объясняли, что процессы в Docker-контейнерах запускаются в изоляции от ОС, то есть все порты между ОС и Docker-контейнером закрыты. Для того, чтобы мы смогли обратиться к Nginx, нужно пробросить порт, что и делает опция -p 8080:80 , где 80 — это порт Nginx внутри контейнера, а 8080 — порт в локальной сети ОС.

Как создать свой Docker-образ
Теперь попробуем создать свой Docker-образ, взяв за основу nginx:latest . Docker умеет создавать Docker-образ, читая текстовые команды, которые записаны в файл Dockerfile.
Вот пример простейшего Dockerfile:
Команда FROM задает базовый (родительский) Docker-образ и всегда вызывается в первую очередь. Команда COPY копирует файлы в Docker-контейнер.
С помощью COPY можно заменить стандартную велком-страницу Nginx на такую страницу:
Узнать подробнее об этих и других командах Docker можно в официальной документации.
Теперь, когда мы разобрались, за что отвечают команды, создадим Docker-образ из Dockerfile:
Поясним, какие команды мы использовали в этом коде:
- -t nginx_custom:latest — это имя будущего Docker-образа, latest — это тег
- -f /opt/src/docker-for-kids/dockerFiles/Nginx-custom/Dockerfile — путь до Dockerfile
- /opt/src/docker-for-kids — директория, в контексте которой будет создан Docker-образ. Контекст — это все то, что доступно для команд из Dockerfile при сборке (билде) образа. Процесс создания Docker-образа может ссылаться на любой из файлов в контексте.
Теперь запускаем команду:
$ docker run -p 8080:80 Nginx_custom:latest

Что такое Docker Compose и как он работает
С ростом количества Docker-контейнеров их становится труднее поддерживать. Конфигурация каждого контейнера описывается в своем Dockerfile, и их нужно запускать отдельной командой. Это же касается сборки или пересборки контейнеров.
Работу облегчает Docker Compose — это инструмент для описания многоконтейнерных приложений. С его помощью можно собрать один файл, в котором наглядно описываются все контейнеры. Еще Docker Compose позволяет собирать, останавливать и запускать файлы одной командой.
Для описания приложений используется YAML-файл.
Если изображать этот код схематично, то описание приложения выглядит так:

Каждый сервис находится внутри Docker-контейнера. Точкой входа в приложение, как и в случае с тем разработчиком и веб-сайтом компании, является Nginx. Пользователи веб-сайта делают запросы к Nginx, у которого проброшен порт 80.
Разберем еще несколько команд, которые реализует Docker:
- network . Как мы объяснили ранее, каждое приложение в Docker-контейнере находится в изоляции. networks объединяет все Docker-контейнеры в одну сеть с именем test-network, и это позволяет обращаться к нужному контейнеру по его имени.
- volumes — это механизм для хранения данных вне Docker-контейнера, то есть в файловой системе нашей ОС. volumes решает проблему совместного использования файлов.
Все примеры, а также исходники Dockerfile можно взять из репозитория на GitHub.
Как создать простое веб-приложение с помощью Docker
Создадим простое веб-приложение, которое покажет нам сообщение об успешном подключении к базе данных. Вместо адреса базы данных используем host=postgres , такое же имя cервиса, как и в YAML-файле. Напомню, что эта возможность появилась благодаря общей сети test-network.
PDO — это интерфейс для доступа к базам данных в PHP. Подробнее об этом можно узнать в официальной документации.
Теперь, чтобы создать все Docker-образы и запустить Docker-контейнеры нужно выполнить:
Выполняем index.php и видим успешное соединение с базой данных.

Веб-приложение для самостоятельного запуска можно найти в репозитории на GitHub.
Освоив Docker, разработчики могут разворачивать все необходимые им сервисы на каком угодно компьютере. Также эта программа — отличный инструмент для быстрой доставки до серверов, тестирования. Изучить Docker не так тяжело, как может показаться новичкам, но зато это умение значительно сэкономит их время на ручной установке софта. Почитать про Docker подробнее можно на официальном сайте.
Изучите основы Docker: На Хекслете есть курс по основам Docker. Пройдите его, чтобы подробнее узнать об этой программе, научиться работать с образами, управлять контейнерами и получить поддержку от менторов и единомышленников.
Docker и docker-compose для начинающих. Докеризуем интернет-магазин
Докер везде. Когда-то на него смотрели, как на очередную забаву неугомонных программистов, но докер оказался не таков. Если раньше в любой вакансии писали jquery и zend framework, то сейчас — git и docker. Не удивлюсь, если докер станет таким же стандартом, как и гит в свое время. Или уже стал, это я только из пещеры вылез.
Зачем мне понадобился докер? Ну не знал и не знал, сидел не умничал, сейчас-то что началось?
Разбираться с ним меня сподвигли вы, дорогие читатели. Да ладно? Серьезно. Четверть вопросов по интернет-магазину звучит примерно так: не работает, что делать? Почти всегда причина в том, что нужно настроить окружение. Поставить веб-сервер, завести php и mysql, развернуть базу и прочие рутинные штуки.
Вопрос разворачивания рабочего окружения для веб-проектов волновал меня давно.
Когда я начал заниматься первыми веб-проектами, то ухитрился поднять apache, php и mysql на windows 7. Было это лет 8 назад. История из серии «один раз получилось, но повторить не смогу». Это медаль, которую получаешь раз в жизни.
Вторая попытка осмыслить вопрос рабочего окружения случилась в 2015 году. Я тогда написал адовую статью, как развернуть окружение для веб-разработчика. Это было страшно, но я сам так работал. Схема предполагала винду как основную ОС, в винде ставилась виртуальная машина VirtualBox, в которой поднимался debian. В debian уже nginx, php, mysql и nodejs. Также ssh-сервер на виртуалке и ssh-клиент на винде. Все это волшебным образом соединялось вместе и реально работало! Я не жалею, что творил эту дичь, но вам не советую проделывать такой же путь. Просто не надо. Мир стал намного проще.
Затем я пересел на linux и сразу стало легче. nginx, php и mysql ставились несколькими командами. Раз поставил, нашел типовую конфигурацию для nginx и фигачишь. Создать виртуальный хост для нового проекта — дело двух минут. По сей день так работаю.
Но вопрос читателей меня не оставлял. Ведь все мы разные. Одни только начинают разбираться в веб-разработке. Другие работают на винде и им так удобнее. Третьи занимаются фронтендом и им вообще до фонаря эти php и базы данных. Они хотят потрогать javascript-код, а как его потрогаешь, если магазин просто не заводится?
Часто меня выручали системы вроде denwer и open server. Я сам ими не пользовался, но видел со стороны, как это работает, и поэтому советовал. В том же денвере apache, php и mysql поднимаются довольно просто, на мой взгляд. Судя по отзывам, некоторых читателей это выручало.
Но пора было делать следующий шаг.
Докер
Докер — это такая штука для разработки и разворачивания приложений. В случае веб-проектов докер позволяет развернуть nginx, php, mysql, phpmyadmin и вообще любые приложения. Причем все это добро не нужно ставить руками и засорять систему. Все сервисы запускаются в виртуальных контейнерах и никак не влияют на основную ОС. То есть у вас в системе будут только докер, редактор кода, браузер и командная строка. Звучит круто, но пока бесполезно, да? Но смотрим дальше.
Если приложение завернуто в докер, то оно запускается одной командой. По ходу статьи мы увидим, как это делается. Представьте, чтобы посмотреть, как работает авторизация или админка в интернет-магазине, вам нужно лишь скачать исходники и выполнить команду
Да-да, это все. Забудьте об nginx, php и mysql, о том, что под капотом крутится вебпак и нужно не забывать делать npm install — всю эту работу возьмет на себя докер. Больше не нужно гадать, заведется ли код на вашей версии php или какую базу данных нужно поставить. Все это докер делает под капотом. Нам остается работать над кодом и не думать об окружении.
Конечно, это все звучит здорово, но прежде чем так легко обращаться с докером, нужно разобраться как и что.
Основы докера
Разбираясь в теме, я прочитал десятка три статей по докеру. Но в голове все уложилось только когда я нашел вот эту
Рекомендую статью всем, кто хочет не просто скопипастить примеры из моей статьи, а понять, что такое докер, образы, контейнеры, как монтировать папки и файлы, как запускать команды и еще много полезных вещей. Статья большая, но написано по-человечески, простым языком, с примерами и аналогиями из жизни.
Докер на практике, docker-compose
docker-compose — это система, которая позволяет управлять набором из докер-контейнеров. То есть работают отдельные контейнеры nginx, php, mysql, но все это еще нужно подружить между собой. Любой туториал по докеру приводит в пример, как запустить nginx, но нам этого мало. Как завести сразу все, что нужно? Иными словами, LEMP — linux, nginx, php и mysql.
Здесь случилось то же самое, что и с теорией по основам докера. Я перепробовал много разных вариантов, но то php не заводился, то mysql не подключался. Удалось все сделать только по примеру из этой статьи
Рекомендую читать всем, но особенно тем, кто уже разбирался с docker и docker-compose. Если вы знаете общие принципы или просто хотите завести свой проект, то лучше прочитать эту статью. Автор расписал коротко и по делу. Это не как у меня, статьи только с литром пива читать.
А еще мне понравилась структура проекта из поста. С разрешения автора в своей статье я использую его структуру и конфиги проекта практически без изменений, разве что слегка сократив.
docker и docker-compose. Аналогия для фронтендщиков
Процесс докеризации проекта напоминает мне сборку фронтенда.
В обоих случаях нам нужно решить набор задач. На фронте это собрать весь javascript в один файл и сжать его, препроцессить стили и тоже их сжать, оптимизировать картинки, запустить watcher. А с докером это поднять nginx, php, mysql и развернуть базу.
Для сборки фронта мы используем npm-пакеты, готовые библиотеки для сжатия и склеивания. В докере это готовые образы nginx, php, mysql.
Все это добро на фронте собирается в один конфиг gulpfile.js или webpack.config.js, а в докере — в docker-compose.yml. И все задачи запускаются одной командой, например, gulp build или docker-compose up —build
Вот такая у меня аналогия. С общими делами разобрались, переходим к практике
Ставим docker и docker-compose
Докер отлично работает на линуксе и маке. Говорят, на 10-й винде тоже, но не пробовал. Я не знаю, какая у вас система, поэтому смотрите инструкции здесь.
Выбирайте версию CE — Community Edition, она бесплатная. EE — enterprise, нам ни к чему.
После установки докера перезагрузитесь и проверьте, все ли в порядке
Если что-то не заработает, то наберите такие команды
Структура проекта
- В папке hosts мы будем хранить конфиги nginx
- В images — образы докера, пока только php
- Папка logs нужна для хранения логов nginx
- mysql будет содержать файлы базы данных
- В www будем складывать непосредственно проекты. Каждый проект в отдельной папке. Для начала — default.test, который будем использовать для примера.
- docker-compose.yml — файл конфига, который соберет все в кучу
Тестовый проект default.test
Он будет очень простой. Закинем в папку www/default.test файлик index.php с содержимым
Вот и весь проект. На первом этапе мы всего лишь убедимся, что правильно настроили nginx и php. Давайте же посмотрим, как это сделать
Конфиг nginx
Это файл hosts/default.conf такого содержимого
Если вам приходилось настраивать nginx, то отличие найдете только одно. Раньше в локейшене \.php$ в fastcgi_pass вы писали что-то вроде
Теперь же php:9000. Это докеровская тема, php — это название хоста, по которому доступен php-контейнер, а 9000 — порт, по которому до него можно достучаться.
Такой конфиг более менее универсальный и подходит для локальной разработки несложных проектов. В статье мы рассмотрим 3 проекта и конфиги в них будут различаться только 4 строками.
- index index.php index.html; — это путь к корневому файлу проекта. Можно оставить оба, и php, и html. Если в папке будет index.php, то исполльзуется он, если нет — то index.html
- server_name default.test; — имя хоста, которое мы будем вбивать в браузере
- error_log /var/log/nginx/default.error.log; — куда складывать error логи nginx. Вот и пригодилась папка logs. Для каждого проекта будем заводить отдельные логи, хотя никто не запрещает складывать все в просто error.log и у вас будет один файл на все проекты. Для разработки годится
- access_log /var/log/nginx/default.access.log; — аналогично, только для access логов
- root /var/www/default.test; — папка проекта. Хост и название папки указываем одинаково, с точкой, чтобы не путаться
Настраиваем php и Dockerfile для него
По идее можно не делать отдельный Dockerfile для php, а взять готовый образ. Именно так мы сделаем с nginx и mysql, когда будем настраивать docker-compose.yml. Но проблема в том, что nginx и mysql прекрасно работают из коробки, а с php немного иначе. Он тоже работает, но в официальный образ не включены никакие расширения, которые могут понадобиться при работе. Именно поэтому мы будем собирать php хитрее, через Dockerfile.
Давайте посмотрим на конфиг. Это файл images/php/Dockerfile
Напоминаю, что мы взяли конфиги из этой статьи. Я чуть сократил конфиг, поэтому читайте исходный, найдете там еще что-то интересное. Кратко что здесь происходит.
- FROM php:7.2-fpm — указываем официальный образ. Напоминаю, он пустой, без всяких расширений
- Блок RUN — куча линукс-команд, которые ставят curl, wget и различные расширения вроде mysqli и mcrypt. Без mysqli, например, наш интернет-магазин просто не заработает
- ADD php.ini /usr/local/etc/php/conf.d/40-custom.ini — это возможность использовать кастомный php.ini. Кстати, добавьте его в папку images/php, пусть будет пустой
- WORKDIR /var/www — рабочая директория для php
- CMD [«php-fpm»] — команда запуска контейнера
Да, Dockerfile для php посложнее, чем стандартный nginx-конфиг. nginx мы просто будем копипастить, меняя хост и пути. Здесь же, чтобы самому написать такой файл, нужно представлять, как работает php, где хранится php.ini, что такое рабочая директория и как ставить расширения. Но с другой стороны, базовые настройки меняться не будет, главное, разобраться со страшной портянкой в RUN.
Блок RUN — это набор команд, которые мы нагуглили «как установить php в linux» и вбили в консоли. Разве что расширения ставятся через docker-php-ext-install. Например, в линуксе мы бы поставили mysqli примерно так
А в докере нужно указать его в строке
Если честно, мне пока сложно понять, где и какие команды используются в тех или иных случаях. Поэтому не вижу других способов, чтобы для каждого конкретного случая копать документацию и гуглить. Но повторюсь, для наших проектов большего не понадобится. В Dockerfile мы больше заглядывать не будем.
Пора собирать nginx и php в единое целое — переходим к docker-compose.yml
Конфиг docker-compose.yml
Файл будет такого содержания
Разберем, что здесь написано.
version: ‘2’ — версия docker-compose. Сейчас есть и 3-я, но там какие-то совсем хитрые штуки, нам хватит и 2
services — здесь перечисляем контейнеры, которые будут у нас работать в связке. Пока что nginx и php, позже добавим mysql
image: nginx:latest — используем последнюю версию образа nginx с официального хранилища dockerhub
ports: — «8000:80» — здесь прокидываем порты. nginx в контейнере работает на дефолтном 80, а мы возьмем 8000. Это значит, в браузере будем открывать не default.test, a default.test:8000
volumes: — здесь монтируем файлы и папки. Или прокидываем их из локальной системы в контейнер. Посмотрим первый пример ./hosts:/etc/nginx/conf.d. В папке hosts у нас лежат конфиги nginx, но контейнер-то об этом не знает. Контейнер изолирован от нашей основной системы, а раздел volumes как раз и позволяет «общаться» контейнеру с нашей ОС. Можно считать эту команду копированием содержимого локальной папки ./hosts в «удаленную папку» контейнера /etc/nginx/conf.d. Или еще лучше настройкой ссылки (симлинки). Аналогично ./www:/var/www указывает рабочую директорию для nginx, а ./logs:/var/log/nginx — расположение логов
links: — php указывает, что контейнер nginx имеет зависимость от php
Дальше раздел php. Здесь короче, потому что основное мы указали в Dockerfile
build: ./images/php — папка, где располагается Dockerfile
volumes: — ./www:/var/www — прокидываем рабочую директорию точно так же, как и для nginx
С конфигом docker-compose.yml пока все. Идем дальше
Правим файл hosts
Чтобы наш пробный сайт default.test заработал в браузере, нужно не забыть добавить его в файл hosts. Открываем /etc/hosts с sudo (на unix-системах) и добавляем в него
Точно так же, как и при работе с локальным веб-сервером. Сохраняем файл, закрываем
Запускаем проект
Наконец-то самое интересное, проверим, как все это работает. В консоли из корневой папки проекта запускаем команду
И ждем. Первый запуск будет проходить не быстро. В консоль будет сыпаться до фига всего разного, но можно будет разглядеть, как скачиваются образы ngnix и php, как выполняются команды RUN из php-шного Dockerfile, как запускаются контейнеры.
Если мы все сделали правильно, то увидим в консоли примерно такую картину
done напротив названий контейнеров говорит, что они успешно запущены. Идем в браузер, переходим на http://default.test:8000/ и видим полный расклад phpinfo. Работает!
Мы запустили наш первый проект, завернутый в докер. Не знаю, как вы, а я испытал какой-то священный трепет, когда все это завелось. С ума сойти, я могу просто взять этот проект, перетащить на другой компьютер и запустить его одной командой в консоли. Да, весь проект всего лишь выводит phpinfo, но эта простенькая штука станет базой для разворачивания более сложных проектов, связанных с базой данных да и вообще с чем угодно. Ниже мы научимся подключать в докере mysql и заведем интернет-магазин.
Но сначала немного отвлечемся и посмотрим, какие команды нам пригодятся при работе с docker-compose и вообще с проектами
Как работать с docker-compose
Первой командой, которую мы запустили, был docker-compose up. Команда анализирует конфиг docker-compose.yml, скачивает нужные образы, монтирует файлы и папки и запускает контейнеры. При этом процесс висит в консоли, а чтобы остановить его, нужно нажать ctrl+C, стандартно. А еще в консоли будут выводиться логи docker-compose.
Можно запустить контейнеры с опцией —build, вот так
При этом принудительно пересоберутся все образы. Это может быть полезно, когда мы что-то поменяли в конфигах и пока еще не понимаем, требует это пересборки или нет. Принудительный билд занимает больше времени, но я пока предпочитаю всегда его использовать. Все равно после самого первого сбора запуск проходит очень быстро, а потерпеть лишние 2 секунды не проблема.
Если вы не хотите, чтобы в консоли висел открытый docker-compose, запускайте его как процесс, с опцией -d
Тогда докер запустит все контейнеры, но в фоне. Все будет работать точно так же, но чтобы остановить контейнеры, нужно будет запускать
А логи смотреть, запуская отдельно
Если мы разворачиваем приложение в продакшене, то конечно, запускать его стоит как фоновый процесс. Но в режиме разработки мне больше нравится держать консоль открытой и сразу смотреть логи. И не думать, нужна ли пересборка всех образов или нет. То есть запускать
Еще при разработке бывает полезно заглянуть в логи nginx. Отслеживать их будем через обычный tail -f
Пока это самое базовое, что может нам потребоваться. Для более тонкой работы с отдельными образами и контейнерами читайте вышеупомянутую статью — Docker самый простой и понятный туториал
Запускаем второй проект. Мое старое портфолио
Предлагаю немного передохнуть и закрепить информацию. Каким образом? Мы создадим второй проект. Он тоже php-ный, но чуть сложнее одного файла. Там уже подключаются шрифты, стили и javascript. Технически это не будет отличаться от первого default.test, но фишка в другом. Мы увидим, как просто нам теперь создавать новые проекты, а заодно и посмотрим на мое старое портфолио, которое я создал лет 6-7 назад. Это простой сайт на php, где рассказывается, какой я замечательный человек и разработчик.
Создаем новую папку www/w-portfolio.test. Кладем туда файлы проекта. Расписывать их нет смысла, все найдете в исходниках.
Дальше добавляем nginx конфиг в hosts — w-portfolio.conf с содержимым
То есть мы скопировали конфиг из дефолтного default.conf и поменяли default на w-portfolio. Что может быть проще?
Осталось добавить в файл hosts строку
И перезапустить docker-compose
И открыть в браузере http://w-portfolio.test:8000
Итак, второй сайт разобрали, идем дальше.
Создаем проект интернет-магазина
Все то же самое, что и с проектом w-portfolio.test.
Создаем папку w-shop.test, копируем туда файлы магазина. Если вы читали статьи по магазину или админке, то в курсе, что это за магазин. Можете просто взять свои локальные файлы. А если нет, то взгляните, как этот самый магазин выглядит shop.webdevkin.ru и берите файлы из исходников
Дальше заводим nginx-конфиг w-shop.conf в папке hosts
И прописываем в /etc/hosts строку
Если вы прямо сейчас перезапустите docker-compose, то у вас откроется первая страница http://w-shop.test:8000/ и корзина http://w-shop.test:8000/cart.html. Будет работать даже добавление в корзину. А вот каталог с фильтрами, каталог с пагинацией и отправка заказов не заведутся, потому что там уже включается база. Давайте разбираться, как работать с mysql
Подключаем mysql
Добрались до самого интересного. Идем сразу в конфиг docker-compose.yml и добавим в services новый раздел mysql, вот так
А в раздел php добавим зависимость от нового контейнера
Разбираемся по порядку.
image: mysql — образ mysql из dockerhub-хранилища
ports: — «3307:3306» — справа дефолтный порт, на котором mysql работает в контейнере. Слева — порт, который займет mysql в локальной ОС. Почему я не оставил тоже дефолтный 3306? Потому что у меня уже установлен локальный mysql. У вас, скорее всего, тоже. И когда я попытался запустить докер, то он мне сказал, извини, чувак, порт 3306 уже занят, не шмогла. Проверяем в консоли
Действительно занят. Можно остановить локальный mysql через sudo service mysql stop, а можно просто повесить докеровский mysql на другой порт. Например, на 3307 или любой другой свободный.
Идем дальше.
volumes: — ./mysql:/var/lib/mysql — монтируем папки, ./mysql — это папка в нашем проекте, куда будем складывать файлы базы, а /var/lib/mysql — это папка, где лежит база по дефолту. По идее, можно держать базу и внутри контейнера, но удобнее вытащить в «свою» ОС. Например, так можно будет делать бэкапы и использовать одну и ту же базу в разных проектах
И последнее
environment: MYSQL_ROOT_PASSWORD: root — переменные среды. Здесь указываем только пароль для root-пользователя. В интернет-магазине у нас использовался root/root, пусть и здесь так же
В php мы добавили блок-зависимость от нового контейнера mysql
links: — mysql
Все, база mysql у нас будет подниматься и будет работать. Но есть одно но. Как с ней работать руками? Чтобы прямо войти и посмотреть.
Конечно, можно подключаться к ней в консоли и фигачить create table и прочие хакерские заклинания, но хочется чего-то попроще. Люди давно изобрели PhpMyAdmin, который стоит на каждом хостинге и нам привычен. Давайте и его заведем в докер.
Устанавливаем PhpMyAdmin
В docker-compose.yml добавляем еще один контейнер
- image: phpmyadmin/phpmyadmin — берем официальный образ
- restart: always — вот этой магии, честно, не понял. Всегда перезапускать контейнер, но почему только этот? Как узнаю, расскажу, а пока оставим так
- links: — mysql:mysql — зависимость от mysql
- ports: — 8001:80 — справа дефолтный порт, на котором phpmyadmin запущен в контейнере, слева — любой свободный, я взял 8001 — следующий за 8000, по которому открываем сам сайт
- И переменные среды: хост, пользователь и пароль. В реальном приложении, конечно, не будем заходить под рутом, но для примера годится
environment: PMA_HOST: mysql, MYSQL_USERNAME: root, MYSQL_ROOT_PASSWORD: root
Готово, скоро будем пробовать. Но пока еще раз отвлечемся
Зависимости в docker-compose
Обратите внимание, как мы проставляли зависимости контейнеров друг от друга.
nginx зависит от php, то есть сначала стартует php, а потом nginx. php от mysql, phpmyadmin тоже от mysql и лишь mysql ни от кого не зависит. Она база, она сама по себе работает.
Когда мы запустим docker-compose снова, то увидим в консоли такую картину
Это как раз демонстрирует порядок запуска контейнеров. А останавливаются они в обратном порядке
Сначала те, от которых никто не зависит, в конце — самые «важные».
Но это было отступление, погнали дальше, проверять mysql
Подключаемся к базе через PhpMyAdmin
Запускаем docker-compose up —build. Снова придется подождать, потому что докеру нужно выкачать 2 новых образа. Ждем, дожидаемся успеха и открываем http://w-shop.test:8001. Видим привычную форму входа в PhpMyAdmin. Вбиваем логин/пароль root/root и входим в интерфейс базы. Но здесь нас может ждать сюрприз.
У меня получилось так — я успешно зашел в PhpMyAdmin один раз, поковырялся там, создал базу и вышел. А вот второй раз зайти уже не смог. Вбиваю root/root, а в ответ mysql not connect или что-то такое.
Полез гуглить. Нашел, что в этом случае нужно из под рута выполнить такой запрос
PASSWORD в смысле root — наш пароль рута. Это понятно, а как войти-то в базу, раз PhpMyAdmin не пускает? Нужно лезть руками, в консоли, по хакерски. mysql -uroot -proot и вот это вот. Тонкость в том, что нужно сначала зайти в контейнер mysql, а уже потом в саму базу mysql. Давайте вспомним статью по основам докера, которую я рекомендовал в самом начале.
Чтобы попасть в контейнер, нужно узнать его id. Набиваем docker ps и видим примерно такой список

Id контейнера mysql — 3825c5051ee9. Давайте заглянем в него
Мы зашли в контейнер и запустили в нем команду bash. Ключ -it нужен, чтобы создать интерактивный терминал. Проще говоря, мы попали в консоль контейнера. Здесь уже привычнее. Подключаемся к базе рутом и выполняем нагугленный запрос
После этого все заработало и PhpMyAdmin стал пускать без ограничений.
Создаем базу данных интернет-магазина
По фэншую мы должны были создать базу и накатить sql-дамп через докер. Запустить команду mysql -uroot -proot