From e1f2516374bf1168d8ae891cf71c2a88f99856d0 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 3 Oct 2026 22:58:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=A6=E7=8F=BE=20Dockerfile=EF=BC=9A?= =?UTF-8?q?=E5=A4=9A=E9=9A=8E=E6=AE=B5=E5=BB=BA=E7=BD=AE=EF=BC=88golang:1.?= =?UTF-8?q?26-alpine=20=E2=86=92=20scratch=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 建置階段:BUILDPLATFORM 原生執行、交叉編譯至目標平臺,BuildKit 快取掛載(go mod download / build cache)加速重複建置 - 執行階段:scratch+單一靜態執行檔(無 CGO、模板與樣式 go:embed 內嵌),以非 root UID 65532 執行,ENTRYPOINT 採 exec 形式直接接收訊號 - .dockerignore 排除 .git、tools/、Markdown 等非建置所需檔案 - README 增加 Docker 段落(建置、連資料庫容器、CLI 子指令用法) 實作 #1 --- .dockerignore | 9 +++++++++ Dockerfile | 33 +++++++++++++++++++++++++++++++++ README.md | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2b5301c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +# 版本控制與本機工具不進入建置脈絡 +.git +.gitignore +.zcode +.zcodeignore +tools/ +*.md +Dockerfile +.dockerignore diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..591917e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +# 多階段建置:Go 編譯 → scratch 執行映像 +# 本專案為純 Go(pgx 驅動,無 CGO)、模板與樣式皆 go:embed 內嵌, +# 可編譯為單一靜態執行檔;執行階段不需要任何系統程式庫與 ca-certificates +# (服務僅對外提供 HTTP/OIDC,資料庫連線 sslmode=disable,無對外 TLS 呼叫)。 + +# ---- 建置階段:以 BUILDPLATFORM 原生執行,交叉編譯到目標平臺 ---- +FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS build +WORKDIR /src + +# 先複製依賴清單,利用層快取加速重複建置 +COPY go.mod go.sum ./ +RUN --mount=type=cache,target=/go/pkg/mod \ + go mod download + +COPY . . +ARG TARGETOS +ARG TARGETARCH +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH \ + go build -trimpath -ldflags="-s -w" -o /out/alterminal ./cmd/alterminal + +# ---- 執行階段:scratch,僅含靜態執行檔 ---- +FROM scratch +# 非 root 執行(scratch 無 /etc/passwd,以數字 UID 呈現) +COPY --from=build --chown=65532:65532 /out/alterminal /alterminal +USER 65532:65532 + +# 服務寫死監聽 :8080(cmd/alterminal/main.go:http.ListenAndServe(":8080", ...)) +EXPOSE 8080 + +# 容器內無 shell,ENTRYPOINT 採 exec 形式(PID 1 即為服務本體,直接收訊號) +ENTRYPOINT ["/alterminal"] diff --git a/README.md b/README.md index 4640689..019f584 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,40 @@ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o alterminal ./cmd/alterminal # ARM 伺服器改用 GOARCH=arm64 ``` +### Docker + +倉庫根目錄提供 `Dockerfile`(多階段建置:`golang:1.26-alpine` 編譯 → `scratch` 執行,無 CGO、以非 root UID 65532 執行、`ENTRYPOINT` 為 exec 形式可直接接收訊號)。建置與執行: + +```bash +# 建置映像(buildx 會依所在平臺自動交叉編譯;BuildKit 快取掛載加速重複建置) +docker build -t alterminal . + +# 讓資料庫容器(上節的 alterminal-db)與服務同網路,以容器名互連 +docker network create alterminal-net 2>/dev/null || true +docker network connect alterminal-net alterminal-db + +docker run -d --name alterminal \ + --network alterminal-net \ + -e DB_HOST=alterminal-db \ + -e DB_PORT=5432 \ + -e DB_USER=postgres \ + -e DB_PASSWORD=postgres \ + -e DB_NAME=alterminal \ + -e ISSUER=http://localhost:8080 \ + -p 8080:8080 \ + alterminal +# 資料庫在 host 上(未容器化)時:Docker Desktop 用 -e DB_HOST=host.docker.internal; +# Linux 加 --add-host=host.docker.internal:host-gateway + +# 驗證 +docker exec alterminal /alterminal create-account -username alice -email alice@example.com -password '...(至少 8 字元)' +curl http://localhost:8080/health # => ok +``` + +- 環境變數同「環境變數」一節(`DB_*`、`ISSUER`;服務固定監聽 `:8080`,`PORT` 尚未支援,容器無須設定) +- 映像為 `scratch`+單一靜態執行檔(模板與樣式已內嵌),不含 shell;CLI 子指令以 `docker exec <容器> /alterminal <子指令>` 執行 +- 建置脈絡以 `.dockerignore` 排除 `.git`、`tools/`、Markdown 等非建置所需檔案 + - 編譯前建議先跑測試:`go test ./...` ### 帳號管理 CLI