GAP·MAP

CI/CD pipelines

[ junior depth ]

What build, test, and deploy mean

A pipeline is a set of jobs with dependencies between them. A common shape is build, test, then deploy. The names are less important than the contract at each boundary.

The build job turns a source revision into a releasable package, such as a container image or compiled archive. Test jobs produce evidence about that revision or package. The deploy job changes an environment to run the selected package. A failed prerequisite should stop dependent work from advancing.

This GitLab CI example publishes dist/ from the build job. The later jobs name the build as a dependency and receive its artifact:

stages: [build, test, deploy]

build_app:
  stage: build
  script: npm run build
  artifacts:
    paths: [dist/]

test_app:
  stage: test
  needs: [build_app]
  script: ./test-release.sh dist/

deploy_app:
  stage: deploy
  needs: [build_app, test_app]
  script: ./deploy.sh dist/

The exact syntax belongs to GitLab. By default, needs downloads artifacts from the jobs it names, so this test checks dist/ and deployment receives that same directory. The general rule is that deployment should consume the release that passed its required checks.

Artifacts and caches have different jobs

An artifact is an output you need to preserve or pass to another job. Build packages, test reports, and logs are common artifacts. A cache saves work that can be regenerated, such as downloaded dependencies. GitLab and GitHub both document this distinction.

Cache availability cannot be a correctness requirement. A runner may miss the cache and regenerate its contents. The cache key should change when inputs that affect the cached data change. This GitLab configuration derives the dependency cache key from the lockfile:

default:
  cache:
    key:
      files:
        - package-lock.json
    paths:
      - .npm/

install:
  script:
    - npm ci --cache .npm --prefer-offline

Wrong "The cache already has the application package, so deployment can use whichever copy it finds."

Right The release package is an identified artifact. A cache is an optimization and the job still works when it is absent.

A green pipeline is evidence with a boundary

Passing tests says that the configured checks passed for a particular input. It does not show how an untested build behaves. Rebuilding in the deploy job weakens the link between test evidence and production.

# Build once and publish this file as the release artifact.
build_app:
  script: ./build.sh --output app.tar.gz
  artifacts:
    paths: [app.tar.gz]

# Deploy the downloaded artifact. Do not rebuild here.
deploy_production:
  script: ./deploy.sh app.tar.gz

Record the source revision and build identifier with the artifact. For byte-level identity, publish under a content digest and verify that digest during deployment. Google describes release binaries that expose the revision and build identifier so an operator can associate a binary with its build record.

[ middle depth ]

Choose a deployment strategy by failure exposure

Build and test decide whether a release may advance. A deployment strategy decides how production moves from the old release to the new one.

In blue-green deployment, two separate environments run different versions. The new environment is prepared and tested before traffic moves from the old environment. Keeping the old environment available makes traffic reversal quick, but the strategy requires parallel capacity during the transition.

A canary deployment exposes a small part of production traffic to the new version first. Exposure increases only after the canary is accepted. The useful property is limited initial impact plus observation under production traffic.

A rolling deployment replaces the fleet in portions. Old and new versions share the fleet while the rollout is in progress. AWS notes that this lack of environment isolation can make rollback more complicated than blue-green.

These labels are not mutually exclusive. A team can send canary traffic to the green environment before a wider blue-green switch, or canary a release on a small part of a rolling fleet.

Wrong "Canary means deploy to staging, test there, then release to everyone."

Right A canary puts a limited share of production traffic on the new version before wider exposure. Staging can be an earlier gate, but it is not the canary group.

Gates answer different questions

An automated test gate answers whether a defined check passed. An approval gate answers whether an authorized reviewer permits the deployment. A wait timer controls when a deployment may proceed. These controls are useful, but they are not interchangeable.

GitHub environments can require reviewers, delay a job, restrict deployment branches, or call custom protection rules. Environment secrets remain unavailable to a job that awaits required approval until a reviewer approves it.

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - run: ./deploy.sh release.tar.gz

The reviewer and branch rules are configured on the production environment. The workflow declares which environment the job targets.

This GitLab dependency shape starts lint and unit tests independently. Deployment waits for both, then stops at a manual production gate:

lint:
  stage: test
  script: npm run lint

unit_tests:
  stage: test
  script: npm test

deploy_production:
  stage: deploy
  needs: [lint, unit_tests]
  when: manual
  environment: production
  script: ./deploy.sh release.tar.gz

Order checks by feedback value, cost, and dependencies. Independent checks can run in parallel when runner capacity permits. A manual gate belongs where authority, change policy, or risk calls for a human decision.

Wrong "A production approval proves the release is healthy."

Right Approval proves that the configured authorization condition passed. Runtime health still needs deployment checks and observation.

Rollback starts before deployment

A rollback target should identify a known previous release instead of a branch name that will be rebuilt later. The retained blue environment supports traffic reversal in blue-green. A canary controller can stop expansion and return traffic to the previous version. A rolling failure can leave updated and old portions in the same fleet, so reversal must account for that mixed state.

Define the artifact, command, permissions, and health condition used for reversal. Then exercise that path before an incident. Google documents release packages with unique hashes and labels, which lets rollout tooling refer to a specific built version.

# The release command receives an immutable version, not "latest".
./deploy.sh --environment production --artifact orders-api@sha256:7f3c...

# The rollback selects the previous known release.
./deploy.sh --environment production --artifact orders-api@sha256:1a92...

The digest values are illustrative. The operational requirement is an unambiguous release identity.

[ senior depth ]

The critical path controls feedback time

Stage lists can introduce waiting that no dependency requires. GitLab documents that a stage-based pipeline waits for every job in an earlier stage, while needs lets a job start as soon as its declared dependencies finish. This forms a directed acyclic graph.

Suppose service A can be built and tested without service B. Separate their dependency paths so a slow B build does not hold A's test job:

build_a:
  stage: build
  script: ./build-a.sh

build_b:
  stage: build
  script: ./build-b.sh

test_a:
  stage: test
  needs: [build_a]
  script: ./test-a.sh

test_b:
  stage: test
  needs: [build_b]
  script: ./test-b.sh

Optimize the dependency graph before weakening checks. Parallel work shortens the critical path when runner capacity is available. Caching avoids repeated downloads or generation, but both GitLab and GitHub state that jobs must tolerate a missing cache.

Trust is a chain from revision to runtime

Google's release engineering guidance calls for consistent, repeatable builds. Its hermetic builds use known tool and dependency versions and do not depend on services outside the build environment. The release record connects a build identifier to its revision, and packaged versions are uniquely identifiable.

That chain gives each gate a stable subject:

source revision -> controlled build -> versioned artifact -> test evidence
                -> approved promotion -> observed rollout

Do not rebuild between those arrows. Promote the same identified artifact. If a pipeline restores cached files, treat them as inputs to verify or regenerate. GitHub warns that restored cache contents should be treated as untrusted input and that secrets do not belong in caches.

Wrong "The command and commit are the same, so a second build is guaranteed to produce the tested bytes."

Right Repeatability requires control over tools and dependencies. Promoting the tested artifact avoids asking a rebuild to reproduce it.

Progressive delivery needs explicit stop conditions

Canary and rolling deployments intentionally create a period in which versions coexist. That affects compatibility requirements between callers, data formats, and dependent services. Blue-green isolates the application environments, but shared dependencies can still constrain a traffic reversal.

A rollout policy should identify the candidate artifact, exposure increments, observation periods, acceptance signals, and the action on failure. That action can be an automatic pause or rollback, or a required decision, depending on the service risk.

release_policy:
  artifact: orders-api@sha256:7f3c...
  steps:
    - traffic_percent: 5
      observe_minutes: 10
    - traffic_percent: 25
      observe_minutes: 20
  on_failed_health_check: rollback

This is policy-shaped YAML rather than syntax for a specific controller. The fields make the decision inputs reviewable. The health check must come from the service's defined production signals; a successful deployment command only reports that the command completed.

Gates should reduce risk without hiding ownership

Google documents access controls for creating releases, changing build configuration, approving changes, and deploying. GitHub environments similarly separate deployment authorization from job execution and can withhold environment secrets until approval.

Use automated gates for repeatable checks. Use approval where policy requires an accountable decision or separation of duties. A pile of approvals on every low-risk release increases waiting without improving the test evidence.

Rollback is part of the release design. Retain the known artifact, preserve authority to deploy it, define how traffic returns, and rehearse the procedure. A pipeline that can deploy forward but cannot select a previous known release has only half of its production path automated.

dig deeper

Primary sources behind these notes - the specs and official docs worth reading in full.

beta

The interviewer part is in the works.

The diagnostic, personal maps, and AI mock interviews are being finished right now. The notes stay free either way. Leave an email and you'll get the first-cohort invite, plus a month of Pro when it opens.

builds on

more Infrastructure & Ops

was this useful?