containerize · diff
git:20260915.06ec8b5 to git:20260916.50d6810
11 added, 43 removed. Audit A to A.
---
name: containerize
- description: Build a minimal non-root OCI image for a uv-managed Python app with a pinned multi-stage Dockerfile, then scan, sign, and attest it. Use when containerizing Python.
+ description: "Build Python container images; scan, sign, and verify digests and attestations with Trivy and Cosign."
license: MIT
metadata:
+ kind: task
author: Médéric HURIER (Fmind)
source: github.com/fmind/dot/tree/main/skills/containerize
created: "2026-07-04"
- updated: "2026-09-14"
+ updated: "2026-09-16"
---
- # Containerize a Python Application
+ # Containerize
- Build a reproducible uv-managed Python image locally, verify it, and publish only within the user's authorized registry scope. [cloud-run](../cloud-run/SKILL.md) deploys it, [trivy](../trivy/SKILL.md) scans it, and [cosign](../cosign/SKILL.md) owns provenance.
+ Build a minimal non-root Python image and verify its immutable digest. Select signing guidance only when publication or verification requires it.
## Workflow
- 1. **Budget and identify resources**: inspect free space on the workspace and Docker storage filesystems, the selected Docker context, `docker system df`, and `docker buildx ls`. Preserve 20 GiB free on the 100 GiB workstation, allowing for context, layers, archive export and extraction. Record task-owned names/IDs before creating resources; use a unique Compose project or resource label so concurrent work stays separate.
- 1. **Adopt the templates**: copy [Dockerfile](references/Dockerfile) and [.dockerignore](references/.dockerignore). Replace `<slug>` with the installed Python console script and verify both image digests before use.
- 1. **Build locally**: emit a Docker archive so the first build and scan require no registry mutation.
-
- ```bash
- mkdir -p tmp
- docker buildx build --output type=docker,dest=tmp/image.tar .
- ```
-
- 1. **Wire the gate** into `mise.toml`; `check:image` scans the exact archive produced by `build:image`.
-
- ```toml
- [tasks."build:image"]
- description = "Build the Python OCI image locally"
- run = ["mkdir -p tmp", "docker buildx build --output type=docker,dest=tmp/image.tar ."]
-
- [tasks."check:image"]
- description = "Scan the local OCI image"
- depends = ["build:image"]
- run = "trivy --config trivy.yaml image --skip-dirs '' --input tmp/image.tar"
- ```
-
- 1. **Exercise the container**: load it with `docker load --input tmp/image.tar`. For the Python web starter, supply required application settings through a reviewed local environment file, then run `docker run --rm -p 127.0.0.1:8080:8080 --env-file <runtime-env-file> -e HOST=0.0.0.0 -e PORT=8080 -e ENVIRONMENT=production <local-reference>` and request `/health` and `/ready`. For a CLI image, exercise its actual command and exit behavior instead of publishing a port.
- 1. **Publish when authorized**: push a reviewed tag with `docker buildx build --push --tag "$IMAGE_REPOSITORY:$TAG" --metadata-file tmp/image-metadata.json .`. Parse `containerimage.digest` from that file, require `sha256:` plus 64 lowercase hex characters, and record `$IMAGE_REPOSITORY@$DIGEST`.
- 1. **Verify the immutable result**: scan the recorded digest, generate a CycloneDX SBOM, sign it, pin the expected certificate identity and issuer during verification, and attest the SBOM per [trivy](../trivy/SKILL.md) and [cosign](../cosign/SKILL.md).
- 1. **Tear down temporary resources** on success and failure, preserving requested deliverables and useful failure evidence. Follow [resource cleanup](references/resource-cleanup.md), verify only recorded task resources disappeared, and report any retained disk footprint and reason.
+ Read only the matching guide and its required resources. Use a known guide directly when shared prerequisites are not needed.
- ## Gotchas
+ ## Task guides
- - **Lock fidelity**: `uv sync --locked` rejects a missing or stale `uv.lock`; `--frozen` skips freshness checks. The template uses `--locked` so manifest drift fails without rewriting the graph.
- - **Non-root runtime**: the template runs as numeric UID/GID 10001 and copies only the locked virtual environment from the build stage. Write temporary data outside the application directory or mount an explicit writable path.
- - **Pinned bases**: both Python and uv use multi-architecture manifest digests. Refresh versions and digests together with [upgrade-tools](../upgrade-tools/SKILL.md).
- - **Small context**: keep virtual environments, caches, logs, local databases, Git state, and plaintext environment files out through [.dockerignore](references/.dockerignore).
- - **Digests over tags**: scans, signatures, attestations, deployment, and rollback all use the same immutable digest reference.
- - **Registry writes**: pushes, signatures, and attestations require explicit authority; local build and scan do not grant it.
- - **Cache ownership**: `--rm` removes a container, not its image, exported archive or build cache. Shared builder cache has no reliable per-agent ownership; reuse it under a reviewed storage budget instead of pruning it at every task end.
+ <!-- guides:start -->
- ## Documentation
+ - [cosign](references/cosign.md): Image signatures, identity verification, and attestations.
+ - [image-build](references/image-build/GUIDE.md): Build Python container images, check runtime behavior, and clean task-owned resources.
- - [Docker multi-stage builds](https://docs.docker.com/build/building/multi-stage/) · [uv Docker guide](https://docs.astral.sh/uv/guides/integration/docker/)
- - [Resource cleanup](references/resource-cleanup.md) · [Build cache garbage collection](https://docs.docker.com/build/cache/garbage-collection/)
- - Releases: [Docker Engine](https://docs.docker.com/engine/release-notes/) · [uv changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md)
- - Companion skills: [python-stack](../python-stack/SKILL.md), [cloud-run](../cloud-run/SKILL.md), [trivy](../trivy/SKILL.md), [cosign](../cosign/SKILL.md), [github-actions](../github-actions/SKILL.md), and [secure](../secure/SKILL.md).
+ <!-- guides:end -->