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

672 lines
40 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
source: https://habr.com/ru/company/nixys/blog/661443/
---
> [!seealso] Все части
> * [Часть 1 - База](Часть%201%20-%20База.md)
> * [Часть 2 - docker-compose](Часть%202%20-%20docker-compose.md)
![[190226ba0ccc3ee44cce82b0a7deeabc.jpg]]
Мы продолжаем [цикл обучающих статей](https://habr.com/ru/company/nixys/blog/645451/) для начинающих системных администраторов. В серии "Настройка #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]]
Все настройки будут проводится на новом сервере. Поэтому для начала рекомендуем сделать базовые настройки, о которых мы писали в предыдущих статьях (если у вас новый сервер!): [Статья по базовой настройке](https://habr.com/ru/company/nixys/blog/645451/).
### Устанавливаем docker
Подготовка системы: обновляем индексы пакетов и устанавливаем нужные пакеты для использования репозиториев через https.
```shell
apt-get update apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
```
Добавьте официальный GPG-ключ Docker:
```shell
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
```
Устанавливаем движок Docker.
Обновляем индексы пакетов и устанавливаем последнюю версию Docker Engine и containerd:
```shell
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io
```
Вся информация об установке была взята из официального мануала docker. Для установки на другие ОС и для более углубленного изучения можете ознакомится на основном сайте [по ссылке](https://docs.docker.com/).
### Начинаем работать с контейнерами
Для начала нам нужно выбрать образ для нашего контейнера. Как это сделать? Идем на сайт со всеми образами контейнеров: [hub.docker.com](https://hub.docker.com/)
Пример: Нам необходим nginx. Ищем на сайте образ nginx. Заходим на официальный сайт и скачиваем самый последний образ, после чего создаем образ нашего nginx.В данном случае это будет выглядеть так:
```shell
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
```
Образ скачан и собран на нашем сервере. Для проверки образов, которые уже установлены и имеются на нашем сервере, используется команда:
```shell
docker images
```
```
#:/# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest c316d5a335a5 2 weeks ago 142MB
```
Анализируем полученную информацию:
- REPOSITORY - репозиторий, откуда загружен и собран наш образ. В данном случае официальный образ взятый с [hub.docker.com/_/nginx](https://hub.docker.com/_/nginx).
- TAG - версия нашего nginx. У нас самая последняя версия образа.
- IMAGE ID - ID нашего образа.
- CREATED - дата, когда был собран данный образ и выложен в репозиторий.
- SIZE - размер образа.
Как видим выше, имеется образ nginx самой последней стабильной версии, выложенный разработчиками nginx 14 дней назад . Он имеет id c316d5a335a5 и занимает 142 MB нашего дискового пространства.
Теперь нам необходимо запустить наш образ. Для этого нам нужна будет команда:
```shell
docker run -d "название нашего образа"
```
В нашем случае получится команда:
```shell
docker run -d nginx
```
Запускаем:
```
#:/# docker run nginx
d9eceddb3c2b25f6863949b776cdda280f132dc0664a4b89c4fcbe9c563436e
```
Для проверки запущенных контейнеров используется команда:
```shell
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 этот трафик обработает. Также есть возможность зайти в наш контейнер. С помощью команды:
```shell
docker exec -it <<id контейнера или его имя>> bash
```
```
\#docker exec -it 8d9eceddb3c2 bash
docker@/#
```
Это необходимо тогда, когда нам необходимо динамически изменить какие-либо параметры без перезагрузки всего контейнера.
Пример: Мы можем перечитать конфигурацию nginx в контейнере. Без перезагрузки всего контейнера.
Давайте поднимем еще один контейнер, только прокинем `80` порт на host сервер (наш физический сервер), назовем его `test_nginx` и возьмем самую последнюю стабильную версию nginx.
- Для название контейнера используем ключ `--name`.
- Для проброса порта используем ключ `-p`.
Получаем такую команду:
```shell
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`.
Получается команда:
```shell
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 адрес. Поэтому используем данную команду:
```shell
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`
Сначала создаем сеть. Она состоит из диапазона подсети и названия сети:
```shell
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` и название контейнера:
```shell
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 нашей сети.
Получаем команду вида:
```shell
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](https://ru.wikipedia.org/wiki/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`, поэтому создаем директорию и идем туда.
```shell
mkdir /var/apps
сd /var/apps
mkdir apache2 nginx
```
Создаем конфигурацию:
```shell
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`:
```shell
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`.
Получаем команду:
```shell
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`:
```shell
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`.
Получается команда:
```shell
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`.
```shell
touch /var/www/DOMAIN_NAME/data/index.php
```
Добавить `HELLO WORLD` в файл:
```shell
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](https://t.me/devops_fm).