# Image Build & Push to Scaleway Registry ## Goal Build runner profile container images from `ansible/files/dockerfiles/linux-runners/`, scan for vulnerabilities, and push to the Scaleway container registry (`a13labs` namespace). ## Decisions | Decision | Choice | Rationale | |---|---|---| | Registry namespace | `a13labs` (existing) | Clean project branding | | Tagging strategy | Git tag + SHA + latest | Full traceability and history | | Initial scope | Runner profiles only (7 → 4) | Consolidated image-build, infra-tools, security-scan into cicd-base | | Trivy scan severity | Warn only | Review manually, never block builds | | Update consumers | Not this iteration | Build+push pipeline first, consumers later | | Path filtering | In-workflow check | Gitea paths filter unreliable with tags | | PR scanning | Disabled | Keep PR builds fast | ## Image Inventory & Dependencies ``` docker.io/gitea/runner:latest ↓ gitea-runner-base (build stage 1, pushed first) ↓ ┌─────────────────────────────┐ │ cicd-base, cpp-build, go-build │ (build stage 2, all parallel) └─────────────────────────────┘ ``` | Image | Dockerfile | Base | |---|---|---| | gitea-runner-base | `Dockerfile.gitea-runner-base` | `docker.io/gitea/runner:latest` | | cicd-base | `Dockerfile.cicd-base` | `local/gitea-runner-base:latest` | | cpp-build | `Dockerfile.cpp-build` | `local/gitea-runner-base:latest` | | go-build | `Dockerfile.go-build` | `local/gitea-runner-base:latest` | > **Note:** `image-build`, `infra-tools`, and `security-scan` runners were decommissioned and their tooling consolidated into `cicd-base`. All workflows now run on `cicd-base` or the language-specific runners (`cpp-build`, `go-build`). ## Registry Naming Images pushed as `fr-par-2.registry.scaleway.com/a13labs/{image-name}:{tag}` ## Phases ### Phase A: Prepare CI Runner (DONE) **Step 1 — Add build tools to `Dockerfile.cicd-base`** DONE. Added the following packages to the existing cicd-base image: - Build packages: `buildah`, `fuse-overlayfs`, `podman`, `shadow-uidmap`, `skopeo`, `slirp4netns`, `iptables` (from `Dockerfile.image-build`) - Storage config: `storage.conf` (vfs driver) and `containers.conf` (from `Dockerfile.image-build`) - Trivy binary download (from `Dockerfile.security-scan`, v0.72.0) **Step 2 — Register updated cicd-base on Gitea runner** (DONE) cicd-base image rebuilt on `ci-01` and Gitea runner container registration updated. ### Phase B: Scaleway IaC Changes (DONE - code changes, manual apply needed) **Step 3 — Add CI IAM app** (`terraform/iac/scaleway/iam.tf`) - DONE - New `scaleway_iam_application` "ci_app" with `RegistryFullAccess` permission set - New `scaleway_iam_policy` "registry_full_access" granting ci_app registry access - New `scaleway_iam_api_key` "ci_app_api" for ci_app credentials **Step 4 — Add registry outputs** (`terraform/iac/scaleway/outputs.tf`) - DONE - `registry_endpoint` — from `scaleway_registry_namespace.a13labs.endpoint` - `ci_app_api_access_key`, `ci_app_api_secret_key` — sensitive **Step 5 — No `sectool.env` changes needed** - DONE The CI app resources are hardcoded, no TF_VAR mappings required. **Step 6 — Apply and extract secrets** (MANUAL) - Add `SCALEWAY_CI_ACCESS_KEY` and `SCALEWAY_CI_SECRET_KEY` to Bitwarden - Run `sectool exec tofu apply` in `terraform/iac/scaleway/` - Add `SCALEWAY_REGISTRY_ENDPOINT`, `SCALEWAY_CI_ACCESS_KEY`, `SCALEWAY_CI_SECRET_KEY` as Gitea repo secrets ### Phase C: Gitea Actions & Workflow (DONE) **Step 7 — Create `.gitea/actions/setup-scaleway-registry/action.yml`** - DONE Composite action that: - Creates `~/.docker/config.json` with Scaleway registry auth - Configures buildah storage and network settings for rootless operation - Inputs: `registry-endpoint`, `registry-username`, `registry-password` **Step 8 — Create `.gitea/workflows/build-and-push-images.yml`** - DONE Jobs: - `check-paths`: Determines if dockerfiles changed (handles push, PR, tag events) - `auth`: Sets up registry authentication (gates on path check) - `build-base`: Builds and pushes `gitea-runner-base` - `build-images`: Matrix build of 6 dependent images Tagging strategy: - Push to main: `{sha}` + `latest` - Push tag (v*): `{tag}` + `{sha}` + `latest` - PR: `pr-{number}` (no scanning) **Step 9 — Create `.gitea/workflows/weekly-image-rebuild.yml`** - DONE Scheduled weekly (`cron: "0 6 * * 1"` — Monday 6AM): - Same build jobs but only tag `:latest` - Uses `--pull-always` to force rebuild against updated upstream base images - Full Trivy scan (warn only, artifacts) ## Build Order & Dependency Resolution Each dependent Dockerfile says `FROM local/gitea-runner-base:latest`. The workflow replaces `local/gitea-runner-base` with the full registry URL in a temp copy before building, so buildah pulls the freshly pushed base image. ## Manual Setup Checklist Before the workflows can run successfully, complete these steps: - [ ] Push code changes to repo (note: `registry.tf` changed `is_public` from `false` to `true` on `a13labs` namespace) - [x] SSH to `ci-01`, rebuild `cicd-base` image locally, update Gitea runner container — DONE - [ ] Add `SCALEWAY_CI_ACCESS_KEY` and `SCALEWAY_CI_SECRET_KEY` to Bitwarden (leave blank initially, they'll be populated after IaC apply) - [ ] Apply Scaleway IaC: `sectool exec tofu apply` in `terraform/iac/scaleway/` - [ ] From IaC outputs, extract `registry_endpoint`, `ci_app_api_access_key`, `ci_app_api_secret_key` - [ ] Add as Gitea repo secrets: `SCALEWAY_REGISTRY_ENDPOINT`, `SCALEWAY_CI_ACCESS_KEY`, `SCALEWAY_CI_SECRET_KEY` - [ ] Push a test commit touching `ansible/files/dockerfiles/linux-runners/` to trigger workflow - [ ] Verify workflow runs and images appear in Scaleway registry ## Gitea Secrets Required | Secret | Source | Used by | |---|---|---| | `SCALEWAY_REGISTRY_ENDPOINT` | IaC output `registry_endpoint` | build-and-push, weekly-rebuild | | `SCALEWAY_CI_ACCESS_KEY` | IaC output `ci_app_api_access_key` | build-and-push, weekly-rebuild | | `SCALEWAY_CI_SECRET_KEY` | IaC output `ci_app_api_secret_key` | build-and-push, weekly-rebuild | ## File Summary | Action | File | Status | |---|---|---| | Modify | `ansible/files/dockerfiles/linux-runners/Dockerfile.cicd-base` | DONE | | Modify | `terraform/iac/scaleway/iam.tf` | DONE | | Modify | `terraform/iac/scaleway/outputs.tf` | DONE | | Modify | `terraform/iac/scaleway/sectool.env` | DONE | | Create | `.gitea/actions/setup-scaleway-registry/action.yml` | DONE | | Create | `.gitea/workflows/build-and-push-images.yml` | DONE | | Create | `.gitea/workflows/weekly-image-rebuild.yml` | DONE | ## Post-Iteration (NOT now) - Update runner Dockerfiles to use registry base URLs - Update Ansible playbooks to `pull` from registry instead of `build` - Add PR close job to clean up `pr-{number}` tags from registry - Expand to AI service Dockerfiles (comfyui, ollama, llamacpp variants) ## Consolidation `image-build`, `infra-tools`, and `security-scan` runner profiles have been decommissioned. Their tooling was already absorbed into `cicd-base`: - **image-build** tools (buildah, podman, storage config) → merged into `Dockerfile.cicd-base` - **security-scan** tools (trivy) → merged into `Dockerfile.cicd-base` - **infra-tools** tools (ansible, pip packages) → installed at workflow runtime via `requirements/ansible.txt` Unused Dockerfiles removed: `Dockerfile.image-build`, `Dockerfile.infra-tools`, `Dockerfile.security-scan`