From f92180af5e2791c7518b069a94927a46cf9884a5 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 14 Aug 2020 13:48:33 -0400 Subject: [PATCH] Add docker cross-compile for arm64 This makes use of the docker buildx to cross-compile images for amd64/arm64. It is worth noting that there are ongoing issues with the Go compiler and qemu (used by buildx/buildkit) and the solution I ended up using here was to limit the affinity to `go build`. Better solutions may be forthcoming. Refs: https://github.com/golang/go/issues/24656 https://bugs.launchpad.net/qemu/+bug/1696773 This relates to issue #11 regarding container images built for running on Raspberry Pi. --- Dockerfile | 10 +++++----- Makefile | 6 +++++- README.md | 11 +++++++++++ example.yaml | 4 ++-- internal/quake/server/server.go | 8 +++++++- 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index a9e48c0..f64f5b4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,19 +11,19 @@ COPY cmd cmd/ COPY internal internal/ COPY public public/ -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o q3 ./cmd/q3 +RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on taskset -c 1 /usr/local/go/bin/go build -a -o q3 ./cmd/q3 FROM alpine:3.12 as quake-n-bake -RUN apk add --no-cache git gcc make libc-dev sdl2-dev mesa-dev +RUN apk add --no-cache git gcc make libc-dev RUN git clone https://github.com/ioquake/ioq3 -RUN cd /ioq3 && make -RUN cp /ioq3/build/release-linux-x86_64/ioq3ded.x86_64 /usr/local/bin/ioq3ded +RUN cd /ioq3 && make BUILD_MISSIONPACK=0 BUILD_BASEGAME=0 BUILD_CLIENT=0 BUILD_SERVER=1 BUILD_GAME_SO=0 BUILD_GAME_QVM=0 BUILD_RENDERER_OPENGL2=0 +RUN cp /ioq3/build/release-linux-$(uname -m)/ioq3ded.$(uname -m) /usr/local/bin/ioq3ded FROM alpine:3.12 COPY --from=builder /workspace/q3 /usr/local/bin COPY --from=quake-n-bake /usr/local/bin/ioq3ded /usr/local/bin -COPY --from=quake-n-bake /lib/ld-musl-x86_64.so.1 /lib +COPY --from=quake-n-bake /lib/ld-musl-*.so.1 /lib ENTRYPOINT ["/usr/local/bin/q3"] diff --git a/Makefile b/Makefile index 5778a5b..cfe85d2 100644 --- a/Makefile +++ b/Makefile @@ -9,9 +9,13 @@ q3: gen gen: ## Generate and embed templates @go run tools/genstatic.go public public -VERSION ?= v1.0.2 +VERSION ?= v1.0.3 IMAGE ?= docker.io/criticalstack/quake:$(VERSION) .PHONY: build build: @docker build . --force-rm --build-arg GOPROXY --build-arg GOSUMDB -t $(IMAGE) + +.PHONY: buildx +buildx: + @docker buildx build . --platform=linux/amd64,linux/arm64 --progress=auto -t $(IMAGE) --push diff --git a/README.md b/README.md index de825cc..6e190b1 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,17 @@ The easiest way to develop quake-kube is building the binary locally with `make` $ bin/q3 server -c config.yaml --assets-dir $HOME/.q3a --agree-eula ``` +### Multi-platform images + +Container images are being cross-compiled with [Docker Buildx](https://docs.docker.com/buildx/working-with-buildx/) so it can run on hardware with different architectures and operating systems. Currently, it is building for `linux/amd64` and `linux/arm64`. While not specifically compiling to the macOS platform (`darwin/amd64`) QuakeKube should also work on macOS and maybe even Windows. This is due to the fact that they both use a linux VM to provide container support. + +Docker Buildx uses [QEMU](https://www.qemu.org/) to virtualize non-native platforms, which has unfortunately had long-running issues running the Go compiler: + +* [golang/go#24656](https://github.com/golang/go/issues/24656) +* [https://bugs.launchpad.net/qemu/+bug/1696773](https://bugs.launchpad.net/qemu/+bug/1696773) + +This issue is circumvented by ensuring that the Go compiler does not run across multiple hardware threads, which is why the affinity is being limited in the Dockerfile. + ## Credits * [inolen/quakejs](https://github.com/inolen/quakejs) - The really awesome QuakeJS project that makes this possible. diff --git a/example.yaml b/example.yaml index 7dace05..9bf85dd 100644 --- a/example.yaml +++ b/example.yaml @@ -22,7 +22,7 @@ spec: - --config=/config/config.yaml - --content-server=http://localhost:9090 - --agree-eula - image: docker.io/criticalstack/quake:v1.0.2 + image: docker.io/criticalstack/quake:v1.0.3 name: server ports: - containerPort: 8080 @@ -40,7 +40,7 @@ spec: - q3 - content - --seed-content-url=http://content.quakejs.com - image: docker.io/criticalstack/quake:v1.0.2 + image: docker.io/criticalstack/quake:v1.0.3 name: content-server ports: - containerPort: 9090 diff --git a/internal/quake/server/server.go b/internal/quake/server/server.go index cbaad58..9807b5b 100644 --- a/internal/quake/server/server.go +++ b/internal/quake/server/server.go @@ -22,14 +22,17 @@ var ( Name: "quake_active_players", Help: "The current number of active players", }) + scores = promauto.NewGaugeVec(prometheus.GaugeOpts{ Name: "quake_player_scores", Help: "Current scores by player, by map", }, []string{"player", "map"}) + pings = promauto.NewGaugeVec(prometheus.GaugeOpts{ Name: "quake_player_pings", Help: "Current ping by player", }, []string{"player"}) + configReloads = promauto.NewCounter(prometheus.CounterOpts{ Name: "quake_config_reloads", Help: "Config file reload count", @@ -97,6 +100,7 @@ func (s *Server) Start(ctx context.Context) error { } tick := time.NewTicker(5 * time.Second) defer tick.Stop() + for { select { case <-tick.C: @@ -107,7 +111,9 @@ func (s *Server) Start(ctx context.Context) error { } actrvePlayers.Set(float64(len(status.Players))) for _, p := range status.Players { - scores.WithLabelValues(p.Name, status.Configuration["mapname"]).Set(float64(p.Score)) + if mapname, ok := status.Configuration["mapname"]; ok { + scores.WithLabelValues(p.Name, mapname).Set(float64(p.Score)) + } pings.WithLabelValues(p.Name).Set(float64(p.Ping)) } case <-ctx.Done():