# devops-base-images One-time-setup repo for mirroring minimized base images into Harbor's `base-images` project, so language builds (via `devops-lib`'s `buildDocker.groovy` fallback templates) never depend on Docker Hub at build time, and the images that actually ship are the leanest official variant available for each language. Not wired into any Jenkins pipeline — this is deliberately a manual, occasional operation (re-run when `images.txt` changes: a new language, a version bump, or picking up an upstream base-image update), using the same one-off `kubectl`-based DinD pod pattern `devops-lib`'s `build-tools.Dockerfile` bootstrap already uses, since the VM itself may not have Docker installed directly. ## One-time setup **1. Create the Harbor project** (public — these are just re-hosted public images, no confidentiality concern, and public avoids needing any pull credentials wired into every build): Harbor UI → New Project → name `base-images` → check **Public** → Create. Or via API: ``` curl -X POST -u admin:'' -H "Content-Type: application/json" \ -d '{"project_name":"base-images","metadata":{"public":"true"}}' \ "http://harbor.192.168.1.7.nip.io/api/v2.0/projects" ``` **2. Run the mirror**, via a throwaway DinD pod (same shape as the `build-tools` image bootstrap): ``` cat <<'EOF' | kubectl apply -f - apiVersion: v1 kind: ConfigMap metadata: name: base-images-mirror namespace: jenkins data: images.txt: | golang:1.22-alpine golang:1.22-alpine alpine:3.20 alpine:3.20 node:20-alpine node:20-alpine python:3.12-alpine python:3.12-alpine maven:3-eclipse-temurin-21-alpine maven:3-eclipse-temurin-21-alpine eclipse-temurin:21-jre-alpine eclipse-temurin:21-jre-alpine php:8.3-cli-alpine php:8.3-cli-alpine mirror.sh: | #!/bin/sh set -eu REGISTRY="harbor.192.168.1.7.nip.io" PROJECT="base-images" while read -r src target; do [ -z "$src" ] && continue case "$src" in \#*) continue ;; esac dest="${REGISTRY}/${PROJECT}/${target}" echo "=== ${src} -> ${dest} ===" docker pull "$src" docker tag "$src" "$dest" docker push "$dest" done < images.txt echo "=== done ===" --- apiVersion: v1 kind: Pod metadata: name: base-images-mirror namespace: jenkins spec: restartPolicy: Never containers: - name: docker image: docker:27-dind securityContext: privileged: true args: - "--insecure-registry=harbor.192.168.1.7.nip.io" env: - name: DOCKER_TLS_CERTDIR value: "" volumeMounts: - name: docker-graph-storage mountPath: /var/lib/docker - name: docker-cli image: docker:27-cli command: ["cat"] tty: true env: - name: DOCKER_HOST value: tcp://localhost:2375 volumeMounts: - name: mirror mountPath: /mirror - name: docker-config mountPath: /root/.docker readOnly: true volumes: - name: docker-graph-storage emptyDir: {} - name: mirror configMap: name: base-images-mirror defaultMode: 0755 - name: docker-config secret: secretName: harbor-robot-dockerconfig items: - key: .dockerconfigjson path: config.json EOF kubectl wait --for=condition=Ready pod/base-images-mirror -n jenkins --timeout=120s kubectl exec -n jenkins base-images-mirror -c docker-cli -- sh -c ' for i in $(seq 1 30); do docker info >/dev/null 2>&1 && break; sleep 2; done cd /mirror && sh mirror.sh ' kubectl delete pod base-images-mirror -n jenkins kubectl delete configmap base-images-mirror -n jenkins ``` **3. Verify:** ``` curl -s http://harbor.192.168.1.7.nip.io/v2/_catalog ``` Should list `base-images/golang`, `base-images/alpine`, `base-images/node`, `base-images/python`, `base-images/maven`, `base-images/eclipse-temurin`, `base-images/php`. ## Adding a new image / updating a version Add a line to `images.txt`, commit, push, then re-run step 2 above (the ConfigMap's `images.txt` needs updating to match — copy the current file content in, same as the initial setup).