В этом гайде разбираемся, для чего нужен Docker и Docker Compose, что такое контейнеризация и Docker-образы, а также как развернуть простое веб-приложение с использованием PHP-FPM, Nginx и Postgres.
- Что такое Docker
- Как работает Docker
- Как создать свой Docker-образ
- Что такое 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. Она разворачивает проект программиста за считанные минуты.
- Освойте азы современных языков программирования
- Изучите работу с Git и командной строкой
- Выберите себе профессию или улучшите навыки
Что такое Docker
Docker — это популярная программа, в основе которой лежит технология контейнеризации. Docker позволяет запускать Docker-контейнеры с приложениями из заранее заготовленных шаблонов — Docker-образов (или по-другому Docker images).
Контейнеризация — это технология, которая помогает запускать приложения изолированно от операционной системы. Приложение как бы упаковывается в специальную оболочку — контейнер, внутри которого находится среда, необходимая для работы.
Простыми словами контейнер — это некая изолированная песочница для запуска ваших приложений.
На картинке видно, что приложение 1 и приложение 2 изолированы как друг от друга, так и от операционной системы.
Что еще может делать Docker:
- Управлять изолированными приложениями
- Ускорять и автоматизировать развертывание приложений
- Доставлять приложения до серверов
- Масштабировать приложения
- Запускать на одном компьютере разные версии одной программы.
Читайте также: Как читать чужой код: 6 правил, которые стоит помнить разработчику
Как работает 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 nginx:latest
RUN echo 'Hi, we are building a custom docker image from nginx:latest!'
COPY nginx-custom-welcome-page.html /usr/share/nginx/html/index.html
Команда FROM
задает базовый (родительский) Docker-образ и всегда вызывается в первую очередь. Команда COPY
копирует файлы в Docker-контейнер.
С помощью COPY
можно заменить стандартную велком-страницу Nginx на такую страницу:
<!DOCTYPE html>
<html>
<body>
<h1>Welcome to custom Nginx page!</h1>
</body>
</html>
Узнать подробнее об этих и других командах Docker можно в официальной документации.
Теперь, когда мы разобрались, за что отвечают команды, создадим Docker-образ из Dockerfile:
$ docker build -t nginx_custom:latest -f /opt/src/docker-for-kids/dockerFiles/Nginx-custom/Dockerfile /opt/src/docker-for-kids
Sending build context to Docker daemon 139.3kB
Step 1/3 : FROM nginx:latest
latest: Pulling from library/nginx
31b3f1ad4ce1: Pull complete
fd42b079d0f8: Pull complete
30585fbbebc6: Pull complete
18f4ffdd25f4: Pull complete
9dc932c8fba2: Pull complete
600c24b8ba39: Pull complete
Digest: sha256:0b970013351304af46f322da1263516b188318682b2ab1091862497591189ff1
Status: Downloaded newer image **for** nginx:latest
---**>** 2d389e545974
Step 2/3 : RUN echo 'Hi, we are building a custom docker image from nginx:latest!'
---**>** Running **in** 05ffd060061f
Hi, we are building a custom docker image from nginx:latest!
Removing intermediate container 05ffd060061f
---**>** 9ac62be4252a
Step 3/3 : COPY nginx-custom-welcome-page.html /usr/share/nginx/html/index.html
---**>** 704121601a45
Successfully built 704121601a45
Successfully tagged nginx_custom:latest
Поясним, какие команды мы использовали в этом коде:
-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-образ готов.
Читайте также: Как настроить VS Code для разработки на PHP и JavaScript
Что такое Docker Compose и как он работает
С ростом количества Docker-контейнеров их становится труднее поддерживать. Конфигурация каждого контейнера описывается в своем Dockerfile, и их нужно запускать отдельной командой. Это же касается сборки или пересборки контейнеров.
Работу облегчает Docker Compose — это инструмент для описания многоконтейнерных приложений. С его помощью можно собрать один файл, в котором наглядно описываются все контейнеры. Еще Docker Compose позволяет собирать, останавливать и запускать файлы одной командой.
Для описания приложений используется YAML-файл.
version: '3'
services:
nginx:
container_name: nginx-test # имя Docker-контейнера
build: # создать Docker-образ из DockerFile
context: . # путь, в контексте которого будет создан Docker-образ
dockerfile: ./dockerFiles/nginx/Dockerfile # путь до Dockerfile, из которого будет собран Docker-образ
ports: # проброс портов
- "80:80"
networks: # имя сети, к которой будет подключен Docker-контейнер
- test-network
depends_on: # эта программа будет запущена только после того, как запустится сервис под именем php-fpm
- php-fpm
volumes: # монтирование директорий, директория-на-хост-машине: директория-в-докере
- ./:/var/www/hello.dev/
php-fpm:
container_name: php-fpm-test
build:
context: .
dockerfile: ./dockerFiles/php-fpm/Dockerfile
networks:
- test-network
volumes:
- ./:/var/www/hello.dev/
postgres:
container_name: postgres-test
image: postgres:14.1-alpine # тег Docker-образа из https://hub.docker.com/
environment:
postgres_PASSWORD: mysecretpass # переменные окружения, которые использует Docker-контейнер
networks:
- test-network
networks: # явно объявленные сети
test-network:
driver: bridge
Если изображать этот код схематично, то описание приложения выглядит так:
Каждый сервис находится внутри Docker-контейнера. Точкой входа в приложение, как и в случае с тем разработчиком и веб-сайтом компании, является Nginx. Пользователи веб-сайта делают запросы к Nginx, у которого проброшен порт 80.
Разберем еще несколько команд, которые реализует Docker:
network
. Как мы объяснили ранее, каждое приложение в Docker-контейнере находится в изоляции.networks
объединяет все Docker-контейнеры в одну сеть с именем test-network, и это позволяет обращаться к нужному контейнеру по его имени.volumes
— это механизм для хранения данных вне Docker-контейнера, то есть в файловой системе нашей ОС.volumes
решает проблему совместного использования файлов.
Все примеры, а также исходники Dockerfile можно взять из репозитория на GitHub.
Полезно узнать: Как настроить маппинг портов между хостом и Docker-контейнером
Как создать простое веб-приложение с помощью Docker
Создадим простое веб-приложение, которое покажет нам сообщение об успешном подключении к базе данных. Вместо адреса базы данных используем host=postgres
, такое же имя cервиса, как и в YAML-файле. Напомню, что эта возможность появилась благодаря общей сети test-network.
index.php
<?php
try {
$pdo = new \PDO("pgsql:host=postgres;dbname=postgres", 'postgres', 'mysecretpass');
echo "Подключение к базе данных установлено! <br>";
return;
} catch (PDOException $exception) {
echo "Ошибка при подключении к базе данных<br><b>{$exception->getMessage()}</b><br>";
}
PDO
— это интерфейс для доступа к базам данных в PHP. Подробнее об этом можно узнать в официальной документации.
Теперь, чтобы создать все Docker-образы и запустить Docker-контейнеры нужно выполнить:
docker-compose up --build
Выполняем index.php и видим успешное соединение с базой данных.
Веб-приложение для самостоятельного запуска можно найти в репозитории на GitHub.
Итог
Освоив Docker, разработчики могут разворачивать все необходимые им сервисы на каком угодно компьютере. Также эта программа — отличный инструмент для быстрой доставки до серверов, тестирования. Изучить Docker не так тяжело, как может показаться новичкам, но зато это умение значительно сэкономит их время на ручной установке софта. Почитать про Docker подробнее можно на официальном сайте.
- Освойте азы современных языков программирования
- Изучите работу с Git и командной строкой
- Выберите себе профессию или улучшите навыки