常规构建
一般情况下,我们的Dockerfile可能是下面这样的
- 这个Dockerfile使用了多步构建,使用golang:1.19.4作为构建容器,二进制文件构建成功后,单独把文件复制到alpine镜像。
- 这样做的好处是最后产出的镜像非常小,一般只有十几MB的样子,如果直接使用golang的镜像来构建,镜像体积就可能达到1G左右。
FROM golang:1.19.4 as builder
ENV GO111MODULE=on GOPROXY=https://goproxy.cn,direct
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o run .
FROM alpine:3.14.2
WORKDIR /app
COPY encdec run.sh /app/
COPY --from=builder /app/run .
EXPOSE 3000
ENTRYPOINT ["/app/run"]
依赖libpcap的构建
如果使用了程序使用了libpcap 来抓包,那么除了我们自己代码产生的二进制文件外,可能还会依赖libpcap的文件。常规打包就会报各种错误,例如文件找不到,缺少so文件等等。
libpcap是一个c库,并不是golang的代码,所以处理起来要不一样。
下面直接给出Dockerfile
# 构建的基础镜像换成了alpine镜像
FROM golang:alpine as builder
# 将alpine镜像换清华源,这样后续依赖的安装会加快
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
# 安装需要用到的C库,和构建依赖
RUN apk --update add linux-headers musl-dev gcc libpcap-dev
# 使用国内的goproxy
ENV GO111MODULE=on GOPROXY=https://goproxy.cn,direct
# 设置工作目录
WORKDIR /app
# 拷贝go相关的依赖
COPY go.mod go.sum ./
# 下载go相关的依赖
RUN go mod download
# 复制go代码
COPY . .
# 编译go代码
RUN CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -a --ldflags '-linkmode external -extldflags "-static -s -w"' -o run main.go
# 使用最小的scratch镜像
FROM scratch
# 设置工作目录
WORKDIR /app
# 拷贝二进制文件
COPY --from=builder /app/run .
EXPOSE 8086
ENTRYPOINT ["/app/run"]
整个Dockerfile比较好理解,重要的部分就是ldflags的参数了,下面着重讲解一下
--ldflags '-linkmode external -extldflags "-static -s -w"'
这个 go build
命令包含以下参数:
-a
:强制重新编译所有的包,即使它们已经是最新的。这个选项通常用于强制更新依赖包或者重建整个程序。--ldflags
:设置链接器选项,这个选项后面的参数会被传递给链接器。-linkmode external
:指定链接模式为 external,即使用外部链接器。-extldflags "-static -s -w"
:传递给外部链接器的选项,其中包含了-static
(强制使用静态链接)、-s
(禁止符号表和调试信息生成)和-w
(禁止 DWARF 调试信息生成)三个选项。
这个命令的目的是生成一个静态链接的可执行文件,其中所有的依赖包都被链接进了最终的二进制文件中,这样可以保证可执行文件的可移植性和兼容性,同时也可以减小文件大小。这个命令的缺点是编译时间较长,特别是在包数量较多的情况下,因为它需要重新编译所有的包,即使它们已经是最新的。