Golang容器化部署最佳实践优质
# 前言
相较于Java而言,Golang本身可以直接打包为各个平台的二进制文件,并不需要安装环境,所以直接采用虚拟机的方式部署也是非常方便的。
但是如今云原生时代,部署并不仅仅是跑起来这么简单,还包括动态扩缩容、状态监控、资源管控等能力,容器化基本上是最佳选择。
本文主要总结了Golang打包Docker的最佳实践,拥有非常小的体积,并且可以用于生产环境。
# 一、最佳实践
话不多说,先上可用域生产环境使用的Dockerfile文件:
FROM golang:1.19-alpine3.16 AS builder
#更新Alpine的软件源为国内源,提高下载速度
RUN echo "https://mirror.tuna.tsinghua.edu.cn/alpine/v3.16/main/" > /etc/apk/repositories
RUN apk add --no-cache tzdata
WORKDIR /build
RUN adduser -u 10001 -D app-runner
ENV GOPROXY https://goproxy.cn
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -a -o httpserver .
FROM alpine:3.16 AS final
WORKDIR /app
COPY /build/httpserver /app/
#COPY --from=builder /build/config /app/config
COPY /etc/passwd /etc/passwd
COPY /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
# 设置时区
ENV TZ Asia/Shanghai
COPY /usr/share/zoneinfo/${TZ} /usr/share/zoneinfo/${TZ}
USER app-runner
ENTRYPOINT ["/app/httpserver"]
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
提示
我们实际上使用的是分阶段打包镜像
其实我们也可以先打包为Linux二进制文件,Dockerfile只把二进制文件COPY到镜像,但是这种方式打包环境和容器基础镜像提供的环境有所不同,而且还要首先安装golang环境,所以并不推荐采用这种方式。
# 二、讲解
- Golang运行只需要Linux内核
- Docker分阶段构建
- 使用最小镜像alpha
# 2.1 添加时区
aplha镜像默认时区是UTC,如果我们需要改为中国的时区,需要安装tzdata
为了加速流水线下载速度,我添加镜像加速地址:
RUN echo "https://mirror.tuna.tsinghua.edu.cn/alpine/v3.16/main/" > /etc/apk/repositories
然后执行alpha镜像的安装命令:
RUN apk add --no-cache tzdata
由于我们是在第一阶段的构建镜像中安装的时区,我们在第二阶段构建最终竟像时,需要把安装好的时区拷贝过去:
ENV TZ Asia/Shanghai
COPY --from=builder /usr/share/zoneinfo/${TZ} /usr/share/zoneinfo/${TZ}
2
我们通过ENV TZ的方式声明我们使用上海的时区,也就是北京时间了
# 2.2 服务名
我们上面打包golang的二进制名字为httpserver,并且启动命令也是httpserver,我们实际上可以通过哦ARG命令把该名字传入进来
使用具体的具备业务含义的名字,这样的好处是查询对应的进程信息时,方便区分不同的服务容器
# 2.3 运行权限
USER app-runner
ENTRYPOINT ["/app/httpserver"]
2
在启动应用之前,先使用命令USER指定用户,这样后面运行的指令将只用指定用户的权限,可以增强安全性,避免应用漏洞导致服务器诶侵入。
# 2.3.1 Linux /etc/passwd
在Linux系统中,/etc/passwd是一个文件,存储基本用户信息,其中一行就代表一条用户信息。
我们通过cat /etc/passwd,可以查看到如下信息:
其中每一行被:分割为7个部分,对应的含义为:
用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录Shell
# 2.4 Docker分阶段构建
Docker 17.05版本以后,官方就提供了一个新的特性:Multi-stage builds(多阶段构建)。
利用多阶段构建,我们可以在一个 Dockerfile 中使用多个 FROM 语句。每个 FROM 指令都可以使用不同的基础镜像,并表示开始一个新的构建阶段。
我们可以很方便的将一个阶段的文件复制到另外一个阶段,在最终的镜像只需要保留必要的内容。
通过这种方式,我们可以很容易实现Docker镜像的瘦身,最终镜像只保留运行时需要的内容,而构建期间用到的内容都可以不保存。
# 三、Docker基础镜像(base image):scratch 、busybox、alpine
# scratch:空镜像,基础镜像
scratch是Docker中预留的最小的基础镜像。bosybox 、 Go语言编译打包的镜像都可以基于scratch来构建。
scratch镜像不在镜像仓库中,但是可以在Dockerfile引用。
如:
FROM scratch
# busybox
busybox镜像只有几兆。
BusyBox是一个集成了一百多个最常用Linux命令和工具(如cat、echo、grep、mount、telnet等)的精简工具箱,它只有几MB的大小,很方便进行各种快速验证,被誉为“Linux系统的瑞士军刀”。BusyBox可运行于多款POSIX环境的操作系统中,如Linux(包括Android)、Hurd、FreeBSD等。
# Alpine
Alpine镜像比busybox大一点,也只有几兆。
Alpine操作系统是一个面向安全的轻型Linux发行版。它不同于通常的Linux发行版,Alpine采用了musl libc和BusyBox以减小系统的体积和运行时资源消耗,但功能上比BusyBox又完善得多。在保持瘦身的同时,Alpine还提供了自己的包管理工具apk,可以通过https://pkgs.alpinelinux.org/packages查询包信息,也可以通过apk命令直接查询和安装各种软件。
Alpine Docker镜像也继承了Alpine Linux发行版的这些优势。相比于其他Docker镜像,它的容量非常小,仅仅只有5MB左右(Ubuntu系列镜像接近200MB),且拥有非常友好的包管理机制。官方镜像来自docker-alpine项目。
目前Docker官方已开始推荐使用Alpine替代之前的Ubuntu作为基础镜像环境。这样会带来多个好处,包括镜像下载速度加快,镜像安全性提高,主机之间的切换更方便,占用更少磁盘空间等。
# 参考资料
- Golang Dockerfile的最佳实践 (opens new window)
- Golang - 如何使用Docker部署Go Web应用 (opens new window)
- 如何使用docker 部署 golang 编译环境最小版 (opens new window)
- docker基础镜像(base image):scratch 、 busybox 、 alpine (opens new window)
- Linux /etc/passwd (opens new window)
- Linux中/etc/passwd文件详细解析 (opens new window)
- Docker多阶段构建 (opens new window)