RU EN HE
About Projects Blog
← Back to blog
Containerization & Podman

Ephemeral Sidecar Pattern: Managing SSH Tunnels in Podman Pods

Introduction

When working with microservice architecture based on Podman, you often need to dynamically manage auxiliary containers within a pod. One of the most common scenarios involves SSH tunnels to remote services: databases, APIs, and monitoring systems. In this article, I'll describe the "ephemeral sidecar container" pattern and its Python implementation.

Pod Architecture

Our Podman pod consists of three main components: Valkey (a Redis fork) for the task queue, an RQ worker for processing tasks, and an ephemeral SSH tunnel that starts on demand. All containers share a pod, which means a shared network namespace — a tunnel opened in the sidecar container is accessible to the worker via localhost.

# Create pod with forwarded ports
podman pod create --name jira-stack 
-p 6379:6379
-p 8080:8080

# Start Valkey in the pod podman run -d --pod jira-stack
–name valkey
docker.io/valkey/valkey:8

# Start the worker podman run -d --pod jira-stack
–name worker
localhost/jira-worker:latest

Python Context Manager for Container Lifecycle

The key element of this pattern is a Python context manager that handles starting and stopping the sidecar container. This guarantees proper resource cleanup even when errors occur.

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”)

Usage in RQ Tasks

Now we can use the context manager when processing tasks. The worker starts the SSH tunnel before executing a task and guarantees its shutdown after completion:

def process_jira_task(issue_key):
with EphemeralContainer(“ssh-tunnel”, “jira-stack”):
# Tunnel is active, connect to Jira via localhost
jira = JIRA(server=http://localhost:8080, …)
issue = jira.issue(issue_key)
# Process the issue
process_issue(issue)
# Tunnel is automatically stopped

Containerfile for the SSH Tunnel

The tunnel container includes an SSH client and a connection script with automatic reconnection:

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 and Monitoring

It’s critical to configure health checks for sidecar containers. Podman supports built-in healthcheck directives in Containerfiles. Our context manager waits for the health check to pass before continuing — this prevents situations where the worker tries to use a connection that hasn’t been established yet.

Error Handling and Worker Restart

When a worker restarts, all ephemeral containers must be properly stopped. We add a signal handler and a startup cleanup procedure that stops any leftover sidecar containers from the previous session. The context manager’s exit method ensures cleanup on both normal completion and exceptions.

Conclusion

The ephemeral sidecar pattern lets you save resources by starting auxiliary services only when needed. Python’s context manager ensures reliable lifecycle management, and Podman pods provide a shared network namespace for container communication. This approach is especially effective for SSH tunnels, database connections, and other resource-intensive connections.