tech-tips/Программное обеспечение/LEMP-стек/Настройка LEMP сервера с помощью docker для простых проектов/Часть 1 - База.md

40 KiB
Raw Permalink Blame History

source
https://habr.com/ru/company/nixys/blog/661443/

[!seealso] Все части

!190226ba0ccc3ee44cce82b0a7deeabc.jpg

Мы продолжаем цикл обучающих статей для начинающих системных администраторов. В серии "Настройка #LEMP сервера с помощью #docker для простых проектов" мы разберем docker и #docker-compose, рассмотрим, как поднять стек #LAMP+ #nginx с помощью docker, а также расскажем вам, в чем преимущество контейнеризации и виртуализации.

Несмотря на то, что тема уже достаточно подробно отражена в сети, мы решили подробно описать общие стандарты администрирования с нуля, поскольку регулярно получаем большое количество базовых вопросов от людей, так или иначе связанных с нашей сферой. Цель серии статей - не показать, как развернуть идеальное окружение, а лишь указать на нюансы в работе и защитить начинающих специалистов от базовых ошибок при настройке.

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

1. Сравнение виртуализации и контейнеризации

Что такое #виртуализация?

Виртуализация - это набор инструментов, который позволяет нам разбить физический сервер на 2, 3 и более сервера. С разными операционными системами, сервисами, зависимостями, библиотеками, модулями и т.д.

Пример: У нас имеется сервер 48 CPU 128 RAM. С использованием виртуализации можно разбить физический сервер на два отдельных от друг-друга сервера.

!ec8a5c4127e431c8f145515a68bf80bc.png

Для чего и когда она необходима?

Чаще всего это используется для разделения DEV- и PROD-окружения, так как проводить тестирование в DEV-окружении будет более безопасно на отдельном сервере. Также это подойдет, когда необходимо развернуть сервисы, которые используют разные зависимости и библиотеки.

Пример: PROD окружение работает на php7.2+apache, а для тестов необходима площадка на php8.1+apache. В этом случае #apache2 как интерпретатор php не может работать с разными версиями #php, поэтому нам необходим отдельный сервер.

Какие минусы виртуализации?

  1. Ограничение в ресурсах. Инструмент виртуализации не сможет добавлять виртуальные машины свыше наших физический ядер CPU и RAM.

Пример: Были созданы 2 сервера вместо одного с 20 CPU и 60 RAM. Соответственно, если необходим еще один виртуальный сервер, инструмент виртуализации сможет добавить сервер, состоящий только из 8 CPU и 8 RAM. Если в конфигурацию добавить параметры, которые будут превышать доступные ресурсы, инструмент виртуализации будет выдавать ошибку.

Пример: Вместо 8 доступных CPU будут указаны 9.

  1. Резервирование ядер под виртуальную машину. Будет создана ВМ с 20 СPU, соответственно данные CPU на хост машине будут использоваться только ВМ. Ресурсы не смогут быть задействованы на физическом сервере.
  2. Отказоустойчивость. Если что-то случиться с физическим сервером, то это повлияет и на наши ВМ.

Пример: Упал наш сервер -> Упали наши виртуальные машины.

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

Что такое #контейнеризация?

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

Пример: В контейнере будет исключен запуск других сервисов (например GUI), что обеспечивает минимальное потребление ресурсов.

!f4f98ddc6eeacc501cf5de4d858f4a0b.png

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

2. #Масштабирование и его виды

Представим, что у нас есть проект, который на текущий момент уже использует 90-100% ресурсов. Код на этом проекте был оптимизирован на все 100%, а значит:

  • В базе данных не имеется зависших процессов.
  • В #backend нет зависших скриптов, и отсутствуют долго выполняющие команды.
  • #Frontend был оптимизирован. Ресурсы, которые используются редко, были закешированны.

Итак, оптимизировать больше нечего. Как поступить?

Необходимо масштабирование сервера. Масштабирование бывает двух типов:

  1. Горизонтальное
  2. Вертикальное

Вертикальное масштабирование

Вертикальное масштабирование - это когда увеличиваются ресурсы сервера, добавляем RAM, увеличиваем CPU и размер дисков.

Пример:

!e39384d5e84a9068013306b2d19c8b88.png

Когда использовать Вертикальное масштабирование?

  • Когда заканчивается дисковое пространство. Необходимо докупить дополнительные диски.
  • Когда сервисы долго отрабатывают операции ввода и вывода. Необходимо менять медленный диск на быстрый.
  • Когда слишком часто приходит OOM Killer из-за нехватки оперативной памяти. Добавляем оперативной памяти на сервер.

Горизонтальное масштабирование

Горизонтальное масштабирование - это когда вместо увеличения ресурсов сервера сервисы переносятся на другие машины и дублируется для отказоустойчивости. Для данных целей лучше использовать разные дата-центры.

Пример:

  • Статические файлы можно вынести на отдельный сервер, либо использовать хранилище S3.
  • Базу данных можно разделить, после чего настроить репликацию. Один сервер будет работать только на чтение, другой только на запись.
  • Поиск по статическим данным нужно отправить на отдельный сервер с быстрыми дисками.

!e93bf88c7d6bd24c039e9080ec8622e3.png

3. Как связаны контейнеризация и масштабирование?

При поднятии контейнера пишутся параметры, которые нам необходимы в контейнере. #yml -файл со всеми зависимостями, модулями.

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

Пример: Представим, что наш проект вырос, и ресурсов уже не хватает. Было принято решение арендовать новый сервер. Для нового сервера будет достаточно дублировать yml-файл, в котором будут подняты все те же самые сервисы, которые были развернуты на старом сервере. И при этом развертывание контейнеров экономит драгоценное время, которого так часто не хватает. Ведь куда приятнее развернуть новый сервер всего за пару минут, чем развертывание сервера пару недель с нуля. Поэтому контейнеризация так необходима в вертикальном масштабировании.

Для знакомства с контейнеризацией используем сервис контейнеризации docker.

Для того, чтобы понять все тонкости работы docker, для начала необходимо понять, как именно работает docker, после чего уже писать полноценный yml-файл, который позволит запускать все сервисы одной командой.

4. Docker. БАЗА.

!8aaa7a14a88df488518b21df858c0597.png

Все настройки будут проводится на новом сервере. Поэтому для начала рекомендуем сделать базовые настройки, о которых мы писали в предыдущих статьях (если у вас новый сервер!): Статья по базовой настройке.

Устанавливаем docker

Подготовка системы: обновляем индексы пакетов и устанавливаем нужные пакеты для использования репозиториев через https.

apt-get update apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

Добавьте официальный GPG-ключ Docker:

curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Устанавливаем движок Docker.

Обновляем индексы пакетов и устанавливаем последнюю версию Docker Engine и containerd:

apt-get update
apt-get install docker-ce docker-ce-cli containerd.io

Вся информация об установке была взята из официального мануала docker. Для установки на другие ОС и для более углубленного изучения можете ознакомится на основном сайте по ссылке.

Начинаем работать с контейнерами

Для начала нам нужно выбрать образ для нашего контейнера. Как это сделать? Идем на сайт со всеми образами контейнеров: hub.docker.com

Пример: Нам необходим nginx. Ищем на сайте образ nginx. Заходим на официальный сайт и скачиваем самый последний образ, после чего создаем образ нашего nginx.В данном случае это будет выглядеть так:

docker pull nginx
#:~# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
5eb5b503b376: Pull complete
1ae07ab881bd: Pull complete
78091884b7be: Pull complete
091c283c6a66: Pull complete
55de5851019b: Pull complete
b559bad762be: Pull complete
Digest:
sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

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

docker images
#:/# docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    c316d5a335a5   2 weeks ago   142MB

Анализируем полученную информацию:

  • REPOSITORY - репозиторий, откуда загружен и собран наш образ. В данном случае официальный образ взятый с hub.docker.com/_/nginx.
  • TAG - версия нашего nginx. У нас самая последняя версия образа.
  • IMAGE ID - ID нашего образа.
  • CREATED - дата, когда был собран данный образ и выложен в репозиторий.
  • SIZE - размер образа.

Как видим выше, имеется образ nginx самой последней стабильной версии, выложенный разработчиками nginx 14 дней назад . Он имеет id c316d5a335a5 и занимает 142 MB нашего дискового пространства.

Теперь нам необходимо запустить наш образ. Для этого нам нужна будет команда:

docker run -d "название нашего образа"

В нашем случае получится команда:

docker run -d nginx

Запускаем:

#:/# docker run nginx
d9eceddb3c2b25f6863949b776cdda280f132dc0664a4b89c4fcbe9c563436e

Для проверки запущенных контейнеров используется команда:

docker ps

Проверяем наш контейнер:

\#docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS              PORTS     NAMES
8d9eceddb3c2   nginx     "/docker-entrypoint.…"   About a minute ago   Up About a minute   80/tcp    fervent_allen

Контейнер запущен и работает. Анализируем полученную информацию:

  • CONTAINER ID - ID нашего контейнера.
  • IMAGE - название нашего изображения.
  • COMMAND - это инструкция которая выполняется при запуске контейнера Docker. В данную инструкцию мы можем поместить все те команды, которые необходимы запускать каждый раз при перезагрузке контейнера. Чтоб не делать данные действия вручную.
  • CREATED - дата, когда мы собрали наш контейнер
  • STATUS - текущий статус контейнера.
  • PORTS - порты которые открыты в контейнере и на которые он принимает соединение.
  • NAMES - название нашего контейнера.

Получаем такую информацию:

Имеем контейнер с id a026e61cf29b, собранный из образа под название nginx, выполняющий команды указанные в docker-entrypoint.sh. Собранный около минуты назад и со статусом up (поднят и работает уже около минуты). Работающий порт 80 внутри контейнера и название контейнера fervent_allen.

Мы получили контейнер (мини виртуальную машину) на нашем сервере.

Что мы можем с ним сделать?

Пример: Пустить трафик на него, и nginx этот трафик обработает. Также есть возможность зайти в наш контейнер. С помощью команды:

docker exec -it <<id контейнера или его имя>> bash
\#docker exec -it 8d9eceddb3c2 bash
docker@/#

Это необходимо тогда, когда нам необходимо динамически изменить какие-либо параметры без перезагрузки всего контейнера.

Пример: Мы можем перечитать конфигурацию nginx в контейнере. Без перезагрузки всего контейнера.

Давайте поднимем еще один контейнер, только прокинем 80 порт на host сервер (наш физический сервер), назовем его test_nginx и возьмем самую последнюю стабильную версию nginx.

  • Для название контейнера используем ключ --name.
  • Для проброса порта используем ключ -p.

Получаем такую команду:

docker run --name test_nginx -p 80:80 -d nginx:latest

Мы не будем использовать команду docker pull, потому что данная команда не обязательна. Все образы будут скачаны автоматически при запуске docker run.

Запускаем:

#:/# docker run --name test_nginx -p 80:80 -d nginx:latest
8d14004eb99c374f8540d3494d4c31fad794a61b878a73bb516d9e794b842164

Проверяем:

#:/# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                               NAMES
8d14004eb99c   nginx:latest   "/docker-entrypoint.…"   48 seconds ago   Up 47 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   test_nginxx
8d9eceddb3c2   nginx          "/docker-entrypoint.…"   25 minutes ago   Up 25 minutes   80/tcp                              fervent_allen

Как видим выше, мы имеем nginx c id номером 8d14004eb99c последней версии, работающий на 80 порту хост сервера, собранный и поднятый ~48 секунд назад с названием test_nginx. Теперь все соединения, которые будут поступать на localhost:80 на хосте, будут автоматически попадать в контейнер test_nginx.

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

  1. Прокинем логи контейнера на хост сервер. Для этого используется ключ -v.
  2. Также изменим порт с 80 на 443 и название на test_nginx1.

Получается команда:

docker run -d -p 443:80 -v/var/log/nginx:/var/log/nginx/ --name test_nginx2 nginx:latesttest

Запускаем:

#:/# docker run -d -p 443:80 -v/var/log/nginx:/var/log/nginx/ --name test_nginx2 nginx:latest
4879ed36031d2b3b7fe461ca19a2784641483cb2ec727c3ed410eddc9a79bd2f

Проверяем:

#:/# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                 NAMES
4879ed36031d   nginx:latest   "/docker-entrypoint.…"   44 seconds ago   Up 43 seconds   0.0.0.0:443->80/tcp, :::443->80/tcp   test_nginxx2
8d14004eb99c   nginx:latest   "/docker-entrypoint.…"   4 minutes ago    Up 4 minutes    0.0.0.0:80->80/tcp, :::80->80/tcp     test_nginx
8d9eceddb3c2   nginx          "/docker-entrypoint.…"   28 minutes ago   Up 28 minutes   80/tcp                                fervent_allen

Итак, у нас имеется контейнер test_nginx1, который слушает 443 порт на хост сервере. Имеет общую директорию с хост сервером /var/log/nginx. Любой файл, который будет добавлен внутри контейнера автоматически появится в /var/log/nginx на хосте. Это работает и наоборот. Любой файл, который вы добавите в /var/log/nginx на хосте, будет и в контейнере. Директория будет общей для хоста и контейнера.

Что мы имеем в итоге? У нас есть три разных контейнера. Два из которых слушают порты на хосте и один, который работает только если поступит запрос.

Как нам сделать запрос в #контейнер?

Для этого необходимо знать ip адрес контейнера. Узнать его мы можем с помощью команды inspect. При запросе команды будет выдана вся информация о контейнере, но нас интересует только ip адрес. Поэтому используем данную команду:

docker inspect <ID либо Имя контейнера> | grep IPAddress
docker inspect test_nginx | grep IPAddress
           "SecondaryIPAddresses": null,
             "IPAddress": "",
                     "IPAddress": "172.16.2.4",

Как видим выше, ip адрес нашего контейнера 172.16.2.4. Он присваивается автоматически при создании контейнера. Он динамический, поэтому, когда будет пересобираться контейнер, ip адрес может изменится.

А если необходим статический адрес? Можно присвоить ip адрес контейнеру. Для начала создаем нашу сеть docker. Рассмотрим команду network. Чаще всего в работе вам понадобится 3 команды:

  1. create - создание сети. docker network create
  2. ls - просмотреть все сети docker. docker network ls
  3. rm - удалить сеть docker. docker network rm

Сначала создаем сеть. Она состоит из диапазона подсети и названия сети:

docker network create --subnet=172.16.0.0/24 test

Мы имеем #подсеть docker в диапазоне 172.16.0.0/24 и с названием test.

Проверяем:

#:/# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
58fcfe449655   test      bridge    local

Как видим выше, у нас здесь имеется:

  • NETWORK ID - id сети.
  • NAME - название сети.
  • DRIVER - драйвер сети (по умолчанию bridge).
  • SCOPE - где работает данная сеть. В данном случае она локальная.

Итак, останавливаем второй созданный нами контейнер под кодовым названием test_nginx. Для остановки используется команда stop и название контейнера:

docker stop test_nginx test_nginx
#:/# docker stop test_nginx test_nginx test_nginx

Удаляем контейнер. Для данного действия нам поможет команда rm.

docker rm test_nginx
#:/# docker rm test_nginx test_nginx

Проверяем, отсутствует ли контейнер:

#:/# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                 NAMES
4879ed36031d   nginx:latest   "/docker-entrypoint.…"   12 minutes ago   Up 12 minutes   0.0.0.0:443->80/tcp, :::443->80/tcp   test_nginx2
8d9eceddb3c2   nginx          "/docker-entrypoint.…"   40 minutes ago   Up 40 minutes   80/tcp                                fervent_allen

Добавляем присваивание ip адреса.

Делается это с помощью 2 ключей.

  • Ключ --net - название сети.
  • Ключ --ip - ip адрес который мы хотим присвоить из диапазона 172.16.0.0/24 нашей сети.

Получаем команду вида:

docker run -d -p 80:80 --net test --ip 172.16.0.2 --name test_nginx nginx:latest

Внимание! Не присваивайте ip адрес с единицей в конце, т.к по умолчанию это ip адрес хоста внутри докера. В нашем примере это 172.16.0.1. То есть, если вам необходимо из контейнера обратиться к хосту, в коде необходимо будет указать 172.16.0.1 вместо localhost.

Выполняем:

## docker run -d -p 80:80 --net test --ip 172.16.0.2 --name test_nginx nginx:latest
b254a1d0a969543466ff77241e8add857054266997674bd6685ff22a589a34a8

Проверяем:

#:/# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS                                 NAMES
b254a1d0a969   nginx:latest   "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp, :::80->80/tcp     test_nginx
4879ed36031d   nginx:latest   "/docker-entrypoint.…"   16 minutes ago       Up 16 minutes       0.0.0.0:443->80/tcp, :::443->80/tcp   test_nginx2
8d9eceddb3c2   nginx          "/docker-entrypoint.…"   43 minutes ago       Up 43 minutes       80/tcp                                fervent_allen

Также проверяем соединение с помощью telnet, например на 80 порт в контейнере:

#:/# telnet 172.16.0.2 80
 Trying 172.16.0.2...
 Connected to 172.16.0.2.
 Escape character is '^]'.

P.S.: telnet держит соединение открытым. Для того чтоб закрыть соединение с вашей стороны. Используйте комбинацию ctrl+c либо напишете в консоли quit.

#:/# telnet 172.16.0.2 80
Trying 172.16.0.2...
Connected to 172.16.0.2.
Escape character is '^]'.

quit
#:/# telnet 172.16.0.2 80
Trying 172.16.0.2...
Connected to 172.16.0.2.
Escape character is '^]'.

^C

Мы видим, что соединение проходит. Теперь мы умеем присваивать имя контейнеру, ip адрес, умеем пробрасывать директории и порты.

Настройка nginx и apache2 для работы в контейнере

Что нам понадобится для полноценной настройки?

  1. Конфигурационные файлы.
  2. Название контейнера.
  3. Образ контейнера.
  4. Директории, которые необходимо пробросить в контейнер.
  5. Директории площадок (для обработки статики nginx) и кода (apache2).
  6. Директория log файлов для удобства просмотра и анализа.
  7. Порты.
  8. Сеть.

Cоздадим конфигурацию apache2 и nginx для нашего проекта DOMAIN_NAME. Конфигурацию можно сохранять куда угодно. Мы привыкли, что все конфигурации docker хранятся по пути /var/apps, поэтому создаем директорию и идем туда.

mkdir /var/apps
сd /var/apps
mkdir apache2 nginx

Создаем конфигурацию:

touch /var/apps/apache2/DOMAIN_NAME.conf /var/apps/nginx/DOMAIN_NAME.conf

Важное уточнение: перед настройкой у вас уже должна быть настроена директория проекта по пути /var/www/DOMAIN_NAME/, создан пользователь DOMAIN_NAME и предоставлены права на данную директорию созданному пользователю. Данные работы описаны в наших предыдущих статьях.

Запускаем apache2. Открываем /var/apps/apache2/DOMAIN_NAME.conf:

mcedit /var/apps/apache2/DOMAIN_NAME.conf

Вставляем в него:

<VirtualHost *:80>
    ServerAdmin webmaster@DOMAIN_NAME
    DocumentRoot /var/www/DOMAIN_NAME/data
    ServerName DOMAIN_NAME.com
    ServerAlias www.DOMAIN_NAME.com
    php_admin_value session.save_path "/var/www/DOMAIN_NAME.com/sess"
    php_admin_value upload_tmp_dir "/var/www/DOMAIN_NAME.com/upload"
    php_admin_value open_basedir "/var/www/DOMAIN_NAME.com:."
    CustomLog /var/www/DOMAIN_NAME/log/apache2/access.log combined
    ErrorLog /var/www/DOMAIN_NAME/log/apache2/error.log
    LogLevel error
    <Directory "/var/www/DOMAIN_NAME/data">
        AllowOverride  All
        Options FollowSymLinks
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>
  • Название контейнера - apache2.
  • Образ - php:8.0-apache.
  • Директории - прокидываем площадку по пути /var/www/DOMAIN_NAME. Прокидываем log файлы по пути /var/log/apache2. Прокидываем конфигурацию по пути /var/apps/apache2/DOMAIN_NAME.conf.
  • Порты - открывать порты для apache2 нам не нужно.
  • Сеть - т.к сеть создана, присвоим ip адрес 172.16.0.3.

Получаем команду:

docker run -d --net test --ip 172.16.0.3 --name apache2 -v/var/www/DOMAIN_NAME.com:/var/www/DOMAIN_NAME.com -v/var/log/apache2:/var/log/apache2 -v/var/apps/apache2:/etc/apache2/sites-enabled php:8.0-apache

Выполняем:

#:/# docker run -d --net test --ip 172.16.0.3 --name apache2 -v/var/www/DOMAIN_NAME.com:/var/www/DOMAIN_NAME.com -v/var/log/apache2:/var/log/apache2 -v/var/apps/apache2:/etc/apache2/sites-enabled php:8.0-apache
 Unable to find image 'php:8.0-apache' locally 8.0-apache:
 Pulling from library/php
 5eb5b503b376: Already exists
8b1ad84cf101: Pull complete
38c937dadeb7: Pull complete
6a2f1dc96e59: Pull complete
f8c3f82c39d4: Pull complete
90fc6462bd8e: Pull complete
c670d99116c9: Pull complete
268554d6fe96: Pull complete
6c29fa0d4492: Pull complete
73e23c50a259: Pull complete
81ac13c96fc2: Pull complete
b60a3e623949: Pull complete
dac5dd67fd59: Pull complete
Digest: sha256:2a251962959a4027456d62a2f02d716b14cd6befc2c16bfdf585e581fe1d6075
Status: Downloaded newer image for php:8.0-apache
e8503234b2458320b38fef304a6040ea455bce45f24fc49a90ec46652c32b45

Проверяем:

#:/var/apps/apache2# docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED              STATUS          PORTS     NAMES
51eb2aea4093   php:8.0-apache   "docker-php-entrypoi…"   About a minute ago   Up 12 seconds   80/tcp    apache2

Контейнер запущен и работает.

Запускаем nginx: Открываем конфигурационный файл по пути /var/apps/DOMAIN_NAME.com.conf:

mcedit /var/apps/DOMAIN_NAME.com.conf

Вставляем:

server {
    listen   80;
    server_name DOMAIN_NAME.com www.DOMAIN_NAME.com;
    access_log /var/www/DOMAIN_NAME/log/nginx/access.log;
    error_log /var/www/DOMAIN_NAME/log/nginx/error.log;
    location ~ /\.(svn|git|hg) {
        deny all;
    }
    location ~* ^.+\.(css|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|swf)$ {
        root /var/www/DOMAIN_NAME/data;
        expires max;
        access_log   off;
    }
    location / {
        proxy_pass         http://172.16.0.3; #     ip адрес контейнера apache2
        proxy_redirect     off;
        proxy_set_header   Host               $host;
        proxy_set_header   X-Real-IP          $remote_addr;
        proxy_set_header   X-Forwarded-For    $remote_addr;
        proxy_set_header   X-Forwarded-Proto  $scheme;
        client_max_body_size       10m;
        client_body_buffer_size    1280k;
        proxy_connect_timeout      90;
        proxy_send_timeout         90;
        proxy_read_timeout         90;
        proxy_buffer_size          4k;
        proxy_buffers              4 32k;
        proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;
    }
}
  • Название контейнера - nginx
  • Образ - nginx:latest
  • Директории - прокидываем площадку по пути /var/www/DOMAIN_NAME.com. Прокидываем log файлы по пути /var/log/nginx. Прокидываем конфигурацию по пути /var/apps/nginx/.
  • Порты - открываем 80 на хосте.
  • Сеть - т.к. сеть создана, присвоим ip адрес 172.16.0.4.

Получается команда:

docker run -d --net test --ip 172.16.0.4 --name nginx -p 80:80 -v/var/www/DOMAIN_NAME.com:/var/www/DOMAIN_NAME.com -v/var/log/nginx:/var/log/nginx -v/var/apps/nginx:/etc/nginx/conf.d nginx:latest

Проверяем:

#:/var/apps/nginx# docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS          PORTS                               NAMES
ea9a37a74237   nginx:latest     "/docker-entrypoint.…"   4 seconds ago    Up 3 seconds    0.0.0.0:80->80/tcp, :::80->80/tcp   nginx
51eb2aea4093   php:8.0-apache   "docker-php-entrypoi…"   18 minutes ago   Up 17 minutes   80/tcp                              apache2

Мы получили два контейнера nginx и apache2, nginx слушает все соединения на 80 порту хоста и проксирует на apache2.

Проверим. Нужно добавить в файл hosts на своем ПК. (Если не знаешь, как это сделать, в интернете полно информации по этому поводу).

127.0.0.1 DOMAIN_NAME.com

Далее добавить index.php на хосте по пути /var/www/DOMAIN_NAME.com/data.

touch /var/www/DOMAIN_NAME/data/index.php

Добавить HELLO WORLD в файл:

echo HELLO WORLD > /var/www/DOMAIN_NAME.com/data/index.php

Выполним запрос с помощью curl:

curl DOMAIN_NAME.com
HELLO WORLD
curl -LI DOMAIN_NAME.com
HTTP/1.1 200 OK
Server: nginx/1.21.6
Date: Thu, 10 Feb 2022 20:44:46 GMT
Content-Type:text/html;
charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/8.0.15

Все работает, поздравляю!!!

Итак, в данной статье мы познакомились с контейнеризацией, ознакомились с базовыми ключами и командами. Научились искать образы на официальном сайте. Научились присваивать контейнеру ip адрес. Научились пробрасывать директории. Это вся та база, которая необходима нам в дальнейшем. Как совет - попрактикуйтесь в развертывании контейнеров. Поиграйте с образами. Настройте их работу. Так как чем больше практики, тем лучше.

Теперь мы имеем два контейнера на хосте, которые взаимодействуют между собой и работают без ошибок. Осталось только залить файлы площадки, установить mysql на хосте и начать работать. Но данный способ больше подходит для тестов. Мы можем каждый раз писать большие команды и запускать их. А если нам необходимо управлять контейнерами? Если необходимо автоматизировать развертывание контейнеров? На помощь приходит инструмент для управления несколькими контейнерами под названием docker-compose. В следующей статье мы будем рассматривать именно его.

Спасибо за уделенное время. Надеемся, статья была для вас познавательна. Если остались вопросы можете спрашивать в комментариях, мы с радостью на них ответим.

Всем удачного администрирования, и пусть ваш PROD никогда не падает!

P.S.: больше полезного материала в нашем телеграм-канале DevOps FM.