Cheat SheetsMicroservicesDeployment

Deployment — Cheat Sheet

Microservices · 5 topics. Download the PDF or the Instagram carousel and share it.

Cheat Sheet · AiCanCode.org
Deployment
Microservices5 topicsQuick revision reference
1

Containerisation with Docker

Each microservice is packaged as a Docker image; multi-stage builds keep images small, and images are tagged with the commit SHA for traceability.

  • Multi-stage Dockerfile: build in JDK stage, copy only the JAR to a minimal JRE runtime stage — keeps images small and secure.
  • Layered JARs (Spring Boot 2.3+) split the fat JAR into layers ordered by change frequency, maximising Docker layer cache reuse.
  • Tag images with commit SHA and semantic version; never use `latest` in production — it prevents reliable rollbacks.
  • Always run containers as non-root users — set runAsNonRoot: true and a specific UID in the K8s securityContext.
  • Set JVM flag -XX:MaxRAMPercentage=75.0 so the JVM respects container memory limits instead of using the host RAM.
  • Always set K8s resource requests and limits — requests are used for scheduling; limits cap CPU/memory consumption.
Dockerfile — Multi-Stage Spring Boot Build
# Stage 1: Build — uses full JDK + Maven, not included in final image
FROM eclipse-temurin:21-jdk AS builder
WORKDIR /build

# Cache dependency layer separately (only invalidated when pom.xml changes)
COPY pom.xml .
COPY .mvn .mvn
COPY mvnw .
RUN ./mvnw dependency:go-offline -q

# Copy source and build
COPY src ./src
RUN ./mvnw package -DskipTests -q

# Extract layered JAR (Spring Boot 2.3+ layered JAR support)
RUN java -Djarmode=layertools -jar target/*.jar extract --destination extracted

# Stage 2: Runtime — minimal JRE image, no build tools
FROM eclipse-temurin:21-jre AS runtime

WORKDIR /app
RUN addgroup --system app && adduser --system --group app
USER app   # run as non-root

# Copy layers in order of change frequency (stable layers first for cache)
COPY --from=builder /build/extracted/dependencies/ ./
COPY --from=builder /build/extracted/spring-boot-loader/ ./
COPY --from=builder /build/extracted/snapshot-dependencies/ ./
COPY --from=builder /build/extracted/application/ ./

EXPOSE 8080
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
2

Kubernetes for Microservices

Kubernetes orchestrates containers across nodes; Deployments, Services, ConfigMaps, and HorizontalPodAutoscalers provide self-healing, scaling, and traffic routing.

  • Deployment manages rolling updates (maxUnavailable=0, maxSurge=1) for zero-downtime deploys across pod replicas
  • Service provides stable cluster-internal DNS (<name>.<namespace>.svc.cluster.local) and load balancing
  • readinessProbe removes a pod from Service endpoints during rolling update until it is ready to serve traffic
  • startupProbe replaces liveness during slow startup, preventing premature restarts of slow-starting JVM applications
  • HPA scales replicas based on CPU utilisation or custom Prometheus metrics (via Prometheus Adapter)
  • Graceful shutdown (server.shutdown=graceful) combined with terminationGracePeriodSeconds prevents request drops on pod termination
YAML — Deployment, Service, and ConfigMap for a Spring Boot microservice
# Deployment — manages pod replicas with rolling updates
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
  namespace: backend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-service
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0     # zero-downtime rolling update
  template:
    metadata:
      labels:
        app: order-service
    spec:
      containers:
        - name: order-service
          image: registry.example.com/order-service:1.2.0
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef:
                name: order-service-config
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: order-service-secrets
                  key: db-password
          resources:
            requests: { memory: "256Mi", cpu: "100m" }
            limits:   { memory: "512Mi", cpu: "500m" }
---
# Service — stable DNS: order-service.backend.svc.cluster.local
apiVersion: v1
kind: Service
metadata:
  name: order-service
  namespace: backend
spec:
  selector:
    app: order-service
  ports:
    - port: 80
      targetPort: 8080
---
# ConfigMap — non-sensitive config
apiVersion: v1
kind: ConfigMap
metadata:
  name: order-service-config
  namespace: backend
data:
  SPRING_PROFILES_ACTIVE: "prod"
  KAFKA_BOOTSTRAP_SERVERS: "kafka.infra:9092"
3

Blue-Green Deployment

Run two identical production environments; switch the load-balancer to the new (green) release instantly, with the old (blue) kept on standby for instant rollback.

  • Blue-green provides instant rollback by switching the load-balancer/Service selector — no gradual traffic shifting.
  • Both environments must remain compatible with the same database schema during the transition window.
  • Use the expand-contract pattern for schema changes: add new columns first, deploy, then remove old columns later.
  • Cold-start latency: warm up green (health checks, cache population) before cutting over to avoid error spikes.
  • Blue-green costs 2× infrastructure; use deployment slots (Azure) or Kubernetes inactive Deployments to manage cost.
  • Blue-green is better than canary for large atomic changes that cannot be partial (e.g. dependent service contracts).
YAML — Kubernetes blue-green Deployments + Service
# blue deployment (currently live)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service-blue
  labels:
    app: order-service
    version: blue
spec:
  replicas: 5
  selector:
    matchLabels:
      app: order-service
      version: blue
  template:
    metadata:
      labels:
        app: order-service
        version: blue
    spec:
      containers:
        - name: order-service
          image: order-service:v1.2.0

# Service — currently pointing to blue
apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector:
    app: order-service
    version: blue    # ← switch this to "green" for cutover
  ports:
    - port: 80
      targetPort: 8080
4

Canary Deployment

Route a small percentage of traffic to the new version, observe error rate and latency, then gradually increase to 100% or roll back based on signals.

  • Start with a small canary slice (1–5%) and use real production traffic — synthetic testing misses real user behavior.
  • Define success criteria before deploying: p99 latency, error rate, and business metrics (conversion, revenue).
  • Always have an automated rollback trigger — manual monitoring of canaries at 2 AM is not a strategy.
  • Canary differs from blue-green: canary is gradual traffic shifting; blue-green is an instant full cutover.
  • Stateful services (databases) require extra care — canary may run a newer schema against shared state.
  • Header-based canary routing (X-Canary: true) is useful for internal testing before enabling percentage-based routing.
YAML — Argo Rollouts canary with analysis
# rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: order-service
spec:
  replicas: 10
  strategy:
    canary:
      steps:
        - setWeight: 5          # 5% canary traffic
        - pause: {duration: 2m}
        - setWeight: 20
        - pause: {duration: 5m}
        - setWeight: 50
        - pause: {duration: 5m}
        - setWeight: 100        # full promotion
      analysis:
        templates:
          - templateName: http-error-rate
        startingStep: 1
      canaryService: order-service-canary
      stableService: order-service-stable
  selector:
    matchLabels:
      app: order-service
5

Service Mesh (Istio)

A service mesh injects sidecar proxies (Envoy) alongside every pod; mTLS, traffic policies, retries, and telemetry are handled by the mesh without application changes.

  • Istio injects Envoy sidecars into every pod — all traffic flows through the sidecar transparently to the application
  • PeerAuthentication STRICT enforces mTLS between all pods in the namespace — no plaintext service-to-service traffic
  • VirtualService defines routing rules (canary weights, header-based routing); DestinationRule defines load balancing and circuit breaker
  • Retries, timeouts, and circuit breakers are configured in VirtualService/DestinationRule — no Resilience4j library needed
  • Sidecars emit automatic telemetry (metrics, traces, access logs) to Prometheus/Jaeger without application instrumentation
  • AuthorizationPolicy implements RBAC at the mesh level — restricts which services can call which endpoints
YAML + CLI — Istio sidecar injection and mTLS enforcement
# Enable Istio sidecar injection for a namespace
kubectl label namespace backend istio-injection=enabled

# Verify sidecars are injected
kubectl get pod -n backend order-service-xyz -o jsonpath='{.spec.containers[*].name}'
# order-service istio-proxy   ← two containers: app + sidecar

# PeerAuthentication — enable mTLS for all services in namespace
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: backend
spec:
  mtls:
    mode: STRICT   # reject all non-mTLS connections (PERMISSIVE=allow both)

# Check mTLS status
istioctl x describe pod order-service-xyz.backend
# Shows: mTLS STRICT, policy, incoming/outgoing port rules

# Mesh-wide mTLS (all namespaces)
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: istio-system   # root namespace = mesh-wide
spec:
  mtls:
    mode: STRICT
Learn this free with Aria, your AI tutor → AiCanCode.org/learn/microservices