# Go 服务 Dockerfile 模板 Go 后端服务的 Docker 容器化模板,支持多种构建场景。 ## 模板类型 ### 1. CI 构建镜像(Dockerfile.ci) **适用场景**:在 CI/CD 中使用,二进制文件已在外部构建完成。 **优点**: - 镜像体积最小(~15MB) - 构建速度快 - 适合生产环境 ```dockerfile # CI 构建专用 Dockerfile # 将不常变化的层放在前面,最大化利用缓存 # 使用固定版本避免 latest 导致的缓存失效和不确定性 FROM alpine:3.21 # 基础设置层 - 很少变化,可以长期缓存 RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \ apk add --no-cache tzdata wget netcat-openbsd && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime # 健康检查脚本 - 偶尔变化 COPY docker-healthcheck.sh . RUN chmod +x docker-healthcheck.sh # 应用二进制 - 每次构建都变化,放在最后 COPY your-binary-name . # 健康检查(根据实际服务修改端口和端点) HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD ./docker-healthcheck.sh CMD ["./your-binary-name"] ``` **使用说明**: 1. 将 `your-binary-name` 替换为实际的二进制文件名 2. 创建 `docker-healthcheck.sh` 健康检查脚本 3. 在 CI workflow 中先构建二进制,再构建镜像 ### 2. 完整构建镜像(Dockerfile) **适用场景**:本地开发、无 CI 环境、独立构建。 **优点**: - 自包含构建流程 - 可在任何环境构建 - 利用 Docker 缓存加速 ```dockerfile # ============================================ # 构建阶段 # ============================================ FROM golang:1.25-alpine AS builder # 安装构建依赖 RUN apk add --no-cache git make # 设置工作目录 WORKDIR /build # 设置 Go 代理(国内加速) ENV GOPROXY=https://goproxy.cn,direct ENV CGO_ENABLED=0 ENV GOOS=linux ENV GOARCH=amd64 # 先复制依赖文件,利用 Docker 层缓存 COPY go.mod go.sum ./ RUN go mod download # 复制源码 COPY . . # 构建应用(根据项目需求修改) RUN go build -o app \ -ldflags '-s -w -X main.GitTag=dev' \ . # ============================================ # 运行阶段 # ============================================ FROM alpine:3.21 # 安装运行时依赖 RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \ apk add --no-cache tzdata wget netcat-openbsd && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime WORKDIR /app # 从构建阶段复制二进制文件 COPY --from=builder /build/app . COPY --from=builder /build/docker-healthcheck.sh . RUN chmod +x app docker-healthcheck.sh # 暴露端口(根据实际服务修改) EXPOSE 8080 # 健康检查 HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD ./docker-healthcheck.sh CMD ["./app"] ``` **使用说明**: 1. 将构建命令修改为项目实际的构建命令 2. 调整 ldflags 参数(版本号注入、符号表去除等) 3. 修改端口号 ### 3. 代码生成支持版(Dockerfile.codegen) **适用场景**:需要在容器中生成代码(如 Ent、Wire、oapi-codegen)。 ```dockerfile # ============================================ # 构建阶段 # ============================================ FROM golang:1.25-alpine AS builder # 安装构建工具 RUN apk add --no-cache git make WORKDIR /build ENV GOPROXY=https://goproxy.cn,direct ENV CGO_ENABLED=0 ENV GOOS=linux ENV GOARCH=amd64 # 复制依赖文件 COPY go.mod go.sum ./ RUN go mod download # 安装代码生成工具(根据项目需求选择) RUN go install entgo.io/ent/cmd/ent@latest && \ go install github.com/google/wire/cmd/wire@latest && \ go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest && \ go install golang.org/x/tools/cmd/stringer@latest # 复制源码 COPY . . # 代码生成(根据项目需求修改) RUN go generate ./... # 或使用 go tool 调用 # RUN go tool ent generate ./ent/schema # RUN go tool wire ./... # RUN go tool oapi-codegen -config oapi.yaml api.yaml # 测试(可选) RUN go test ./... RUN go vet ./... # 构建 RUN go build -o app \ -ldflags '-s -w' \ . # ============================================ # 运行阶段 # ============================================ FROM alpine:3.21 RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \ apk add --no-cache tzdata wget netcat-openbsd && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime WORKDIR /app COPY --from=builder /build/app . COPY --from=builder /build/docker-healthcheck.sh . RUN chmod +x app docker-healthcheck.sh EXPOSE 8080 HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD ./docker-healthcheck.sh CMD ["./app"] ``` ## 健康检查脚本 ### docker-healthcheck.sh(基础版) ```bash #!/bin/sh # Docker 健康检查脚本 # 检查应用端口是否在监听 if nc -z localhost 8080 2>/dev/null; then exit 0 fi exit 1 ``` ### docker-healthcheck.sh(HTTP 端点版) ```bash #!/bin/sh # Docker 健康检查脚本 # 检查 HTTP 端点是否可访问 # 使用 /health 或 /metrics 端点 if wget --spider --quiet --timeout=5 http://localhost:8080/health 2>/dev/null; then exit 0 fi # 备用:检查端口是否在监听 if nc -z localhost 8080 2>/dev/null; then exit 0 fi exit 1 ``` ### docker-healthcheck.sh(多端口版) ```bash #!/bin/sh # Docker 健康检查脚本 # 检查多个端口(适用于多个 API 服务) # 检查端口 2020 (Platform API) if ! nc -z localhost 2020 2>/dev/null; then echo "Port 2020 is not responding" exit 1 fi # 检查端口 2021 (WxMP API) if ! nc -z localhost 2021 2>/dev/null; then echo "Port 2021 is not responding" exit 1 fi # 或使用 HTTP 端点 # if ! wget --spider --quiet --timeout=5 http://localhost:2020/metrics 2>/dev/null; then # exit 1 # fi exit 0 ``` ## 高级配置 ### 环境变量配置 ```dockerfile # 在 Dockerfile 中设置默认环境变量 ENV MODE=production ENV LOG_LEVEL=info ENV GIN_MODE=release # 运行时可覆盖 # docker run -e MODE=test -e LOG_LEVEL=debug your-image ``` ### 配置文件挂载 ```dockerfile # 创建配置目录 RUN mkdir -p /app/configs # 运行时挂载配置文件 # docker run -v ./configs:/app/configs your-image ``` ### 非 root 用户运行 ```dockerfile # 创建非特权用户 RUN addgroup -g 1000 appuser && \ adduser -D -u 1000 -G appuser appuser WORKDIR /app # 复制文件 COPY --from=builder --chown=appuser:appuser /build/app . # 切换用户 USER appuser CMD ["./app"] ``` ### 多阶段构建优化 ```dockerfile # ============================================ # 依赖下载阶段(缓存 go.mod) # ============================================ FROM golang:1.25-alpine AS deps WORKDIR /build ENV GOPROXY=https://goproxy.cn,direct COPY go.mod go.sum ./ RUN go mod download # ============================================ # 构建阶段 # ============================================ FROM golang:1.25-alpine AS builder WORKDIR /build # 从依赖阶段复制缓存 COPY --from=deps /go/pkg /go/pkg ENV CGO_ENABLED=0 ENV GOOS=linux ENV GOARCH=amd64 COPY . . RUN go build -o app -ldflags '-s -w' . # ============================================ # 运行阶段 # ============================================ FROM alpine:3.21 # ... 省略后续步骤 ``` ## 镜像优化技巧 ### 1. 减小镜像体积 ```dockerfile # 使用 Alpine 基础镜像 FROM alpine:3.21 # 去除符号表和调试信息 RUN go build -ldflags '-s -w' -o app # 使用 upx 压缩(可选,启动时间会变长) RUN apk add --no-cache upx && \ upx --best --lzma app && \ apk del upx ``` ### 2. 利用构建缓存 ```dockerfile # 先复制 go.mod 和 go.sum,利用依赖缓存 COPY go.mod go.sum ./ RUN go mod download # 再复制源码(源码变化频繁) COPY . . ``` ### 3. 合并 RUN 命令 ```dockerfile # 合并多个 RUN 命令减少层数 RUN apk add --no-cache tzdata wget netcat-openbsd && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ addgroup -g 1000 appuser ``` ### 4. 使用 .dockerignore ``` # .dockerignore .git/ .gitignore *.md docs/ tests/ .github/ .gitea/ Dockerfile* docker-compose.yml *.log tmp/ vendor/ ``` ## 构建命令示例 ### 本地构建 ```bash # 基础构建 docker build -t your-service:latest . # 指定 Dockerfile docker build -f Dockerfile.ci -t your-service:latest . # 传递构建参数 docker build --build-arg GIT_TAG=v1.0.0 -t your-service:1.0.0 . # 查看构建过程 docker build --progress=plain -t your-service:latest . ``` ### CI/CD 构建 ```bash # 使用 BuildKit 缓存 export DOCKER_BUILDKIT=1 # 使用注册表缓存 docker build \ --cache-from=type=registry,ref=your-service:buildcache \ --cache-to=type=registry,ref=your-service:buildcache,mode=max \ -t your-service:latest \ . ``` ## 运行容器示例 ```bash # 基础运行 docker run -d -p 8080:8080 your-service:latest # 挂载配置文件 docker run -d \ -p 8080:8080 \ -v ./configs:/app/configs \ -v ./logs:/app/logs \ your-service:latest # 设置环境变量 docker run -d \ -p 8080:8080 \ -e MODE=production \ -e DATABASE_URL=postgres://... \ your-service:latest # 查看日志 docker logs -f # 进入容器调试 docker exec -it /bin/sh ``` ## 安全建议 ### 1. 使用特定版本标签 ```dockerfile # 不推荐:使用 latest FROM alpine:latest # 推荐:使用特定版本 FROM alpine:3.21 ``` ### 2. 定期更新依赖 ```bash # 更新 Go 模块 go get -u ./... go mod tidy # 更新基础镜像 docker pull alpine:3.21 ``` ### 3. 扫描漏洞 ```bash # 使用 Trivy 扫描 docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \ aquasec/trivy image your-service:latest ``` ### 4. 最小权限原则 ```dockerfile # 使用非 root 用户 USER appuser # 只读文件系统(如果适用) # docker run --read-only your-service ``` ## 常见问题 ### Q1: 时区不正确 **原因**: 容器默认使用 UTC 时区 **解决方案**: ```dockerfile RUN apk add --no-cache tzdata && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ``` ### Q2: 网络连接超时 **原因**: DNS 解析问题或网络配置 **解决方案**: ```bash # 运行时指定 DNS docker run --dns 8.8.8.8 your-service # 或在 Dockerfile 中配置 RUN echo 'nameserver 8.8.8.8' > /etc/resolv.conf ``` ### Q3: CGO 依赖问题 **错误信息**: `binary was compiled with 'CGO_ENABLED=1'` **解决方案**: ```dockerfile # 禁用 CGO ENV CGO_ENABLED=0 # 或安装 gcc RUN apk add --no-cache gcc musl-dev ``` ### Q4: 静态链接失败 **错误信息**: `dynamic executable` **解决方案**: ```dockerfile # 确保 CGO_ENABLED=0 ENV CGO_ENABLED=0 # 或使用 musl 交叉编译 RUN apk add --no-cache musl-dev RUN go build -ldflags '-linkmode external -extldflags "-static"' -o app ``` ## 参考资源 - [Go 官方 Docker 指南](https://docs.docker.com/language/golang/) - [Alpine Linux 包搜索](https://pkgs.alpinelinux.org/packages) - [Docker 多阶段构建文档](https://docs.docker.com/build/building/multi-stage/) - [Go 编译器标志](https://pkg.go.dev/cmd/go)