Skip to content

Blueprint for a Local GitLab + Kubernetes CI/CD Stack

A reproducible, fully local GitLab + Kubernetes CI/CD stack — one repo, one machine, agent-driven. A 5-node kind cluster hosts a self-managed GitLab (chart-bundled Envoy Gateway terminates *.local.example.net), a registered Runner, and OpenBao for secret injection. Push a commit, get a running workload on https://<app>.apps.local.example.net.

What you'll build, and how long it takes

The blueprint delivers three layers, each with its own runbook and idempotent re-run contract:

Phase What lands on your machine Wall-clock
Phase 1 — Cluster 5-node kind cluster (1 control-plane + 4 workers), local-path StorageClass, host-side port mappings 127.0.0.1:{80,443,22} → {30080,30443,30022} ~2 minutes
Phase 2 — Stack Gateway API CRDs, self-signed wildcard CA + certs (*.local.example.net infra tier + *.apps.local.example.net apps tier), bootstrap-OpenBao, GitLab CE 19.x with bundled OpenBao subchart, in-cluster registry, GitLab Runner (k8s executor), chart-bundled Postgres/Redis/MinIO ~10–15 minutes (mostly GitLab's first boot)
Phase 3 — App blueprint-apps GitLab group + 4 projects (shared-code, guestbook, redis, redis-slave), per-project .gitlab-ci.yml rendered from apps/shared-code/templates/, smoke pipelines green ~3 minutes

End state: https://gitlab.local.example.net for the GitLab UI, https://guestbook.apps.local.example.net for the demo workload — both behind the same Envoy Gateway data plane, both served from one NodePort Service (30443) on the kind control-plane.

Designed to be run by an AI coding agent

The repo ships four Agent Skills that walk an agent (GitHub Copilot, Cursor, Claude Code, Codex — anything that follows the agentskills.io standard) through each phase end-to-end, plus the per-app publishing flow:

Each skill has the same shape: Pre-flight → Install → Smoke tests → Iteration loop. The smoke tests are the contract — the skill doesn't declare a phase "done" until they pass.

A typical agent session looks like:

Open k8s-cicd-gitlab/ in your agent. The skills auto-load as background context. Then prompt:

Run provision-phase-1 end-to-end and report when the 5 nodes are Ready. Then run provision-phase-2 and report when GitLab is reachable at https://gitlab.local.example.net. Then run provision-phase-3 and report when the four GitLab projects exist and the smoke pipelines are green. Then run provision-new-3p-app for headlamp. Don't run anything that needs sudo — print the command and ask me to run it. Follow each skill's Smoke tests section before declaring green.

If your agent doesn't auto-discover skills, paste the four SKILL.md files into the first message — they're self-contained.

How to use this site

The site mirrors docs/ in the repo and is the rendered MkDocs Material view. The recommended reading order is:

  1. Prerequisites — what's installed on the host (kind, kubectl, helm, tofu, uv, docker/podman, ~10 GB RAM).
  2. Phase 1 — cluster bring-up via OpenTofu, with the node-shapes + port-mappings + storage contract.
  3. Phase 2 — bootstrap package architecture, the install pipeline (12+ steps, all idempotent), secrets inventory.
  4. Phase 3 — GitLab-side provisioning, the per-project CI template, the apps-tier routing architecture (*.apps.<domain>).
  5. Accessing apps — the *.apps.<domain> listener on the chart-managed gitlab-gw Gateway; how the apps-wildcard cert + cross-namespace redis wiring work.
  6. Provisioning 3rd-party apps — how to add an upstream-helm-chart app (headlamp, kyverno, anything vendored) as a GitOps-managed GitLab project. Covers blueprint-new-app (scaffold the source-of-truth files) + blueprint-publish-app (sync to GitLab, render CI, set variables, commit + push, trigger pipeline).
  7. Secrets — where each secret comes from, who owns it, how it survives a tofu destroy.
  8. Smart docs / C4 architecture — system context, container, component, and 5 deep dives on the bootstrap package, the Phase-2 pipeline, the Phase-3 pipeline, the OpenTofu IaC layer, and the sample apps.

If anything in this site disagrees with ../README.md or ../AGENTS.md, the source wins — the site is generated, the source is canonical.

What you get at the end

Cluster infrastructure — 5-node kind cluster + local-path StorageClass

Hold "Alt" / "Option" to enable pan & zoom
flowchart LR
  CP[Control-plane] --> N1[Worker 1]
  CP --> N2[Worker 2]
  CP --> N3[Worker 3]
  CP --> N4[Runner worker]
  SC[local-path SC]

Application pods (Phase 2) — CloudNativePG, Redis, MinIO, bootstrap-OpenBao

Hold "Alt" / "Option" to enable pan & zoom
flowchart LR
  PG[CloudNativePG] --> R[Redis]
  R --> M[MinIO]
  M --> OB[OpenBao]

GitLab stack — Envoy Gateway + GitLab CE 19.x + chart-bundled OpenBao + Runner + 4 projects + registry

Hold "Alt" / "Option" to enable pan & zoom
flowchart LR
  EG[Envoy Gateway] --> GL[GitLab CE]
  GL --> CBO[Chart-bundled OpenBao]
  GL --> R[Runner]
  GL --> P[4 projects<br/>blueprint-apps/*]
  GL --> Reg[In-cluster registry]

Sample workload — guestbook Pod reachable as https://guestbook.apps.local.example.net

Apps don't share a listener with the GitLab-infra FQDNs — they ride a separate chart-managed apps-https listener on the same Gateway (gitlab-gw), backed by its own wildcard cert (*.apps.<domain>). The Redis Services live in different namespaces (redis-demo, redis-slave-demo); the chart's env-var-driven REDIS_MASTER_HOST / REDIS_REPLICA_HOST config wires the cross-namespace connection declaratively. See Accessing apps for the full two-listener / two-cert / cross-ns design.

Hold "Alt" / "Option" to enable pan & zoom
flowchart LR
  Reg[Registry<br/>guestbook image] --> Pod[guestbook Pod]
  Pod -->|apps-https listener<br/>+ HTTPRoute| URL[https://guestbook.apps.local.example.net]
  Pod -->|REDIS_MASTER_HOST env| RM[redis-master.redis-demo]
  Pod -->|REDIS_REPLICA_HOST env| RR[redis-replica.redis-slave-demo]

Out-of-cluster — browser hits two wildcard tiers; git push triggers Runner pipelines

Hold "Alt" / "Option" to enable pan & zoom
flowchart LR
  B[Browser] -->|HTTPS infra| Infra[*.<br/>local.example.net]
  B -->|HTTPS apps| Apps[*.<br/>apps.local.example.net]
  Push[git push] -->|webhook| R[Runner]
  R -->|helm lint → kaniko → helm upgrade| Deploy[Deploy]

What this site contains

This site is the rendered MkDocs view of the docs/ directory in this repo. It contains:

  • RunbooksPrerequisites, Phase 1, Phase 2, Phase 3, Accessing apps, Secrets. These are the per-phase how-tos for both humans and AI agents.
  • Smart docs (C4 architecture)Project Overview, Architecture Overview, Workflow Overview, plus five Deep dives covering the bootstrap package, the Phase-2 pipeline, the Phase-3 pipeline, the OpenTofu IaC layer, and the sample apps.

The canonical sources live in this repo:

  • README.md — top-level quick start, post-install cheat-sheet, iteration loop.
  • AGENTS.md — hard rules + layout map for AI agents and humans.
  • .agents/skills/provision-phase-{1,2,3}/SKILL.md — the per-phase iteration loop runbooks.

If anything in this site disagrees with ../README.md or ../AGENTS.md, the source wins — the site is generated, the source is canonical.