Sidecar Pattern
Contents
Sidecar Pattern
It deploys helper components (sidecars) alongside main microservices to handle cross-cutting concerns like logging, monitoring and configuration management. This allows the main services to focus solely on business logic.
- Centralizes tasks such as logging and monitoring, reducing complexity in the main service.
- Commonly used in Kubernetes environments, where each microservice runs with a sidecar for auxiliary functions.
Key concepts:
- Independent: The sidecar is developed and deployed independently of the main application.
- Proximate: It resides on the same host or pod to ensure low latency.
- Lifecycle-Bound: If the main application stops, the sidecar usually stops as well.
Common use cases:
| Use Case | Description | Examples |
|---|---|---|
| Service Mesh Proxy | Handles mTLS, circuit breaking, and routing. | Envoy, Linkerd |
| Log Collection | Tail logs from the main app and ship them to ELK/Splunk. | Fluentd, Logstash |
| Monitoring | Collects metrics (Prometheus) and health checks. | Prometheus Exporter |
| Configuration | Periodically pulls config updates and refreshes the app. | Spring Cloud Config, Consul |
| Security | Handles authentication/authorization (AuthZ) tokens. | Open Policy Agent (OPA) |
Advantages
- Separation of Concerns: Developers focus on business logic; DevOps focus on the sidecar.
- Polyglot Support: You can use the same security or logging sidecar for Java, Go, and Python services.
- No Code Intrusion: You don’t “pollute” your Java code with infrastructure boilerplate.
Disadvantages
- Resource Overhead: Each pod now runs two containers, increasing memory usage.
- Latency: Inter-process communication (IPC) adds a tiny overhead to network calls.
- Debugging: It can be harder to troubleshoot network issues when there is a “hidden” proxy in the middle.
Implementation patterns
- Ambassador Pattern: A sidecar specifically for outbound network requests.
- Adapter Pattern: A sidecar that standardizes the inbound/outbound interface of an application.
Java code examples
- The Migration Sidecar (Ambassador Pattern)
The Sidecar Configuration (NGINX): This sidecar runs alongside your Java app. Your Java code always calls localhost:9000. The sidecar decides where to send it.
# Simplified NGINX Sidecar Config
http {
upstream legacy_monolith {
server monolith.production.svc:8080;
}
upstream new_user_service {
server user-service.production.svc:8080;
}
server {
listen 9000;
# Strangled Route: Send users to the new microservice
location /api/v1/users {
proxy_pass http://new_user_service;
}
# Legacy Route: Everything else goes to the monolith
location / {
proxy_pass http://legacy_monolith;
}
}
}@Service
public class UserServiceProxy {
private final RestTemplate restTemplate;
public UserServiceProxy(RestTemplateBuilder builder) {
// The Java app ONLY talks to the sidecar on localhost
this.restTemplate = builder.rootUri("http://localhost:9000").build();
}
public UserDTO getUser(String id) {
// Logic is routed by the sidecar, not the code
return restTemplate.getForObject("/api/v1/users/" + id, UserDTO.class);
}
}- The Observability Sidecar (Adapter Pattern)
If you have a Java app using an older metrics format, you use a sidecar to “translate” it for Prometheus without touching the legacy code.
Kubernetes config
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-service
spec:
template:
spec:
containers:
# 1. PRIMARY CONTAINER: Your Java Revenue System
- name: example-app
image: example-app:2.1
volumeMounts:
- name: logs-vol
mountPath: /app/logs
# 2. SIDECAR CONTAINER: Log Shipper (Fluentd)
- name: log-shipper
image: fluentd:latest
volumeMounts:
- name: logs-vol
mountPath: /var/log/app
# This sidecar reads the files revenue-app writes and ships to ELK
volumes:
- name: logs-vol
emptyDir: {} # Shared disk space between both containers