-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathDockerfile.control
More file actions
66 lines (61 loc) · 3.18 KB
/
Copy pathDockerfile.control
File metadata and controls
66 lines (61 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# Wrap ANY agent image so its whole environment becomes rewindable — with zero
# changes to the agent (it calls no API, uses any language, writes any path).
#
# Build from the agentenv repo (this is the build context; no pre-built binary
# needed — stage 1 compiles the static binary):
# docker build -f Dockerfile.control --build-arg BASE=<your-agent-image> -t my-agent-rewindable .
#
# Run (args after the image are your UNCHANGED agent command):
# docker run --security-opt seccomp=unconfined my-agent-rewindable <agent command...>
# # a Kubernetes pod that allows unprivileged user namespaces needs no extra privilege
#
# Roll the whole environment back, out-of-band (does not touch the agent's code):
# docker exec <container> agentenv ctl checkout <node-id>
# docker exec <container> agentenv ctl log # find a node to roll back to
# (the agent is killed and relaunched from the restored environment)
#
# ---------------------------------------------------------------------------
# SEED_AT_BUILD: bake the managed rootfs INTO the image at build time.
#
# docker build -f Dockerfile.control --build-arg BASE=<img> \
# --build-arg SEED_AT_BUILD=1 -t my-agent-rewindable .
#
# Without it (default), the entrypoint seeds `init --from /` on FIRST run —
# correct, but on a multi-GB image that's a slow copy at every fresh start.
# With it, the seed happens once during `docker build` (cached in a layer),
# so container start is instant: the entrypoint sees an existing meta.json
# and goes straight to `supervise`.
#
# Trade-offs:
# + instant start; the slow copy is a cached build layer, not a runtime tax
# + SAFER re: Kubernetes secrets — they're mounted at RUN time, so they
# simply don't exist during build and can't be captured into snapshots
# (the runtime path needs an explicit secret-stash dance; this doesn't)
# - ~2× image size: the image keeps both its original / and the seeded copy
# under AGENTENV_ROOT (overlay layers don't dedup like reflink/hardlink)
# - captures the image's own files as-is; don't bake secrets into the BASE
# ---------------------------------------------------------------------------
ARG BASE=ubuntu:24.04
# --- stage 1: build the static, dependency-free agentenv binary ---
FROM golang:1.26 AS build
ARG GOPROXY
ENV GOPROXY=${GOPROXY:-https://proxy.golang.org,direct}
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /agentenv .
# --- stage 2: your agent image + agentenv injected around it ---
FROM ${BASE}
COPY --from=build /agentenv /usr/local/bin/agentenv
COPY scripts/agentenv-entrypoint.sh /usr/local/bin/agentenv-entrypoint
RUN chmod +x /usr/local/bin/agentenv /usr/local/bin/agentenv-entrypoint
ENV AGENTENV_ROOT=/var/lib/agentenv
# Optional build-time seed (see header). The init runs as a pure file copy +
# snapshot freeze — no namespaces/privilege needed, so it works in a plain
# `docker build`. When set, the entrypoint's `[ ! -f meta.json ]` guard is
# already satisfied, so runtime skips straight to supervise.
ARG SEED_AT_BUILD=
RUN if [ -n "$SEED_AT_BUILD" ]; then \
echo "agentenv: baking managed rootfs at build time (init --from /)"; \
agentenv init --from /; \
fi
ENTRYPOINT ["/usr/local/bin/agentenv-entrypoint"]