mirror of
https://github.com/napnap75/multiarch-docker-images.git
synced 2026-11-12 00:52:11 +01:00
archivist: scratch runtime Dockerfile (static binary only, non-root, CA bundle + tzdata); .dockerignore; README build section; arch.md packaging; fix ARCHIVIST_HTTP_ADDR doc row
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
# Keep the build context to the Go sources the builder stage copies.
|
||||||
|
# config.jsonc is mounted at runtime, never baked into the image.
|
||||||
|
e2e/
|
||||||
|
pb_data/
|
||||||
|
*.md
|
||||||
|
config.jsonc
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# archivist: multi-stage build. The builder compiles a static binary;
|
||||||
|
# the runtime is scratch with only that binary and the files it needs.
|
||||||
|
|
||||||
|
# --- build stage ------------------------------------------------------------
|
||||||
|
FROM golang:1.23-alpine AS build
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
# ca-certificates and tzdata are copied into the runtime image below.
|
||||||
|
RUN apk add --no-cache ca-certificates tzdata
|
||||||
|
|
||||||
|
# TARGETARCH is set by buildx for multi-platform builds; it is unset for a
|
||||||
|
# plain docker build, where go builds for the host architecture.
|
||||||
|
ARG TARGETARCH
|
||||||
|
|
||||||
|
# go.sum is not committed yet: go mod tidy resolves and pins the exact
|
||||||
|
# versions at build time. Once go.sum is committed, replace the tidy line
|
||||||
|
# with `go mod download` for fully reproducible builds.
|
||||||
|
COPY go.mod main.go internal/ ./
|
||||||
|
RUN go mod tidy
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} go build -trimpath -ldflags="-s -w" -o /archivist .
|
||||||
|
|
||||||
|
# Minimal runtime tree assembled next to the binary:
|
||||||
|
# - CA bundle: the S3 endpoint is HTTPS by default
|
||||||
|
# - timezone database: the cron and date rendering honor TZ
|
||||||
|
# - /app/pb_data (SQLite database) and /tmp, the only writable directories,
|
||||||
|
# owned by the unprivileged runtime user 65532
|
||||||
|
RUN mkdir -p /out/etc/ssl/certs /out/usr/share /out/app/pb_data /out/tmp \
|
||||||
|
&& cp /etc/ssl/certs/ca-certificates.crt /out/etc/ssl/certs/ \
|
||||||
|
&& cp -r /usr/share/zoneinfo /out/usr/share/zoneinfo \
|
||||||
|
&& chown -R 65532:65532 /out/app /out/tmp
|
||||||
|
|
||||||
|
# --- runtime stage -----------------------------------------------------------
|
||||||
|
FROM scratch
|
||||||
|
COPY --from=build /out/ /
|
||||||
|
COPY --from=build /archivist /archivist
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
ENV TMPDIR=/tmp
|
||||||
|
USER 65532:65532
|
||||||
|
VOLUME /app/pb_data
|
||||||
|
EXPOSE 8090
|
||||||
|
ENTRYPOINT ["/archivist"]
|
||||||
+11
-1
@@ -40,6 +40,14 @@ docker run -d --name archivist \
|
|||||||
|
|
||||||
The dashboard is available at `http://<server>:8090/`, the PocketBase admin at `http://<server>:8090/_/`.
|
The dashboard is available at `http://<server>:8090/`, the PocketBase admin at `http://<server>:8090/_/`.
|
||||||
|
|
||||||
|
## Building the image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t napnap75/archivist:latest archivist/
|
||||||
|
```
|
||||||
|
|
||||||
|
The build has two stages: the builder compiles a static binary (CGO disabled), and the runtime image is `scratch` containing only that binary, the CA bundle (the S3 endpoint is HTTPS by default), the timezone database, and the writable data directories. The container runs as the non-root user 65532: a named volume for `/app/pb_data` works out of the box; for a host bind mount, `chown 65532:65532` the directory first. The image has no shell, so `docker exec` is not available.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Two distinct configurations:
|
Two distinct configurations:
|
||||||
@@ -62,7 +70,7 @@ The functional configuration is reloaded only when the container restarts.
|
|||||||
| `ARCHIVIST_POLL_INTERVAL` | no | Cron expression for polling `inbox/`, default `* * * * *` (every minute) |
|
| `ARCHIVIST_POLL_INTERVAL` | no | Cron expression for polling `inbox/`, default `* * * * *` (every minute) |
|
||||||
| `ARCHIVIST_ADMIN_EMAIL` | yes | Admin account (dashboard and PocketBase) |
|
| `ARCHIVIST_ADMIN_EMAIL` | yes | Admin account (dashboard and PocketBase) |
|
||||||
| `ARCHIVIST_ADMIN_PASSWORD` | yes | Admin account password |
|
| `ARCHIVIST_ADMIN_PASSWORD` | yes | Admin account password |
|
||||||
| `ARCHIVIST_HTTP_PORT` | no | Internal listening port, default `8090` |
|
| `ARCHIVIST_HTTP_ADDR` | no | Listen address, default `0.0.0.0:8090` |
|
||||||
|
|
||||||
The `pb_data` volume holds the PocketBase SQLite database (documents, history, full-text search index): it must persist across restarts.
|
The `pb_data` volume holds the PocketBase SQLite database (documents, history, full-text search index): it must persist across restarts.
|
||||||
|
|
||||||
@@ -128,6 +136,8 @@ cd archivist
|
|||||||
E2E_IMAGE=archivist:e2e go test ./e2e -v -count=1
|
E2E_IMAGE=archivist:e2e go test ./e2e -v -count=1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Build the image first: `docker build -t archivist:e2e .` (see Building the image).
|
||||||
|
|
||||||
Without `E2E_IMAGE` the suite skips. The suite drives the poller through the superuser-only `POST /api/archivist/poll` route instead of waiting for the cron. `E2E_KEEP=1` leaves the containers running after the run for debugging; `GARAGE_IMAGE` overrides the Garage image (default `dxflrs/garage:latest`). See arch.md section 10.
|
Without `E2E_IMAGE` the suite skips. The suite drives the poller through the superuser-only `POST /api/archivist/poll` route instead of waiting for the cron. `E2E_KEEP=1` leaves the containers running after the run for debugging; `GARAGE_IMAGE` overrides the Garage image (default `dxflrs/garage:latest`). See arch.md section 10.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|||||||
@@ -257,4 +257,11 @@ The scenarios form one narrative; each subtest names the US it proves:
|
|||||||
|
|
||||||
The gate is a regression detector for dependency upgrades (PocketBase, minio-go, ledongthuc/pdf, expr, Garage), not an acceptance proof: acceptance criteria are reviewed on the stories themselves. `E2E_KEEP=1` leaves the containers running after the run for debugging.
|
The gate is a regression detector for dependency upgrades (PocketBase, minio-go, ledongthuc/pdf, expr, Garage), not an acceptance proof: acceptance criteria are reviewed on the stories themselves. `E2E_KEEP=1` leaves the containers running after the run for debugging.
|
||||||
|
|
||||||
|
## 11. Packaging
|
||||||
|
|
||||||
|
`Dockerfile`, two-stage build:
|
||||||
|
|
||||||
|
- Builder: `golang:1.23-alpine`, CGO disabled, static binary, `TARGETARCH` honored for multi-platform builds under buildx. `go mod tidy` runs there because `go.sum` is not committed; once it is committed, the line becomes `go mod download` for fully reproducible builds.
|
||||||
|
- Runtime: `scratch` with only the `/archivist` binary, the CA bundle (the S3 endpoint is HTTPS by default), the timezone database (the cron and date rendering honor `TZ`), and `/app/pb_data` + `/tmp`, the only writable directories, owned by the unprivileged runtime user 65532. `config.jsonc` is never baked in: it is mounted at runtime, `ARCHIVIST_CONFIG` defaulting to `config.jsonc` relative to `/app`.
|
||||||
|
|
||||||
|
The container runs as 65532:65532 (non-root), exposes 8090, declares `/app/pb_data` as a volume, and has no shell: `docker exec` is not available. `.dockerignore` keeps the build context to the Go sources; the E2E harness is not part of the image.
|
||||||
|
|||||||
Reference in New Issue
Block a user