Files
devops-lib-gcp/resources/org/homelab/dind-pod.yaml
T
Mukul SharmaandClaude Opus 5 3e09eecbfe GKE: point the pipeline at this cluster's registry, over TLS
The GCP counterpart of devops-lib. Registered in Jenkins under the same
name, so consuming repos need no change: the two-line Jenkinsfile is
identical on both clusters, and which library it resolves to is a property
of the Jenkins running it.

Substantive changes, all consequences of GKE being a real cloud:

- Harbor speaks TLS here, so dind no longer passes --insecure-registry.
  It mounts the private CA at
  /etc/docker/certs.d/harbor.35.238.248.203.nip.io/ca.crt instead, from the
  registry-ca ConfigMap. This is not redundant with the node pool's trust:
  that covers pulls, performed by containerd on the node, while the push
  comes from dockerd in the build pod with its own trust store. Without it,
  pushes fail TLS verification while pulls of the same image succeed —
  which reads like a broken registry rather than a missing trust anchor.

- The registry hostname changes in the push target and all five fallback
  Dockerfiles. It still must be spelled identically everywhere, because
  Docker matches credentials and trust by exact hostname.

- helm_repo_url moves to cluster DNS. That clone runs in a build pod, so
  sending it out through the ingress and back would make the pipeline
  depend on Contour for pod-to-pod traffic. syncArgoApp already addressed
  ArgoCD this way and needed no change.

- build-tools.Dockerfile is removed: devops-base-images-gcp owns it now,
  next to the mirrored base images, and the pod references the result by
  tag at base-images/build-tools:1. The base-images project is public, so
  the pod can pull it before it has any credentials.

Verified: no homelab addresses remain; the pod template parses with the CA
mount, the new image and no insecure-registry flag; and every fallback
template's base image, with the default version buildDocker would pick, is
present in the mirror manifest — an unmirrored tag now fails the build
rather than silently falling back to Docker Hub.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEsTefWWifp4ikvhHF5s6N
2026-09-13 01:27:05 +05:30

120 lines
5.7 KiB
YAML

# New resource — didn't exist in the original devops-lib. Homelab's real
# pipelines built on static agents (node('slave02')) with Docker already
# available; this homelab's Jenkins uses dynamic per-build Kubernetes
# agents (agent.enabled in the jenkins chart), which don't have a Docker
# daemon by default. This pod template adds one as a sidecar container —
# the "docker" container runs privileged dind, "docker-cli" is what the
# pipeline actually execs into via container('docker-cli'), talking to
# its sibling over localhost since containers in one pod share a network
# namespace.
apiVersion: v1
kind: Pod
spec:
containers:
- name: docker
image: docker:27-dind
securityContext:
privileged: true
# No --insecure-registry, unlike the homelab: Harbor here serves a real
# certificate, issued by cert-manager from the private CA that the node
# pool was told to trust when it was created.
#
# That node trust covers image PULLS, which containerd performs on the
# node. This push is a different client — dockerd, inside this pod,
# with its own trust store and no knowledge of what the node trusts —
# so it needs the CA mounted itself. dockerd looks it up at
# /etc/docker/certs.d/<registry host>/ca.crt, and the directory name
# must be the registry hostname exactly; anything else is silently
# ignored, and the push then fails TLS verification while a pull of the
# very same image works.
#
# The registry hostname (rather than harbor-core.harbor.svc.cluster.local)
# carries over unchanged from the homelab, for a reason that still
# holds: cluster DNS resolves from this pod but not from the node's
# containerd doing the real Deployment pull, and Docker matches both
# stored credentials and trust by exact hostname — so push and pull
# have to name the registry identically.
env:
- name: DOCKER_TLS_CERTDIR
value: ""
volumeMounts:
- name: docker-graph-storage
mountPath: /var/lib/docker
- name: registry-ca
mountPath: /etc/docker/certs.d/harbor.35.238.248.203.nip.io
readOnly: true
- name: docker-cli
# Custom image, built and pushed by hand from devops-base-images-gcp
# (build-tools.Dockerfile there) — bakes in git/yq/bash/python3 with
# pip and venv/curl so nothing needs installing on every single build,
# which was slow and quietly undermined reproducibility.
#
# It lives in the base-images project rather than homelab because that
# project is public: this pod pulls the image before any credential is
# available to it.
#
# Versioned tag, never :latest — rebuilding the tools image must not
# roll out until this pin is bumped deliberately.
image: harbor.35.238.248.203.nip.io/base-images/build-tools:1
command: ["cat"]
tty: true
env:
- name: DOCKER_HOST
value: tcp://localhost:2375
# docker-config below mounts the Harbor push-auth secret
# read-only at /root/.docker (needed so `docker push` finds
# config.json without an explicit `docker login` step) — but
# modern `docker build` defaults to BuildKit/buildx, which wants
# to create its own state dir at /root/.docker/buildx and fails
# with "read-only file system" since the whole mount is
# read-only. Forcing the classic builder avoids needing to write
# there at all.
- name: DOCKER_BUILDKIT
value: "0"
# For syncArgoApp.groovy — read directly from the ESO-managed
# Secret, not a Jenkins-native credential (nothing in this
# pipeline uses Jenkins' own credential store; staying consistent
# rather than mixing the two approaches).
- name: ARGOCD_TOKEN
valueFrom:
secretKeyRef:
name: argocd-jenkins-ci-token
key: token
# Without this, every build using this pod template hard-fails
# to even start until the token secret exists — including the
# very first demo-go-app run, before the manual
# `argocd account generate-token` bootstrap step has happened.
optional: true
volumeMounts:
- name: docker-config
mountPath: /root/.docker
readOnly: true
volumes:
- name: docker-graph-storage
emptyDir: {}
- name: registry-ca
configMap:
# Published by devops-infra-argo-config-gcp (extra-manifests). The
# CA's public certificate only — its private key never leaves
# Terraform state and cert-manager, which is why this is a ConfigMap
# rather than a Secret.
name: registry-ca
- name: docker-config
secret:
secretName: harbor-robot-dockerconfig
# kubernetes.io/dockerconfigjson secrets store their data under
# the fixed key `.dockerconfigjson` (mandated, since that's what
# kubelet reads for imagePullSecrets) — without this remap, the
# mounted file at /root/.docker is literally named
# `.dockerconfigjson`, not `config.json`, which is the only
# filename the docker CLI itself ever reads for stored
# credentials. Docker found nothing there and silently pushed
# unauthenticated, which Harbor correctly rejected as
# unauthorized — confirmed the robot account/credentials
# themselves were fine the whole time by requesting a push token
# directly from Harbor's token endpoint with the same username/
# password and getting one back with push access granted.
items:
- key: .dockerconfigjson
path: config.json