122 lines
5.1 KiB
Text
122 lines
5.1 KiB
Text
# syntax=docker/dockerfile:1.6
|
|
#
|
|
# Dockerfile.mc-ai — Linux container for mc-ai autoplay batches on apricot.
|
|
#
|
|
# Purpose: provide a single docker-cgroup boundary around the entire autoplay
|
|
# batch (build artifact + Godot processes) so a runaway sim cannot wedge the
|
|
# host the way bare `systemd-run --user` did. Mirrors the freeze-proofing
|
|
# pattern from Dockerfile.godot/godot-docker.sh, applied to the simulator
|
|
# half of the loop.
|
|
#
|
|
# Build context = the per-run scratch worktree (the same path apricot-run.sh
|
|
# launcher.sh creates via `git worktree add`). The image bakes the
|
|
# libmagic_civ_physics_gdext.so artifact for that exact SHA so cargo never
|
|
# runs at container start. Tag the image with the short SHA:
|
|
#
|
|
# docker build --tag mc-ai:$(git rev-parse --short HEAD) \
|
|
# --file tools/docker/Dockerfile.mc-ai $SCRATCH
|
|
#
|
|
# At runtime, scripts/mc-ai-docker.sh bind-mounts the worktree at /work and
|
|
# the entrypoint installs the baked .so into the worktree's addons dir before
|
|
# exec'ing the requested command.
|
|
#
|
|
# Base-image digest refresh:
|
|
# docker buildx imagetools inspect debian:bookworm-slim # → index digest
|
|
# docker buildx imagetools inspect rust:1-bookworm # → index digest
|
|
#
|
|
# ── stage 1: build the GDExtension shared object ────────────────────────────
|
|
FROM rust@sha256:6258907abe69656e41cd992e0b705cdcfabcbbe3db374f92ed2d47121282d4a1 AS builder
|
|
|
|
# build-essential + pkg-config + libssl-dev cover the native deps wgpu /
|
|
# tokio / openssl-sys transitively pull in. Keep this list short — the
|
|
# simulator workspace is intentionally light on C deps.
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends \
|
|
build-essential \
|
|
pkg-config \
|
|
libssl-dev \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Copy only what build-gdext.sh actually needs to keep cargo's input set
|
|
# minimal — full game/ tree (.tscn/.gd/.import etc.) is not part of the
|
|
# Rust build.
|
|
WORKDIR /build
|
|
COPY src/simulator ./src/simulator
|
|
|
|
# BuildKit cache mounts persist cargo registry + target dir across image
|
|
# rebuilds, so the second build of any SHA reuses everything that didn't
|
|
# change. CARGO_TARGET_DIR is set so build-gdext.sh's find_build helper
|
|
# locates the .so under /build-target/.
|
|
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=locked \
|
|
--mount=type=cache,target=/usr/local/cargo/git,sharing=locked \
|
|
--mount=type=cache,target=/build-target,sharing=locked \
|
|
set -eux; \
|
|
cd src/simulator; \
|
|
CARGO_TARGET_DIR=/build-target \
|
|
bash build-gdext.sh x86_64-unknown-linux-gnu; \
|
|
mkdir -p /out; \
|
|
cp /build-target/x86_64-unknown-linux-gnu/release/libmagic_civ_physics_gdext.so \
|
|
/out/libmagic_civ_physics.x86_64.so
|
|
|
|
# ── stage 2: runtime — Godot headless + the baked .so ───────────────────────
|
|
FROM debian@sha256:0104b334637a5f19aa9c983a91b54c89887c0984081f2068983107a6f6c21eeb AS runtime
|
|
|
|
ARG GODOT_VERSION=4.6.2
|
|
ARG GODOT_RELEASE=stable
|
|
|
|
ENV DEBIAN_FRONTEND=noninteractive
|
|
|
|
# Mirrors Dockerfile.godot's runtime deps. coreutils + util-linux cover the
|
|
# nice/ionice calls autoplay-batch.sh wraps each seed in (its systemd-run
|
|
# branch is auto-skipped inside the container since systemd-run is absent).
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends \
|
|
ca-certificates \
|
|
wget \
|
|
unzip \
|
|
coreutils \
|
|
util-linux \
|
|
libgl1-mesa-glx \
|
|
libfontconfig1 \
|
|
libxi6 \
|
|
libxrandr2 \
|
|
libxcursor1 \
|
|
libxinerama1 \
|
|
libasound2 \
|
|
libpulse0 \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
RUN set -eux; \
|
|
arch="$(dpkg --print-architecture)"; \
|
|
case "$arch" in \
|
|
arm64) godot_arch="linux.arm64" ;; \
|
|
amd64) godot_arch="linux.x86_64" ;; \
|
|
*) echo "unsupported arch: $arch" >&2; exit 1 ;; \
|
|
esac; \
|
|
url="https://github.com/godotengine/godot-builds/releases/download/${GODOT_VERSION}-${GODOT_RELEASE}/Godot_v${GODOT_VERSION}-${GODOT_RELEASE}_${godot_arch}.zip"; \
|
|
wget -q -O /tmp/godot.zip "$url"; \
|
|
unzip -q /tmp/godot.zip -d /opt; \
|
|
mv /opt/Godot_v${GODOT_VERSION}-${GODOT_RELEASE}_${godot_arch} /usr/local/bin/godot; \
|
|
chmod +x /usr/local/bin/godot; \
|
|
rm /tmp/godot.zip
|
|
|
|
# uid/gid 1000 matches the apricot operator account so bind-mount writes
|
|
# (RESULTS dir, addons/ install) land with host-friendly ownership.
|
|
RUN useradd --create-home --uid 1000 --shell /bin/bash mcai
|
|
|
|
# Baked simulator artifact — entrypoint installs it into the bind-mounted
|
|
# worktree at container start.
|
|
COPY --from=builder /out/libmagic_civ_physics.x86_64.so /opt/mc-ai/libmagic_civ_physics.x86_64.so
|
|
RUN chown -R mcai:mcai /opt/mc-ai
|
|
|
|
# Entrypoint copies the baked .so into the worktree's addons dir so Godot
|
|
# loads the image's exact SHA-matched artifact (overriding anything the
|
|
# bind-mounted worktree might carry). Exec form preserves signal handling.
|
|
COPY tools/docker/mc-ai-entrypoint.sh /usr/local/bin/mc-ai-entrypoint
|
|
RUN chmod 0755 /usr/local/bin/mc-ai-entrypoint
|
|
|
|
USER mcai
|
|
WORKDIR /work
|
|
|
|
ENTRYPOINT ["/usr/local/bin/mc-ai-entrypoint"]
|
|
CMD ["godot", "--version"]
|