go服务docker实践-缩小镜像占用

小张开始学习go语言啦,从服务发布开始吧

背景: 需要发布GO服务,所以开始编辑dockerfile,遇到了些问题,在此记录下,一起学习吧,文档同时更新到公众号里了,可以加个关注呦,写的不对的地方请指出,3Q

1 说在前面

本文环境建立在已安装docker服务基础上,请先准备好docker环境

2 docker镜像要求

我们首先思考一下云原生对应用运行时的不同需求:

体积更小:对于微服务分布式架构而言,更小的体积意味着更少的下载带宽,更快的分发下载速度。

启动速度更快:对于传统单体应用,启动速度与运行效率相比不是一个关键的指标。原因是,这些应用重启和发布频率相对较低。然而对于需要快速迭代、水平扩展的微服务应用而言,更快的的启动速度就意味着更高的交付效率,和更加快速的回滚。尤其当你需要发布一个有数百个副本的应用时,缓慢的启动速度就是时间杀手。对于Serverless 应用而言,端到端的冷启动速度则更为关键,即使底层容器技术可以实现百毫秒资源就绪,如果应用无法在 500ms 内完成启动,用户就会感知到访问延迟。

占用资源更少:运行时更低的资源占用,意味着更高的部署密度和更低的计算成本。

(本次我们讨论如何把体积缩小)

3 创建第一版dockerfile

在这个dockerfile中,我主要做了下面这几件事

1 打包

为了摆脱开发环境对打包的影响,我选择了把打包过程放在了dockerfile中

2 启动

在第一阶段打包完成后,我们可以直接执行打包后的可执行文件

下面我们来看第一版dockerfile

FROM golang
    MAINTAINER  天南
    WORKDIR /go/src/git.liebaopay.com/cm/cm_ad_free
    COPY . .
    RUN go build main.go
    EXPOSE 20020 20021 20022
    CMD ["./main","./config_local.ini",":20020",":20021",":20022"]
复制代码

下面我们一步一步解析此dockerfile:

# 我们以官方golang镜像为基础镜像,官方golang的gopath默认在 /go/src中,所以可以直接把我们的项目放在此# # gopath中
    FROM golang
    # 指定维护者名称
    MAINTAINER  天南
    # 指定容器内的工作目录,不存在目录会自动创建
    WORKDIR /go/src/git.liebaopay.com/cm/cm_ad_free
    # 把dockerfile当前目录下的所有目录和文件都复制到上步指定的工作目录下
    COPY . .
    # 开始打包
    RUN go build main.go
    # 暴露服务端口
    EXPOSE 20020 20021 20022
    # 使用cmd执行命令,这个命令映射到容器内部的命令为  ./main ./config_local.ini :20020 :20021 :20022
    CMD ["./main","./config_local.ini",":20020",":20021",":20022"]
复制代码

构建镜像,并启动

docker build -t cm_ad_free_img_v1 .
复制代码

构建个镜像,指定tag名称为 cm_ad_free_img_v1

下图可以看到,镜像构建过程

镜像构建成功后,我们进行启动一个容器服务

docker run --name cm_ad_free_container_v1  -it  -p 9988:20022 cm_ad_free_img_v1
复制代码

下面说下参数信息

--name 指定容器名称

-t 让docker分配一个伪终端并绑定到容器的标准输入上

-i 则让容器的标准输入保持打开 

-d 会采用后台进行

-p 为端口映射,宿主机端口:容器端口
复制代码

检查下生成的docker镜像

我哩个去! 这镜像占用也太大了,足足占用了890Mb,原因是什么呢? 原来我们在构建镜像的时候,引入的golang基础镜像以及做了不少操作,在操作的过程中,产生了不少临时文件,这些临时文件在运行时是不需要的

4 镜像瘦身

Docker 提供了 Multi-stage Build(多阶段构建),可以实现镜像瘦身。

我们把dockerfile构建过程可以简单分为两个阶段,

  • 第一个阶段是生成可执行文件阶段,使用了golang的基础镜像,并做了go build操作
  • 第二个阶段是执行可执行文件阶段,其实第二个阶段用到了第一阶段的执行文件和基础配置,执行过程中并不再依赖golang基础镜像

所以我们在最终发布的镜像中,只包含运行程序必要的文件和配置,不包含任何编译时的依赖,这样就减少了镜像的体积

我们来看第二版的dockerfile,只对增加命令进行注释

# 引入golang作为基础命令并起别名为 build
    FROM golang as build
    MAINTAINER  天南
    WORKDIR /go/src/git.liebaopay.com/cm/cm_ad_free
    COPY . .
    RUN go build main.go
    # 引入alphine最小linux镜像
    FROM alpine
    # 设置工作目录
    WORKDIR /data/app
    # 复制生成的可执行命令和一些配置文件
    COPY --from=build /go/src/git.liebaopay.com/cm/cm_ad_free/main .
    COPY --from=build /go/src/git.liebaopay.com/cm/cm_ad_free/config_local.ini .
    COPY --from=build /go/src/git.liebaopay.com/cm/cm_ad_free/logformat_local.xml .
    # !!! 注意,经测试发现alpine中缺少动态库,经查询后的解决方式为创建一个软链
    RUN  mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
    EXPOSE 20020 20021 20022
    CMD ["./main","./config_local.ini",":20020",":20021",":20022"]
复制代码

构建镜像后,查看下占用磁盘,直接减少到26Mb,看来胖子变为瘦子了,哈哈

创建容器,成功启动服务,可以开心玩耍了 ~

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章