专栏首页网管叨bi叨线上Go项目的Docker镜像应该怎么构建?

线上Go项目的Docker镜像应该怎么构建?

上期的文章:Kubernetes入门实践--部署运行Go项目发布后,有网友留言说我文章里演示的镜像是把项目文件和Go都打包到了镜像里,这样镜像的占用空间会比较大。

Go开发的程序在编译成二进制文件后是可以在没有安装Go环境的系统里执行的,如果只把编译完的二进制文件直接放到镜像里就能节省很多镜像空间了。我给的回复是文章的侧重点是Kubernetes的实践所以镜像方面就没有占太多篇幅。

确实线上项目的应用镜像一般都不像之前文章里讲的那样构建,因为生产项目各方面要求更严格些。镜像构建的过程一般都是先用Docker容器把项目编译成二进制文件,然后把编译好的文件拷贝到一个新的容器镜像里,新镜像里一般只包含Linux系统运行需要的最基本的文件,不需要有Go环境,因此能减少很多占用空间。整个这个过程都发生在镜像构建的过程中,这样就能保证多环境的一致性,上面这个构建Docker镜像的方式叫做多阶段构建(multi stage build)。

多阶段构建是17.05版本才有的功能,所以使用前要先确定下使用的Docker Engine的版本。

Docker Engine版本

下面就来介绍一下怎么使用Docker的多阶段构建制作Go应用的镜像。

之前文章Kubernetes入门实践--部署运行Go项目里镜像的Dockerfile长这样:

FROM golang:1.14-alpine
RUN mkdir /app
COPY . /app
WORKDIR /app
RUN go build -o main . 
CMD ["/app/main"]

我们使用多阶段构建的方式构建镜像后,Dockerfile会变成类似下面这样:

FROM golang:alpine AS build

RUN mkdir /app
COPY . /app
WORKDIR /app
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp

### 
FROM scratch as final
COPY --from=build /app/myapp .
CMD ["/myapp"]

Go项目应用的Dockerfile通常大概类似这样,但是每个项目的细节可能有所不同。FROM golang:alpine指定了开始阶段的基础映像(其中包含Go工具和库,用于构建程序),AS build是给这个阶段取名为build

golang:alpine指定了Go基础映像的alpine版本, alpine是专门为容器设计的小型Linux发行版。这个Dockerfile中使用了两次FROM指令,第二条FROM scratch行,它告诉Docker从一个全新的,完全空的容器镜像重新开始,然后将上个阶段编译好的程序复制到其中。这个才是我们随后将用于运行的Go应用程序的容器镜像。

scratch镜像是Docker项目预定义的最小的镜像。使用scratch镜像可以节省大量空间,因为我们实际上不需要Go工具或其他任何东西来运行我们的编译好的程序,这可能也是Go在容器时代的一个优势吧。

使用scratch镜像制作的Go应用镜像在运行时会有一个不识别时区的问题。这个也是我们最近项目往Kubernetes上迁移时遇到的第一个问题,不过还好经过Google和查看Go加载系统时区的源码我帮新来的运维小哥哥找到了解决方法,具体怎么解决的下期的文章再告诉大家。

本文分享自微信公众号 - 网管叨bi叨(kevin_tech),作者:KevinYan11

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 编写Dockerfile的最佳实践

    虽然 Dockerfile 简化了镜像构建的过程,并且把这个过程可以进行版本控制,但是很多人构建镜像的时候,都有一种冲动——把可能用到的东西都打包到镜像中。这种...

    KevinYan
  • 在Go中使用Protobuf

    本教程使用proto3版本的protocol buffer语言,提供了一个基本的在Go程序中使用protocol buffer的介绍。通过创建一个简单的示例应用...

    KevinYan
  • 如何正确的开始用Go编程

    本文会演示简单的Go软件包的开发过程,并介绍了 go命令行工具,这是我们获取,构建和安装Go软件包和命令的标准方法。

    KevinYan
  • 如何先执行input (checkbox,radio)再执行函数

    遇到一个问题,当input type="checkbox"点击时,没有立即执行勾选或去勾,而是先执行函数,如下代码

    山河木马
  • 加入创业公司前需要考虑的11件事

    社会上有些关于创业公司工作状况的说法,每个公司都是独一无二的,它们将拥有自己的文化,不同的资金和不同的经理人。然而,还是有一种“我们都是这样”的感觉。 一些人...

    华章科技
  • 使用FindBugs插件检查Android代码

    用户1205080
  • MapReduce执行过程分析【问题】

    这个是个问题贴,由about云会员提问。会员答疑。提问和回答都比较有水平,分享出来。

    用户1410343
  • 排障集锦:九九八十一难之第十难!mysq备份恢复,Could not read entry at offset *: Error in log format or read error.

    经查阅资料发现 --start-position=‘655’ 是个存储过程的中间位置,无法直接读取,所以会报错。

    不吃小白菜
  • iOS Programming – 触摸事件处理(2)

    iOS Programming – 触摸事件处理(2) 在上一篇《iOS Programming – 触摸事件处理(1)》中了解触摸、事件和响应者之后,接下去...

    猿人谷
  • Web Pentester Sqlinject

    4、 SQL注入题目 4.1 sql1 url为http://129.129.1.38/sqli/example1.php?name=root,下面显示id、n...

    企鹅号小编

扫码关注云+社区

领取腾讯云代金券