docker 镜像拉取下来一看近一个G实在不能忍受,所以要减肥。
首先来个配置一个docker国内镜像代理。
Dockerfile 文件:
FROM golang:alpine AS builder
WORKDIR $GOPATH/src/docker_package/builder/
COPY . .
# 获取改项目所要依赖的包文件 合并多个RUN
# RUN go get -d -v xxxx.xxx.xxx
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -ldflags="-w -s" -o hello
FROM alpine:latest AS production
WORKDIR /root/
COPY --from=builder /go/src/docker_package/builder/hello .
EXPOSE 8081
CMD ["./hello"]
瘦身文件说明:
1. 使用更小的基础镜像
常用的Linux系统基础镜像有Debian、Ubuntu、CentOS和Alpine等,其中Alpine是面向安全的轻量级Linux发行版。在这些镜像中,Debian和Alpine镜像只有不到5M的大小,而其他镜像则是几十MB的大小。因此,Alpine非常适用做基础镜像。
使用基于Linux alpine 打好的 golang 镜像
- alpine 是Linux 发型稳定版中最小的的系统推荐使用。
- AS 将镜像另为别名的作用,下面好用
2. go build 打包避免交叉编译
- CGO_ENABLED=0 用于标识(声明) cgo 工具是否可用。
存在交叉编译的情况时,cgo 工具是不可用的
CGO_ENABLED=0的意思是使用C语言版本的GO编译器,参数配置为0的时候就关闭C语言版本的编译器了。自从golang1.5以后go就使用go语言编译器进行编译了。在golang1.9当中没有使用CGO_ENABLED参数发现依然可以正常编译。当然使用了也可以正常编译。比如把CGO_ENABLED参数设置成1,即在编译的过程当中使用CGO编译器,我发现依然是可以正常编译的。
实际上如果在go当中使用了C的库,比如import “C”默认使用go build的时候就会启动CGO编译器,当然我们可以使用CGO_ENABLED=0来控制go build是否使用CGO编译器。
- -a 强制重新编译
简单来说,就是不利用缓存或已编译好的部分文件,直接所有包都是最新的代码重新编译和关联 - -installsuffix cgo 在软件包安装的目录中增加后缀标识,以保持输出与默认版本分开 - -ldflags=“-w -s” 设置编译参数
arguments to pass on each go tool link invocation
-w为去掉调试信息(无法使用gdb调试),-s为去掉符号表。 为了安全起见防止别人debug你的程序。
- -o 打包为 可以直接写 xxx/xxx/name 也可以只写 name
3. 压缩RUN语句&清理多余垃圾
在该文件中 RUN 语言只有一个,但是放开注释的那个RUN 就有多个。 因为 Docker 镜像是分层的,Dockerfile中的每一条RUN语句都会增加一层镜像,导致镜像非常臃肿。多个RUN命令应尽量用一条RUN命令完成,用“&&”和“\”串联每一条命令。如下:
RUN go get -d -v xxxx.xxx.xxx && \
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -ldflags="-w -s" -o hello
4. 多阶段打包
从 Docker 17.05 开始,一个Dockerfile文件可以使用多条FROM语句,每条FROM语句可以使用不同的镜像。这样我们可以把Docker的构建阶段分层多个阶段,以两个FROM语句为例,我们可以使用一个镜像编译我们的程序;另一个镜像使用更精简的镜像,拷贝上一阶段的编译的结果。
内容中有两个 FROM 为多阶段打包镜像可减少镜像体积,第一个builder可作为第二个的基础包执行。
在使用FROM语句时,我们可以用AS为不同的镜像起别名,方便后续操作。用COPY命令从其他镜像拷贝文件时,我们可以用–from=alias src dst从别的阶段复制文件;如果没有为镜像起别名,第一个镜像的ID为0,第二个为1,我们可以用ID从别的阶段拷贝文件,–from=0 src dst
最后打出的镜像只有11M:
参考文章