Skip to content

Build, promote, and deploy an image in CI

Use one CI job to build an application image, update its Kix pin, commit the pin, and deploy the cluster. The committed pin records the image digest that the deployment consumes.

This guide assumes:

  • The project already has a committed pin named web.
  • The cluster reads that pin and is named production.
  • The runner can push the image, push to the Git repository, and reach the Kubernetes cluster.
  • kix, Docker, Nix, and git are installed on the runner.

Configure the CI system to set SOURCE_CHANGED=true when files that can affect the application image have changed. Include the application source, Dockerfile, build inputs, and dependency lock files.

The image build must be conditional. A pin commit may start the job again. On that run, the application inputs have not changed, so the job skips the image build and does not create another pin commit.

Add the following script to the deployment job. Replace the image repository, pin file, and cluster name with values from your project:

ci/deploy.sh
#!/usr/bin/env bash
set -euo pipefail
: "${CI_COMMIT_SHA:?set CI_COMMIT_SHA to the source revision}"
: "${CI_BRANCH:?set CI_BRANCH to the deployment branch}"
: "${SOURCE_CHANGED:?set SOURCE_CHANGED to true or false}"
IMAGE_REPOSITORY="registry.example.com/acme/web"
IMAGE_TAG="main"
if [[ "$SOURCE_CHANGED" == "true" ]]; then
docker build --tag "$IMAGE_REPOSITORY:$IMAGE_TAG" .
docker push "$IMAGE_REPOSITORY:$IMAGE_TAG"
kix pin set web \
--repository "$IMAGE_REPOSITORY" \
--tag "$IMAGE_TAG" \
--source-rev "$CI_COMMIT_SHA" \
--pins-file pins.json
kix pin check \
--key web \
--source-rev "$CI_COMMIT_SHA" \
--pins-file pins.json
git add pins.json
if ! git diff --cached --quiet; then
git commit -m "Promote web image from $CI_COMMIT_SHA"
git push origin "HEAD:$CI_BRANCH"
fi
fi
git fetch origin "$CI_BRANCH"
test "$(git rev-parse HEAD)" = "$(git rev-parse "origin/$CI_BRANCH")"
kix deploy production -y

Use a stable tag such as main for the image stream. kix pin set resolves the current content behind that tag and records its digest, so the pin diff is the promotion record.

The kix pin check --source-rev command verifies that the pin was updated for the source revision built by this run. Keep it inside the source-change branch; a job started by the subsequent pin commit has a different commit SHA and no new application image.

Set the commit identity once in the CI job:

CI job setup
git config user.name "Kix deployment bot"
git config user.email "[email protected]"

Use your CI system’s push credential for git push. Protect the deployment branch so only the expected job can write promotion commits.

The second run caused by the pin commit should set SOURCE_CHANGED=false. It skips the image build and pin update, then reaches kix deploy with an unchanged activation. No additional commit is created.

Do not rebuild the image on every invocation of this job. Container builds are not necessarily reproducible, so rebuilding unchanged source can produce a new digest and another commit each time.