强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

27 - 容器化:多阶段构建、scratch 镜像、CGO 交叉编译

27 - 容器化

27.1 基本 Dockerfile

# 最简单的 Dockerfile
FROM golang:1.24-alpine

WORKDIR /app

# 先复制依赖文件(利用 Docker 缓存)
COPY go.mod go.sum ./
RUN go mod download

# 复制源代码
COPY . .

# 编译
RUN go build -o server ./cmd/server

# 暴露端口
EXPOSE 8080

# 运行
CMD ["./server"]

⚠️ 问题:这个镜像包含完整的 Go 工具链,体积约 300MB+。

27.2 多阶段构建(Multi-stage Build)

# ===== 阶段 1: 编译 =====
FROM golang:1.24-alpine AS builder

WORKDIR /app

# 安装 git(go mod 需要)
RUN apk add --no-cache git

COPY go.mod go.sum ./
RUN go mod download

COPY . .

# 编译优化
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
    go build -ldflags="-s -w" -o server ./cmd/server

# ===== 阶段 2: 运行 =====
FROM alpine:3.19

# 安装必要的系统依赖
RUN apk add --no-cache ca-certificates tzdata

# 设置时区
ENV TZ=Asia/Shanghai

WORKDIR /app

# 从编译阶段复制二进制
COPY --from=builder /app/server .
COPY --from=builder /app/config ./config

# 非 root 用户运行
RUN adduser -D -s /bin/sh appuser
USER appuser

EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=3s \
    CMD wget -qO- http://localhost:8080/health || exit 1

ENTRYPOINT ["./server"]

27.3 scratch 镜像

scratch 是空镜像,最终镜像只包含你的二进制文件。

FROM golang:1.24-alpine AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
    go build -ldflags="-s -w" -o server ./cmd/server

# 使用 scratch(空镜像)
FROM scratch

# 复制 SSL 证书(HTTPS 需要)
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# 复制时区数据
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo

# 复制二进制
COPY --from=builder /app/server /server

EXPOSE 8080

ENTRYPOINT ["/server"]
基础镜像大小Shell包管理器适用场景
golang:1.24~800MB仅编译阶段
alpine:3.19~7MB需要调试
distroless~20MB安全生产
scratch0MB极简生产

27.4 CGO 交叉编译

# 禁用 CGO(纯 Go 编译,支持交叉编译)
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o server .

# 多平台编译
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o server-arm64 .
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o server-mac .
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o server.exe .

# 需要 CGO 时(如使用 SQLite)
# 需要安装交叉编译工具链
# apt install gcc-aarch64-linux-gnu
CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -o server-arm64 .

Dockerfile 多平台构建

FROM --platform=$BUILDPLATFORM golang:1.24-alpine AS builder

ARG TARGETOS
ARG TARGETARCH

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .

RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
    go build -ldflags="-s -w" -o server ./cmd/server

FROM alpine:3.19
COPY --from=builder /app/server /server
ENTRYPOINT ["/server"]
# 构建多平台镜像
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest .

27.5 Docker Compose

# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb?sslmode=disable
      - REDIS_URL=redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    volumes:
      - redisdata:/data

volumes:
  pgdata:
  redisdata:

27.6 .dockerignore

# .dockerignore
.git
.github
.vscode
*.md
Makefile
docker-compose.yml
Dockerfile
.env
tmp/
vendor/
public/
coverage.out

27.7 优化技巧

# Makefile
APP_NAME := myapp
VERSION := $(shell git describe --tags --always)
BUILD_TIME := $(shell date -u '+%Y-%m-%dT%H:%M:%SZ')
LDFLAGS := -s -w \
    -X main.version=$(VERSION) \
    -X main.buildTime=$(BUILD_TIME)

.PHONY: build docker

build:
	CGO_ENABLED=0 go build -ldflags="$(LDFLAGS)" -o bin/$(APP_NAME) ./cmd/server

docker:
	docker build \
		--build-arg VERSION=$(VERSION) \
		--build-arg BUILD_TIME=$(BUILD_TIME) \
		-t $(APP_NAME):$(VERSION) .

docker-run:
	docker-compose up -d

docker-stop:
	docker-compose down

🏢 业务场景

  1. 微服务部署:每个服务一个 Docker 镜像
  2. Kubernetes:Docker 镜像部署到 K8s
  3. CI/CD:Docker 构建自动化
  4. 本地开发:docker-compose 一键启动所有依赖

📖 扩展阅读