Непрерывная интеграция/внедрение приложения symfony с помощью docker-compose и gitlab ci

2: Создание конфигурационного файла Docker Compose

Сборка приложений с помощью Docker Compose упрощает настройку и контроль версий в инфраструктуре. Чтобы настроить приложение Laravel, давайте создадим файл docker-compose и определим в нем сервисы веб-сервера, базы данных и приложения.

Откройте файл:

В файле docker-compose нужно определить три сервиса: app, webserver и db. Вставьте в файл такой код (только укажите свой сложный пароль root в MYSQL_ROOT_PASSWORD, переменной среды  сервиса db):

В файл входят следующие сервисы:

  • app: определение сервиса, которое содержит приложение Laravel и запускает кастомный образ Docker, его мы определим позже. Также оно присваивает значение /var/www для параметру working_dir в контейнере.
  • webserver: загружает образ nginx:alpine и открывает порты 80 и 443.
  • db: извлекает образ mysql:5.7.22 и определяет новые переменные среды, в том числе БД laravel для приложения и пароль пользователя root этой БД. Вы можете использовать любое имя для базы данных. Также вам следует заменить your_mysql_root_password собственным паролем. Это определение также связывает порт хоста 3306 и такой же порт контейнера .

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

Для простоты взаимодействия между контейнерами сервисы подключаются к соединительной сети app-network. Соединительная сеть использует программный мост, который позволяет подключенным к этой сети контейнерам взаимодействовать друг с другом. Драйвер устанавливает правила хоста автоматически, чтобы контейнеры из разных соединительных сетей не могли взаимодействовать напрямую. Это повышает безопасность приложений, поскольку взаимодействовать в таких условиях смогут только связанные сервисы. Кроме того, так вы сможете указать разные сети и сервисы, подключающиеся к функциям: например, клиентские сервисы приложениймогут использовать сеть frontend, а серверные — сеть backend.

Step 3 — Running Docker Compose

With the file in place, we can now execute Docker Compose to bring our environment up. The following command will download the necessary Docker images, create a container for the service, and run the containerized environment in background mode:

Docker Compose will first look for the defined image on your local system, and if it can’t locate the image it will download the image from Docker Hub. You’ll see output like this:

Your environment is now up and running in the background. To verify that the container is active, you can run:

This command will show you information about the running containers and their state, as well as any port redirections currently in place:

You can now access the demo application by pointing your browser to either if you are running this demo on your local machine, or if you are running this demo on a remote server.

You’ll see a page like this:

Because the shared volume you’ve set up within the file keeps your folder files in sync with the container’s document root. If you make any changes to the file, they will be automatically picked up by the container and thus reflected on your browser when you reload the page.

In the next step, you’ll see how to manage your containerized environment with Docker Compose commands.

Docker and Docker Compose Concepts

Using Docker Compose requires a combination of a bunch of different Docker concepts in one, so before we get started let’s take a minute to review the various concepts involved. If you’re already familiar with Docker concepts like volumes, links, and port forwarding then you might want to go ahead and skip on to the next section.

Docker Images

Each Docker container is a local instance of a Docker image. You can think of a Docker image as a complete Linux installation. Usually a minimal installation contains only the bare minimum of packages needed to run the image. These images use the kernel of the host system, but since they are running inside a Docker container and only see their own file system, it’s perfectly possible to run a distribution like CentOS on an Ubuntu host (or vice-versa).

Most Docker images are distributed via the Docker Hub, which is maintained by the Docker team. Most popular open source projects have a corresponding image uploaded to the Docker Registry, which you can use to deploy the software. When possible it’s best to grab “official” images, since they are guaranteed by the Docker team to follow Docker best practices.

Communication Between Docker Images

Docker containers are isolated from the host machine by default, meaning that by default the host machine has no access to the file system inside the Docker container, nor any means of communicating with it via the network. Needless to say, this makes configuring and working with the image running inside a Docker container difficult by default.

Docker has three primary ways to work around this. The first and most common is to have Docker specify environment variables that will be set inside the Docker container. The code running inside the Docker container will then check the values of these environment variables on startup and use them to configure itself properly.

Another commonly used method is a Docker data volume. Docker volumes come in two flavors — internal and shared.

Specifying an internal volume just means that for a folder you specify for a particular Docker container, the data will be persisted when the container is removed. For example if you wanted to make sure your log files hung around you might specify an internal volume.

A shared volume maps a folder inside a Docker container onto a folder on the host machine. This allows you to easily share files between the Docker container and the host machine, which we’ll explore in the Docker data volume article.

The third way to communicate with a Docker container is via the network. Docker allows communication between different Docker containers via , as well as port forwarding, allowing you to forward ports from inside the Docker container to ports on the host server. For example, you can create a link to allow your WordPress and MariaDB Docker containers to talk to each other and port-forwarding to expose WordPress to the outside world so that users can connect to it.

8: Запуск контейнеров и изменение настроек среды

Итак, мы определили все сервисы в файле docker-compose и создали конфигурации для всех сервисов. Теперь можно запустить контейнеры. В качестве последнего шага мы создадим копию файла .env.example, который Laravel включает по умолчанию, и назовем ее .env, поскольку именно такой файл Laravel использует для определения среды:

После запуска контейнеров мы вставим в этот файл параметры.

Теперь все сервисы определены в файле docker-compose, и вам нужно просто запустить одну команду, которая запустит все контейнеры, создаст тома и настройки и подключит сети:

При первом запуске команда docker-compose up загрузит все необходимые образы Docker, что может занять некоторое время. После загрузки образов на локальный компьютер Compose создаст контейнеры. Флаг -d преобразует процесс в демон, что позволяет поддерживать работу контейнеров в фоновом режиме.

После завершения этого процесса используйте следующую команду, чтобы запросить список всех запущенных контейнеров:

Вы увидите следующий вывод с данными о контейнерах app, webserver и db:

В этом выводе CONTAINER ID — это уникальный идентификатор контейнера, а NAMES перечисляет имена сервисов. Вы можете использовать оба эти идентификатора для доступа к контейнерам. IMAGE определяет имя образа каждого контейнера, а STATUS предоставляет данные о состоянии.

Теперь вы можете отредактировать файл .env в контейнере app, чтобы добавить необходимые параметры.

Откройте файл с помощью docker-compose exec, что позволяет запускать определенные команды в контейнерах. В данном случае команда откроет файл для редактирования:

Найдите блок DB_CONNECTION и определите в нем особенности настройки вашей системы. Нужно изменить следующие поля:

  • DB_HOST – нужно указать контейнер базы данных db.
  • DB_DATABASE – укажите здесь БД laravel.
  • DB_USERNAME – укажите имя пользователя БД. В этом случае мы используем laraveluser.
  • DB_PASSWORD – надежный пароль этого пользователя.

Сохраните и закройте файл.

Затем настройте ключ для приложения Laravel с помощью команды php artisan key:generate. Она сгенерирует ключ и скопирует его в файл .env, что защитит сессии пользователя и шифрованные данные:

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

Конфигурации будут загружены в /var/www/bootstrap/cache/config.php в контейнере.

Теперь откройте в браузере сайт http://your_server_ip. На экране появится главная страница приложения Laravel.

Теперь можно перейти к настройке данных пользователя БД  laravel в контейнере db.

Step 4 — Obtaining SSL Certificates and Credentials

We can start our containers with the command, which will create and run our containers in the order we have specified. If our domain requests are successful, we will see the correct exit status in our output and the right certificates mounted in the folder on the web server container.

To run the containers in the background, use the command with the flag:

You will see similar output confirming that your services have been created:

Check the status of the services using the command:

We will see the , , and services with a of , while will be exited with a status message:

If you see anything other than in the column for the , , or services, or an exit status other than for the container, be sure to check the service logs with the command:

We can now check that our certificates mounted on the container using the command:

This will give the following output:

Now that everything runs successfully, we can edit our service definition to remove the flag.

Open the file, go to the service definition, and replace the flag in the command option with the flag, which will tell Certbot that you want to request a new certificate with the same domains as an existing certificate. The updated definition will look like this:

~/drupal/docker-compose.yml

We need to run again to recreate the container. We will also include the option to tell Compose that it can skip starting the service, since it is already running:

We will see output indicating that our certificate request was successful:

Now that we have successfully generated our certificates, we can update our Nginx Configuration to include SSL.

Step 6 — Running the Application with Docker Compose

We’ll now use commands to build the application image and run the services we specified in our setup.

Build the image with the following command:

This command might take a few minutes to complete. You’ll see output similar to this:

When the build is finished, you can run the environment in background mode with:

This will run your containers in the background. To show information about the state of your active services, run:

You’ll see output like this:

Your environment is now up and running, but we still need to execute a couple commands to finish setting up the application. You can use the command to execute commands in the service containers, such as an to show detailed information about files in the application directory:

We’ll now run to install the application dependencies:

You’ll see output like this:

The last thing we need to do before testing the application is to generate a unique application key with the Laravel command-line tool. This key is used to encrypt user sessions and other sensitive data:

Now go to your browser and access your server’s domain name or IP address on port 8000:

Note: In case you are running this demo on your local machine, use to access the application from your browser.

You’ll see a page like this:

You can use the command to check the logs generated by your services:

If you want to pause your Docker Compose environment while keeping the state of all its services, run:

You can then resume your services with:

To shut down your Docker Compose environment and remove all of its containers, networks, and volumes, run:

For an overview of all Docker Compose commands, please check the Docker Compose command-line reference.

Как это всё работает

Файл Compose

Как видно на рисунке выше, моя «композиция» состоит из четырёх сервисов:

  1. — утилита certbot от EFF
  2. — обратный прокси, осуществляющий SSL offloading
  3. — сервер Commento
  4. — база данных PostgreSQL

Файл содержит декларации собственной Docker-сети, названной , и трёх томов, из которых два являются внешними (то есть, должны создаваться вне Compose):

  • хранит данные сервера PostgreSQL для Commento: пользователей, модераторов, комментариев и т.д.
  • содержит сертификаты, полученные -ом.

Nginx

Контейнер Nginx построен на базе легковесного официального образа, основанного на Alpine, и использует следующий скрипт для запуска:

  • В строке 3 (ARRGHHH, Хабр не поддерживает отображение номеров строк в коде — прим. перев.) регистрируется обработчик прерывания, чтобы Nginx и фоновый процесс мониторинга благополучно завершали работу при остановке контейнера.
  • В строке 27 вызывается функция ожидания, приостанавливающая процесс запуска Nginx до тех пор, пока не появятся конфигурационные файлы SSL, создаваемые контейнером . Без этого Nginx отказался бы запускаться.
  • В строке 30 создаётся фоновый процесс, которые регулярно, каждые десять секунд, проверяет наличие файла-флага с именем , и, как только обнаружит его, подаёт Nginx команду перезагрузить конфигурацию. Этот файл также создаёт certbot, в момент когда сертификат обновляется.
  • Строка 34 запускает Nginx в нормальном режиме. При этом означает, что текущий shell-процесс замещается процессом Nginx.

Ещё один важный файл в данном образе — это конфигурация виртуального сервера Commento, заставляющая Nginx пересылать HTTPS-запросы в контейнер :

Первый server-блок (строки 1-21) описывает работу с HTTPS и правило форвардинга. Именно здесь и упоминаются файлы сертификата Let’s Encrypt (или заглушки, используемые вместо них).

Домен, обслуживаемый сервером, передаётся в качестве аргумента при построении образа; он заменяет строку в конфиге сервера.

Второй блок (строки 23-38) — это конфигурация HTTP-сервера, который используется certbot-ом для подтверждения владения доменом (так называемый «ACME challenge»). Все прочие запросы вызывают редирект на соответствующий адрес через HTTPS.

certbot

Наш образ certbot основан на официальной сборке с добавлением нижеследующего скрипта:

Краткая экскурсия по его строкам:

  • Строка 3, как и в предыдущем скрипте, требуется для штатного завершения работы контейнера.
  • В строках 17-19 проверяются требуемые переменные.
  • А в строках 22-25 — что необходимые для работы certbot каталоги правильно смонтированы.
  • Дальше следует развилка:
    • Строки 30-50 выполняются лишь при первом запуске контейнера:
      • Копируется фиктивный сертификат, позволяющий Nginx нормально стартовать.
      • Nginx тем временем ждёт окончания этого процесса, после чего продолжает загрузку.
      • Как только Nginx запустился, certbot инициирует процесс получения взаправдашнего сертификата у Let’s Encrypt.
      • И, наконец, как только сертификат получен, создаётся файл , намекающий Nginx, что пора перезагрузить конфиг.
    • Строка 54 ждёт, пока Nginx запустится — в случае, когда полноценный сертификат уже имеется в наличии.
  • После всего этого (строки 58-63) он продолжает крутить цикл, раз в 12 часов проверяя необходимость продления сертификата и сигналя Nginx перезапуститься.

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

Сервис Systemd

Строки:

  • В строке 6 подразумевается, что код проекта склонирован в каталог — так намного проще.
  • В строках 7-8 создаются внешние тома, если их ещё нет.
  • В строке 9 удаляются возможные останки прежних контейнеров. Внешние тома при этом сохраняются.
  • Строка 10 знаменует собой, собственно, запуск Docker Compose. Флаг прибивает всю стаю контейнеров при останове любого из них. Благодаря этому systemd, как минимум, будет в курсе, что сервис остановлен.
  • Строка 11 — это вновь очистка и удаление контейнеров, сетей и томов.

3: Постоянное хранение данных

Docker предоставляет удобные средства для постоянного хранения данных. Для этого в данном тестовом приложении мы будем использовать тома и монтируемые образы. Мы будем хранить файлы базы данных, приложения и конфигурации. Тома очень гибкие в резервном копировании, их легко сохранять по истечении жизненного цикла контейнера, а монтируемые образы упрощают редактирование кода во время разработки и немедленно отражают изменения файлов или каталогов хоста в контейнерах. Мы используем оба варианта.

Важно! Монтируемые образы позволяют менять файловую систему хоста через работающие в контейнерах процессы, в том числе создавать, изменять и удалять важные системные файлы и каталоги. Это может повлиять на процессы в системе хоста, не связанные с Docker

Монтируемые образы следует использовать очень осторожно.
Для постоянного сохранения базы данных MySQL определите том dbdata в файле docker-compose,  в определении сервиса db:

Том dbdata используется для постоянного сохранения содержимого /var/lib/mysql в контейнере. Это позволяет останавливать и перезапускать сервис db, не теряя данных.

Вставьте в конец файла определение тома dbdata:

Теперь можно использовать этот том для разных сервисов.

Затем добавьте к сервису db привязку монтируемого образа для конфигурационных файлов MySQL, которые мы создадим позже.

Это привяжет файл ~/laravel-app/mysql/my.cnf к каталогу /etc/mysql/my.cnf в контейнере.

А теперь добавьте монтируемые образы в сервис webserver. Образов будет два: один для кода приложения, а второй — для определения настроек Nginx.

Первый образ привязывает код приложения из каталога ~/laravel-app к каталогу /var/www внутри контейнера. Конфигурационный файл, добавляемый в ~/laravel-app/nginx/conf.d/, также монтируется в папку /etc/nginx/conf.d/ в контейнере, что позволяет менять содержимое каталога по мере необходимости.

Теперь добавьте следующие привязки образов в сервис app для кода приложения и конфигурационных файлов:

Сервис app привязывает монтируемый образ каталога ~/laravel-app, который содержит код приложения, к /var/www. Это позволяет ускорить разработку, поскольку все изменения в локальном каталоге приложения сразу же отразятся в контейнере. Также конфигурационный файл PHP ~/laravel-app/php/local.ini привязывается к файлу /usr/local/etc/php/conf.d/local.ini в контейнере. Мы создадим локальный конфигурационный файл PHP в разделе 5.

Теперь файл docker-compose имеет такой вид:

Сохраните и закройте файл.

Теперь пора создать пользовательский образ вашего приложения.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector