极致优化大小
缓存挂载
编译指定服务(注意路径调整)
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