From 6777461268e198815025d1aed5d5cc68c662e76f Mon Sep 17 00:00:00 2001 From: oyaegeli98668 Date: Sat, 20 Jun 2026 02:27:09 +0000 Subject: [PATCH] =?UTF-8?q?chore(deploy):=20=E7=94=9F=E4=BA=A7=20docker=20?= =?UTF-8?q?compose=20+=20scratch=20Dockerfile=20+=20=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docker-compose.prod.yml:仅 api 绑 127.0.0.1:8120,DB/redis/minio 不暴露,restart=unless-stopped,凭据走 .env - api/Dockerfile.prod:runtime 改用 scratch + 拷贝 ca-certs(gcr.io/distroless 不可达环境),Go 模块走 goproxy.cn - .env.example / docs/deploy.md Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .env.example | 7 +++++ api/Dockerfile.prod | 16 +++++++++++ docker-compose.prod.yml | 61 +++++++++++++++++++++++++++++++++++++++++ docs/deploy.md | 25 +++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 .env.example create mode 100644 api/Dockerfile.prod create mode 100644 docker-compose.prod.yml create mode 100644 docs/deploy.md diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..25c227d --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +# Copy to .env and fill in real values before running docker-compose.prod.yml. +# Used by docker-compose.prod.yml for production deployment. +POSTGRES_USER=opengoods +POSTGRES_PASSWORD=change-me +POSTGRES_DB=opengoods +MINIO_ROOT_USER=opengoods +MINIO_ROOT_PASSWORD=change-me diff --git a/api/Dockerfile.prod b/api/Dockerfile.prod new file mode 100644 index 0000000..71ea1f5 --- /dev/null +++ b/api/Dockerfile.prod @@ -0,0 +1,16 @@ +# Build stage +FROM golang:1.23-alpine AS build +ENV GOPROXY=https://goproxy.cn,direct +WORKDIR /src +COPY go.mod go.sum ./ +RUN go mod download +COPY . . +RUN CGO_ENABLED=0 go build -o /out/server ./cmd/server + +# Runtime stage: scratch + ca-certs copied from the build image. +# Used for deployments where gcr.io/distroless is not reachable. +FROM scratch +COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=build /out/server /server +EXPOSE 8080 +ENTRYPOINT ["/server"] diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..84de166 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,61 @@ +name: goods +services: + postgres: + image: postgres:16-alpine + restart: unless-stopped + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + volumes: + - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] + interval: 5s + timeout: 5s + retries: 10 + + redis: + image: redis:7-alpine + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 5s + retries: 10 + + minio: + image: minio/minio:latest + restart: unless-stopped + command: server /data --console-address ":9001" + environment: + MINIO_ROOT_USER: ${MINIO_ROOT_USER} + MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} + volumes: + - miniodata:/data + healthcheck: + test: ["CMD", "mc", "ready", "local"] + interval: 5s + timeout: 5s + retries: 10 + + api: + build: + context: ./api + dockerfile: Dockerfile.prod + restart: unless-stopped + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + environment: + OPENGOODS_ADDR: ":8080" + OPENGOODS_DATABASE_URL: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?sslmode=disable" + OPENGOODS_REDIS_URL: "redis://redis:6379/0" + ports: + - "127.0.0.1:8120:8080" + +volumes: + pgdata: + miniodata: diff --git a/docs/deploy.md b/docs/deploy.md new file mode 100644 index 0000000..e0be14d --- /dev/null +++ b/docs/deploy.md @@ -0,0 +1,25 @@ +# 生产部署 (Docker) + +用 `docker-compose.prod.yml` 部署,与本地 `docker-compose.yml` 的区别: + +- 仅 `api` 映射宿主端口,且绑定 `127.0.0.1:8120`(由外层 nginx 反代 + HTTPS);`postgres`/`redis`/`minio` 不对外暴露端口,仅容器内网互通。 +- 所有服务 `restart: unless-stopped`。 +- 凭据从 `.env` 注入(见 `.env.example`),不写入仓库。 +- `api` 使用 `api/Dockerfile.prod`:运行镜像用 `scratch`(从构建镜像拷贝 ca-certs),适用于 `gcr.io/distroless` 不可达的环境;Go 模块走 `goproxy.cn`。 + +## 步骤 + +```bash +cp .env.example .env # 填入真实随机密码 +docker compose -f docker-compose.prod.yml up -d --build + +# 迁移(migrate 容器接入同一网络,DSN 指向 postgres 服务) +set -a; . ./.env; set +a +DBURL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?sslmode=disable" +docker run --rm --network goods_default -v "$PWD/migrations:/migrations" \ + migrate/migrate -path=/migrations -database "$DBURL" up + +curl -s http://127.0.0.1:8120/healthz # {"status":"ok"} +``` + +nginx 反代(子域 + HTTPS):80 端口 301 跳转到 443,443 `proxy_pass http://127.0.0.1:8120`,证书用 acme.sh 签发并配 `--reloadcmd "nginx -s reload"` 自动续期。