常用做法
基于 golang 官方基础镜像打包,Dockerfile如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# 基于 golang 官方基础镜像打包
FROM golang:1.12
NV GO111MODULE=on \
GOPROXY=https://goproxy.cn,direct
WORKDIR /app
COPY . .
RUN go build .
EXPOSE 10010
ENTRYPOINT ["./app"]
但是最终 docker build 出来的镜像高达300多M, 这是由于 golang 这个基础镜像中的工具链及其依赖项(git,mercurial 等)重达几百MB,而这一部分我们在运行的时候是不需要的。
因此,我们需要对基础镜像进行精简。
精简镜像
使用 scratch
该镜像是一个空的镜像,可以用于构建 busybox 等超小镜像,可以说是真正的从零开始构建属于自己的镜像。在此基础镜像上运行的应用程序只能访问内核,尽管Go宣称自己只需要Linux内核,但是我们在真实的项目中或多或少会有其他依赖项,比如 我们项目会用到 CGO 等等。所以在构建 Golang 项目是,一般不建议直接采用 scratch 做基础镜像,否则你需要在 Dockerfile 中手动加载很多依赖项。
1 | # 基于 scratch 官方基础镜像打包 |
使用 alpine
Alpine 操作系统是一个面向安全的轻型 Linux 发行版。它不同于通常 Linux 发行版,alpine 采用了 musl libc 和 busybox 以减小系统的体积和运行时资源消耗,但功能上比 busybox 又完善的多,因此得到开源社区越来越多的青睐。
Alpine Docker 镜像也继承了 Alpine Linux 发行版的这些优势。相比于其他 Docker 镜像,它的容量非常小,仅仅只有 5 MB 左右(对比 Ubuntu 系列镜像接近 200 MB),且拥有非常友好的包管理机制。官方镜像来自 docker-alpine 项目。目前 Docker 官方已开始推荐使用 Alpine 替代之前的 Ubuntu 做为基础镜像环境。
Alpine 和其他通用 Linux 发行版对于 Golang 编译出来的可执行文件要求有所不同,Alpine 要求可执行文件必须是静态链接的可执行文件。所以在编译 Golang 时需要添加 -tags netgo ,来生成静态链接的可执行文件。
1 | # 基于 alpine 官方基础镜像打包 |
但是对 C 的支持不太好。
在 Alpine Docker 镜像上运行 cgo 项目会出现问题,提示一下问题:1
panic: standard_init_linux.go:175: exec user process caused "no such file or directory"
原因是当 cgo 开启时,默认是按照动态库的方式来链接 so 文件的,但 alpine 只支持静态链接,所以会出错。
解决方案有两种:
通过设置 CGO_ENABLED=0 来解决,此时 cgo 也不可用了
调用 go build –ldflags “-extldflags -static” ,来让gcc使用静态编译可以解决问题
使用 ubuntu
ubuntu 镜像
1 | # 基于 ubuntu 官方基础镜像打包 |
最佳实践
多层构建方式
FROM golang:1.12
用对go功能比较齐全镜像编译源程序,生成可执行文件
FROM ubuntu
用精简镜像作为最终的容器的镜像
拷贝可执行文件到容器内
打包生成最终的镜像
Dockerfile:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31# 打包依赖阶段使用golang作为基础镜像
FROM golang:1.12 as builder
LABEL version="1.0" description="xiaolong.li" by="xiaolonghuster"
# 启用go module
ENV GO111MODULE=on \
GOPROXY=https://goproxy.cn,direct
WORKDIR /app-pkg
COPY . /app-pkg
# 指定OS等,并go build
RUN GOOS=linux GOARCH=amd64 && cd src && go build -o app main.go
# 由于不止依赖二进制文件,还依赖conf文件夹下的配置文件,将这些文件放到了publish文件夹
RUN mkdir publish && cp src/app publish && \
cp -r conf publish
# 运行阶段为精简镜像包,指定ubuntu作为基础镜像
FROM ubuntu
WORKDIR /app
# 将上一个阶段publish文件夹下的所有文件复制进来
COPY --from=builder /app-pkg/publish .
EXPOSE 10086
ENTRYPOINT ["./app"]