Mastering Container Patterns: A Developer’s Guide to Modern Deployment

Nabajyoti Borah
5 min readFeb 15, 2025

--

In today’s world of microservices and containerized deployments, managing how your applications run inside containers is as important as the code itself. Container patterns offer tried-and-tested methods for addressing common challenges — such as logging, networking, task distribution, and startup initialization — when working with containers. In this article, we’ll explore several container patterns, explain their purpose, and provide practical examples using FastAPI to illustrate how you can incorporate these patterns into your own projects.

Photo by Lucas van Oort on Unsplash

Why Are Container Patterns Important?

Before diving into the patterns, let’s understand why they matter. Containers are lightweight, portable, and scalable, but they also introduce challenges like logging, monitoring, networking, and task distribution. Container patterns provide reusable solutions to these challenges, ensuring your application remains robust and maintainable.

For example, imagine you’re building a FastAPI -based microservice that needs to log requests, communicate with other services, and handle background tasks. Without proper container patterns, managing these requirements can quickly become chaotic. Let’s see how container patterns simplify this process.

We’ll discuss five common container patterns:

  • Sidecar Pattern
  • Adapter Pattern
  • Ambassador Pattern
  • Work Queue Pattern
  • Init Pattern

Each of these patterns addresses specific concerns and can be mixed and matched to suit your deployment strategy.

1. Sidecar Pattern

What Is It?

The Sidecar pattern involves running a helper container alongside your main application container. This sidecar container performs auxiliary tasks like logging, monitoring, or collecting metrics.

Example: Logging with Python and FastAPI

Suppose you have a FastAPI application running in one container. You want to collect logs from this application and push them to an external logging service like Elasticsearch or Datadog .

Here’s how you can implement the Sidecar pattern:

fastapi-app/
├── app/
│ └── main.py # FastAPI application code
├── Dockerfile # Builds the FastAPI app container
└── docker-compose.yml # Defines multi-container deployment
FROM python:3.11
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir -r /code/requirements.txt
COPY ./app /code/app
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
services:
app:
image: fastapi-app:latest
ports:
- "8000:8000"
depends_on:
- logger
logger:
image: fluentd:latest
volumes:
- ./logs:/fluentd/log

2. Adapter Pattern

What Is It?

The adapter pattern is used when you need to bridge a legacy system with modern protocols or requirements. An adapter container acts as a translator — converting requests from one protocol to another, so that older applications can integrate with new systems.

Example : Flask Legacy App with graphql adapter

Consider a legacy service that only understands REST, but your clients prefer GraphQL. You can deploy an adapter container that runs a lightweight FastAPI application acting as a GraphQL server. This adapter translates GraphQL queries into REST API calls directed at your legacy system.

High-level flow:

  1. Client sends a GraphQL query to the adapter container.
  2. Adapter translates the query into one or more REST calls.
  3. Legacy service responds in its native REST format.
  4. Adapter converts the REST response back into GraphQL format.
services:
legacy-api:
image: flask-legacy-api:latest
ports:
- "5000:5000"
graphql-adapter:
image: graphql-adapter:latest
environment:
- LEGACY_API_URL=http://legacy-api:5000
ports:
- "4000:4000"

3. Ambassador Pattern

What Is It?

The ambassador pattern involves running a dedicated container that manages external communications on behalf of the main application. This container can handle tasks such as proxying, routing, or even authentication.

Example : FastAPI app using nginx for java payment gateway

Suppose your FastAPI app needs to interact with external services like payment gateways or third-party APIs. Instead of hardcoding network details into your FastAPI app, you deploy an ambassador container that abstracts these network complexities. Your FastAPI application then communicates with the ambassador, which in turn forwards the requests to the proper external service.

This setup not only simplifies your main application code but also allows you to update network configurations independently.

services:
fastapi-app:
image: fastapi-app:latest
ports:
- "8000:8000"
ambassador:
image: nginx:latest
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- payment-gateway
payment-gateway:
image: java-payment-gateway:latest
ports:
- "9000:9000"

4. Work Queue Pattern

What Is It?

The work queue pattern helps distribute background tasks across multiple worker containers. A queue container — using tools like RabbitMQ or Kafka — receives tasks from the main application and distributes them to worker containers that process these tasks concurrently.

Example : Fastapi and RabbitMq

Imagine your FastAPI application handles file uploads that need further processing (e.g., image resizing). Instead of processing the file synchronously, the FastAPI route can enqueue a job which is then handled by rabbitmq in background

services:
fastapi-app:
image: fastapi-app:latest
ports:
- "8000:8000"
depends_on:
- rabbitmq
- worker
rabbitmq:
image: rabbitmq:latest
ports:
- "5672:5672"
worker:
image: celery-worker:latest
environment:
- CELERY_BROKER_URL=amqp://rabbitmq

5. Init Pattern

What Is It?

Before your main application starts, you might need to perform initialization tasks — like running database migrations, seeding data, or pre-checks to ensure external services are reachable. The init pattern uses an init container to perform these tasks, exiting once completed.

Example : FastAPI and Alembic

If your FastAPI app depends on a database schema, you can use an init container to run migrations before starting the main container.

services:
init_container:
image: your-migration-tool:latest
command: ["alembic", "upgrade", "head"]
depends_on:
- db
fastapi_app:
build: .
depends_on:
- init_container
ports:
- "80:80"
db:
image: postgres:13
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass

Key Takeaways

  • Sidecar Pattern: Run a helper container alongside your FastAPI app for logging or monitoring.
  • Adapter Pattern: Use an adapter container to translate protocols (e.g., GraphQL to REST).
  • Ambassador Pattern: Isolate external communications through a dedicated container.
  • Work Queue Pattern: Offload background tasks to worker containers via a message queue.
  • Init Pattern: Ensure all necessary startup tasks (like migrations) are completed before launching your main app.

Conclusion

Container patterns provide a strategic framework for managing the complexities of containerized applications. By adopting patterns like sidecar, adapter, ambassador, work queue, and init, you can build robust, scalable, and maintainable systems. The examples using FastAPI not only illustrate these patterns in action but also demonstrate how modern Python web frameworks can work seamlessly within a containerized ecosystem.

Implement these patterns in your next project to improve deployment efficiency and operational resilience — and let your containers do the heavy lifting while your FastAPI app focuses on delivering great features.

Happy coding, and may your containers always run smoothly!

Photo by Shaah Shahidh on Unsplash

Sign up to discover human stories that deepen your understanding of the world.

--

--

Nabajyoti Borah
Nabajyoti Borah

Written by Nabajyoti Borah

I am a Fullstack Python developer with 2+ years of industrial experience with additional knowledge of cloud services like AWS

No responses yet

Write a response