mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
* fix(release): give the Docker boot-smoke a writable /app, and run it in CI The v1.2.0-alpha.3 release run died at "Boot-smoke Docker image": a bare `docker run` of the distroless image has nowhere the uid-65532 server can write — /app is root-owned, and the VOLUME /app/data anonymous volume is created root-owned too — so config.Load failed on "writing default config: open config.yaml: permission denied" and the container exited. Real deployments bind-mount config.yaml and data/, which is why the image itself is fine. Move the smoke into Server/scripts/docker-smoke.sh, run the container with `--tmpfs /app --tmpfs /app/data` (Docker's tmpfs default mode is 1777, so the non-root server can write both), and call the same script from ci.yml's docker-build job — loading the image it already builds — so the smoke is exercised on every PR to main instead of for the first time at tag time. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(docker): ship /app and /app/data owned by the runtime uid so a bare run boots The tmpfs approach did not survive CI: runc re-applies the underlying directory's mode to a tmpfs mounted over an existing path, so /app stayed root:755 and the write still failed. Fix the image instead of the harness: stage /app/data in the builder, chown it to 65532, COPY --chown it into the distroless stage before WORKDIR. Docker seeds the VOLUME's anonymous volume from that image dir, ownership included, so `docker run <image>` with no mounts now boots and answers /health — which is also the contract the smoke should be testing, so it goes back to a bare `docker run`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
52 lines
2.0 KiB
Docker
52 lines
2.0 KiB
Docker
# syntax=docker/dockerfile:1
|
|
|
|
# ─── Build stage ────────────────────────────────────────────────────────────
|
|
FROM golang:1.26-bookworm AS builder
|
|
|
|
ARG VERSION=dev
|
|
|
|
WORKDIR /src
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
COPY . .
|
|
RUN CGO_ENABLED=0 GOOS=linux go build \
|
|
-o /chatserver \
|
|
-ldflags "-s -w -X main.version=${VERSION}" \
|
|
.
|
|
|
|
# Skeleton for the runtime image's working dir. The server writes its default
|
|
# config.yaml to the cwd and the SQLite DB, cert and uploads under data/, and
|
|
# it runs as uid 65532 — so both must be owned by that uid or a bare
|
|
# `docker run` dies on boot with "writing default config: permission denied"
|
|
# (a WORKDIR created by the final stage is root-owned, and Docker seeds the
|
|
# VOLUME's anonymous volume from the image dir, ownership included). Staged
|
|
# here because distroless has no shell to chown with.
|
|
RUN mkdir -p /skel/app/data && chown -R 65532:65532 /skel/app
|
|
|
|
# ─── Final stage ─────────────────────────────────────────────────────────────
|
|
# gcr.io/distroless/static-debian12: no shell, includes CA certs (needed for
|
|
# TLS/ACME) and timezone data. Attack surface is minimal.
|
|
FROM gcr.io/distroless/static-debian12
|
|
|
|
COPY --from=builder --chown=65532:65532 /skel/app /app
|
|
WORKDIR /app
|
|
|
|
COPY --from=builder /chatserver /chatserver
|
|
|
|
# /app/data is the default data_dir (SQLite DB + uploads).
|
|
# Mount a named volume here to persist data across container restarts.
|
|
VOLUME ["/app/data"]
|
|
|
|
# Server listens on this port by default (configurable via config.yaml).
|
|
EXPOSE 8443
|
|
|
|
# Refuses the in-place self-update endpoint (the binary is image content;
|
|
# upgrades are image pulls). See Server/updater/container.go.
|
|
ENV OWNCORD_CONTAINER=1
|
|
|
|
# Run as non-root (distroless provides uid 65532 = "nonroot").
|
|
USER 65532:65532
|
|
|
|
ENTRYPOINT ["/chatserver"]
|