环境:go1.10
结果:镜像从200m瘦身到10.2m,上传到harbor后是3.5m。下图是上传到harbor的,也就是压缩后的。
总的思路:
1、瘦镜像。这个好说,换个小点的镜像就行。
2、瘦go。这个需要对go的编译过程有些了解。
服务容器化,用docker和go是最合适的。go可以静态编译好之后只把二进制文件上传到镜像便可提供服务,实现了“一次编译,处处运行”。
从网上拉了一个centos的镜像,上传完二进制文件后,打包一看700m+,太大了。
后来了解到一个scratch的空镜像,啥都没有,包括各种命令,都没有,只有最基本的内核包。是一个纯粹的“平台”,这对于go来说最好不过了,只在纯粹的平台上提供纯粹的微服务,过着纯粹的生活。
分别生成个名为foo和foo_total_static的二进制文件。
分别 ldd foo 和 ldd foo_total_static 会分别输出如下:
$ ldd foo
linux-vdso.so.1 => (0x00007ffc95fde000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fd150f27000)
libc.so.6 => /lib64/libc.so.6 (0x00007fd150b93000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd151156000)
$ ldd foo_total_static
not a dynamic executable
什么意思,ldd是查看程序所用到的动态库的命令。由此可以看出,go的build这个命令默认编译出来的foo并不是完全静态编译的,它还是需要那些动态库的;而“CGO_ENABLED=0 go build -a -ldflags '-s -w' -o foo_total_static main.go”命令,首先上来把cgo ban掉(至少我的程序里是没用到cgo的,所以我要ban掉,),然后执行了 go build -a -ldflags '-s -w',这个命令的参数的意思是:-a就是重新构建代码包(我个人感觉可能是“强刷ctrl+f5”的感觉,因为我发现-n的时候,有的编译过程会直接去~/.cache/go-build目录下找所引用到的,有待探索)。其次参数-ldflags '-s -w'的意思是,首先ldflags是用于给编译时候传参数的,这里传的是-s和-w,意思是去掉debug的信息,减少文件的冗余数据(效果还是很明显的)。
对于我们docker的scratch镜像来说,我们只需要最小能提供服务的环境需要,而且容器只用来提供服务,不在上面操作什么,所以把此时生成的二进制包打包进scratch并tag版本,上传到公司的hub。
本文只是一个“瘦身”的实践,理论部分,原理部分可以自己搜。
参考:
这篇白大的文章很不错,深度好文。也谈Go的可移植性
这篇英文的,看看前面那部分,讲build的几个参数,包括-w和-extldflags "-static"。On Golang, “static” binaries, cross-compiling and plugins
这个是一些go build的参数,可能还有能“瘦身”的命令,只是我还不知道。Compile packages and dependencies
这个是对ldflags命令的一个生动的例子。Setting Go variables from the outside
这个是stackoverflow的提问,关于-w的用途。Avoid debugging information on golang
这个是官方的ldflags的参数。command line
这个是帮助“瘦身”的方法,可以看看。Shrink your Go binaries with this one weird trick
这个文章是最开始的时候受的启发,很感谢。What is a Docker container?
这个csdn的提问也可以看一下。给golang程序进行一次廋身