Repository navigation
Expand file tree
/
Copy pathContainerfile.nezha
More file actions
98 lines (80 loc) · 4.68 KB
/
Copy pathContainerfile.nezha
File metadata and controls
98 lines (80 loc) · 4.68 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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# Containerfile.nezha — multi-binary image for the nezha distributed-boot full stack.
#
# Builds the four runtime services from this repo and selects one at container
# start time via the SERVICE environment variable (grpc | api | server | monitor).
# This replaces the legacy ./Dockerfile, which referenced the non-existent
# `make build-server` target and copied a never-produced `translator-server`
# binary (Phase-1 finding, §11.4.6 — verified: Makefile has no build-server
# target; the real targets are grpc-server, api-server, unified-translator;
# cmd/server is the TLS REST/WS+HTTP3 server, cmd/monitor-server the :8090 hub).
#
# Build context = repo root. Go module requires Go 1.26 (see go.mod); the legacy
# Dockerfile pinned 1.24 which cannot compile this module.
#
# Usage (per service, podman/docker):
# podman build -f Containerfile.nezha -t helixtranslate:nezha .
# podman run -e SERVICE=grpc -p 50051:50051 helixtranslate:nezha
# podman run -e SERVICE=api -p 8080:8080 helixtranslate:nezha
# podman run -e SERVICE=server -p 8443:8443 -v ./certs:/app/certs:ro helixtranslate:nezha
# podman run -e SERVICE=monitor -p 8090:8090 helixtranslate:nezha
# Normally driven by compose.nezha.yml (one image, per-service SERVICE env).
# ---- build stage ----
FROM docker.io/library/golang:1.26-alpine AS builder
# gcc + musl-dev are required because the LLMsVerifier bridge (used by the
# translation path AND the cmd/server startup) opens a go-sqlite3 store, and
# go-sqlite3 requires cgo. Without cgo the binary ships a stub that fatals at
# runtime ("Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo").
RUN apk add --no-cache git ca-certificates gcc musl-dev
WORKDIR /build
# Full source FIRST. This module uses local `replace` directives pointing at
# in-tree directories (./challenges, ./containers, ./llms_verifier/llm-verifier,
# etc.), so `go mod download` cannot run against only the root go.mod — it needs
# every replaced module's go.mod present on disk. Copying the whole context
# before resolving modules is the correct ordering for local-replace modules
# (the dependency-only cache layer that copies just go.mod/go.sum BREAKS here:
# `reading challenges/go.mod: no such file or directory`).
COPY . .
# Resolve modules now that all replace targets are present.
RUN go mod download
# Build the four runtime services with real, existing cmd targets.
# CGO enabled (go-sqlite3 needs it); static-linked against musl via the external
# linker so the binaries still run on the plain alpine final stage with no
# dynamic-lib dependency. -X sets the app version.
ENV CGO_ENABLED=1 GOOS=linux
RUN go build -tags "sqlite_omit_load_extension" -ldflags '-X main.appVersion=2.3.0 -linkmode external -extldflags "-static"' -o /out/grpc-server ./cmd/grpc-server \
&& go build -tags "sqlite_omit_load_extension" -ldflags '-X main.appVersion=2.3.0 -linkmode external -extldflags "-static"' -o /out/api-server ./cmd/api-server \
&& go build -tags "sqlite_omit_load_extension" -ldflags '-X main.appVersion=2.3.0 -linkmode external -extldflags "-static"' -o /out/server ./cmd/server \
&& go build -tags "sqlite_omit_load_extension" -ldflags '-X main.appVersion=2.3.0 -linkmode external -extldflags "-static"' -o /out/monitor-server ./cmd/monitor-server
# ---- final stage ----
FROM docker.io/library/alpine:3.20
# Runtime deps: TLS roots, timezone data, curl/wget for healthchecks.
RUN apk add --no-cache ca-certificates tzdata curl
# Non-root runtime user.
RUN addgroup -g 1000 appuser \
&& adduser -D -u 1000 -G appuser appuser
WORKDIR /app
# Service binaries.
COPY --from=builder /out/grpc-server /app/grpc-server
COPY --from=builder /out/api-server /app/api-server
COPY --from=builder /out/server /app/server
COPY --from=builder /out/monitor-server /app/monitor-server
# Web assets: the api-server calls gin LoadHTMLGlob("web/templates/*") +
# Static("/static", "./web/static") relative to its WORKDIR (/app), and panics
# at startup if web/templates/* matches no files. Ship them into /app/web.
COPY web/ /app/web/
# Per-service dispatch entrypoint.
COPY scripts/nezha-entrypoint.sh /app/nezha-entrypoint.sh
RUN chmod +x /app/nezha-entrypoint.sh
# Mount points: TLS certs (read-only) for the `server` TLS service, and a
# writable config dir for the config-file-driven `server`.
RUN mkdir -p /app/certs /app/config /app/output \
&& chown -R appuser:appuser /app
USER appuser
# Documented service ports (only the one matching SERVICE actually binds).
# grpc -> 50051
# api -> 8080 (HTTP REST/WS proxy to grpc backend)
# server -> 8443 (TLS REST/WS + optional HTTP3)
# monitor -> 8090
EXPOSE 50051 8080 8443 8090
ENV SERVICE=api
ENTRYPOINT ["/app/nezha-entrypoint.sh"]