From 6422cb261b3348d35850be69bcac1da4a8ed357d Mon Sep 17 00:00:00 2001 From: NadeeshaMedagama Date: Tue, 3 Mar 2026 18:12:45 +0530 Subject: [PATCH 1/3] feat: add multi-stage Dockerfile, test Dockerfile, and .dockerignore - Dockerfile: Multi-stage build with builder, test, and runtime stages - Builder stage compiles cri-dockerd as a static Go binary with version/revision ldflags using golang:1.24.9-bookworm - Test stage runs the full unit test suite (targetable via --target test) - Runtime stage produces a minimal debian:bookworm-slim image with only ca-certificates and the cri-dockerd binary - Supports multi-arch builds (linux/amd64, linux/arm64) via TARGETOS and TARGETARCH build args - Dockerfile.test: Lightweight standalone test image that runs 'go test -v ./...' for isolated CI test execution - .dockerignore: Excludes .git, docs, packaging artifacts, IDE files, and markdown from the Docker build context to optimize build speed --- .dockerignore | 28 ++++++++++++++++++++++++++++ Dockerfile | 44 ++++++++++++++++++++++++++++++++++++++++++++ Dockerfile.test | 18 ++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 Dockerfile.test diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..0502b5fe3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,28 @@ +# Git +.git +.github +.gitignore + +# Build artifacts +build/ +packaging/deb/ +packaging/rpm/ +packaging/windows/ + +# Documentation +docs/ + +# IDE & editor +.idea/ +*.swp +*.swo +*~ + +# OS files +.DS_Store +Thumbs.db + +# Markdown (not needed in image) +*.md +LICENSE + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..27ee3b9ab --- /dev/null +++ b/Dockerfile @@ -0,0 +1,44 @@ +# syntax=docker/dockerfile:1 + +# ---- Build Stage ---- +ARG GO_VERSION=1.24.9 +FROM golang:${GO_VERSION}-bookworm AS builder + +ARG VERSION="" +ARG REVISION="" +ARG PRERELEASE="" +ARG TARGETOS=linux +ARG TARGETARCH=amd64 + +WORKDIR /go/src/github.com/Mirantis/cri-dockerd + +# Cache Go modules +COPY go.mod go.sum ./ +RUN go mod download + +# Copy source +COPY . . + +# Build the binary +RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath \ + -ldflags "-s -w \ + -X github.com/Mirantis/cri-dockerd/cmd/version.Version=${VERSION} \ + -X github.com/Mirantis/cri-dockerd/cmd/version.PreRelease=${PRERELEASE} \ + -X github.com/Mirantis/cri-dockerd/cmd/version.GitCommit=${REVISION}" \ + -o /usr/local/bin/cri-dockerd + +# ---- Test Stage ---- +FROM builder AS test +RUN go test ./... + +# ---- Final Stage ---- +FROM debian:bookworm-slim AS runtime + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /usr/local/bin/cri-dockerd /usr/local/bin/cri-dockerd + +ENTRYPOINT ["cri-dockerd"] + diff --git a/Dockerfile.test b/Dockerfile.test new file mode 100644 index 000000000..5f407db48 --- /dev/null +++ b/Dockerfile.test @@ -0,0 +1,18 @@ +# syntax=docker/dockerfile:1 + +# Dockerfile for running unit tests in CI +ARG GO_VERSION=1.24.9 +FROM golang:${GO_VERSION}-bookworm + +WORKDIR /go/src/github.com/Mirantis/cri-dockerd + +# Cache Go modules +COPY go.mod go.sum ./ +RUN go mod download + +# Copy source +COPY . . + +# Default command: run all unit tests +CMD ["go", "test", "-v", "./..."] + From 35b9cfac1fadd1f8b4cb8e1b5efb74ffa9deac81 Mon Sep 17 00:00:00 2001 From: NadeeshaMedagama Date: Tue, 3 Mar 2026 18:13:27 +0530 Subject: [PATCH 2/3] ci: add Docker test, build, and push workflow (docker.yml) Add a reusable GitHub Actions workflow (.github/workflows/docker.yml) that provides a complete Docker CI/CD pipeline with two stages: Stage 1 - docker-test: - Builds the Dockerfile.test image using Docker Buildx - Runs the full unit test suite inside an isolated container - Uses GitHub Actions cache (GHA) for layer caching Stage 2 - docker-build-push: - Runs only after tests pass successfully - Extracts version metadata from git tags (semver, revision, prerelease) - Sets up QEMU and Buildx for multi-architecture builds - Authenticates to Docker Hub via repository secrets - Generates smart image tags using docker/metadata-action: semver, major.minor, branch name, short SHA, and latest - Builds and pushes linux/amd64 and linux/arm64 images - Passes Go version and build metadata as build args Requires DOCKERHUB_USERNAME and DOCKERHUB_TOKEN repository secrets. --- .github/workflows/docker.yml | 127 +++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 .github/workflows/docker.yml diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 000000000..f1e89f2b1 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,127 @@ +name: Docker Test, Build & Push + +on: + workflow_call: + secrets: + DOCKERHUB_USERNAME: + required: true + description: "Docker Hub username" + DOCKERHUB_TOKEN: + required: true + description: "Docker Hub access token" + +env: + IMAGE_NAME: mirantis/cri-dockerd + +jobs: + # ----------------------------------------------------------- + # Stage 1 – Run unit tests inside a Docker container + # ----------------------------------------------------------- + docker-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Load environment + uses: c-py/action-dotenv-to-setenv@v4 + with: + env-file: .github/.env + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build test image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile.test + build-args: | + GO_VERSION=${{ env.GO_VERSION }} + push: false + load: true + tags: cri-dockerd-test:ci + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Run unit tests in container + run: docker run --rm cri-dockerd-test:ci + + # ----------------------------------------------------------- + # Stage 2 – Build multi-arch image & push to Docker Hub + # ----------------------------------------------------------- + docker-build-push: + runs-on: ubuntu-latest + needs: [docker-test] + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 # needed for git describe + + - name: Load environment + uses: c-py/action-dotenv-to-setenv@v4 + with: + env-file: .github/.env + + - name: Set version metadata + id: meta + run: | + VERSION=$(git describe --tags 2>/dev/null | sed 's/^v//' || echo "dev") + REVISION=$(git log -1 --pretty='%h') + PRERELEASE=$(echo "${VERSION}" | grep -q dev && echo "pre" || echo "") + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "revision=${REVISION}" >> "$GITHUB_OUTPUT" + echo "prerelease=${PRERELEASE}" >> "$GITHUB_OUTPUT" + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Docker metadata (tags & labels) + id: docker_meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + # tag semver on release tags + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + # branch name + type=ref,event=branch + # short SHA + type=sha,prefix= + # "latest" on default branch + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.docker_meta.outputs.tags }} + labels: ${{ steps.docker_meta.outputs.labels }} + build-args: | + GO_VERSION=${{ env.GO_VERSION }} + VERSION=${{ steps.meta.outputs.version }} + REVISION=${{ steps.meta.outputs.revision }} + PRERELEASE=${{ steps.meta.outputs.prerelease }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Print image digest + run: echo "Image pushed with digest ${{ steps.docker_meta.outputs.digest }}" + From 99d2b144b879775901976773c0ae94d978e2e411 Mon Sep 17 00:00:00 2001 From: NadeeshaMedagama Date: Tue, 3 Mar 2026 18:14:28 +0530 Subject: [PATCH 3/3] ci: integrate Docker workflow into Release, Merge, and PR pipelines Wire the new docker.yml reusable workflow into the three main CI entry points so Docker images are automatically tested, built, and pushed to Docker Hub as part of the standard development lifecycle: - Release.yml: Adds docker job after all quality gates pass (build, e2e, integration, unit-test, vet). Docker images are tagged with semver from the release tag and pushed to Docker Hub. - Merge.yml: Adds docker job on push to master branch after build, vet, and unit-test succeed. Pushes images tagged with branch name (master) and latest. - PR.yml: Adds docker job on pull requests to run containerized tests and validate the Docker build without pushing. All three pass DOCKERHUB_USERNAME and DOCKERHUB_TOKEN secrets to the reusable workflow. --- .github/workflows/Merge.yml | 7 +++++++ .github/workflows/PR.yml | 7 +++++++ .github/workflows/Release.yml | 7 +++++++ 3 files changed, 21 insertions(+) mode change 100644 => 100755 .github/workflows/Merge.yml mode change 100644 => 100755 .github/workflows/PR.yml mode change 100644 => 100755 .github/workflows/Release.yml diff --git a/.github/workflows/Merge.yml b/.github/workflows/Merge.yml old mode 100644 new mode 100755 index a8b49d3ad..327137e63 --- a/.github/workflows/Merge.yml +++ b/.github/workflows/Merge.yml @@ -20,3 +20,10 @@ jobs: if: ${{ always() && contains(join(needs.*.result, ','), 'success') }} needs: [build, vet, unit-test] uses: ./.github/workflows/integration.yml + docker: + if: ${{ always() && contains(join(needs.*.result, ','), 'success') }} + needs: [build, vet, unit-test] + uses: ./.github/workflows/docker.yml + secrets: + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/PR.yml b/.github/workflows/PR.yml old mode 100644 new mode 100755 index d4c5905e5..e79fdb188 --- a/.github/workflows/PR.yml +++ b/.github/workflows/PR.yml @@ -23,3 +23,10 @@ jobs: if: ${{ always() && contains(join(needs.*.result, ','), 'success') }} needs: [build, vet, unit-test] uses: ./.github/workflows/integration.yml + docker: + if: ${{ always() && contains(join(needs.*.result, ','), 'success') }} + needs: [build, vet, unit-test] + uses: ./.github/workflows/docker.yml + secrets: + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml old mode 100644 new mode 100755 index 06de89e61..f008cd46a --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -29,6 +29,13 @@ jobs: if: ${{ always() && contains(join(needs.*.result, ','), 'success') }} needs: [build, e2e, integration, unit-test, vet] uses: ./.github/workflows/publish.yml + docker: + if: ${{ always() && contains(join(needs.*.result, ','), 'success') }} + needs: [build, e2e, integration, unit-test, vet] + uses: ./.github/workflows/docker.yml + secrets: + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} docs: if: ${{ always() && contains(join(needs.*.result, ','), 'success') }} needs: [build, e2e, integration, unit-test, vet]