feat(@projects): add docker container wrapper for godot

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-05-25 14:06:52 -07:00
parent 5ef09a243c
commit 7678f4668f
2 changed files with 139 additions and 0 deletions

85
scripts/godot-docker.sh Executable file
View file

@ -0,0 +1,85 @@
#!/usr/bin/env bash
# godot-docker.sh — run Godot Linux headless inside a freeze-proof Docker container.
#
# Why: `godot --headless --import` and similar commands kernel-panicked plum
# twice and freeze apricot when run cold. Containers on macOS run inside a
# Linux VM with its own kernel, fully isolated from macOS — no chance of
# tripping the GPU/video kexts that caused the panics. Cgroup limits below
# also keep the VM from starving itself.
#
# See: ~/.claude/plans/godot-container-runner.md
#
# Usage:
# scripts/godot-docker.sh [args...] # passed straight to godot
# scripts/godot-docker.sh --version # smoke test
# scripts/godot-docker.sh --headless --import # warm the import cache
# scripts/godot-docker.sh --headless --script res://addons/gut/gut_cmdln.gd -gexit -gtest=res://engine/tests/unit/test_city_buildable_helper.gd
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
DOCKERFILE="$REPO_ROOT/tools/docker/Dockerfile.godot"
IMAGE="mc-godot:4.6.2"
VOLUME="mc-godot-cache"
WORKDIR_IN_CONTAINER="/work/src/game"
# Cgroup hard caps so the container can't starve the host VM.
# Defaults sized for Docker Desktop with ≥7 GiB allocated.
CPUS="${MC_GODOT_CPUS:-4}"
MEMORY="${MC_GODOT_MEMORY:-6g}"
PIDS_LIMIT="${MC_GODOT_PIDS:-256}"
ensure_image() {
if docker image inspect "$IMAGE" >/dev/null 2>&1; then
return 0
fi
echo "[godot-docker] image $IMAGE not found — building..." >&2
docker build \
--tag "$IMAGE" \
--file "$DOCKERFILE" \
"$REPO_ROOT/tools/docker"
}
ensure_volume() {
if docker volume inspect "$VOLUME" >/dev/null 2>&1; then
return 0
fi
echo "[godot-docker] creating named volume $VOLUME for warm import cache" >&2
docker volume create "$VOLUME" >/dev/null
}
ensure_docker_running() {
if ! docker info >/dev/null 2>&1; then
echo "ERROR: Docker daemon not reachable. Start Docker Desktop first." >&2
exit 2
fi
}
main() {
ensure_docker_running
ensure_image
ensure_volume
# Force a TTY only when stdout is a terminal; CI invocations stay non-interactive.
local tty_flag=""
if [[ -t 1 ]]; then
tty_flag="-t"
fi
docker run \
--rm \
-i $tty_flag \
--cpus "$CPUS" \
--memory "$MEMORY" \
--memory-swap "$MEMORY" \
--pids-limit "$PIDS_LIMIT" \
--volume "$REPO_ROOT:/work" \
--volume "$VOLUME:/work/src/game/.godot" \
--workdir "$WORKDIR_IN_CONTAINER" \
"$IMAGE" \
"$@"
}
main "$@"

View file

@ -0,0 +1,54 @@
# Godot 4.6.2 Linux headless — freeze-proof runtime for asset import + GUT tests.
# See ~/.claude/plans/godot-container-runner.md for why this exists.
FROM debian:bookworm-slim
ARG GODOT_VERSION=4.6.2
ARG GODOT_RELEASE=stable
# Pinned official SHA256 — update together with GODOT_VERSION.
# Compute via: sha256sum Godot_v${GODOT_VERSION}-${GODOT_RELEASE}_linux.x86_64.zip
ARG GODOT_SHA256=
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
wget \
unzip \
libgl1-mesa-glx \
libfontconfig1 \
libxi6 \
libxrandr2 \
libxcursor1 \
libxinerama1 \
libasound2 \
libpulse0 \
&& rm -rf /var/lib/apt/lists/*
# Detect arch at build time so this image works on both Apple-silicon Docker
# Desktop (linux/arm64) and amd64 hosts.
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
# Runtime user with a stable uid/gid so bind-mounted files don't get chown'd
# by container writes. Docker Desktop on macOS handles uid mapping
# transparently, so picking 1000 is fine.
RUN useradd --create-home --uid 1000 --shell /bin/bash godot
USER godot
WORKDIR /work
ENTRYPOINT ["/usr/local/bin/godot"]
CMD ["--version"]