Docker - упрощение жизни разработчика

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

Небольшое предисловие…
Когда проект выходит за рамки простого сайта, начинается головная боль с деплоем, особенно если все крутится не только на php но и на nodejs и т.д. Вот и у меня так получилось, beckend на laravel, фронт на nuxtjs, админка отдельным приложением и на поддомене тоже на nuxtjs, так же redis, websocket сервер. Полный набор для кошмарных ночей при деплое =)))

Что же такое Docker и как он мне помог?
Docker это система контейнеризации — каждое приложение изолируется друг от друга и работает самостоятельно (в технические подробности вдаваться не буду, понять достаточно сложно).
Написав «шаблон» для Docker его можно развернуть на рабочем компьютере и на сервере абсолютно с одинаковыми настройками, тут мы снимаем большую головную боль даже на примере версии php, не надо постоянно ее проверять и менять.

Итак давайте напишем простой пример для Docker. Напишу как поднять nginx + php, если будет интересно могу написать заметку более углубленно (nginx-proxy + nginx + php + nodejs + mysql + redis + автоматическое получение ssl сертификата letsencrypt) + управление через Makefile =)))

Структура проекта:
├──  Docker
│    ├── nginx
│    │   ├──  nginx.conf
│    │   └── ...
│    ├── php
│    │   ├──  Dockerfile
│    │   └── ...
│    ├── src  # Исходники приложения
│        ├── app
│        ├── bootstrap
│        ├── config
│        ├── artisan
│        └── ...
│   ├──  docker-compose.yml
│   ├──  README.md
│   └── ...

Для начала напишем файл docker-compose.yml — в нем основные инструкции для запуска контейнеров

version: '3'

services:
  nginx:
    image: nginx:1.17
    restart: always
    ports:
      - 80:80
    volumes:
      - ./src:/usr/share/nginx/html
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
    working_dir: /usr/share/nginx/html

  php:
    build: ./php
    restart: always
    volumes:
      - ./src:/usr/share/nginx/html
    working_dir: /usr/share/nginx/html

Что же тут происходит?
Мы создаем два Docker контейнера nginx и php, давайте разберем что за что отвечает.
Nginx:
image — подключаем готовый образ nginx версии 1.17 c docker hub
restart: always — в случае падения перезапускаем
ports — проброс портов (в контейнере порт 80 прокидываем наружу тоже на 80 порт)
volumes — самая сложная для понимания инструкция. Монтируем содержимое папки src внутрь контейнера в папку /usr/share/nginx/html и так же монтируем конфиг nginx
working_dir — рабочая папка внутри контейнера, что бы при заходе в контейнер сразу попадать в эту папку.

C php тоже самое только образ мы берем не с docker hub а собираем сами, поэтому вместо image мы используем build с сылкой на Dockerfile внутри папки php.

Dockerfile:
# Версия php, в нашем случае именно fpm
FROM php:7.3-fpm
# Устанавливаем расшерения
RUN apt-get update && apt-get install -y \
        zip \
        unzip\
        supervisor \
        curl \
        wget \
        git \
        libxslt-dev \
        libicu-dev \
        libmcrypt-dev \
        libwebp-dev \
        libjpeg62-turbo-dev \
        libpng-dev libxpm-dev \
        libfreetype6-dev \
        libzip-dev \
    && docker-php-ext-install -j$(nproc) iconv \
    && docker-php-ext-configure gd \
        --with-gd \
        --with-webp-dir \
        --with-jpeg-dir \
        --with-png-dir \
        --with-zlib-dir \
        --with-xpm-dir \
        --with-freetype-dir \
        --enable-gd-native-ttf \
    && docker-php-ext-install \
        iconv \
        gd \
        mysqli \
        pdo \
        pdo_mysql \
        mbstring \
        tokenizer \
        opcache \
        exif \
        zip \
        pcntl

RUN pecl install redis \
    && pecl install xdebug \
    && pecl install mcrypt \
    && docker-php-ext-enable mcrypt \
    && docker-php-ext-enable redis xdebug

# устанавливаем compose, если нужно
RUN curl -sS https://getcomposer.org/installer | \
            php -- --install-dir=/usr/bin/ --filename=composer

CMD ["php-fpm"]
Отлично! php у нас работает, теперь необходимо связать php и nginx, и настроить nginx. Помните в docker-compose.yml мы монтировали настройки nginx? =)

nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    map $sent_http_content_type $expires {
        "text/html" epoch;
        "text/html; charset=utf-8"  epoch;
        default off;
    }
    # backend server
    server {
        listen 80;
        server_name localhost;
        root /usr/share/nginx/html/public;
        add_header X-Frame-Options "SAMEORIGIN";
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options "nosniff";
        index index.html index.htm index.php;
        charset utf-8;
        client_max_body_size 32m;
        location / {
            try_files $uri $uri/ /index.php?$query_string;
        }
        location = /favicon.ico { access_log off; log_not_found off; }
        location = /robots.txt  { access_log off; log_not_found off; }
        error_page 404 /index.php;
        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;
        }
        location ~ /\.(?!well-known).* {
            deny all;
        }
    }
}

Теперь можно запускать Docker командой
docker-compose up --build — билдим и можем смотреть за логами
docker-compose up --build -d — запускается в фоновом режиме
docker-compose stop — останавливаем
docker-compose ps или docker ps — список запущенных контейнеров

Так же хочу сказать что монтирование папок в Docker великолепная вещь! В папке src мы можем спокойно править код и все изменения увидим на сайте без пересборки контейнера

Статья получилась достаточно сложной для понимания, задавайте вопросы в комментариях.
П.С. В конфигах nginx не особо силен, если где ошибки прошу меня поправить.

Спасибо за внимание =)
Руслан Сафин
19 октября 2019, 23:39
modx.pro
1
4 932
+11

Комментарии: 14

Alexander V
20 октября 2019, 00:06
0
Чем обычный сервер шаред-хостинга не устраивать?
    Руслан Сафин
    20 октября 2019, 00:11
    0
    Когда проект требует одновременно php, nodejs, redis и при этом нужно окружение для разработки один в один как на продакшене, шаред хостинга уже не хватает)))
      Alexander V
      20 октября 2019, 00:12
      0
      У вас конфиг обычного LEMP. На кой там вообще докер? Да и самих конфигов PHP-FPM нет. Вы уверены, что дефолтные подойдут?
        Руслан Сафин
        20 октября 2019, 00:15
        +1
        Я же написал, что это базовый пример) Если будет интересно распишу свой боевой пример, там и нода и получение автоматически ссл сертификатов и немного Makefile
          Alexander V
          20 октября 2019, 00:18
          -1
          Сразу бы написали. Hello World! мы умеем.
    Павел Бигель
    20 октября 2019, 00:21
    0
    Докер на проде — тема достаточно холиварная
      Руслан Сафин
      20 октября 2019, 00:24
      0
      Ещё больше холивара о бд в контенейре)
      Александр Мельник
      20 октября 2019, 10:48
      0
      Поскольку статья «для самых маленьких и мало что в этой технологии понимающих», то есть как раз для меня)) то задам свои вопросы. Ну вот правда, совершенно не понимаю ни как работает Докер ни зачем он нужен.
      1. Вот вы создаете контейнер nginx на основании готового образа. Куда он устанавливается? В операционную систему которая не сервере? Или создается своя файловая система внутри докера? Вот к примеру указано что настройки сервера тут /etc/nginx/nginx.conf — это находится в операционной системе сервера? А как быть если до запуска вашего контейнера на сервере (машине) уже стоял сервер (nginx)? Вы затрете его конфигурационный файл?
      2. Контейнер с php -вы пишите что мол мы не берем готовый а делаем сами по информации из докер файла в директории php. И в этом файле команды по установке (хотя и несколько искаженные как мне кажется, видимо это синтаксис такой докер файла.) Опять таки — куда устанавливается интерпретатор? В систему сервера? А что если там уже установлена своя версия языка, необходимая для других проектов?
      3. Каким образом работает перенаправление запроса от пользователя в нужный контейнер? Ну тоесть докер более или менее — это виртуализация. Есть машина сервер с IP 2.2.2.2 Пользователь делает запрос на домен test.com, DNS сервер его отправляет на ваш сервер на порт 80. И как дальше то? К примеру у вас есть 5 контейнеров, в каждом из которых работает свой nginx и лежит свой сайт. А значит есть 5 директорий site-available (ну или как-то так), в которых должны лежать конфигурации для привязки домена к конкретной директории. Как и кто занимается разбором в каком из запущенных контейнеров лежит тот сайт, который запросил пользователь?
      4. Правильно я понимаю, что если работать с докер контейнерами, в которых живут сайты(проекты), то все администрирование сервера нужно вести исключительно без применения каких либо визуальных панелей и интерфейсов. Что я имею ввиду. У меня есть сервер выделенный с установленой там убунтой, apache, php и с бесплатной панелью vesta. Через панель я могу создавать новые www домены, для которых автоматом создается директория и конфигурационный файл. Могу работать с базой данных и так далее. Но все это бессмысленно, если на сервере запущено 5 разных nginx, 5 разных, баз данных и так далее, панель это все просто не увидит.
      Ну и еще конечно куча вопросов рождаются в голове, но пока хватит)Спасибо.
        Руслан Сафин
        20 октября 2019, 13:05
        +2
        Спасибо за интерес к статье =)

        1) Каждый контейнер изолирован друг от друга и внутри контейнера своя файловая система, внутрь контейнера мы можем монтировать папки через volume. Именно внутрь контейнера, а не внутрь файловой системы сервера.

        2) Как говорил выше, контейнеры изолированы. В моем примере nginx связан с php через fastcgi

        3) Этот вопрос достаточно сложный, сам долго искал решение, т.к. у меня: api сервер на ларавель, 2 отдельных приложения на nuxtjs и вебсокет сервер и это все на разных поддоменах. Домен и поддомены через А запись направлены на ип сервера и разруливается nginx-proxy с достаточно простым синтаксисом

        4) На самом деле все намного проще ))) Если будет интересно напишу более углубленную статью, в ней расскажу как поднять nginx-proxy + получение автоматом ссл сертификата, в этой связке разворачивание нового сайта сводится к клону гитхаба и запуска контейнера.
          Александр Мельник
          20 октября 2019, 15:18
          +2
          Если будет интересно напишу более углубленную статью
          Было бы очень не плохо.
            Семён Кудрявцев
            21 октября 2019, 08:07
            0
            Поддерживаю, тоже очень интересно! Ждём полной версии
            Іван Клімчук
            30 октября 2019, 12:03
            0
            А можно посмотреть в сторону traefik.io/ и забыть про nginx-proxy и секс с портами навсегда ;)
          Степан Прищепенко
          21 октября 2019, 09:30
          0
          Пиши исчо! Действительно по доккеру очень мало «понятной» документации. И лучше с более подробным описание шагов, имею ввиду с командами CLI при действиях.
            SEQUEL.ONE
            08 ноября 2019, 13:41
            0
            Для приблежения к боевому серверу использую связку vagrant и Virtual Box. А там уже конфиг под что хочешь можно настроить и при первом запуске всё что нужно установиться. Я так Ubuntu поднимаю сразу с настроенным LAMP и nodejs). Начал серию статей по vagrant писать.
              Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
              14