build: pin and verify image inputs
This commit is contained in:
@@ -119,7 +119,13 @@ def docker_cp(src: str, dest: str) -> None:
|
||||
f"{(result.stderr or '').strip() or '<no stderr>'}")
|
||||
|
||||
|
||||
def build_image(ref: str, context: str, *, dockerfile: str = "") -> None:
|
||||
def build_image(
|
||||
ref: str,
|
||||
context: str,
|
||||
*,
|
||||
dockerfile: str = "",
|
||||
build_args: dict[str, str] | None = None,
|
||||
) -> None:
|
||||
"""Invokes `docker build` every call. Layer cache makes no-change
|
||||
rebuilds cheap; running every time means Dockerfile edits land
|
||||
without manual `docker rmi`.
|
||||
@@ -139,10 +145,26 @@ def build_image(ref: str, context: str, *, dockerfile: str = "") -> None:
|
||||
args.append("--no-cache")
|
||||
if dockerfile:
|
||||
args.extend(["-f", dockerfile])
|
||||
for name, value in (build_args or {}).items():
|
||||
args.extend(["--build-arg", f"{name}={value}"])
|
||||
args.append(context)
|
||||
subprocess.run(args, check=True)
|
||||
|
||||
|
||||
def image_id(ref: str) -> str:
|
||||
"""Return the exact content-addressed ID for a local image.
|
||||
|
||||
This is used when one locally built image is another Dockerfile's base:
|
||||
passing the ID prevents a mutable tag from being resolved between builds.
|
||||
"""
|
||||
result = run_docker(["docker", "image", "inspect", "--format", "{{.Id}}", ref])
|
||||
image = result.stdout.strip()
|
||||
if result.returncode != 0 or not image.startswith("sha256:"):
|
||||
detail = (result.stderr or result.stdout or "").strip()
|
||||
die(f"could not resolve exact image ID for {ref!r}: {detail or '<no detail>'}")
|
||||
return image
|
||||
|
||||
|
||||
def verify_agent_image(image: str, argv: tuple[str, ...]) -> None:
|
||||
"""Run `argv` inside a throwaway container of a freshly built agent
|
||||
image and die loudly if it fails, instead of shipping an image
|
||||
|
||||
@@ -49,9 +49,9 @@ _ARTIFACT_FORMAT = "1"
|
||||
# from its own generic package; the Dockerfiles baked into each differ (only the
|
||||
# orchestrator rootfs carries buildah), so the versions are hashed separately.
|
||||
ROLES = ("orchestrator", "gateway")
|
||||
_DOCKERFILES = {
|
||||
_BUILD_INPUTS = {
|
||||
"orchestrator": ("Dockerfile.orchestrator", "Dockerfile.orchestrator.fc"),
|
||||
"gateway": ("Dockerfile.gateway",),
|
||||
"gateway": ("Dockerfile.gateway", "requirements.gateway.lock"),
|
||||
}
|
||||
|
||||
_DEFAULT_BASE = "https://gitea.dideric.is"
|
||||
@@ -101,7 +101,7 @@ def infra_artifact_version(
|
||||
h.update(str(path.relative_to(repo_root)).encode())
|
||||
h.update(b"\0")
|
||||
h.update(path.read_bytes())
|
||||
for name in _DOCKERFILES[role]:
|
||||
for name in _BUILD_INPUTS[role]:
|
||||
h.update(name.encode())
|
||||
h.update(b"\0")
|
||||
h.update((repo_root / name).read_bytes())
|
||||
|
||||
@@ -133,10 +133,15 @@ def build_infra_images_with_docker() -> None:
|
||||
root = str(resources.build_root())
|
||||
docker_mod.build_image(
|
||||
_ORCHESTRATOR_IMAGE, root, dockerfile="Dockerfile.orchestrator")
|
||||
orchestrator_id = docker_mod.image_id(_ORCHESTRATOR_IMAGE)
|
||||
docker_mod.build_image(
|
||||
_GATEWAY_IMAGE, root, dockerfile="Dockerfile.gateway")
|
||||
docker_mod.build_image(
|
||||
_ORCHESTRATOR_FC_IMAGE, root, dockerfile="Dockerfile.orchestrator.fc")
|
||||
_ORCHESTRATOR_FC_IMAGE,
|
||||
root,
|
||||
dockerfile="Dockerfile.orchestrator.fc",
|
||||
build_args={"ORCHESTRATOR_BASE_IMAGE": orchestrator_id},
|
||||
)
|
||||
|
||||
|
||||
def build_rootfs_dir(role: str) -> Path:
|
||||
|
||||
Reference in New Issue
Block a user