Запуск контейнеров с Podman на RHEL

Red Hat Enterprise LinuxBeginner
Практиковаться сейчас

Введение

В этой лабораторной работе вы узнаете, как развернуть многоуровневое веб-приложение с использованием Podman на Red Hat Enterprise Linux (RHEL). Вы создадите полное решение, развернув контейнер базы данных MariaDB в качестве серверной части (backend) и контейнер веб-сервера Apache в качестве клиентской части (frontend). Этот практический опыт проведет вас через основные этапы развертывания контейнеризованного приложения, от начальной конфигурации до обеспечения публичного доступа к сервису.

Вы начнете с запуска контейнера MariaDB и его настройки при запуске с использованием переменных окружения. Далее вы настроите постоянное хранилище (persistent storage), чтобы обеспечить сохранность данных для базы данных, и создадите пользовательскую сеть для взаимодействия между контейнерами. Затем вы развернете веб-сервер Apache, откроете его порт для проверки подключения и, наконец, узнаете, как управлять контейнером как сервисом systemd для надежной и автоматизированной работы.

Запуск контейнера базы данных MariaDB с переменными окружения

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

Во-первых, убедитесь, что вы находитесь в правильном рабочем каталоге. Вся работа для этой лабораторной работы будет выполняться внутри каталога ~/project.

cd ~/project

Перед запуском контейнера рекомендуется явно извлечь образ из реестра. Это гарантирует, что у вас будет правильная версия локально. Мы будем использовать образ mariadb:10.6 для этой лабораторной работы, чтобы обеспечить согласованность.

podman pull mariadb:10.6

Выберите образ mariadb:10.6 из реестра docker.

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

10.6: Pulling from library/mariadb
...
Status: Downloaded newer image for mariadb:10.6
docker.io/library/mariadb:10.6

Теперь вы можете запустить контейнер MariaDB. Команда podman run создает и запускает новый контейнер. Мы будем использовать несколько флагов:

  • -d: Запускает контейнер в detached mode (в фоновом режиме).
  • --name mariadb_server: Присваивает запоминающееся имя нашему контейнеру.
  • -e VARIABLE=value: Устанавливает переменную окружения внутри контейнера. Образ MariaDB использует их для настройки базы данных при первом запуске.

Выполните следующую команду, чтобы запустить контейнер MariaDB. Мы устанавливаем пароль root, а также создаем новую базу данных с именем webappdb со специальным пользователем webappuser.

podman run -d \
  --name mariadb_server \
  -e MARIADB_ROOT_PASSWORD=supersecret \
  -e MARIADB_DATABASE=webappdb \
  -e MARIADB_USER=webappuser \
  -e MARIADB_PASSWORD=userpass \
  mariadb:10.6

Команда выведет длинный идентификатор контейнера, что подтверждает создание контейнера.

a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2

Чтобы убедиться, что контейнер запущен, используйте команду podman ps.

podman ps

Вы должны увидеть mariadb_server в списке запущенных контейнеров.

CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS      NAMES
a1b2c3d4e5f6   mariadb:10.6   "docker-entrypoint.s…"   15 seconds ago   Up 14 seconds   3306/tcp   mariadb_server

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

podman logs mariadb_server

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

...
2024-05-20 10:30:00+00:00 [Note] [Entrypoint]: /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/
...
2024-05-20 10:30:15+00:00 [Note] mariadbd: ready for connections.
Version: '10.6.x-MariaDB-1:10.6.x+maria~ubu2004'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution

Вы успешно запустили и настроили контейнер MariaDB, используя переменные окружения.

Настройка постоянного хранилища для контейнера MariaDB

На этом шаге вы узнаете, как настроить постоянное хранилище для контейнера. По умолчанию все данные, созданные внутри контейнера, хранятся в перезаписываемом слое, который привязан к жизненному циклу контейнера. Если вы удалите контейнер, все эти данные будут потеряны. Для stateful приложений (приложений с сохранением состояния), таких как базы данных, это не идеально. Чтобы решить эту проблему, мы используем Podman volumes или bind mounts для хранения данных в файловой системе хоста, независимо от контейнера.

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

Остановите запущенный контейнер mariadb_server:

podman stop mariadb_server

Вы увидите имя контейнера в выводе, подтверждающем получение команды.

mariadb_server

Теперь удалите остановленный контейнер:

podman rm mariadb_server

Опять же, имя контейнера будет выведено обратно.

mariadb_server

Далее создайте каталог на вашем хост-компьютере в каталоге ~/project. Этот каталог будет содержать файлы базы данных MariaDB.

mkdir ~/project/mariadb_data

При использовании Podman в rootless mode (без прав root) нам нужно установить правильные разрешения для смонтированного каталога. Контейнер MariaDB запускается от имени определенного пользователя (UID 999), поэтому нам нужно убедиться, что каталог доступен. Мы будем использовать флаг --userns=keep-id и установим соответствующие разрешения:

chmod 755 ~/project/mariadb_data

Теперь снова запустите контейнер MariaDB. Эта команда аналогична команде из предыдущего шага, но с добавлением флага -v и --userns=keep-id для правильной обработки сопоставления пространства имен пользователя. Флаг -v монтирует каталог ~/project/mariadb_data с вашего хоста в каталог /var/lib/mysql внутри контейнера, где MariaDB хранит свои данные. Мы используем $(pwd)/mariadb_data, чтобы предоставить абсолютный путь к команде podman.

podman run -d \
  --name mariadb_server \
  --userns=keep-id \
  -e MARIADB_ROOT_PASSWORD=supersecret \
  -e MARIADB_DATABASE=webappdb \
  -e MARIADB_USER=webappuser \
  -e MARIADB_PASSWORD=userpass \
  -v $(pwd)/mariadb_data:/var/lib/mysql:Z \
  mariadb:10.6

Суффикс :Z в монтировании тома указывает Podman перемаркировать содержимое с помощью частной неразделяемой метки, что важно для совместимости с SELinux.

После запуска контейнера вы можете убедиться, что данные хранятся на вашем хост-компьютере. Выведите список содержимого каталога ~/project/mariadb_data.

ls -l ~/project/mariadb_data

Поскольку механизм базы данных контейнера был инициализирован, вы увидите несколько файлов и каталогов, созданных внутри ~/project/mariadb_data. Это подтверждает, что ваши данные теперь постоянны. Даже если вы удалите контейнер, эти данные останутся.

total 110632
-rw-rw---- 1 labex labex    16384 May 20 10:45 aria_log.00000001
-rw-rw---- 1 labex labex       52 May 20 10:45 aria_log_control
-rw-rw---- 1 labex labex      983 May 20 10:45 ib_buffer_pool
-rw-rw---- 1 labex labex 12582912 May 20 10:45 ibdata1
-rw-rw---- 1 labex labex 50331648 May 20 10:45 ib_logfile0
-rw-rw---- 1 labex labex 50331648 May 20 10:45 ib_logfile1
drwx------ 2 labex labex     4096 May 20 10:45 mysql
drwx------ 2 labex labex     4096 May 20 10:45 performance_schema
drwx------ 2 labex labex     4096 May 20 10:45 sys
drwx------ 2 labex labex     4096 May 20 10:45 webappdb

Вы успешно настроили свой контейнер MariaDB для использования постоянного хранилища, гарантируя, что данные вашей базы данных будут сохраняться при перезапусках и удалениях контейнера.

Создание пользовательской сети и развертывание веб-сервера Apache

На этом шаге вы создадите пользовательскую сеть для ваших контейнеров и развернете веб-сервер Apache. Хотя Podman предоставляет сеть по умолчанию, использование пользовательских сетей является лучшей практикой. Они обеспечивают лучшую изоляцию и, что наиболее важно, включают автоматическое разрешение DNS между контейнерами. Это позволяет контейнерам взаимодействовать друг с другом, используя их имена, что более надежно, чем использование IP-адресов, которые могут меняться.

Во-первых, давайте создадим пользовательскую bridge network (мостовую сеть) для нашего приложения. Мы назовем ее webapp-network.

podman network create webapp-network

Команда выведет имя вновь созданной сети.

webapp-network

Вы можете вывести список всех сетей Podman, чтобы убедиться, что ваша сеть была успешно создана.

podman network ls

Вы должны увидеть webapp-network в списке, наряду с сетями по умолчанию.

NETWORK ID     NAME               DRIVER    SCOPE
...
f1e2d3c4b5a6   webapp-network     bridge    local
...

Далее нам нужно пересоздать наш контейнер mariadb_server в этой новой сети. Из-за конфигурации сетевого бэкенда в этой среде мы не можем подключить существующий контейнер к новой сети. Вместо этого мы остановим и пересоздадим контейнер с новой конфигурацией сети.

Остановите запущенный контейнер mariadb_server:

podman stop mariadb_server

Удалите остановленный контейнер:

podman rm mariadb_server

Теперь пересоздайте контейнер MariaDB с новой сетью. Эта команда аналогична команде из предыдущего шага, но с добавлением флага --network webapp-network:

podman run -d \
  --name mariadb_server \
  --network webapp-network \
  --userns=keep-id \
  -e MARIADB_ROOT_PASSWORD=supersecret \
  -e MARIADB_DATABASE=webappdb \
  -e MARIADB_USER=webappuser \
  -e MARIADB_PASSWORD=userpass \
  -v $(pwd)/mariadb_data:/var/lib/mysql:Z \
  mariadb:10.6

Теперь давайте развернем наш веб-сервер. Мы будем использовать официальный образ Apache httpd. Во-первых, создайте каталог на хосте для хранения файлов вашего веб-сайта.

mkdir ~/project/webapp_content

Создайте простой файл index.html в этом новом каталоге. Это будет домашняя страница нашего веб-приложения.

echo "<h1>Welcome to My Web App</h1>" > ~/project/webapp_content/index.html

Установите правильные разрешения для каталога контента веб-приложения, чтобы контейнер Apache мог получить доступ к файлам:

chmod 755 ~/project/webapp_content

Теперь запустите контейнер Apache httpd. Мы подключим его к нашей webapp-network и смонтируем каталог webapp_content в качестве volume (тома). Это гарантирует, что веб-сервер сможет обслуживать файл index.html, который мы только что создали.

podman run -d \
  --name web_server \
  --network webapp-network \
  -v $(pwd)/webapp_content:/usr/local/apache2/htdocs/:Z \
  httpd:2.4

Давайте разберем параметры:

  • --network webapp-network: Подключает новый контейнер к нашей пользовательской сети.
  • -v $(pwd)/webapp_content:/usr/local/apache2/htdocs/:Z: Это монтирует наш локальный каталог webapp_content в контейнер в /usr/local/apache2/htdocs/, который является каталогом по умолчанию, из которого Apache обслуживает файлы. Суффикс :Z указывает Podman перемаркировать содержимое с помощью частной неразделяемой метки для совместимости с SELinux.

Убедитесь, что оба контейнера запущены.

podman ps

Теперь вы должны увидеть как mariadb_server, так и web_server в списке запущенных контейнеров.

CONTAINER ID  IMAGE                           COMMAND           CREATED         STATUS         PORTS       NAMES
6a3f46c0ab3a  docker.io/library/mariadb:10.6  mariadbd          29 seconds ago  Up 29 seconds  3306/tcp    mariadb_server
da5d52ce9c41  docker.io/library/httpd:2.4     httpd-foreground  7 seconds ago   Up 7 seconds   80/tcp      web_server

Оба контейнера теперь находятся в одной пользовательской сети и могут взаимодействовать друг с другом по имени.

Открытие порта веб-сервера и проверка подключения

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

Сопоставления портов определяются при создании контейнера. Поэтому мы должны сначала остановить и удалить контейнер web_server, который мы создали на предыдущем шаге. Не беспокойтесь о содержимом веб-сайта; оно в безопасности в каталоге ~/project/webapp_content на нашем хосте, потому что мы использовали bind mount (монтирование).

Сначала остановите контейнер:

podman stop web_server
web_server

Далее удалите остановленный контейнер:

podman rm web_server
web_server

Теперь мы снова запустим контейнер web_server, но на этот раз мы добавим флаг -p (или --publish), чтобы сопоставить порт с хоста с портом в контейнере. Мы сопоставим порт 8080 на хосте с портом 80 (порт HTTP по умолчанию) внутри контейнера.

podman run -d \
  --name web_server \
  --network webapp-network \
  -v $(pwd)/webapp_content:/usr/local/apache2/htdocs/:Z \
  -p 8080:80 \
  httpd:2.4

Новый флаг -p 8080:80 указывает Podman перенаправлять весь трафик с порта 8080 на хосте на порт 80 внутри контейнера web_server.

Давайте проверим, что контейнер запущен и порт правильно сопоставлен, используя podman ps.

podman ps

Обратите внимание на столбец PORTS для контейнера web_server. Теперь он показывает сопоставление от 0.0.0.0:8080 к 80/tcp, указывая на то, что порт успешно открыт.

CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                  NAMES
c5d4e3f2a1b6   httpd:2.4      "httpd-foreground"       10 seconds ago   Up 9 seconds    0.0.0.0:8080->80/tcp   web_server
a1b2c3d4e5f6   mariadb:10.6   "docker-entrypoint.s…"   25 minutes ago   Up 25 minutes   3306/tcp               mariadb_server

Наконец, давайте проверим подключение с нашей хост-машины, используя команду curl. Это отправляет HTTP-запрос на localhost по порту 8080.

curl http://localhost:8080

Вы должны увидеть HTML-контент из вашего файла index.html в качестве вывода, подтверждающего, что ваш веб-сервер теперь доступен с хоста.

<h1>Welcome to My Web App</h1>

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

Управление контейнером веб-сервера как службой systemd

На этом заключительном шаге вы узнаете, как настроить контейнер для автоматического запуска, обеспечивая устойчивость вашей службы к сбоям или перезагрузкам системы. В стандартной системе Red Hat Enterprise Linux systemd является основным инструментом для управления службами. Однако среда Podman в этой лаборатории не использует systemd для прямого управления контейнерами.

Вместо этого мы достигнем того же результата — автоматического перезапуска службы — используя встроенные restart policies (политики перезапуска) Podman. Это стандартный, контейнерно-ориентированный способ обеспечения автоматического запуска контейнера демоном Podman. Мы настроим наш web_server на постоянный перезапуск, если он остановится по какой-либо причине.

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

Остановите контейнер web_server:

podman stop web_server
web_server

А теперь удалите его:

podman rm web_server
web_server

Далее пересоздайте контейнер web_server с той же конфигурацией, что и раньше, но добавьте флаг --restart always. Этот флаг предписывает демону Podman отслеживать контейнер и перезапускать его, если он когда-либо завершит работу.

podman run -d \
  --name web_server \
  --network webapp-network \
  -v $(pwd)/webapp_content:/usr/local/apache2/htdocs/:Z \
  -p 8080:80 \
  --restart always \
  httpd:2.4

Контейнер запустится как обычно. Чтобы подтвердить, что политика перезапуска активна, вы можете проверить конфигурацию контейнера.

podman inspect web_server --format '{{.HostConfig.RestartPolicy.Name}}'

Команда должна вернуть always, подтверждая, что политика установлена.

always

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

Сначала давайте проверим текущую конфигурацию политики перезапуска:

podman inspect web_server --format '{{.HostConfig.RestartPolicy.Name}}'

Это должно показать always, подтверждая, что наша политика перезапуска настроена.

always

Теперь давайте протестируем ручной перезапуск, чтобы смоделировать восстановление после сбоя:

podman start web_server
web_server

Убедитесь, что контейнер запущен:

podman ps

Вы должны увидеть оба запущенных контейнера с действующей политикой перезапуска:

CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS                  NAMES
e7f6g5h4i3j2   httpd:2.4      "httpd-foreground"       About a minute ago   Up 5 seconds        0.0.0.0:8080->80/tcp   web_server
a1b2c3d4e5f6   mariadb:10.6   "docker-entrypoint.s…"   About an hour ago    Up About an hour    3306/tcp               mariadb_server

Наконец, убедитесь, что служба доступна:

curl http://localhost:8080
<h1>Welcome to My Web App</h1>

Понимание политик перезапуска:

Настроенная вами политика --restart always гарантирует, что:

  • Контейнер будет перезапускаться автоматически, если он неожиданно завершит работу
  • Контейнер будет запускаться автоматически при запуске службы Podman (например, после перезагрузки системы)
  • Это обеспечивает устойчивость для производственных развертываний

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

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

Резюме

В этой лабораторной работе вы изучили фундаментальный процесс развертывания многоконтейнерного веб-приложения на RHEL с использованием Podman. Вы начали с запуска контейнера базы данных MariaDB, настраивая его начальное состояние — включая пароль root, новую базу данных и выделенного пользователя — путем передачи переменных окружения во время выполнения. Затем вы настроили постоянное хранилище для контейнера базы данных, обеспечив сохранение критически важных данных при перезапусках контейнера.

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