原文作者:smallnest
虽然曾有一些文章介绍了如何创建一个最小的Go Docker镜像,我也曾写过一篇文章,但是随着Go的新的版本的发布, 以及docker本身的进化,有些技巧已经发生了变化, 本文介绍了最新的创建超小的Go镜像的方法。
首先让我们创建一个很简单的Go程序:
1package main
2import "fmt"
3func main() {
4 fmt.Println("hello world")
5}
运行下面的命令会创建一个超小的镜像, 这是我们的第一种方式:
1GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go && tar c app | docker import - app:latest
下一节介绍其中的编译参数
查看镜像, 生成的镜像只有 1.21MB
:
1# docker images app
2REPOSITORY TAG IMAGE ID CREATED SIZE
3app latest b716e13758cd 11 seconds ago 1.21MB
这命令将编译、打包、输入镜像集成到一条命令了。
第二种方式是使用一个Dockerfile文件:
1FROM scratch
2ADD app /
3CMD ["/app"]
运行下面的命令创建一个镜像:
1docker build -t app2 .
查看生成的镜像, 也是 1.21MB
:
1# docker images app2
2REPOSITORY TAG IMAGE ID CREATED SIZE
3app2 latest 4e2af2ffb695 4 seconds ago 1.21MB
第三种方式是利用Docker的 multistage 功能,在镜像中编译,Dockerfile文件:
1Dockerfile.multistage
2docker build -t app3 -f Dockerfile.multistage .
查看生成的镜像, 也是``:
1# docker images app3
2REPOSITORY TAG IMAGE ID CREATED SIZE
3app3 latest 9177859dad64 16 seconds ago 1.21MB
你可以结合你的情况选择一种生成镜像的方式。
上面的例子中我们使用下面的命令编译Go程序:
1GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go
你可能在其它一些文章中还看到installsuffix
参数:
1GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -installsuffix cgo -o app app.go
自Go 1.10以后,你不必再使用installsuffix
参数(或许更早的版本),Go的核心开发人员Ian Lance Taylor已经确认了这一点。
你可能有人还使用-a
参数,它强制重新编译相关的包,一般你不会使用它。
-s
忽略符号表和调试信息,-w
忽略DWARF符号表,通过这两个参数,可以进一步减少编译的程序的尺寸,更多的参数可以参考go link, 或者 go tool link -help
(另一个有用的命令是go tool compile -help
)。
你也可以使用strip
工具对编译的Go程序进行裁剪。
本身Go是静态编译的, 对于CGO, 如果设置CGO_ENABLED=0
,则完全静态编译,不会再依赖动态库。
如果设置CGO_ENABLED=0
,并且你的代码中使用了标准库的net
包的话,有可能编译好的镜像无法运行,报sh: /app: not found
的错误,尽管/app
这个文件实际存在,并且如果讲基础镜像换为centos
或者ubuntu
的话就能执行。这是一个奇怪的错误,原因在于:
默认情况下net
包会使用静态链接库, 比如libc
知道了原因,解决办法也很简单,就是完全静态链接或者在基础镜像中加入libc库。
下面是几种解决办法:
CGO_ENABLED=0
go build -tags netgo -a -v
RUN apk add --no-cache libc6-compat
、frolvlad/alpine-glibc有的同学说了,我代码中确实必须使用CGO,因为需要依赖一些C/C++的库。目前没有对应的Go库可替代, 那么可以使用-extldflags "-static"
,go tool link help
介绍了extldflags
的功能:
-extldflags flags Set space-separated flags to pass to the external linker. -static means do not link against shared libraries
其实前面已经列出了一些常用的基础镜像:
显然。 你应该只在编译阶段使用Go的镜像,这样才能将你的镜像减小到最小。
版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。