创建最小的Go docker 镜像
source link: http://colobu.com/2018/08/13/create-minimal-docker-image-for-go-applications/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
虽然曾有一些文章介绍了如何创建一个最小的Go Docker镜像,我也曾写过一篇文章,但是随着Go的新的版本的发布, 以及docker本身的进化,有些技巧已经发生了变化, 本文介绍了最新的创建超小的Go镜像的方法。
一个简单Go程序的镜像
首先让我们创建一个很简单的Go程序:
package main import "fmt" func main() { fmt.Println("hello world") }
运行下面的命令会创建一个超小的镜像, 这是我们的 第一种 方式:
GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go && tar c app | docker import - app:latest
下一节介绍其中的编译参数
查看镜像, 生成的镜像只有 1.21MB
:
# docker images app REPOSITORY TAG IMAGE ID CREATED SIZE app latest b716e13758cd 11 seconds ago 1.21MB
这命令将编译、打包、输入镜像集成到一条命令了。
第二种方式是使用一个Dockerfile文件:
FROM scratch ADD app / CMD ["/app"]
运行下面的命令创建一个镜像:
docker build -t app2 .
查看生成的镜像, 也是 1.21MB
:
# docker images app2 REPOSITORY TAG IMAGE ID CREATED SIZE app2 latest 4e2af2ffb695 4 seconds ago 1.21MB
第三种方式是利用Docker的 multistage 功能,在镜像中编译,Dockerfile文件:
1
docker build -t app3 -f Dockerfile.multistage .
查看生成的镜像, 也是``:
# docker images app3 REPOSITORY TAG IMAGE ID CREATED SIZE app3 latest 9177859dad64 16 seconds ago 1.21MB
你可以结合你的情况选择一种生成镜像的方式。
编译Go程序
上面的例子中我们使用下面的命令编译Go程序:
GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go
你可能在其它一些文章中还看到 installsuffix
参数:
GOOS=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的net:
go build -tags netgo -a -v
-
使用基础镜像加glibc(或等价库musl、uclibc), 比如 busybox:glibc
、alpine +
RUN apk add --no-cache libc6-compat
、 frolvlad/alpine-glibc
基础镜像
其实前面已经列出了一些常用的基础镜像:
- scratch: 空的基础镜像,最小的基础镜像
- busybox: 带一些常用的工具,方便调试, 以及它的一些扩展busybox:glibc
- alpine: 另一个常用的基础镜像,带包管理功能,方便下载其它依赖的包
显然。 你应该只在编译阶段使用 Go的镜像 ,这样才能将你的镜像减小到最小。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK