Unit 3: Deploying Microservices

INT363 — Cloud Microservices 11 min read

I. Orientation — From Source Code to Running Services

Deploying microservices means packaging independently developed services, releasing them into a computing environment, and operating them reliably. Modern deployment commonly combines Docker containers, an orchestration platform such as Kubernetes, and Continuous Integration pipelines that automatically validate each change.

  • Core principle—independent deployability: Each microservice should be buildable, testable, versioned, and deployed without rebuilding the entire application.
  • Immutable deployment unit: A container image is built once and promoted through test, staging, and production environments without modifying its contents.
  • Declarative operation: Desired state is described in configuration—such as “run three replicas”—and an orchestrator continuously works to maintain it.
  • Automation: Repeatable commands and pipelines replace manual building, testing, and releasing.
  • Isolation: Services run with their own processes, dependencies, configuration, and resource limits.
  • Scalability: Individual services can be replicated according to their workload rather than scaling the entire application.
  • Resilience: Health checks, restarts, multiple replicas, and controlled rollouts reduce the effect of failures.
  • Observability: Logs, metrics, traces, deployment status, and image versions make distributed behavior measurable.
  • Externalized configuration: Environment-specific values—database addresses, ports, and credentials—remain outside the image.
  • Security assumptions: Images should use trusted minimal bases, run without root privileges where possible, and never contain embedded secrets.

II. Containerization with Docker — Portable Runtime Isolation

Docker packages an application and its runtime dependencies into an image, from which isolated container processes are created. Unlike a virtual machine, a container normally shares the host operating-system kernel and therefore starts with less overhead.

A. Containerization with Docker

Containerization provides a consistent environment for running a microservice across development, testing, and production.

  • Image: A read-only, layered template containing application code, libraries, runtime, metadata, and a default command; for example, orders:1.4.0.
  • Container: A running instance of an image with a writable container layer and isolated process, network, and filesystem views.
  • Docker Engine: The daemon manages images, containers, networks, and volumes; the docker client sends commands through the Docker API.
  • Registry: A service such as Docker Hub or a private registry stores and distributes tagged images.
  • Lifecycle commands:
    BASH
      docker pull registry.example.com/orders:1.4.0
      docker run -d --name orders -p 8080:8080 registry.example.com/orders:1.4.0
      docker logs orders
      docker stop orders
      docker rm orders
    • -d runs in the background.
    • -p 8080:8080 maps host port 8080 to container port 8080.
  • Persistence: Volumes preserve data beyond container deletion; stateless microservices generally store durable data in external databases.
  • Networking: Containers on a user-defined Docker network can communicate through container or service names.

B. Operational Significance and Limitations

Docker improves portability, but containers still require disciplined design and management.

  • Benefits: Fast startup, reproducible dependencies, efficient host use, process isolation, and standardized distribution.
  • Twelve-factor alignment: Services emit logs to standard output, receive configuration through the environment, and avoid local session state.
  • Isolation boundary: Containers are not complete virtual machines; shared-kernel vulnerabilities and excessive privileges remain security risks.
  • Operational constraint: A single Docker host does not by itself provide cluster scheduling, automatic rescheduling, or multi-node scaling.
  • Image discipline: Floating tags such as latest weaken traceability; version tags or immutable image digests provide reliable identification.

III. Dockerfile and Image Construction — Reproducible Packaging

A Dockerfile is a declarative sequence of instructions used by docker build to create image layers. Good Dockerfiles produce small, secure, cache-efficient images whose contents are reproducible.

A. Dockerfile and container image creation

Dockerfile instructions define the base environment, copied artifacts, build steps, exposed port, and startup process.

  • Typical Dockerfile:
    DOCKERFILE
      FROM eclipse-temurin:21-jre
      WORKDIR /app
      COPY target/orders.jar app.jar
      RUN useradd --system appuser
      USER appuser
      EXPOSE 8080
      ENTRYPOINT ["java", "-jar", "app.jar"]
  • Instruction roles:
    • FROM selects the base image.
    • WORKDIR establishes the directory for later instructions.
    • COPY transfers the application artifact into the image.
    • RUN executes a command while building and creates a layer.
    • USER selects the non-root runtime identity.
    • EXPOSE documents the intended listening port but does not publish it.
    • ENTRYPOINT defines the executable launched when a container starts.
  • Build and publication:
    BASH
      docker build -t registry.example.com/orders:1.4.0 .
      docker push registry.example.com/orders:1.4.0

    The final . is the build context sent to the Docker builder.
  • Layer caching: Stable instructions should precede frequently changing source-code copies so unchanged layers can be reused.
  • Build context control: A .dockerignore file excludes .git, logs, local dependencies, test output, and secrets.
  • Multi-stage builds: One stage compiles the program and a smaller final stage contains only the runtime and compiled artifact.

B. Image Quality and Security

An image should minimize unnecessary content while preserving predictable runtime behavior.

  • Small base image: Fewer packages reduce download time and attack surface, although minimal images may make debugging harder.
  • Pinned dependencies: Explicit runtime and dependency versions reduce unexpected changes between builds.
  • Secret handling: Passwords, tokens, private keys, and .env files must not be copied into layers because deleted files can remain in image history.
  • Scanning: CI tools can identify known vulnerabilities and enforce severity policies before publication.
  • Runtime validation: The image should be tested as a container, because a successful image build does not prove that the process starts or becomes healthy.

IV. Container Orchestration — Coordinating Containers at Scale

Container orchestration automates the placement, networking, scaling, recovery, configuration, and updating of containers across a cluster of machines.

A. Container orchestration

An orchestrator converts declared workload requirements into scheduled and continuously managed runtime resources.

  • Scheduling: Workloads are assigned to nodes according to available CPU, memory, placement rules, and constraints.
  • Desired-state reconciliation: If the specification requests three replicas but one fails, the platform creates a replacement.
  • Service discovery: Stable logical names and virtual addresses allow clients to locate changing container instances.
  • Load distribution: Requests are spread across healthy replicas instead of targeting transient container addresses.
  • Self-healing: Failed containers are restarted, and workloads on failed nodes can be rescheduled elsewhere.
  • Scaling: Replica counts may be changed manually or automatically using measurements such as CPU utilization.
  • Rolling updates: New versions replace old replicas gradually, reducing downtime and allowing rollout monitoring.
  • Configuration management: Non-secret settings and sensitive values are supplied separately from images.

B. Operational Trade-offs

Orchestration improves reliability but introduces a distributed control system that must itself be operated.

  • Advantages: Standardized deployment, efficient resource sharing, failure recovery, horizontal scaling, and controlled releases.
  • Complexity: Networking, storage, access control, upgrades, and observability require specialist knowledge.
  • Stateful workloads: Databases need persistent storage, stable identity, backup, consistency, and careful failover—not merely container restarts.
  • Resource accuracy: Requests that are too large waste capacity; requests that are too small cause contention or throttling.

V. Kubernetes — Declarative Cluster Management

Kubernetes is an open-source container orchestration platform originally developed at Google and released in 2014. It organizes a cluster into a control plane, which manages desired state, and worker nodes, which execute workloads.

A. Overview of Kubernetes and its architecture

Kubernetes stores resource specifications through its API and uses controllers to reconcile actual cluster state with those specifications.

  • Control plane components:
    • API server: Validates and exposes the Kubernetes API; tools such as kubectl communicate with it.
    • etcd: A distributed key-value store containing cluster state and configuration.
    • Scheduler: Selects a suitable node for each unscheduled Pod.
    • Controller manager: Runs reconciliation loops for resources such as Deployments, ReplicaSets, and Nodes.
  • Worker-node components:
    • kubelet: Ensures that assigned Pods and their containers are running.
    • Container runtime: Starts containers through the Container Runtime Interface.
    • kube-proxy: Implements Service networking rules on nodes.
  • Pod: The smallest schedulable unit; its containers share networking and can share volumes.
  • Deployment: Manages stateless Pods through ReplicaSets and supports scaling and rolling updates.
  • Service: Gives a selected group of Pods a stable virtual endpoint.
  • Ingress: Defines external HTTP or HTTPS routing when an Ingress controller is installed.
  • Namespace: Provides a logical scope for names, permissions, and resource policies.
  • ConfigMap and Secret: Store non-confidential configuration and sensitive data respectively; a Secret still requires encryption and access controls.

B. Architectural Significance and Limitations

Kubernetes abstractions separate application intent from individual machines.

  • Label selection: Services and controllers identify Pods through labels such as app: orders, rather than fixed IP addresses.
  • Extensibility: Custom resources and operators add domain-specific controllers to the Kubernetes API.
  • High availability: Production clusters commonly replicate control-plane components and distribute workloads across failure zones.
  • Limitation: Kubernetes manages infrastructure behavior, but it cannot correct faulty service logic, poor database design, or unsafe API compatibility.

VI. Microservice Deployment — Releasing Services Safely

Deploying a microservice involves publishing its image, declaring runtime requirements, exposing it through stable networking, and verifying its health during rollout.

A. Deploying microservices

A Kubernetes Deployment and Service provide a common declarative pattern for running a stateless microservice.

  • Deployment manifest:
    YAML
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: orders
      spec:
        replicas: 3
        selector:
          matchLabels:
            app: orders
        template:
          metadata:
            labels:
              app: orders
          spec:
            containers:
              - name: orders
                image: registry.example.com/orders:1.4.0
                ports:
                  - containerPort: 8080
                readinessProbe:
                  httpGet:
                    path: /ready
                    port: 8080
  • Application command:
    BASH
      kubectl apply -f orders-deployment.yaml
      kubectl rollout status deployment/orders
  • Readiness probe: Prevents traffic from reaching a Pod until /ready succeeds.
  • Liveness probe: Detects a stuck process and can trigger a container restart; it should not fail merely because a downstream dependency is temporarily unavailable.
  • Resources: CPU and memory requests guide scheduling, while limits constrain consumption.
  • Service exposure: A ClusterIP Service provides internal access; an Ingress or LoadBalancer Service can provide external access.
  • Rollback: Kubernetes retains rollout history, enabling kubectl rollout undo deployment/orders when a revision fails.

B. Deployment Strategies and Risks

Release strategy determines how quickly a new version receives traffic and how failures are contained.

  1. Rolling deployment: Gradually replaces old Pods with new ones; it is resource-efficient but temporarily runs both versions.
  2. Blue-green deployment: Maintains complete old and new environments and switches traffic after validation; rollback is fast but capacity cost is higher.
  3. Canary deployment: Sends a small traffic percentage to the new version before wider promotion; it needs reliable metrics and traffic control.
  • Compatibility requirement: API and database changes should tolerate overlapping service versions during gradual rollout.
  • Failure protection: Timeouts, retries with backoff, circuit breakers, and idempotent operations reduce cascading failures.
  • Verification: Error rate, latency, restart count, and business metrics should determine whether promotion continues.

VII. Continuous Integration — Fast, Automated Validation

Continuous Integration is the practice of frequently merging small code changes into a shared repository and validating every change through an automated pipeline.

A. Continuous Integration (CI) principles

CI aims to detect integration defects quickly and keep the main branch in a releasable state.

  • Frequent integration: Developers merge small changes regularly, reducing long-lived branch divergence.
  • Automated build: The pipeline compiles code and resolves dependencies in a clean, repeatable environment.
  • Layered tests: Fast unit tests run first, followed by integration, contract, security, and container smoke tests.
  • Fail-fast design: Formatting, static analysis, and unit tests precede expensive image builds or environment deployments.
  • Reproducible artifacts: One versioned image is produced from a commit and promoted without rebuilding.
  • Pipeline sequence:
    TEXT
      Commit → Lint → Unit Test → Build → Integration Test
             → Image Scan → Push Image → Deployment Candidate
  • Quality gates: A failed test, critical vulnerability, or policy violation stops artifact publication.
  • Traceability: Commit identifier, pipeline run, image tag or digest, test results, and deployment revision are linked.
  • Feedback speed: Developers should receive actionable failure information quickly enough to correct the change before further work accumulates.

B. CI Boundaries and Operational Value

CI validates changes continuously, but deployment automation and production release controls remain distinct concerns.

  • CI versus delivery: CI builds and tests each change; continuous delivery keeps validated changes deployable, while continuous deployment automatically releases every qualifying change.
  • Environment parity: Running tests against the built container reduces differences between pipeline and production environments.
  • Pipeline security: Credentials should come from protected secret stores, permissions should be minimal, and untrusted code should not access production tokens.
  • Limitation: Weak or flaky tests can create false confidence; CI effectiveness depends on reliable test coverage, deterministic builds, and prompt repair of broken pipelines.