RU EN HE
Обо мне Проекты Блог
← Назад к блогу
Контейнеризация и Podman

Паттерн эфемерных sidecar-контейнеров: управление SSH-туннелями в Podman-подах

Введение

При работе с микросервисной архитектурой на базе 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-туннелей, подключений к базам данных и других ресурсоёмких соединений.