极致优化大小
缓存挂载
编译指定服务(注意路径调整)
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:nonrootalpine: 3.21 MB
docker pull alpine:latestCompose
在 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.21FROM --platform=$BUILDPLATFORM ${GO_IMAGE} AS compile
ARG TARGETOS=linuxARG TARGETARCHARG SERVICEARG VERSION=devARG GOPROXY=https://goproxy.cn,directARG 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 finalCOPY --from=compile /app/$SERVICE /app/serviceENTRYPOINT ["/app/service"]保守方案: 增加几 MB 大小, 最终镜像使用持续维护的alpine:
ARG GO_IMAGE=golang:1.24.2-alpine3.21FROM --platform=$BUILDPLATFORM ${GO_IMAGE} AS compile
ARG TARGETOS=linuxARG TARGETARCHARG SERVICEARG VERSION=devARG GOPROXY=https://goproxy.cn,directARG 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 SERVICEENV 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 COMMENTbdd19af5b498 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:95d6205IMAGE CREATED CREATED BY SIZE COMMENT4876b595bf30 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