跳到主要内容

极致优化大小

缓存挂载

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

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