Chapter 4. Artifact Hygiene at Home
1) Tagging: predictable, unique, effortless
Use a semver + git metadata tag on every build. Example:
<app>:<semver>-<YYYYMMDD>-<shortsha> # e.g., app:0.1.0-20251009-a1b2c3d
Makefile snippet
APP_NAME ?= app
IMAGE_REG ?=
IMAGE_REPO ?= $(IMAGE_REG)ship-securely/$(APP_NAME)
DATE := $(shell date +%Y%m%d)
SHA := $(shell git rev-parse --short HEAD 2>/dev/null || echo "dev")
TAG ?= 0.1.0-$(DATE)-$(SHA)
IMAGE := $(IMAGE_REPO):$(TAG)
IMAGE_LATEST := $(IMAGE_REPO):latest
print-image:
@echo "IMAGE=$(IMAGE)"
2) Immutability: don’t mutate tags
- Treat every content tag (
:0.1.0-…) as immutable. - You may move
:latestfor convenience, but never overwrite a content tag.
Makefile helper
tag-latest:
@docker tag $(IMAGE) $(IMAGE_LATEST)
3) Retention: keep what matters, prune the rest
- Keep last N content tags locally (e.g., 20).
- Keep all evidence (
./artifacts/*) for releases. - Periodically prune unused images:
docker image prune -f
Optionally log built images:
log-image:
@mkdir -p artifacts
@echo "$(IMAGE)" >> artifacts/images-$(DATE).txt
4) Registry or no registry?
Option A — No registry (simplest, default)
Use Minikube’s in-node cache:
mk-image-load:
minikube -p $(PROFILE) image load $(IMAGE)
Pros: fewer moving parts, faster in class. Cons: not shareable with teammates out of the box.
Option B — Local registry (registry:2)
Spin up a registry on localhost:5000 to push/pull locally.
docker compose file (optional): infra/docker/registry.yaml
version: "3.9"
services:
registry:
image: registry:2
ports: [ "5000:5000" ]
restart: unless-stopped
environment:
REGISTRY_STORAGE_DELETE_ENABLED: "true"
Makefile helpers
reg-up:
docker compose -f infra/docker/registry.yaml up -d
reg-down:
docker compose -f infra/docker/registry.yaml down
push:
@docker tag $(IMAGE) localhost:5000/$(APP_NAME):$(TAG)
@docker push localhost:5000/$(APP_NAME):$(TAG)
If you use a local registry with Minikube, tell K8s to pull from
localhost:5000by either (a) enabling the Docker driver so node can reach host, or (b) port-forwarding/hostAliases. For this book, Option A is simpler.
5) Store SBOMs & signature proofs under ./artifacts
You already generate:
artifacts/sbom.json(Syft)artifacts/cosign-verify.txt(cosign verify)artifacts/trivy-image.json(Trivy)
Keep them per build (zip with date) using your evidence target.
Checklist
- Content tag format selected and implemented in Makefile
- Immutable content tags (no overwrites)
- Decision made: minikube image load (default) vs local registry
- SBOM & signature evidence present under
./artifacts/