Введение
При работе с микросервисной архитектурой на базе Podman часто возникает потребность в динамическом управлении вспомогательными контейнерами внутри пода. Один из самых распространённых сценариев — SSH-туннели к удалённым сервисам: базам данных, API, системам мониторинга. В этой статье я расскажу о паттерне «эфемерных sidecar-контейнеров» и его реализации на Python.
Архитектура пода
Наш Podman-под состоит из трёх основных компонентов: Valkey (форк Redis) для очереди задач, RQ-воркер для обработки задач и эфемерный SSH-туннель, который запускается по требованию. Все контейнеры находятся в одном поде, что означает общее сетевое пространство — туннель, открытый в sidecar-контейнере, доступен воркеру через localhost.
# Создание пода с проброшенными портами
podman pod create --name jira-stack
-p 6379:6379
-p 8080:8080
# Запуск Valkey в поде
podman run -d --pod jira-stack
–name valkey
docker.io/valkey/valkey:8
# Запуск воркера
podman run -d --pod jira-stack
–name worker
localhost/jira-worker:latest
Python Context Manager для жизненного цикла контейнера
Ключевой элемент паттерна — Python context manager, который управляет запуском и остановкой sidecar-контейнера. Это гарантирует корректную очистку ресурсов даже при возникновении ошибок.
import subprocess
import logging
logger = logging.getLogger(name)
class EphemeralContainer:
def init(self, name, pod_name):
self.name = name
self.pod_name = pod_name
def enter(self):
logger.info(f"Starting container {self.name}")
subprocess.run(
[“podman”, “start”, self.name],
check=True,
capture_output=True
)
self._wait_healthy()
return self
def exit(self, *args):
logger.info(f"Stopping container {self.name}“)
subprocess.run(
[“podman”, “stop”, ”-t", “5”, self.name],
capture_output=True
)
def _wait_healthy(self):
for _ in range(30):
result = subprocess.run(
[“podman”, “healthcheck”, “run”, self.name],
capture_output=True
)
if result.returncode == 0:
return
time.sleep(1)
raise TimeoutError(“Container health check failed”)
Использование в задачах RQ
Теперь мы можем использовать контекстный менеджер при обработке задач. Воркер запускает SSH-туннель перед выполнением задачи и гарантирует его остановку после завершения:
def process_jira_task(issue_key):
with EphemeralContainer(“ssh-tunnel”, “jira-stack”):
# Туннель активен, подключаемся к Jira через localhost
jira = JIRA(server=“http://localhost:8080”, …)
issue = jira.issue(issue_key)
# Обрабатываем задачу
process_issue(issue)
# Туннель автоматически остановлен
Containerfile для SSH-туннеля
Контейнер туннеля содержит SSH-клиент и скрипт подключения с автоматическим переподключением:
FROM docker.io/library/alpine:3.19
RUN apk add --no-cache openssh-client
COPY tunnel.sh /tunnel.sh
RUN chmod +x /tunnel.sh
HEALTHCHECK --interval=5s --timeout=3s
CMD nc -z localhost 8080 || exit 1
ENTRYPOINT [“/tunnel.sh”]
Health Checks и мониторинг
Критически важно настроить проверки здоровья для sidecar-контейнеров. Podman поддерживает встроенные healthcheck-директивы в Containerfile. Наш контекстный менеджер ожидает прохождения проверки перед продолжением работы — это предотвращает ситуации, когда воркер пытается использовать ещё не установленное соединение.
Обработка ошибок и перезапуск воркера
При перезапуске воркера все эфемерные контейнеры должны быть корректно остановлены. Для этого мы добавляем обработчик сигналов и процедуру очистки при запуске, которая останавливает все оставшиеся sidecar-контейнеры из предыдущей сессии. Метод exit контекстного менеджера обеспечивает очистку при нормальном завершении и при исключениях.
Заключение
Паттерн эфемерных sidecar-контейнеров позволяет экономить ресурсы, запуская вспомогательные сервисы только при необходимости. Python context manager обеспечивает надёжное управление жизненным циклом, а Podman-поды предоставляют общее сетевое пространство для взаимодействия контейнеров. Этот подход особенно эффективен для SSH-туннелей, подключений к базам данных и других ресурсоёмких соединений.