Быстрый гайд как поднять сайт в Docker

Всем привет! Постараюсь описать не вдаваясь в сложные термины, как же быстро и без проблем поднять сайт в Docker при помощи docker-compose.

Первый шаг


Для начала нам нужен сам сайт. Предположим, что у нас уже есть некоторый index.php который отдаёт "Hello world" в браузер. Так же предположим, что Docker у вас уже установлен.

Второй шаг: создание файла docker-compose.yml


Контейнеры в Docker - это не виртуальные машины, это просто скорее некоторые выделенные пространства. Нам нужно определиться, какие нам нужны.
Для начала нам должно хватить трёх: первый - это обычный mysql. Второй - это phpmyadmin. Третий - это наше приложение.
Создаём сначала папку db рядом с папкой app, так же следом создаём в корне файл docker-compose.yml.
В папке db mysql сам нашуршит свои файлы баз данных чтобы они не потерялись если вдруг вы будете пересобирать контейнеры. Папка для базы, да.
Структура получается вот такая:

Ну а сам docker-compose.yml такого содержания:

version: '3'
services:
  db: #добавляем сюда контейнер с названием db
    image: 'mysql:latest' #образ берём последний
    environment:
      MYSQL_ROOT_PASSWORD: 12345 #здесь нужно обязательно задать пароль для root
    command: mysqld --default-authentication-plugin=mysql_native_password
    ports:
      - '3306:3306' #порт для mysql
    volumes:
      - './db:/var/lib/mysql' #говорим что папка db проброшена внутрь контейнера и будет использоваться вместо /var/lib/mysql
    networks:
      - default #говорим, чтобы контейнер использовал дефолтную сеть
  phpmyadmin: #контейнер с phpmyadmin
    image: phpmyadmin/phpmyadmin
    links:
      - 'db:db' #делаем линк
    ports:
      - '8000:80' #сажаем 80 порт ИЗ контейнера на 8000 порт в нашей системе
    environment:
      PMA_HOST: db #дефолтный хост для базы
      PMA_PORT: 3306 #дефолтный порт для базы
  app: #наш основной контейнер с сайтом
    build: . #билдить надо всё что в нашей папке
    ports:
      - '80:80' #сажаем 80 порт из контейнера на 80 порт нашего компьютера. Т.е. получается, что мы сможем из браузера по ссылке http://localhost попадать куда надо
    volumes:
      - './app:/var/www/html/' #говорим, что папка app будет использоваться вместо /var/www/html
    restart: always #всегда перезапускать если контейнер упал или закончил работу
    links:
      - db
    networks:
      - default
volumes:
  persistent: null

Третий шаг: создание Dockerfile


Теперь нам нужно определить, что за контейнер у нас будет и что в нём будет. Для этого мы так же создаём в корне Dockerfile и наполняем его командами для установки nginx и php.
Dockerfile:
FROM ubuntu:20.04 as intermediate

# Выставляем по умолчанию московское время внутри контейнера
RUN ln -snf /usr/share/zoneinfo/"Europe/Moscow" /etc/localtime && echo "Europe/Moscow" > /etc/timezone

# Установка пакетов php и nginx через apt (он используется по умолчанию для ubuntu)
RUN apt-get update \
        && apt-get install -y nginx php7.4 php7.4-cli php7.4-common php7.4-curl php7.4-dev php7.4-mysql php7.4-fpm

# Берём из нашей папки conf (создадим чуть позже) конфиг, который помещаем внутрь и кладём по пути /etc/nginx/sites-available/default
COPY conf/nginx.conf /etc/nginx/sites-available/default

# Нам нужен entrypoint.sh скрипт который будет работать бесконечно и не давать контейнеру заглохнуть
COPY conf/entrypoint.sh /entrypoint.sh
# Так же даём ему немножко прав
RUN chmod a+x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

Четвёртый шаг: nginx.conf и entrypoint.sh


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

В файл entrypoint.sh вешаем запуск php-fpm, nginx и чтение лога.

#!/bin/bash

echo "Запускаю nginx & php-fpm"
nginx && php-fpm7.4

#Здесь мы вешаем бесконечный просмотр лога nginx который будет показывать ошибки пока контейнер запущен
tail -f /var/log/nginx/error.log

Ну а файл nginx.conf заполняем практически стоковой для таких файлов конфигурацией.

server {
    listen 80;
    listen [::]:80;
    server_name  localhost;

    root /var/www/html/;
    
    location / {
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/index\.php(/|$) {
       fastcgi_split_path_info  ^(.+\.php)(/.+)$;
       fastcgi_index            index.php;
       fastcgi_pass             unix:/var/run/php/php7.4-fpm.sock;
       include                  fastcgi_params;
       fastcgi_param   PATH_INFO       $fastcgi_path_info;
       fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
       internal;
    }

    location ~ \.php$ {
        return 404;
    }

    error_log /var/log/nginx/project_error.log;
    access_log /var/log/nginx/project_access.log;

}

Первый запуск


Запускаем $ docker-compose up в консоли и ждём, пока всё соберётся. :)

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

Подключение к базе данных


Для проверки подключения к базе данных давайте попробуем модифицировать наш файл index.php в вот такой:
<?php
$host = 'db';
$user = 'root';
$password = '12345';
$database = 'mysql';

// подключаемся к контейнеру db, если не подключится, сработает exit и слов "огонь" мы не увидим
$link = mysqli_connect($host, $user, $password, $database)
or exit("Ошибка " . mysqli_error($link));

echo "Огонь, подключение к базе успешно";

// закрываем подключение
mysqli_close($link);

Проверяем: