将Go程序打包成Docker镜像
1、Go程序
hello.go
文件的内容:
package main
import "fmt"
func main() {
fmt.Println("hello world!")
}
2、编写Dockerfile文件
FROM golang:alpine
WORKDIR /build
COPY hello.go .
RUN go build -o hello hello.go
CMD ["./hello"]
3、生成镜像
$ docker build -t hello:v1 .
Sending build context to Docker daemon 4.096kB
Step 1/5 : FROM golang:alpine
---> 9e57a8e81959
Step 2/5 : WORKDIR /build
---> Running in 8f2b5f3a7a67
Removing intermediate container 8f2b5f3a7a67
---> 5eec1827e58b
Step 3/5 : COPY hello.go .
---> 40fa3fb77c75
Step 4/5 : RUN go build -o hello hello.go
---> Running in 6be6b967a873
Removing intermediate container 6be6b967a873
---> ae169d199066
Step 5/5 : CMD ["./hello"]
---> Running in b62da09aad56
Removing intermediate container b62da09aad56
---> 68296087b8d0
Successfully built 68296087b8d0
Successfully tagged hello:v1
查看构建过程:
$ docker history hello:v1
IMAGE CREATED CREATED BY SIZE COMMENT
68296087b8d0 18 minutes ago /bin/sh -c #(nop) CMD ["./hello"] 0B
ae169d199066 18 minutes ago /bin/sh -c go build -o hello hello.go 26.5MB
40fa3fb77c75 19 minutes ago /bin/sh -c #(nop) COPY file:72d9bcc020ef9348… 76B
5eec1827e58b 19 minutes ago /bin/sh -c #(nop) WORKDIR /build 0B
9e57a8e81959 12 days ago /bin/sh -c #(nop) WORKDIR /go 0B
<missing> 12 days ago /bin/sh -c mkdir -p "$GOPATH/src" "$GOPATH/b… 0B
<missing> 12 days ago /bin/sh -c #(nop) ENV PATH=/go/bin:/usr/loc… 0B
<missing> 12 days ago /bin/sh -c #(nop) ENV GOPATH=/go 0B
<missing> 12 days ago /bin/sh -c set -eux; apk add --no-cache --v… 247MB
<missing> 12 days ago /bin/sh -c #(nop) ENV GOLANG_VERSION=1.20.5 0B
<missing> 12 days ago /bin/sh -c #(nop) ENV PATH=/usr/local/go/bi… 0B
<missing> 12 days ago /bin/sh -c apk add --no-cache ca-certificates 516kB
<missing> 12 days ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 12 days ago /bin/sh -c #(nop) ADD file:1da756d12551a0e3e… 7.33MB
主要是:
/bin/sh -c go build -o hello hello.go
/bin/sh -c set -eux; apk add --no-cache
这两个过程比较占用空间。
4、查看镜像
# 发现镜像占用空间218M
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello v1 68296087b8d0 3 seconds ago 281MB
golang alpine 9e57a8e81959 12 days ago 254MB
5、运行
$ docker run -it hello:v1
hello world!
$ docker run -it hello:v1 ls -l /build
total 1812
-rwxr-xr-x 1 root root 1847520 Jun 27 07:59 hello
-rw-r--r-- 1 root root 76 Jun 27 07:31 hello.go
我们生成的镜像运行没有问题,只是生成的镜像占用空间比较大。
我们可以尝试先将 hello.go 进行编译,然后再拷贝进去。
6、重新构造镜像
# 提前编译好go文件
$ go build hello.go
# 这里我们不在需要编译go文件,因此将golang:alpine换为alpine
FROM alpine
WORKDIR /build
COPY hello .
CMD ["./hello"]
# 此次生成镜像速度特别快
$ docker build -t hello:v2 .
Sending build context to Docker daemon 1.943MB
Step 1/4 : FROM alpine
---> c1aabb73d233
Step 2/4 : WORKDIR /build
---> Running in 29fecf779165
Removing intermediate container 29fecf779165
---> 45f7c46a90af
Step 3/4 : COPY hello .
---> 48b0b089166a
Step 4/4 : CMD ["./hello"]
---> Running in 1a97a57604e1
Removing intermediate container 1a97a57604e1
---> aadbd54c2f2d
Successfully built aadbd54c2f2d
Successfully tagged hello:v2
发现重新生成的镜像所占用的空间变小了。
# 生成的镜像的大小只有9.27MB
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello v2 aadbd54c2f2d 40 seconds ago 9.27MB
hello v1 68296087b8d0 35 minutes ago 281MB
golang alpine 9e57a8e81959 12 days ago 254MB
alpine latest c1aabb73d233 12 days ago 7.33MB
查看生成过程:
$ docker history hello:v2
IMAGE CREATED CREATED BY SIZE COMMENT
aadbd54c2f2d About a minute ago /bin/sh -c #(nop) CMD ["./hello"] 0B
48b0b089166a About a minute ago /bin/sh -c #(nop) COPY file:705516e6f5c7bf5e… 1.94MB
45f7c46a90af About a minute ago /bin/sh -c #(nop) WORKDIR /build 0B
c1aabb73d233 12 days ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 12 days ago /bin/sh -c #(nop) ADD file:1da756d12551a0e3e… 7.33MB
运行:
$ docker run -it hello:v2
$ docker run -it hello:v2 ls -l /build
total 1896
-rwxr-xr-x 1 root root 1937447 Jun 27 08:12 hello
综合上面的两个步骤我可以写出一个完整的Dockerfile。
7、综合Dockerfile
# 第一步编译go文件
FROM golang:alpine AS builder
WORKDIR /build
ADD go.mod .
COPY . .
RUN go build -o hello hello.go
# 第二步部生成镜像
FROM alpine
WORKDIR /build
COPY --from=builder /build/hello /build/hello
CMD ["./hello"]
生成:
$ docker build -t hello:v3 .
Sending build context to Docker daemon 1.943MB
Step 1/9 : FROM golang:alpine AS builder
---> 9e57a8e81959
Step 2/9 : WORKDIR /build
---> Using cache
---> 5eec1827e58b
Step 3/9 : ADD go.mod .
---> d59e6bcf895e
Step 4/9 : COPY . .
---> 44cbf7b9c5b6
Step 5/9 : RUN go build -o hello hello.go
---> Running in 27ecc4c5e2d7
Removing intermediate container 27ecc4c5e2d7
---> b2313317a6d1
Step 6/9 : FROM alpine
---> c1aabb73d233
Step 7/9 : WORKDIR /build
---> Using cache
---> 45f7c46a90af
Step 8/9 : COPY --from=builder /build/hello /build/hello
---> 58a1c5d9a53d
Step 9/9 : CMD ["./hello"]
---> Running in 9027de2e8dbc
Removing intermediate container 9027de2e8dbc
---> 2313f46cff16
Successfully built 2313f46cff16
Successfully tagged hello:v3
查看生成的镜像:
# 这里会生成一个中间镜像,如果不想要这个中间镜像,可以在build的时候添加参数--rm
# docker build -t hello:v3 --rm .
# 如果编译和平台相关的可以添加参数--platform linux/amd64
# docker build -t hello:v3 --rm --platform linux/amd64 .
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello v3 2313f46cff16 30 seconds ago 9.18MB
<none> <none> b2313317a6d1 31 seconds ago 283MB
hello v2 aadbd54c2f2d 6 minutes ago 9.27MB
hello v1 68296087b8d0 41 minutes ago 281MB
golang alpine 9e57a8e81959 12 days ago 254MB
alpine latest c1aabb73d233 12 days ago 7.33MB
查看生成过程:
$ docker history hello:v3
IMAGE CREATED CREATED BY SIZE COMMENT
2313f46cff16 About a minute ago /bin/sh -c #(nop) CMD ["./hello"] 0B
58a1c5d9a53d About a minute ago /bin/sh -c #(nop) COPY file:4d5797c47f0fede3… 1.85MB
45f7c46a90af 6 minutes ago /bin/sh -c #(nop) WORKDIR /build 0B
c1aabb73d233 12 days ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 12 days ago /bin/sh -c #(nop) ADD file:1da756d12551a0e3e… 7.33MB
运行:
$ docker run -it hello:v3
hello world!
$[root@omdev om]# docker run -it hello:v3 ls -l /build
total 1808
-rwxr-xr-x 1 root root 1847520 Jun 27 08:40 hello
关于多步构建镜像请参考:
https://docs.docker.com/build/building/multi-stage/
8、go工具生成Dockerfile
# 安装
$ go install github.com/zeromicro/go-zero/tools/goctl@latest
# 生成dockerfile
$ goctl docker -go hello.go
Done.
查看生成的内容:
FROM golang:alpine AS builder
LABEL stage=gobuilder
ENV CGO_ENABLED 0
ENV GOPROXY https://goproxy.cn,direct
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk update --no-cache && apk add --no-cache tzdata
WORKDIR /build
ADD go.mod .
ADD go.sum .
RUN go mod download
COPY . .
RUN go build -ldflags="-s -w" -o /app/hello hello.go
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
ENV TZ Asia/Shanghai
WORKDIR /app
COPY --from=builder /app/hello /app/hello
CMD ["./hello"]
- 默认禁用了 cgo
- 启用了 GOPROXY 加速 go mod download
- 去掉了调试信息
-ldflags="-s -w"
以减小镜像尺寸 - 安装了 ca-certificates,这样使用 TLS 证书就没问题了
- tzdata 在 builder 镜像安装,并在最终镜像只拷贝了需要的时区
- 自动设置了本地时区,这样我们在日志里看到的是北京时间了
如果缺 go.sum 文件则新建一个即可。
生成镜像:
docker build -t hello:v4 .
Sending build context to Docker daemon 5.12kB
Step 1/19 : FROM golang:alpine AS builder
---> 9e57a8e81959
Step 2/19 : LABEL stage=gobuilder
---> Running in 6cd172282921
Removing intermediate container 6cd172282921
---> 115f5d1cdcf9
Step 3/19 : ENV CGO_ENABLED 0
---> Running in 07038c7d7de2
Removing intermediate container 07038c7d7de2
---> 389710709d4d
Step 4/19 : ENV GOPROXY https://goproxy.cn,direct
---> Running in 2973c66264f1
Removing intermediate container 2973c66264f1
---> 9686c8997bfa
Step 5/19 : RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
---> Running in 10dd563aa985
Removing intermediate container 10dd563aa985
---> c64df5014c82
Step 6/19 : RUN apk update --no-cache && apk add --no-cache tzdata
---> Running in f1711c396d56
fetch https://mirrors.aliyun.com/alpine/v3.18/main/x86_64/APKINDEX.tar.gz
fetch https://mirrors.aliyun.com/alpine/v3.18/community/x86_64/APKINDEX.tar.gz
v3.18.2-172-g9cc21627ccc [https://mirrors.aliyun.com/alpine/v3.18/main]
v3.18.2-175-g8680db500bf [https://mirrors.aliyun.com/alpine/v3.18/community]
OK: 20062 distinct packages available
fetch https://mirrors.aliyun.com/alpine/v3.18/main/x86_64/APKINDEX.tar.gz
fetch https://mirrors.aliyun.com/alpine/v3.18/community/x86_64/APKINDEX.tar.gz
(1/1) Installing tzdata (2023c-r1)
OK: 11 MiB in 17 packages
Removing intermediate container f1711c396d56
---> 65159ffacc89
Step 7/19 : WORKDIR /build
---> Running in 87ce395807d7
Removing intermediate container 87ce395807d7
---> 246414a07ddf
Step 8/19 : ADD go.mod .
---> f7458fabf27d
Step 9/19 : ADD go.sum .
---> baba6bcce93f
Step 10/19 : RUN go mod download
---> Running in 6fc5c82c0e59
go: no module dependencies to download
Removing intermediate container 6fc5c82c0e59
---> 8efabaedc150
Step 11/19 : COPY . .
---> 3a03d14c48ba
Step 12/19 : RUN go build -ldflags="-s -w" -o /app/hello hello.go
---> Running in f91a7d951206
Removing intermediate container f91a7d951206
---> e0fb09ae5bdf
Step 13/19 : FROM scratch
--->
Step 14/19 : COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
---> 39c3a35c7da3
Step 15/19 : COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
---> 2ca366a09bfc
Step 16/19 : ENV TZ Asia/Shanghai
---> Running in 4ef75e26b3d3
Removing intermediate container 4ef75e26b3d3
---> 07e58484ab0c
Step 17/19 : WORKDIR /app
---> Running in 76de31d5eeca
Removing intermediate container 76de31d5eeca
---> 14a13570ccaf
Step 18/19 : COPY --from=builder /app/hello /app/hello
---> 36a202422d79
Step 19/19 : CMD ["./hello"]
---> Running in 1fbac50eb0aa
Removing intermediate container 1fbac50eb0aa
---> 50943134a8b0
Successfully built 50943134a8b0
Successfully tagged hello:v4
查看生成的镜像:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello v4 50943134a8b0 50 seconds ago 1.44MB
<none> <none> e0fb09ae5bdf 52 seconds ago 281MB
hello v3 2313f46cff16 13 minutes ago 9.18MB
<none> <none> b2313317a6d1 13 minutes ago 283MB
hello v2 aadbd54c2f2d 19 minutes ago 9.27MB
hello v1 68296087b8d0 54 minutes ago 281MB
golang alpine 9e57a8e81959 12 days ago 254MB
alpine latest c1aabb73d233 12 days ago 7.33MB
这里生成的镜像更小。
查看生成过程:
$ docker history hello:v4
IMAGE CREATED CREATED BY SIZE COMMENT
50943134a8b0 About a minute ago /bin/sh -c #(nop) CMD ["./hello"] 0B
36a202422d79 About a minute ago /bin/sh -c #(nop) COPY file:19d791be1a41b87f… 1.23MB
14a13570ccaf About a minute ago /bin/sh -c #(nop) WORKDIR /app 0B
07e58484ab0c About a minute ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
2ca366a09bfc About a minute ago /bin/sh -c #(nop) COPY file:9b62331971fdb1f9… 561B
39c3a35c7da3 About a minute ago /bin/sh -c #(nop) COPY file:cee95daa6036230f… 215kB
运行:
$ docker run -it hello:v4
hello world!