希曼日记

极致优化大小

本页目录 8
  1. 缓存挂载
  2. Buildx 远程缓存
  3. 应用层优化
  4. 压缩镜像
  5. 镜像选择
  6. Compose
  7. 最终
  8. 对比

缓存挂载

编译指定服务(注意路径调整)

RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \

Buildx 远程缓存

docker buildx build . \
  -f application/auth/Dockerfile \
  --progress=plain \
  -t ccr.ccs.tencentyun.com/sumery/auth:95d6205 \
  --build-arg SERVICE=auth \
  --build-arg CGOENABLED=0 \
  --build-arg GOIMAGE=golang:1.24.0-alpine3.21 \
  --build-arg VERSION=95d6205 \
  --platform linux/arm64,linux/amd64 \
  --push \
  --cache-from type=registry,ref=ccr.ccs.tencentyun.com/sumery/auth:cache \  # 从仓库拉取缓存
  --cache-to type=registry,ref=ccr.ccs.tencentyun.com/sumery/auth:cache,mode=max  # 推送缓存到仓库

应用层优化

go build -ldflags="-s -w -X main.Version=$VERSION" -o /app/$SERVICE ./...

压缩镜像

在编译阶段使用 UPX 压缩二进制文件:

RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    apk add --no-cache upx && \
    GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=$CGOENABLED go build -ldflags="-s -w" -o /app/$SERVICE ./... && \
    upx --best --lzma /app/$SERVICE

镜像选择

distroless.static-debian12: 664.4 KB:

docker pull hubmirrorbytogettoyou/gcr.io.distroless.static-debian12:nonroot

alpine: 3.21 MB

docker pull alpine:latest

Compose

在 Dockerfile 中使用了 多阶段构建(Multi-stage Build),分为 compile(编译阶段)和 final(运行时阶段)。target: final 的作用是告诉 Docker 在构建时仅执行到 final 阶段,并生成最终镜像。

关键点

  • 构建阶段隔离compile 阶段负责编译代码,生成二进制文件;final 阶段仅复制二进制文件和运行时依赖,丢弃编译环境和中间文件。

  • 镜像大小优化:最终镜像仅包含 final 阶段的内容,体积更小,安全性更高。

  • Compose 中的行为:当执行 docker compose build 或 docker compose up --build 时,Compose 会基于 target: final 构建镜像,直接生成最终镜像,无需手动操作。

services:

  gateway:
    platform: linux/amd64
    build:
      context: .
      target: final

最终

Dockerfile:

# 编译阶段
ARG GO_IMAGE=golang:1.24.0-alpine3.21
FROM --platform=$BUILDPLATFORM ${GO_IMAGE} AS compile

ARG TARGETOS=linux
ARG TARGETARCH
ARG SERVICE
ARG VERSION=dev
ARG GOPROXY=https://goproxy.cn,direct
ARG CGOENABLED=0

WORKDIR /build

# 挂载依赖缓存
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    go mod download -x

# 编译代码
COPY . .
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=$CGOENABLED \
    go build -ldflags="-s -w -X main.Version=$VERSION" -o /app/$SERVICE ./application/${SERVICE}/cmd/${SERVICE}

# 最终镜像
FROM gcr.io/distroless/static-debian12 AS final
COPY --from=compile /app/$SERVICE /app/service
ENTRYPOINT ["/app/service"]

保守方案: 增加几 MB 大小, 最终镜像使用持续维护的alpine:

ARG GO_IMAGE=golang:1.24.2-alpine3.21
FROM --platform=$BUILDPLATFORM ${GO_IMAGE} AS compile

ARG TARGETOS=linux
ARG TARGETARCH
ARG SERVICE
ARG VERSION=dev
ARG GOPROXY=https://goproxy.cn,direct
ARG CGOENABLED=0

WORKDIR /build

# 挂载依赖缓存
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    go mod download -x

COPY . .
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=$CGOENABLED \
    go build -ldflags="-s -w -X main.Version=$VERSION" -o /app/$SERVICE ./application/${SERVICE}/cmd/${SERVICE}

# 最终镜像
FROM alpine:3.21 AS final

ARG SERVICE
ENV TZ=Asia/Shanghai

# 安装依赖并配置时区
RUN apk add --no-cache tzdata ca-certificates && \
    ln -sf "/usr/share/zoneinfo/$TZ" /etc/localtime && \
    echo "$TZ" > /etc/timezone

COPY --from=compile /app/$SERVICE /app/service

ENTRYPOINT ["/app/service"]

compose.yml

services:

  gateway:
    image: ccr.ccs.tencentyun.com/kratos/gateway:v2.0.0
    platform: linux/amd64
    build:
      context: .
      target: final
    ports:
      - "8080:8080"
      - "8443:443/tcp"
      - "8443:443/udp"
    container_name: ecommerce-gateway
    restart: on-failure:3
    environment:
      - DISCOVERY_DSN=consul://apikv.com:8500
      - DISCOVERY_CONFIG_PATH=ecommerce/gateway/config.yaml
    volumes:
      # 仅挂载本地配置文件(开发环境)
      - ./dynamic-config:/app/dynamic-config
    command: [ "/app/gateway" ]
    networks:
      - ecommerce

对比

代码不变, 仅Dockerfile 变化

优化前二进制文件大小: 40.9MB

docker history ccr.ccs.tencentyun.com/sumery/user:95d6205

IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
bdd19af5b498   46 minutes ago   ENTRYPOINT ["/app/service"]                     0B        buildkit.dockerfile.v0
<missing>      46 minutes ago   EXPOSE map[30003/tcp:{} 30004/tcp:{}]           0B        buildkit.dockerfile.v0
<missing>      46 minutes ago   COPY /app/user /app/service # buildkit          40.9MB    buildkit.dockerfile.v0
<missing>      46 minutes ago   RUN |1 SERVICE=user /bin/sh -c apk add --no-…   1.01MB    buildkit.dockerfile.v0
<missing>      46 minutes ago   ENV TZ=Asia/Shanghai                            0B        buildkit.dockerfile.v0
<missing>      46 minutes ago   ARG SERVICE=user                                0B        buildkit.dockerfile.v0
<missing>      2 months ago     CMD ["/bin/sh"]                                 0B        buildkit.dockerfile.v0
<missing>      2 months ago     ADD alpine-minirootfs-3.21.3-x86_64.tar.gz /…   7.83MB    buildkit.dockerfile.v0

优化后二进制文件大小: 28.1MB

docker history ccr.ccs.tencentyun.com/sumery/user:95d6205
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
4876b595bf30   55 seconds ago   ENTRYPOINT ["/app/service"]                     0B        buildkit.dockerfile.v0
<missing>      55 seconds ago   EXPOSE map[30003/tcp:{} 30004/tcp:{}]           0B        buildkit.dockerfile.v0
<missing>      55 seconds ago   COPY /app/user /app/service # buildkit          28.1MB    buildkit.dockerfile.v0
<missing>      48 minutes ago   RUN |1 SERVICE=user /bin/sh -c apk add --no-…   1.01MB    buildkit.dockerfile.v0
<missing>      48 minutes ago   ENV TZ=Asia/Shanghai                            0B        buildkit.dockerfile.v0
<missing>      48 minutes ago   ARG SERVICE=user                                0B        buildkit.dockerfile.v0
<missing>      2 months ago     CMD ["/bin/sh"]                                 0B        buildkit.dockerfile.v0
<missing>      2 months ago     ADD alpine-minirootfs-3.21.3-x86_64.tar.gz /…   7.83MB    buildkit.dockerfile.v0