Files
CosmicClash/Dockerfile
T
Josh Creek d40344a2c0 fix(deploy): ship runnable control-plane and matcher workloads
The Kubernetes base deployed a control-plane image the Dockerfile never
built -- cmd/control-plane was absent from the Go build stage and no
target existed -- while the Dockerfile built a matcher image no manifest
ever deployed. Applying the checked-in base therefore could not produce
the advertised topology: one required workload had no repository-defined
artifact, and nothing consumed queued tickets. Tickets could be created
but never became proposals.

Add the production control-plane build and image target, explicitly not
the testkit-api target, which injects a fake login accepting any ticket.
Add casual and ranked matcher Deployments as separate workloads: they
have different match sizes, and separating them keeps a ranked backlog
from delaying casual formation. One replica each -- CreateProposal's
SKIP LOCKED fences make more replicas safe, but they would halve the
candidate pool each worker sees per poll and worsen formation for no
throughput gain at this scale. Their PDB uses maxUnavailable, since
minAvailable against a single replica blocks node drains outright.

Also fix both blocked traffic directions. No ingress policy admitted
UDP/7777 to game-server pods, so an allocated server was unreachable
from the internet under the namespace-wide default deny. And
control-plane ingress admitted only edge-gateway pods, so roster fetch,
registration, connection receipts, shutdown and result submission from
game servers were dropped even inside the cluster, despite their egress
being permitted. The default deny stays.

Manifest tests now assert every required role is deployed, both
playlists are scheduled, every referenced image maps to a real
Dockerfile target, and both traffic directions are permitted. Each was
verified to fail against the defect it covers. The control-plane image
was built and run to confirm the target works.
2026-09-05 10:52:52 +01:00

119 lines
6.6 KiB
Docker

# Local-only dedicated-server build and verification image. Pin the Godot
# release family used by project.godot; no image is pushed by this repository.
# barichello/godot-ci:4.7.1 (linux/amd64), resolved 2026-08-29.
FROM --platform=linux/amd64 barichello/godot-ci@sha256:622e5ca81b54cd8038ecf7de5d157b47efc800d7cf635af2eec18a6aee4bab7e AS project-imported
WORKDIR /workspace
# The pinned headless Godot image already runs imports without fontconfig.
# Do not refresh its old Ubuntu archive here: its historical keyring rejects
# current Noble signatures, while this source-only import stage needs no OS
# packages at all.
COPY Game /workspace/Game
# `--import` starts the editor, waits for resource import to finish, then
# exits. Do not combine it with `--quit`, which ends the editor after one
# iteration and can interrupt generation of `.godot/imported` resources.
RUN godot --headless --path Game --import \
&& test -f Game/.godot/imported/nebula_station.glb-fa9a6dd87ae3789d04205b52215e2e76.scn \
&& test -f Game/.godot/imported/nebula_debris.glb-39af77a17c0998b5b73172577d906cb9.scn \
&& test -f Game/.godot/imported/nebula_planet.glb-2431590907ff85cf1057e7d6ad614ed7.scn
# Test the source client from an untouched, fully imported project. The
# dedicated-server export below rewrites the main scene and must not be used
# to run client integration tests.
FROM project-imported AS enet-test
COPY scripts/verify_enet_integration.sh /workspace/scripts/verify_enet_integration.sh
# Godot dedicated exports disallow command-line scene overrides. Bake the
# server scene into this export (the interactive project's source stays
# unchanged), then generate the global-script/autoload metadata it needs.
FROM project-imported AS exporter
RUN sed -i 's|^run/main_scene=.*$|run/main_scene="res://scenes/server_boot.tscn"|' Game/project.godot \
&& mkdir -p /opt/cosmic-clash \
&& godot --headless --path Game --export-release "Linux Dedicated Server" /opt/cosmic-clash/CosmicClashServer.x86_64
# ubuntu:noble linux/amd64 manifest, resolved 2026-09-03. The prior pin
# carried an obsolete archive keyring and rejected current Noble signatures
# during apt-get update. This remains a digest pin; package verification is
# deliberately not bypassed.
FROM --platform=linux/amd64 ubuntu@sha256:1e0a86e57d247923571b75e0aaf48a1449cf8c543d51fb3e07a4a7d7bfa79316 AS server
RUN apt-get update && apt-get install -y --no-install-recommends libfontconfig1 libgl1 libstdc++6 && rm -rf /var/lib/apt/lists/*
COPY --from=exporter /opt/cosmic-clash/ /opt/cosmic-clash/
COPY deploy/cosmic-clash-server /opt/cosmic-clash/cosmic-clash-server
RUN chmod 0755 /opt/cosmic-clash/cosmic-clash-server
WORKDIR /opt/cosmic-clash
EXPOSE 7777/udp
ENTRYPOINT ["/opt/cosmic-clash/cosmic-clash-server"]
# Test-only target: runs the source client harness against the exported server.
FROM exporter AS smoke-client
WORKDIR /workspace
ENTRYPOINT ["godot", "--headless", "--path", "Game", "res://tests/export_server_smoke.tscn", "--"]
# Builds the process supervisor (server/supervisor, multiplayer-next.md task
# 8.27/8.28) that wraps the Agones-allocated dedicated server as PID 1.
# golang:1.23-alpine (matches server/go.mod's `go 1.23`), resolved 2026-09-01.
FROM --platform=linux/amd64 golang@sha256:383395b794dffa5b53012a212365d40c8e37109a626ca30d6151c8348d380b5f AS supervisor-build
WORKDIR /workspace/server
COPY server/go.mod server/go.sum ./
RUN go mod download
COPY server/ ./
RUN CGO_ENABLED=0 go build -o /opt/cosmic-clash/game-server-supervisor ./cmd/game-server-supervisor
RUN CGO_ENABLED=0 go build -o /opt/cosmic-clash/control-plane ./cmd/control-plane
RUN CGO_ENABLED=0 go build -o /opt/cosmic-clash/testkit-api ./cmd/testkit-api
RUN CGO_ENABLED=0 go build -o /opt/cosmic-clash/matcher ./cmd/matcher
RUN CGO_ENABLED=0 go build -o /opt/cosmic-clash/allocator ./cmd/allocator
RUN CGO_ENABLED=0 go build -o /opt/cosmic-clash/maintenance ./cmd/maintenance
# Agones-allocated fleet image: the same dedicated-server export as `server`
# (unchanged above; make verify-phase6 exercises that target exactly as
# before), wrapped by the Go supervisor as PID 1 instead of the direct
# launcher script -- required for process-ready/assignment-ready Agones SDK
# calls and control-plane registration (multiplayer-next.md §8.27/§8.28).
# deploy/k8s/base/fleet.yaml invokes this target with the deployment-specific
# supervisor flags and mounts the roster/signing material required by the
# allocated startup path. Workload credentials are delivered through the
# Agones allocation annotation; a projected token volume is not required.
FROM server AS game-server
COPY --from=supervisor-build /opt/cosmic-clash/game-server-supervisor /opt/cosmic-clash/game-server-supervisor
RUN chmod 0755 /opt/cosmic-clash/game-server-supervisor
ENTRYPOINT ["/opt/cosmic-clash/game-server-supervisor"]
# The production control-plane API. deploy/k8s/base/control-plane-deployment.yaml
# has always referenced this image, but nothing built it: cmd/control-plane was
# absent from the Go build stage and no target existed, so the checked-in
# Kubernetes base could not produce its own advertised topology.
#
# This must never be substituted with the testkit-api target below, which
# injects a fake login provider that accepts any ticket string.
FROM server AS control-plane
COPY --from=supervisor-build /opt/cosmic-clash/control-plane /opt/cosmic-clash/control-plane
COPY server/migrations /opt/cosmic-clash/migrations
RUN chmod 0755 /opt/cosmic-clash/control-plane
EXPOSE 8080
ENTRYPOINT ["/opt/cosmic-clash/control-plane"]
# TEST ONLY. Supplies a fake Steam login that accepts any ticket; never deploy
# this in place of the control-plane target above.
FROM server AS testkit-api
COPY --from=supervisor-build /opt/cosmic-clash/testkit-api /opt/cosmic-clash/testkit-api
COPY server/migrations /opt/cosmic-clash/migrations
RUN chmod 0755 /opt/cosmic-clash/testkit-api
ENTRYPOINT ["/opt/cosmic-clash/testkit-api"]
FROM server AS matcher
COPY --from=supervisor-build /opt/cosmic-clash/matcher /opt/cosmic-clash/matcher
COPY server/migrations /opt/cosmic-clash/migrations
RUN chmod 0755 /opt/cosmic-clash/matcher
ENTRYPOINT ["/opt/cosmic-clash/matcher"]
FROM server AS allocator
COPY --from=supervisor-build /opt/cosmic-clash/allocator /opt/cosmic-clash/allocator
COPY server/migrations /opt/cosmic-clash/migrations
RUN chmod 0755 /opt/cosmic-clash/allocator
ENTRYPOINT ["/opt/cosmic-clash/allocator"]
FROM server AS maintenance
COPY --from=supervisor-build /opt/cosmic-clash/maintenance /opt/cosmic-clash/maintenance
COPY server/migrations /opt/cosmic-clash/migrations
RUN chmod 0755 /opt/cosmic-clash/maintenance
ENTRYPOINT ["/opt/cosmic-clash/maintenance"]