CI/CD Pipelines with Jenkins or GitHub Actions

Chapter 9
Containers, Infrastructure, and Deployment Automation

Diploma in DevOps
CI/CD Pipelines with Jenkins or GitHub Actions   •   Diploma

Containers, Infrastructure, and Deployment Automation

Introduction and Context

Continuous integration and continuous delivery (CI/CD) become substantially more powerful when a pipeline can create the same application environment repeatedly. Containers package an application with its runtime dependencies; infrastructure as code (IaC) describes the resources on which it runs; configuration management establishes operating-system and application settings; and deployment automation coordinates release, verification, and rollback.

This chapter examines how Jenkins and GitHub Actions can build secure container images and deploy applications to virtual machines, cloud services, and Kubernetes. The central engineering principle is repeatability: a deployment should be derived from version-controlled definitions rather than from undocumented manual actions.

Learning Objectives

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

  • explain how containers, images, registries, infrastructure, and configuration management relate;
  • design a secure, reproducible container image build;
  • distinguish provisioning, configuration, and application deployment;
  • create CI/CD stages for virtual machines, cloud platforms, and Kubernetes;
  • apply IaC practices using tools such as Terraform or OpenTofu;
  • integrate Ansible or cloud-init with a pipeline;
  • implement approvals, health checks, rollback, and audit controls;
  • evaluate operational, security, and governance limitations.

1. The Deployment Automation Model

A modern delivery system usually contains four layers:

LayerMain purposeTypical tools
Source and pipelineValidate and coordinate changeGitHub, Jenkins, GitHub Actions
ArtifactPackage an immutable releaseOCI image, package, binary
InfrastructureCreate networks, compute, storage, and identityTerraform, OpenTofu, CloudFormation
Configuration and releaseConfigure hosts and run the applicationAnsible, cloud-init, Helm, kubectl

Provisioning creates or changes infrastructure. Configuration management installs software and establishes desired host state. Application deployment releases a particular application version. These activities may occur in one pipeline, but they have different ownership, risks, and lifecycles.

A useful flow is:

Commit → test → build image → scan → sign → publish
       → plan infrastructure → approve → apply
       → configure target → deploy → verify → promote or roll back

A container image is an immutable artifact in principle, whereas a running container is an instance of that artifact. An image normally consists of ordered filesystem layers plus metadata such as the entrypoint, environment defaults, and supported architecture. An OCI registry stores images and their manifests. Tags are convenient labels, but a digest is a content-addressed identifier and is preferable for production deployment.

2. Building Secure Container Images

2.1 Reproducible Dockerfiles

A secure Dockerfile should be small, explicit, and deterministic. A multi-stage build separates compilation tools from the production runtime:

FROM node:22-alpine AS build
WORKDIR /src
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:1.27-alpine
COPY --from=build /src/dist /usr/share/nginx/html
USER 101
EXPOSE 8080

The example is illustrative; the runtime image must actually be able to bind to the declared port and serve the application. Important practices include:

  • pin base images by a reviewed version, and preferably by digest;
  • use a lock file and deterministic dependency installation;
  • copy dependency manifests before source code to improve cache use without sacrificing correctness;
  • exclude secrets and unnecessary files with .dockerignore;
  • use a non-root user and a read-only filesystem where possible;
  • avoid shell-based installers and unverified downloads;
  • remove package-manager caches and build tools from the final stage;
  • set explicit health and resource behaviour in the deployment platform;
  • rebuild regularly because a pinned image does not automatically receive security fixes.

A container is not a security boundary by itself. The host kernel, runtime, registry, orchestration platform, credentials, and application remain relevant attack surfaces.

2.2 Supply-chain controls

A pipeline should scan source dependencies, the built image, and infrastructure definitions. Scanning is useful but imperfect: a vulnerability database may contain false positives, miss a newly disclosed issue, or report a vulnerable library that is unreachable in the deployed path. Risk decisions should consider severity, exploitability, exposure, compensating controls, and remediation availability.

A stronger supply chain uses:

  1. trusted and reviewed base images;
  2. dependency lock files and provenance records;
  3. image scanning before publication and again at deployment time;
  4. signed images and verification at admission or deployment;
  5. software bills of materials (SBOMs);
  6. short-lived credentials through workload identity or OIDC;
  7. protected branches, reviewed workflow changes, and immutable logs.

Do not place passwords, cloud keys, or tokens in Dockerfiles, image layers, repository files, or pipeline logs. Build-time secrets should use the build system’s secret mechanism and should not become part of a layer.

3. Infrastructure as Code

IaC expresses desired infrastructure in declarative or procedural definitions stored with version control. A declarative tool compares the desired configuration with observed state and proposes a change. Terraform and OpenTofu commonly maintain a state file, which maps declared resources to real resources. State is sensitive and must be stored remotely with access control, encryption, locking, backup, and recovery procedures.

A typical workflow is:

format/validate → plan → peer review → approved apply → output and audit

plan is not merely a convenience. It is a change preview that supports review and separation of duties. Production applies should use the reviewed plan, not an unreviewed re-plan whose inputs may have changed.

Example fragment:

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type
  subnet_id     = var.subnet_id

  tags = {
    Name        = "web-${var.environment}"
    ManagedBy   = "terraform"
  }
}

The exact resource syntax and security controls depend on the cloud provider. A complete design also specifies network policy, encryption, identity, monitoring, backups, availability, and deletion behaviour.

Desired state and drift

Drift occurs when the actual environment differs from the version-controlled definition, perhaps because an administrator changed it manually or a cloud service modified a value. Detection should be scheduled and alerts should be reviewed. The remedy may be to reconcile the environment, update the code through review, or deliberately preserve an externally managed setting. Blindly overwriting production can cause an outage; ignoring drift undermines reliability.

IaC modules should have clear inputs, outputs, versioning, documentation, and tests. Avoid copying large configurations between environments. Use separate state boundaries for security and operational isolation, while avoiding excessive fragmentation that makes dependencies invisible.

4. Configuration Management and Virtual Machines

Virtual machines often require operating-system updates, users, packages, service units, certificates, firewall rules, and monitoring agents. Ansible represents these changes as tasks and playbooks. Idempotence means that applying the same playbook repeatedly should converge on the same state rather than duplicate or corrupt configuration.

Example:

- hosts: web
  become: true
  tasks:
    - name: Install web server
      ansible.builtin.package:
        name: nginx
        state: present
    - name: Install application unit
      ansible.builtin.template:
        src: app.service.j2
        dest: /etc/systemd/system/app.service
        mode: '0644'
      notify: Restart application
  handlers:
    - name: Restart application
      ansible.builtin.systemd:
        name: app
        state: restarted
        daemon_reload: true

Secrets should be encrypted or retrieved at runtime from a secrets manager. Inventory should avoid embedding sensitive data. Use least-privilege SSH or cloud access, host verification, patch management, and a tested rollback procedure.

A VM deployment commonly follows this sequence: provision the instance, bootstrap a minimal agent or Python runtime, configure the host, retrieve an image or package, start the service, run health checks, and remove or drain the old version. Blue-green or rolling replacement can reduce downtime. A deployment is incomplete until the system’s observable behaviour has been checked.

5. Deploying to Cloud Platforms

Cloud platforms offer managed virtual machines, container services, serverless runtimes, and managed Kubernetes. The more managed the platform, the less operating-system work the team performs, but the more important platform configuration, identity, quotas, networking, and observability become.

A cloud deployment pipeline should separate:

  • build identity, which publishes artifacts;
  • deployment identity, which changes a target environment;
  • read-only verification identity, which reads health and deployment status.

GitHub Actions can use OIDC to exchange a short-lived workflow identity for cloud credentials. Jenkins can use a cloud credential provider or workload identity rather than storing long-lived keys. Restrict identities by repository, branch, environment, resource, and action. Production environments should require approval where the risk warrants it.

Deployment strategies include:

StrategyDescriptionMain trade-off
RecreateStop old version, start new versionSimple, but causes downtime
RollingReplace instances graduallyLower risk, requires compatibility
Blue-greenMaintain two complete environmentsFast rollback, higher cost
CanaryExpose a small traffic percentage firstStrong evidence, more routing complexity

A promotion decision should use objective signals such as error rate, latency, saturation, health checks, business transactions, and log anomalies. A successful process exit code alone is not evidence that users can use the service.

6. Kubernetes Deployment Automation

Kubernetes declares objects such as Deployments, Services, ConfigMaps, Secrets, Ingress resources, and policies. A Deployment usually maintains a desired number of Pods and performs a rolling update. A Service provides stable networking to selected Pods.

Example deployment excerpt:

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/web@sha256:REPLACE_WITH_DIGEST
          ports:
            - containerPort: 8080
          securityContext:
            runAsNonRoot: true
            readOnlyRootFilesystem: true
          readinessProbe:
            httpGet:
              path: /ready
              port: 8080

A readiness probe controls whether a Pod receives traffic; a liveness probe indicates whether a container should be restarted. They are not interchangeable. Poorly designed probes can cause restart loops or route traffic to an unready application. Resource requests assist scheduling, while limits can protect a node but may cause termination if set below real demand.

Use namespaces, RBAC, NetworkPolicies, Pod Security controls, admission policies, resource quotas, and encrypted secrets. Kubernetes Secrets are encoded rather than automatically safe; protect the API server and integrate an external secret manager when appropriate.

Helm packages Kubernetes templates, while Kustomize composes YAML overlays. GitOps tools such as Argo CD or Flux continuously reconcile a cluster with a repository. In a push model, Jenkins or Actions directly invokes the cluster API; in a pull model, a controller performs reconciliation. Pull-based delivery reduces direct cluster credentials in CI, but requires governance of the Git repository and controller.

Do not deploy mutable tags such as latest to production when deterministic rollback matters. Record the image digest, manifest revision, configuration revision, and deployment actor for every release.

7. Pipeline Design with Jenkins and GitHub Actions

A robust pipeline has distinct stages and explicit artefacts:

  1. Validate: lint application, Dockerfile, IaC, and Kubernetes manifests.
  2. Test: execute unit, integration, and security tests.
  3. Build: create an image for the required architecture.
  4. Scan and attest: generate SBOM, scan, sign, and record provenance.
  5. Publish: push the immutable image to an approved registry.
  6. Plan: produce an IaC plan and policy results.
  7. Approve: obtain review for protected environments.
  8. Deploy: apply infrastructure and release the digest.
  9. Verify: run smoke, health, and business-transaction tests.
  10. Promote or recover: continue, pause, or roll back according to defined criteria.

Jenkins Pipeline supports agents, stages, credentials bindings, approvals, artefact archiving, and shared libraries. GitHub Actions supports jobs, reusable workflows, environments, environments’ protection rules, caches, artefacts, and OIDC. In both systems, pin third-party actions or plugins to reviewed versions, restrict runners, prevent untrusted pull requests from accessing secrets, and avoid printing environment variables.

Pipeline code is production code. It should be reviewed, tested, versioned, and monitored. A compromised workflow can often modify infrastructure or publish a trusted-looking artifact; therefore repository administration and workflow permissions belong within the threat model.

8. Worked Application: A Retail API

Consider an illustrative online retailer whose API runs in containers and whose production environment consists of a managed Kubernetes cluster and a managed database.

Background and problem

The team previously built images manually, used a shared cloud administrator key, and deployed the mutable tag release. Rollbacks were slow, and nobody could reliably identify which source revision was running.

Analysis

The major risks are non-reproducible artifacts, excessive identity privileges, unreviewed infrastructure changes, and insufficient release evidence. The solution must improve traceability without making every change a manual operation.

Approach

The team implements the following design:

  • pull requests run tests, Dockerfile linting, IaC validation, and manifest policy checks;
  • a protected branch builds an image and publishes an SBOM;
  • the image is signed and addressed by digest;
  • GitHub Actions obtains short-lived cloud credentials using OIDC;
  • Terraform plans infrastructure changes and stores state in a locked, encrypted backend;
  • production deployment requires two reviewers;
  • the Kubernetes Deployment references the digest, has three replicas, and defines readiness and liveness probes;
  • a canary receives a small traffic share and is evaluated using error rate and latency;
  • failed verification pauses promotion and restores the previous manifest revision.

Outcome

The organisation can identify source, image digest, infrastructure revision, and approvers for each release. The pipeline reduces manual credential exposure and makes rollback a version change rather than a reconstruction exercise. It does not eliminate risk: database migrations, provider outages, faulty probes, and compromised dependencies still require operational preparation.

Learning points

Automation is valuable only when it produces evidence and safe control points. Immutable artefacts, least privilege, declarative infrastructure, health-based promotion, and tested recovery form a system; no single tool supplies all of these properties.

9. Limitations, Governance, and Contemporary Practice

Automation can amplify errors at machine speed. A bad IaC module can remove many resources; a vulnerable base image can be replicated across environments; an overly broad deployment identity can turn a pipeline compromise into a cloud compromise. Controls should therefore include peer review, policy as code, approvals for high-impact changes, backups, disaster recovery exercises, audit retention, and separation of duties.

Regulatory obligations may require evidence of access control, change approval, vulnerability management, data location, retention, and incident response. Do not treat compliance as a scan checkbox. Map controls to actual risks and preserve evidence without collecting unnecessary personal data.

Environmental efficiency is also relevant. Multi-stage images reduce transfer and storage, caching reduces repeated computation, and right-sized runners and clusters reduce waste. Security and efficiency must not be achieved by removing required logging, redundancy, or recovery capacity.

Current practice is moving toward provenance attestations, policy-driven admission, ephemeral runners, workload identity, software supply-chain frameworks, and GitOps reconciliation. AI-assisted coding may generate Dockerfiles, workflow definitions, or Terraform, but generated infrastructure must be reviewed, tested, scanned, and applied under normal controls. AI does not establish trust merely because it produced syntactically valid configuration.

Best-Practice Checklist

  • Build immutable, minimal images with non-root execution.
  • Pin and regularly update base images and dependencies.
  • Scan, sign, and record SBOM and provenance information.
  • Keep secrets outside source, images, state files, and logs.
  • Use remote, encrypted, locked IaC state with controlled access.
  • Review plans and apply the exact approved change.
  • Prefer short-lived, least-privilege workload identities.
  • Use readiness checks, observability, and explicit rollback criteria.
  • Deploy by image digest rather than a mutable tag.
  • Test backups, disaster recovery, and rollback—not only the happy path.

Chapter Summary

Containers package applications consistently, but secure delivery also requires trusted bases, dependency control, non-root execution, scanning, signing, and provenance. IaC provisions infrastructure through reviewed desired state, while configuration management establishes repeatable host settings. Jenkins and GitHub Actions can coordinate validation, image publication, infrastructure planning, approval, deployment, and verification. VM, cloud, and Kubernetes targets require different operational controls, yet all benefit from immutable artefacts, least privilege, health-based promotion, observability, and tested recovery. Automation improves reliability only when its identities, definitions, state, and governance are themselves protected.

Key Terms

Container image: Immutable package containing application files, dependencies, and runtime metadata.

Container registry: Service that stores and distributes OCI images.

Image digest: Content-addressed identifier for an image manifest.

Multi-stage build: Build method that excludes compilation tools from the runtime image.

SBOM: Software bill of materials listing components in an artifact.

Provenance: Evidence describing how and from what sources an artifact was built.

Infrastructure as code: Version-controlled definition of infrastructure resources.

State file: IaC record linking declared resources with real resources.

Drift: Difference between declared and actual infrastructure state.

Idempotence: Property whereby repeated application converges without unwanted duplication.

Configuration management: Automated establishment of desired host or service settings.

Workload identity: Short-lived identity assigned to a workload or pipeline.

Rolling deployment: Gradual replacement of instances or Pods.

Blue-green deployment: Release strategy using two parallel environments.

Canary deployment: Limited initial exposure used to evaluate a release.

Readiness probe: Check determining whether a workload should receive traffic.

GitOps: Operational model in which a controller reconciles runtime state with version-controlled definitions.

Policy as code: Machine-evaluated rules governing configuration or deployment.

Review Questions

Short Answer Questions

  1. Why is an image digest more reliable than a mutable image tag for production deployment?
  2. Distinguish infrastructure provisioning from configuration management.
  3. What is infrastructure drift, and why should it be reviewed?
  4. Explain the difference between a Kubernetes readiness probe and a liveness probe.
  5. Why should CI/CD systems use short-lived workload identities?

Long Answer Questions

  1. Describe a secure pipeline from source commit to production deployment, including artefacts and approval points.
  2. Compare recreate, rolling, blue-green, and canary deployment strategies.
  3. Explain how Terraform or OpenTofu state should be protected and governed.
  4. Discuss security risks specific to container image construction and methods for reducing them.
  5. Compare push-based Kubernetes deployment from CI with pull-based GitOps reconciliation.

Analytical / Application Questions

  1. A team deploys latest, stores cloud administrator keys in Jenkins, and has no health checks. Analyse the risks and propose a staged remediation plan.
  2. An approved Terraform plan changes a firewall rule unexpectedly after a provider refresh. What investigative and governance steps should occur before applying it?
  3. A canary release shows normal CPU usage but elevated checkout failures. Decide whether to promote, pause, or roll back, and identify the evidence required for your decision.

Multiple Choice Questions with Answers

Question 1

Which identifier is most appropriate for a deterministic production container deployment?

A. The mutable tag latest

B. The image digest

C. The registry display name

D. The build runner hostname

Correct Answer: B. The image digest

Question 2

What is the primary purpose of a multi-stage container build?

A. To expose more network ports

B. To avoid using a registry

C. To keep build tools out of the runtime image

D. To make secrets permanent in an image

Correct Answer: C. To keep build tools out of the runtime image

Question 3

What does an IaC plan principally provide?

A. A preview of proposed infrastructure changes

B. A replacement for application testing

C. Automatic encryption of every secret

D. A guarantee that a provider will not fail

Correct Answer: A. A preview of proposed infrastructure changes

Question 4

Which practice best reduces long-lived credential exposure in GitHub Actions?

A. Printing credentials in logs

B. Using a shared administrator key

C. Storing keys in a Dockerfile

D. Using OIDC with short-lived cloud credentials

Correct Answer: D. Using OIDC with short-lived cloud credentials

Question 5

What does a Kubernetes readiness probe determine?

A. Whether a Pod should receive traffic

B. Whether source code compiles

C. Whether the cluster has unlimited capacity

D. Whether an image has an SBOM

Correct Answer: A. Whether a Pod should receive traffic

Question 6

Which deployment strategy initially exposes only a small portion of traffic to a new version?

A. Recreate

B. Canary

C. Full replacement

D. Static provisioning

Correct Answer: B. Canary

Question 7

Why is remote IaC state commonly encrypted and locked?

A. To increase image size

B. To prevent all configuration changes

C. To protect sensitive state and coordinate concurrent operations

D. To replace peer review

Correct Answer: C. To protect sensitive state and coordinate concurrent operations

Question 8

Which statement about container security is correct?

A. Containers eliminate host-kernel risk

B. Running as root is always required

C. A registry tag is immutable by definition

D. Containers reduce packaging differences but are not complete security boundaries

Correct Answer: D. Containers reduce packaging differences but are not complete security boundaries

Question 9

What is the main function of configuration-management idempotence?

A. Repeated runs converge without unwanted duplication

B. Every run creates a new server

C. It disables audit logging

D. It prevents all software updates

Correct Answer: A. Repeated runs converge without unwanted duplication

Question 10

In a pull-based GitOps model, who normally reconciles cluster state with repository definitions?

A. A cluster-side controller

B. A database user

C. A Dockerfile parser

D. A vulnerability database

Correct Answer: A. A cluster-side controller

CI/CD Pipelines with Jenkins or GitHub Actions
Chapter 9 of 14