initial commit: base image mirror manifest + one-off setup docs
This commit is contained in:
@@ -0,0 +1,135 @@
|
|||||||
|
# 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:'<harbor admin password>' -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).
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
# Manifest of base images mirrored into Harbor's base-images project.
|
||||||
|
# One line each: <source image on Docker Hub> <target name:tag under base-images>
|
||||||
|
#
|
||||||
|
# All chosen as the leanest official variant that still keeps a shell +
|
||||||
|
# package manager (not distroless — deliberate choice: homelab
|
||||||
|
# debuggability via kubectl exec matters more here than the last bit of
|
||||||
|
# attack-surface reduction). go/alpine were already minimal and are
|
||||||
|
# mirrored unchanged; node/python/java/php all moved from their
|
||||||
|
# Debian-slim (or, for php, full Apache+Debian) default to an Alpine
|
||||||
|
# equivalent.
|
||||||
|
#
|
||||||
|
# Re-run mirror.sh after editing this file to add a language/version or
|
||||||
|
# pick up a base image update — nothing here happens automatically.
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Reads images.txt and pulls/retags/pushes each entry into Harbor's
|
||||||
|
# base-images project. Meant to run inside a docker-capable container
|
||||||
|
# with push credentials already available (docker-cli + dind sidecar,
|
||||||
|
# harbor-robot-dockerconfig mounted at /root/.docker/config.json) — same
|
||||||
|
# pattern devops-lib's build-tools.Dockerfile bootstrap already uses, see
|
||||||
|
# README.md's one-off kubectl pod commands. Not run through any Jenkins
|
||||||
|
# pipeline — genuinely one-time/occasional, re-run by hand when
|
||||||
|
# images.txt changes.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
REGISTRY="${REGISTRY:-harbor.192.168.1.7.nip.io}"
|
||||||
|
PROJECT="${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 ==="
|
||||||
Reference in New Issue
Block a user