Kaniko Docker Builds¶
CWIQ uses Kaniko to build Docker images inside Kubernetes pods without requiring privileged mode or Docker-in-Docker. This page explains the build process, image naming, tag strategy, and how the built image is passed between pipeline stages.
Why Kaniko¶
Docker-in-Docker (DinD) requires the runner pod to run in privileged mode, which is a security risk in a shared Kubernetes cluster. Kaniko builds Docker images entirely in userspace — it reads the Dockerfile and pushes the resulting image to a registry without needing a Docker daemon or elevated privileges.
The executor image is:
This image is pulled through the Nexus Docker proxy cache, not directly from Google Container Registry:
Kaniko uses BusyBox — not a full shell
The kaniko/executor:debug image provides a minimal BusyBox shell for the entrypoint. Standard shell utilities may not behave identically to bash. In particular, use /kaniko/.docker/config.json to provide registry credentials — do not call docker login, which is not available.
Registry Authentication¶
Kaniko authenticates to Nexus using a config.json file written to /kaniko/.docker/config.json before the build starts. The credentials are fetched from Vault using GitLab's JWT authentication in the job's before_script:
before_script:
- |
# Authenticate with Vault via GitLab JWT
VAULT_TOKEN=$(curl -s --request POST \
"${VAULT_ADDR}/v1/auth/jwt/login" \
--data "{\"jwt\": \"${CI_JOB_JWT_V2}\", \"role\": \"gitlab-ci\"}" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['auth']['client_token'])")
# Fetch Nexus push credentials
NEXUS_USER=$(curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
"${VAULT_ADDR}/v1/secret/nexus/svc-orchestrator" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['data']['username'])")
NEXUS_PASS=$(curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
"${VAULT_ADDR}/v1/secret/nexus/svc-orchestrator" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['data']['password'])")
# Write Kaniko auth file
mkdir -p /kaniko/.docker
echo "{\"auths\":{\"nexus.shared.cwiq.io:8443\":{\"username\":\"${NEXUS_USER}\",\"password\":\"${NEXUS_PASS}\"}}}" \
> /kaniko/.docker/config.json
Image Naming Convention¶
All CWIQ Docker images follow the pattern orchestrator-{project} — note there is no cwiq- prefix on application-level image names.
| Project | Image Name | Full Push Path |
|---|---|---|
| server | orchestrator-server |
nexus.shared.cwiq.io:8443/orchestrator-server |
| ui | orchestrator-ui |
nexus.shared.cwiq.io:8443/orchestrator-ui |
| agent | orchestrator-agent |
nexus.shared.cwiq.io:8443/orchestrator-agent |
| mcp | orchestrator-mcp |
nexus.shared.cwiq.io:8443/orchestrator-mcp |
| runner-api | orchestrator-runner-api |
nexus.shared.cwiq.io:8443/orchestrator-runner-api |
| iam-api | orchestrator-iam-api |
nexus.shared.cwiq.io:8443/orchestrator-iam-api |
| notification-api | orchestrator-notification-api |
nexus.shared.cwiq.io:8443/orchestrator-notification-api |
Push port: 8443 (Nexus hosted Docker repository, write access)
Pull port: 8444 (Nexus Docker group repository, includes proxy cache for Docker Hub and GCR)
Tag Strategy¶
| Trigger | Tags Applied | Example |
|---|---|---|
Push to main |
main-{short-sha}, latest |
main-a1b2c3d, latest |
| Feature branch | branch-{slug}-{short-sha} |
branch-feature-search-a1b2c3d |
Version tag (v*) |
{version}, stable |
1.0.0, stable |
The short-sha is the first 8 characters of $CI_COMMIT_SHA. The branch slug replaces non-alphanumeric characters with hyphens and truncates to 40 characters.
latest is pushed by the push-latest job in the push stage (separate from the build stage) and runs only on main.
The build.env Artifact¶
The build job writes a single-line artifact file that records the exact image tag produced:
This file is declared as a dotenv artifact in the job definition:
GitLab's dotenv artifact type automatically injects the variables into any downstream job that uses needs: with artifacts: true. This means the deploy-dev, trivy-image-scan, and push-latest jobs all automatically have $IMAGE_TAG available as an environment variable without any manual parsing.
Always reference $IMAGE_TAG from build.env, never construct the tag manually
Constructing the image tag manually in deploy or scan jobs (e.g., main-${CI_COMMIT_SHORT_SHA}) creates a risk of mismatch if the build job uses different logic. Always use $IMAGE_TAG injected from build.env.
Build Arguments¶
The Kaniko executor passes these build arguments to every Dockerfile via --build-arg:
| Build Arg | Value | Example |
|---|---|---|
VERSION |
$CI_COMMIT_TAG (empty on non-tag pipelines) |
1.2.0 |
BUILD_DATE |
ISO 8601 timestamp | 2026-03-18T09:00:00Z |
VCS_REF |
Full commit SHA ($CI_COMMIT_SHA) |
a1b2c3d4e5f6... |
These are typically stored as OCI image labels in the Dockerfile:
ARG VERSION
ARG BUILD_DATE
ARG VCS_REF
LABEL org.opencontainers.image.version="${VERSION}"
LABEL org.opencontainers.image.created="${BUILD_DATE}"
LABEL org.opencontainers.image.revision="${VCS_REF}"
Build Cache¶
Kaniko uses a layer cache stored in Nexus to speed up repeated builds. The cache repository is separate from the image repository:
Cache hits are most effective when RUN pip install or RUN npm install layers are placed before COPY . . in the Dockerfile, so that dependency installation is only re-executed when requirements.txt or package.json changes.
Full Kaniko Executor Command¶
The build-push job runs Kaniko with the following arguments (simplified for readability):
/kaniko/executor \
--context "${CI_PROJECT_DIR}" \
--dockerfile "${CI_PROJECT_DIR}/Dockerfile" \
--destination "nexus.shared.cwiq.io:8443/orchestrator-${CI_PROJECT_NAME}:main-${CI_COMMIT_SHORT_SHA}" \
--destination "nexus.shared.cwiq.io:8443/orchestrator-${CI_PROJECT_NAME}:latest" \
--cache=true \
--cache-repo="nexus.shared.cwiq.io:8443/orchestrator-${CI_PROJECT_NAME}/cache" \
--build-arg "VERSION=${CI_COMMIT_TAG}" \
--build-arg "BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--build-arg "VCS_REF=${CI_COMMIT_SHA}"
Related Documentation¶
- Pipeline Stages — Where the
buildandpushstages fit - CI Template Reference — The
.docker-buildand.docker-push-latesttemplate jobs - Deploy Patterns — How
IMAGE_TAGfrombuild.envis used in deployment - Nexus Docker Registry — Port architecture, repositories, and pull/push rules