Continuous Integration and Automation with DevOps

Chapter 8
Containers and Cloud-Native Automation

Diploma in Cloud Computing
Continuous Integration and Automation with DevOps   •   Diploma

Containers and Cloud-Native Automation

Introduction

Containers have become a foundational technology in modern DevOps because they package an application together with its runtime dependencies in a portable, repeatable unit. A container is not a lightweight virtual machine. It is an isolated process that shares the host operating system kernel while using operating-system mechanisms such as namespaces and control groups. This distinction explains both the efficiency and the security responsibilities of containers.

Cloud-native automation extends containerization into a broader operating model. Applications are described declaratively, built through automated pipelines, stored in registries, deployed to orchestration platforms, monitored through health signals, and scaled according to demand. Kubernetes is the most widely used example of a container orchestration platform. It continuously compares the desired state declared by an operator with the actual state of the cluster and takes corrective action.

This chapter focuses on practical foundations: building secure images, writing efficient Dockerfiles, managing registries, deploying workloads to Kubernetes, implementing health checks and scaling, and applying declarative operations in a professional DevOps environment.

Learning Objectives

By the end of this chapter, you should be able to:

  1. Explain containers, images, registries, and orchestration.
  2. Construct secure and efficient Dockerfiles.
  3. Apply image-minimization, dependency, and secret-management practices.
  4. Explain container registries and image promotion.
  5. Describe Kubernetes architecture and core resources.
  6. Create declarative Kubernetes deployments and services.
  7. Distinguish readiness, liveness, and startup probes.
  8. Explain horizontal scaling and resource requests and limits.
  9. Use rolling deployment and rollback strategies.
  10. Evaluate governance, security, reliability, and operational trade-offs.

1. Containers as a Deployment Abstraction

A container image is an immutable package containing an application, its libraries, configuration defaults, and metadata. When the image is started, a container is created from that image. Multiple containers may be created from the same image, improving consistency between development, testing, and production.

A typical container workflow is:

Source code → Build image → Scan and test → Push to registry → Deploy → Observe → Update or roll back

An image is generally composed of read-only layers. A Dockerfile instruction such as RUN, COPY, or ADD may create a layer, although the exact storage representation depends on the builder. At runtime, the container receives a writable layer above the image layers. Because writable container storage is normally temporary, persistent application data should be placed in an external volume or managed data service.

Containers and virtual machines

Virtual machines emulate or virtualize complete guest operating systems. Each machine normally includes a guest kernel, whereas containers share the host kernel. Containers usually start faster and consume fewer resources, but they provide a different isolation boundary. A kernel vulnerability or unsafe privilege configuration can affect multiple containers on the same host.

FeatureContainerVirtual machine
Main abstractionIsolated processVirtual computer
KernelShared with hostGuest kernel normally included
StartupUsually rapidUsually slower
Typical densityHighLower
Isolation boundaryProcess and kernel controlsHypervisor and guest OS
Best usePortable services and workloadsStronger OS isolation or different kernels

Containers are therefore a packaging and execution mechanism, not a complete security strategy.

2. Dockerfile Design and Image Construction

A Dockerfile is a build specification. Common instructions include:

  • FROM: selects a base image.
  • WORKDIR: defines the working directory.
  • COPY: copies local build-context files.
  • RUN: executes commands during image construction.
  • ENV: defines environment variables.
  • EXPOSE: documents an intended network port; it does not publish the port by itself.
  • USER: selects the runtime user.
  • ENTRYPOINT: defines the principal executable.
  • CMD: supplies default arguments or a default command.

A simple Dockerfile might be:

FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY src/ .

RUN useradd --create-home --uid 10001 appuser
USER 10001

EXPOSE 8080
CMD ["python", "server.py"]

The order is significant. Copying dependency manifests before application source allows a build system to reuse the dependency layer when source files change. Copying the entire project at the beginning can invalidate the cache unnecessarily.

Multi-stage builds

A multi-stage build separates compilation tools from the final runtime image:

FROM golang:1.22 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/service ./cmd/service

FROM gcr.io/distroless/static-debian12
COPY --from=build /out/service /service
USER 65532:65532
ENTRYPOINT ["/service"]

The first stage contains compilers and source code; the final stage contains only the executable and a minimal runtime environment. This reduces image size and attack surface. However, minimal images can make troubleshooting harder because they may not include shells or diagnostic tools. Operational teams should provide approved debugging methods rather than adding unnecessary tools to production images.

Image optimization principles

Effective image design includes:

  1. Use a trusted and specific base image. Prefer organizationally approved images and pin versions or digests where reproducibility is important.
  2. Use a small build context. A .dockerignore file should exclude .git, local caches, secrets, test output, and unrelated files.
  3. Order instructions for useful caching. Stable dependency steps should precede frequently changing source steps.
  4. Combine related package operations carefully. Package indexes and temporary files should not remain in the final layer.
  5. Use multi-stage builds. Build tools should not be shipped to runtime.
  6. Run as a non-root user. Root inside a container can become a serious risk when combined with excessive capabilities or a runtime escape vulnerability.
  7. Make the process foreground-oriented. The main application should run as the container’s principal process and handle termination signals correctly.
  8. Avoid embedding configuration and secrets. Environment-specific configuration belongs in deployment systems, secret stores, or mounted configuration objects.

Image size affects download time and storage, but smaller is not automatically safer. A maintained, patched image with useful diagnostics may be preferable to an extremely minimal but abandoned image.

3. Container Security and Supply-Chain Controls

Container security begins before deployment. A secure process covers the source, build environment, image, registry, runtime, and cluster.

Build-time controls

Build pipelines should use locked dependency versions where practical, verify package sources, and scan dependencies for known vulnerabilities. Image scanners compare packages and libraries with vulnerability databases. A scan is evidence, not proof of safety: false positives, unlisted vulnerabilities, reachable-code questions, and configuration weaknesses still require human evaluation.

Important controls include:

  • Never copy passwords, tokens, private keys, or cloud credentials into an image.
  • Use secret-management facilities for build-time and runtime secrets.
  • Restrict the build context and review Dockerfiles as code.
  • Use trusted builders and isolate untrusted build instructions.
  • Generate a software bill of materials where organizational policy requires it.
  • Sign images or attach verifiable provenance and attestations.
  • Define vulnerability severity thresholds, exceptions, ownership, and expiry dates.

An image digest identifies content more precisely than a mutable tag. A tag such as release may be moved to another image, while a digest refers to a particular content-addressed artifact. Production deployment policies often use signed images and digest pinning, while human-friendly tags remain useful for discovery.

Runtime controls

Runtime hardening may include:

  • non-root execution;
  • a read-only root filesystem where compatible;
  • dropped Linux capabilities;
  • seccomp and mandatory access-control profiles;
  • restricted host-network and host-filesystem access;
  • resource requests and limits;
  • network policies;
  • admission policies that reject unsafe workloads;
  • encryption in transit and appropriate encryption at rest.

Security must be balanced with operability. For example, a read-only filesystem improves resistance to modification but may require a writable temporary volume for caches or runtime files.

4. Registries and Image Promotion

A container registry stores and distributes images and related artifacts. It may be public, private, cloud-hosted, or self-managed. A registry normally provides repositories, authentication, access control, vulnerability scanning, retention policies, and replication.

A professional promotion path separates build from release:

Build once → Test and scan → Sign → Store immutable artifact → Promote same artifact → Deploy

Rebuilding separately for each environment can produce different binaries, even when source code is unchanged. Promoting the same digest reduces this risk. Environment-specific values should be supplied at deployment time rather than baked into the image.

Registry governance should define who may push, who may pull, which repositories are public, how long artifacts are retained, and how compromised images are quarantined. Authentication should use short-lived credentials or workload identity when available. Pull secrets must be protected because they can provide access to private repositories.

5. Kubernetes Architecture and Resource Model

Kubernetes is a control system for scheduling and managing containers. A cluster consists conceptually of a control plane and worker nodes.

The control plane commonly includes:

  • API server: the authenticated interface through which resources are submitted and observed.
  • Scheduler: selects suitable nodes for unscheduled Pods.
  • Controller managers: run reconciliation loops for resources such as Deployments and Nodes.
  • State store: persists cluster state, commonly using etcd.

Worker nodes run components such as a container runtime, a node agent called kubelet, and networking facilities. Kubernetes distributions may package these components differently.

The basic unit scheduled by Kubernetes is a Pod, not an individual container. A Pod may contain one or more tightly coupled containers sharing networking and volumes. Most application workloads use one primary container per Pod, with additional sidecars only when their lifecycle and operational relationship justify them.

Declarative reconciliation

Imperative operation says, “run this command now.” Declarative operation says, “the system should have this state.” Kubernetes stores the desired state and controllers repeatedly work toward it. If a Pod terminates unexpectedly, a controller can create a replacement. If a node fails, workloads may be rescheduled subject to their constraints and storage requirements.

This model does not eliminate imperative commands. Commands are useful for inspection, emergency diagnosis, and controlled administrative actions. However, durable configuration should normally be represented in version-controlled manifests or generated through a controlled configuration system.

6. Core Kubernetes Resources

Deployment

A Deployment describes a desired number of equivalent, replaceable Pods and manages ReplicaSets. It supports rolling updates and rollback history.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: registry.example.com/web@sha256:abc123...
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "250m"
              memory: "256Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"
          readinessProbe:
            httpGet:
              path: /ready
              port: 8080
          livenessProbe:
            httpGet:
              path: /health
              port: 8080

The selector must match the labels on the Pod template. A mismatch can cause the Deployment to manage no Pods or the wrong Pods.

Service

Pods are replaceable and their IP addresses can change. A Service provides a stable virtual endpoint and selects Pods through labels. Common Service types include ClusterIP for internal access, NodePort for exposing a port on nodes, and LoadBalancer when integrated with a cloud provider’s external load balancer.

ConfigMap and Secret

A ConfigMap stores non-sensitive configuration. A Secret is intended for sensitive values, although encoding in a Secret manifest is not equivalent to encryption. Access control, encryption at rest, audit logging, and external secret managers remain important.

Namespace

Namespaces provide a logical boundary for names, access policies, quotas, and operational organization. They are not a complete security boundary by themselves.

Persistent storage

A PersistentVolumeClaim requests storage with particular capacity and access characteristics. Workloads requiring state should consider backup, recovery, replication, consistency, and failure behavior rather than assuming that a container restart preserves data.

7. Health Checks and Reliable Service Operation

Kubernetes supports three principal probe types:

ProbePurposeEffect of failure
StartupAllows slow applications to initializeDelays other probe evaluation
ReadinessDetermines whether a Pod should receive trafficPod is removed from Service endpoints
LivenessDetects an unhealthy processContainer may be restarted

A readiness probe should represent the ability to serve traffic, not merely process existence. It may check that essential dependencies are available, but overly strict dependency checks can remove all instances during a partial outage and make recovery worse.

A liveness probe should detect a condition from which the process cannot recover. It should not restart a process simply because an external database is temporarily unavailable. A startup probe is valuable for applications with long initialization times; without one, an aggressive liveness probe may repeatedly kill a healthy but slow-starting process.

Probe parameters include delay, period, timeout, failure threshold, and success threshold. These values should be based on measured startup and response behavior. Poorly designed probes can create cascading restarts, false failures, and unnecessary traffic removal.

8. Scaling and Resource Management

Kubernetes scaling may be manual or automatic. Manual scaling changes the replica count. A Horizontal Pod Autoscaler (HPA) adjusts replicas based on observed metrics, commonly CPU utilization, memory utilization, or custom application metrics.

For resource-based scaling, a CPU utilization target is interpreted relative to requested CPU. A simplified conceptual relationship is:

CPU utilization (%) = (observed CPU usage ÷ requested CPU) × 100

The numerator and denominator must refer to compatible CPU units over a comparable measurement interval. If a Pod requests 250 millicores and uses 125 millicores, its utilization relative to the request is 50%. This is not the percentage of the entire node’s CPU capacity.

Requests influence scheduling: the scheduler seeks a node with sufficient allocatable resources. Limits constrain consumption, although exact CPU and memory behavior differs. CPU above a limit is generally throttled, while a container exceeding its memory limit may be terminated by the kernel. Setting requests too low can cause contention; setting them too high can waste capacity and prevent scheduling.

Autoscaling has delays. Metrics collection, stabilization windows, startup time, and workload variability mean that an HPA is not an instantaneous control system. Applications should also use graceful shutdown, connection draining, queue-based back-pressure, and appropriate timeout policies.

9. Automated Deployment and Release Strategies

A CI/CD pipeline for Kubernetes commonly performs these stages:

  1. Validate source and manifests.
  2. Run unit, integration, and security tests.
  3. Build an image.
  4. Scan, sign, and publish the image.
  5. Update a version-controlled deployment definition.
  6. Apply or reconcile the desired state.
  7. Wait for rollout health.
  8. Record deployment evidence and notify stakeholders.

A rolling update gradually replaces old Pods with new Pods. Its safety depends on readiness probes, replica counts, update limits, capacity, and application compatibility. During schema changes, backward-compatible database migration is often necessary because old and new application versions may coexist.

Blue-green deployment maintains two environments and switches traffic from the old version to the new version. It can simplify rollback but may require nearly double capacity. Canary deployment sends a small proportion of traffic to a new version and increases exposure after observing metrics. It provides strong risk control but requires traffic management and meaningful observability.

Rollback is not always a complete solution. If a release has already changed a database schema or produced incompatible data, application rollback may not restore compatibility. Release design must therefore include migration strategy and recovery testing.

10. Illustrative Case: Automating a Retail Ordering Service

Background

A fictional retailer operates an ordering API on manually configured virtual machines. Releases are infrequent, deployment steps differ between environments, and an unhealthy process may continue receiving traffic.

Problem

The team experiences configuration drift, inconsistent dependency versions, slow recovery, and uncertainty about which artifact is running in production. Credentials have also been stored in deployment scripts.

Analysis

The service is stateless at the API layer, but it uses a managed relational database and a message queue. The team determines that containerization is appropriate for the API, while persistent data should remain in managed services. A deployment requires at least three replicas for availability, readiness checks for traffic admission, and a controlled image-promotion process.

Approach and solution

The team creates a multi-stage Dockerfile and runs the final process as a non-root user. A .dockerignore file excludes source-control metadata and local files. The CI pipeline runs tests, scans dependencies and the image, creates an SBOM, signs the image, and pushes it to a private registry.

The deployment references an immutable image digest. A Kubernetes Deployment specifies three replicas, CPU and memory requests, a readiness endpoint, and a liveness endpoint. A Service selects Pods through labels. Database credentials are supplied through an external secret mechanism, while non-sensitive settings are stored in a ConfigMap. A Horizontal Pod Autoscaler responds to CPU and request-rate metrics. The pipeline waits for the rollout to become ready and stops automatically if error rate or latency exceeds defined thresholds.

Outcome

Deployments become repeatable, and the same signed artifact is promoted through test and production environments. Failed containers are removed from service through readiness checks, while genuinely stuck processes are restarted. The team can identify the deployed digest and compare release health with the previous version.

Learning points

The main improvement does not come from containers alone. It comes from combining immutable artifacts, declarative configuration, health-aware routing, automated verification, observability, and controlled access. Kubernetes can automate failure recovery, but it cannot compensate for poor probes, unsafe credentials, inadequate monitoring, or incompatible database changes.

11. Challenges, Governance, and Professional Practice

Cloud-native systems introduce operational complexity. Teams must manage cluster upgrades, network policies, identity, cost, observability, storage, and incident response. A poorly governed cluster can become a shared concentration of risk.

Important governance questions include:

  • Who may deploy to each namespace or environment?
  • Are images from approved registries and signed sources?
  • Are privileged containers and host mounts prohibited by policy?
  • Are secrets audited and rotated?
  • Are logs, metrics, and traces retained according to legal and business requirements?
  • Can the organization restore workloads and data after a regional or cluster failure?
  • Are automated decisions explainable to operators during an incident?

Privacy regulations may apply to logs, images, configuration, and telemetry if they contain personal or sensitive information. Teams should minimize collected data, restrict access, define retention periods, and avoid exposing secrets in logs. Automated remediation should be observable and reversible where possible.

Artificial intelligence can assist with manifest generation, anomaly detection, log summarization, and incident investigation. It should not be trusted blindly to create privileged policies or modify production systems without review. Generated configurations require validation for security, resource behavior, compatibility, and organizational policy.

Best Practices Checklist

  • Build once and promote the same immutable artifact.
  • Pin important dependencies and use trusted base images.
  • Keep secrets out of images, source repositories, and logs.
  • Use multi-stage builds and non-root runtime users.
  • Scan images and dependencies, then manage exceptions explicitly.
  • Use labels and selectors consistently.
  • Define requests and limits from measured workload behavior.
  • Design readiness, liveness, and startup probes for different purposes.
  • Store declarative manifests in version control.
  • Use progressive delivery for high-risk changes.
  • Monitor availability, latency, errors, saturation, and rollout status.
  • Test rollback, backup, restore, and cluster-failure procedures.
  • Apply least privilege to users, service accounts, workloads, and registries.

Chapter Summary

Containers package applications and dependencies into portable execution units, but they share the host kernel and therefore require deliberate security controls. Secure image construction depends on trusted bases, controlled build contexts, dependency management, multi-stage builds, non-root execution, secret protection, scanning, signing, and provenance.

Registries provide artifact storage, distribution, access control, and governance. Promoting the same immutable image digest through environments improves reproducibility. Kubernetes adds orchestration through Pods, Deployments, Services, ConfigMaps, Secrets, storage claims, and controllers. Its declarative model continuously reconciles actual state with desired state.

Readiness, liveness, and startup probes have distinct purposes. Resource requests support scheduling and inform utilization-based autoscaling, while limits constrain consumption. Rolling, blue-green, and canary deployments provide different balances of capacity, complexity, and release risk. Successful cloud-native automation combines technology with version control, observability, security governance, progressive delivery, and tested recovery procedures.

Key Terms

Container: An isolated process packaged with its runtime dependencies.

Container image: An immutable package used to create containers.

Dockerfile: A text specification describing how to build an image.

Layer: A filesystem change contributing to an image.

Multi-stage build: A build using separate stages to exclude tools from the runtime image.

Container registry: A repository and distribution service for images and related artifacts.

Image digest: A content-based identifier for a particular image artifact.

Pod: Kubernetes’ smallest schedulable unit, containing one or more containers.

Deployment: A Kubernetes resource that manages replicated, replaceable Pods.

ReplicaSet: A controller that maintains a specified number of matching Pods.

Service: A stable network endpoint selecting Pods by labels.

ConfigMap: A Kubernetes resource for non-sensitive configuration.

Secret: A Kubernetes resource intended for sensitive configuration values.

Namespace: A logical Kubernetes boundary for organization, policy, and access.

Readiness probe: A health check determining whether a Pod should receive traffic.

Liveness probe: A health check used to identify a container requiring restart.

Startup probe: A health check protecting slow-starting applications during initialization.

Horizontal Pod Autoscaler: A controller that adjusts replica count using metrics.

Declarative operation: Defining desired state for a system to reconcile.

Rolling update: A release strategy that gradually replaces old instances with new ones.

Review Questions

Short Answer Questions

  1. How does a container differ from a virtual machine?
  2. What is the purpose of a multi-stage Docker build?
  3. Why should production images preferably be referenced by digest?
  4. Distinguish a readiness probe from a liveness probe.
  5. What role does a Kubernetes Service perform?

Long Answer Questions

  1. Explain the main stages of a secure container image supply chain.
  2. Describe Kubernetes control-plane and worker-node responsibilities.
  3. Explain how requests, limits, and autoscaling interact.
  4. Compare rolling, blue-green, and canary deployment strategies.
  5. Discuss the benefits and limitations of declarative Kubernetes operations.

Analytical / Application Questions

  1. A service is repeatedly restarted during a five-minute initialization process. Its liveness probe begins after 10 seconds and fails after three checks. Analyze the likely cause and propose a safer probe design.
  2. A team copies database passwords into a Dockerfile and deploys one image separately for each environment. Identify the security and reproducibility problems and design an improved workflow.
  3. A new release passes unit tests but causes high latency after all traffic is switched at once. Recommend a deployment, observability, and rollback approach that reduces the risk of recurrence.

Multiple Choice Questions with Answers

Question 1

Which Dockerfile practice most directly prevents build tools from being included in the production image?

A. Using an EXPOSE instruction

B. Using a multi-stage build

C. Adding more environment variables

D. Increasing the container port

Correct Answer: B. Using a multi-stage build

Question 2

What does a Kubernetes readiness probe primarily determine?

A. Whether a node has sufficient disk space

B. Whether a container should be restarted

C. Whether a Pod should receive service traffic

D. Whether an image has a valid signature

Correct Answer: C. Whether a Pod should receive service traffic

Question 3

Why is copying dependency manifests before application source often useful in a Dockerfile?

A. It disables image scanning

B. It improves reuse of cached dependency layers

C. It automatically encrypts dependencies

D. It exposes the application port

Correct Answer: B. It improves reuse of cached dependency layers

Question 4

Which Kubernetes resource provides a stable network endpoint for replaceable Pods?

A. Service

B. ConfigMap

C. Namespace

D. ReplicaSet

Correct Answer: A. Service

Question 5

A Pod requests 250 millicores of CPU and uses 125 millicores. What is its CPU utilization relative to its request?

A. 25%

B. 50%

C. 75%

D. 125%

Correct Answer: B. 50%

Question 6

Which statement about container image tags and digests is correct?

A. A tag is always immutable

B. A digest identifies image content more precisely than a mutable tag

C. A digest is only a human-readable nickname

D. Tags cannot be used in registries

Correct Answer: B. A digest identifies image content more precisely than a mutable tag

Question 7

What is the main purpose of a Kubernetes Deployment?

A. To store passwords in encrypted form automatically

B. To manage a desired set of replicated application Pods

C. To provide physical storage hardware

D. To compile application source code

Correct Answer: B. To manage a desired set of replicated application Pods

Question 8

Which probe is most appropriate for protecting an application that takes a long time to initialize?

A. Startup probe

B. Network policy

C. Service account

D. Resource quota

Correct Answer: A. Startup probe

Question 9

Which practice best protects a database password used by a containerized application?

A. Embedding it in the image layer

B. Committing it to the Dockerfile repository

C. Supplying it through an appropriate secret-management mechanism

D. Printing it during the build for troubleshooting

Correct Answer: C. Supplying it through an appropriate secret-management mechanism

Question 10

What is the central idea of declarative Kubernetes operation?

A. Operators manually restart every failed process

B. The desired state is recorded and controllers reconcile actual state toward it

C. All workloads must run on one node

D. Images are rebuilt whenever a Pod restarts

Correct Answer: B. The desired state is recorded and controllers reconcile actual state toward it

Continuous Integration and Automation with DevOps
Chapter 8 of 15