如何为Go程序创建一个最小的Docker Image详解

前言

之前给大家介绍了关于在docker中部署golang项目的相关内容,对大家的入门具有一定的参考价值,本文将会给大家介绍如何使用docker打包一个golang编写的应用程序,最终的产物就是一个Dockerfile文件,可别小瞧这短短几行代码,涉及的知识点可不少,接下来我们就仔细剖析一下吧。

FROM golang:alpine

ADD src /go/src
RUN go install -v test 

ENTRYPOINT ["/go/bin/test"]
CMD ["-logtostderr"]

1. 基础镜像选择

第一行是指定一个基础镜像,在此基础上创建我们的镜像,此处使用的是golang:alpine版本,
这是一个相对较小的linux系统,砍掉了linux中的许多工具,包管理工具使用的是apk,可以把这个镜像docker pull下来把玩一番,默认的shell是sh,执行命令docker run -t-i golang:alpine /bin/sh 进入命令行。进入后执行env查看环境变量,因为其GOPATH这个环境变量对后面的环境部署有用,可以看到环境变量GOPATH默认值为/go

2. 映射代码文件并安装

使用 ADD src /go/src 将主机scr文件映射到/go/src目录下,为什么非得是这个/go/src这个目录呐?没错就是上面的GOPATH环境变量的路径,因为我们后面需要执行go install命令进行安装,否则的话就需要重新设置GOPATH才能安装编译后的二进制文件。

需要注意的是:此时本地主机中src目录中文件的组织,要执行go install就要严格遵循生成包的文件结构,test是程序的主程序,glog是使用的开源日志库,整个文件结构如下,因为在main.go导入包的时候使用的是"github.com/golang/glog"这个路径,所以需要给其一个合理的路径。

.
├── Dockerfile
└── src
 ├── github.com
 │ └── golang
 │ └── glog
 │  ├── glog_file.go
 │  ├── glog.go
 │  ├── glog_test.go
 │  ├── LICENSE
 │  └── README
 └── test
 └── main.go

还有一个小tips是程序的日志库使用的是第三方开源的glog,当我们使用git对我们上述代码进行版本管理的时候就不需要重复包含glog的代码,直接添加一个对其的引用就可以,这样有很多好处,当库中代码被修改后可以直接更新到远程的代码仓库中,在clone的时候可以自动导入该库,也就是说在本地会拉取具体的代码,但是在远程仓库只是保存引用。

可以通过命令生成glog这个子模块: git submodule add https://github.com/golang/glog.git src/github.com/golang/glog注意:git remoule命令中被引用到的位置为src/github.com/golang而不是直接的src/ 中,因为执行该命令后本地代码仓库会clone glog这个代码仓库,将它的代码拉下来,只是创建glog这个目录,所以前面的一些父目录需要自己创建。

关于命令更多的介绍参见 Git

组织好文件结构就可以进行go install了,生成的可执行在$GOPATH/bin中,后面就是基本的指定入口程序和参数。通过docker build -t="name" . 生成镜像

3.更进一步:提前编译

上面的方式是将代码拷贝进基础镜像并在其内部编译,毫无疑问的是golang:alpine中包含一系列程序运行的依赖,程序运行会动态加载这些库,我们可以用ldd命令查看所生成的二进制文件的依赖:

linux-vdso.so.1 => (0x00007ffc5b1e4000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f50a1f13000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f50a1b4a000)
/lib64/ld-linux-x86-64.so.2 (0x00005611a4b0a000)

那么问题来了? 如果将这些依赖静态编译至可执行文件中那就不需要在环境中保存这些多余的信息了,就可以创建一个更小的镜像了。幸运的是无论是golang的编译机制还是docker的基础镜像都提供这样的实现:

使用命令生成静态编译的二进制文件:CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

此时用ldd查看生成的可执行文件的依赖,可以看到显示not a dynamic executable,这里我们禁用CGO使其生成静态二进制文件,同时设置系统为linux。我们将基础镜像设置为 scratch,这是一个很小的的镜像。

重新编写的Dockerfile如下:

FROM scratch
ADD main /
ENTRYPOINT ["/main"]
CMD ["-logtostderr"]

执行docker build -t example-scratch .生成镜像,可以看到该镜像的大小只有8.27M大小,并且可以正常执行。

在实际情况中有时会将两种情况结合使用,先在一个镜像中构建,在另一个镜像中执行。下面的Dockerfile摘自prometheus这个第三方监控的演示案例的Dockerfile,可以看到它是首先在builder镜像中下载对应的依赖并且编译程序,最后在scratch基础镜像中执行程序。

# This Dockerfile builds an image for a client_golang example.
#
# Use as (from the root for the client_golang repository):jingx
# docker build -f examples/$name/Dockerfile -t prometheus/golang-example-$name .

# Builder image, where we build the example.
FROM golang:1.9.0 AS builder
WORKDIR /go/src/github.com/prometheus/client_golang
COPY . .
WORKDIR /go/src/github.com/prometheus/client_golang/prometheus
RUN go get -d
WORKDIR /go/src/github.com/prometheus/client_golang/examples/simple
RUN CGO_ENABLED=0 GOOS=linux go build -a -tags netgo -ldflags '-w'

# Final image.
FROM scratch
LABEL maintainer "The Prometheus Authors <prometheus-developers@googlegroups.com>"
COPY --from=builder /go/src/github.com/prometheus/client_golang/examples/simple .
EXPOSE 8080
ENTRYPOINT ["/simple"]

参考

Building Minimal Docker Containers for Go Applications

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Docker与Golang的巧妙结合

    Docker与Golang的巧妙结合 [编者的话]这是一个展示在使用Go语言时如何让Docker更有用的提示与技巧的简辑.例如,如何使用不同版本的Go工具链来编译Go代码,如何交叉编译到不同的平台(并且测试结果!),或者如何制作真正小的容器镜像. 下面的文章假定你已经安装了Docker.不必是最新版本(这篇文章不会使用Docker任何花哨的功能). 没有go的Go ...意思是:"不用安装go就能使用Go" 如果你写Go代码,或者你对Go语言有一点点兴趣,你肯定要安装了Go编译器和Go

  • 详解如何在 Docker 中设置 Go 并部署应用

    嗨,在本教程中,我们将学习如何使用 docker 部署 golang web 应用程序. 你可能已经知道,由于 golang 的高性能和可靠性,docker 是完全是用 golang 写的.在我们详细介绍之前,请确保你已经安装了 docker 以及 golang 并对它们有基本了解. 关于 docker Docker 是一个开源程序,它可以将应用及其完整的依赖包捆绑到一起,并打包为容器,与宿主机共享相同的 Linux 内核.另一方面,像 VMware 这样的基于 hypervisor 的虚拟化操

  • docker中部署golang项目的步骤详解

    理解Docker Docker可以帮您为自己的应用程序创建一个单一的可部署"单位".这样的单位也叫做容器,其中包含了应用程序需要的一切.例如代码(或二进制文件).运行时.系统工具,以及系统库文件.将所有这些需要的内容打包为一个单一的单位,可确保无论将应用程序部署在何处,都能提供完全相同的环境.这种技术还可以帮您维持完全一致的开发和生产环境,通常这些环境是很难被追踪的. 一旦搭建完成,容器的创建和部署将可自动进行.这本身就可以避免一系列问题.这些问题中大部分都是因为文件不同步,或开发和生

  • 如何为Go程序创建一个最小的Docker Image详解

    前言 之前给大家介绍了关于在docker中部署golang项目的相关内容,对大家的入门具有一定的参考价值,本文将会给大家介绍如何使用docker打包一个golang编写的应用程序,最终的产物就是一个Dockerfile文件,可别小瞧这短短几行代码,涉及的知识点可不少,接下来我们就仔细剖析一下吧. FROM golang:alpine ADD src /go/src RUN go install -v test ENTRYPOINT ["/go/bin/test"] CMD ["

  • Flutter学习之创建一个内嵌的navigation详解

    目录 简介 搭建主Navigator 构建子路由 总结 简介 我们在flutter中可以使用Navigator.push或者Navigator.pushNamed方法来向Navigator中添加不同的页面,从而达到页面调整的目的. 一般情况下这样已经足够了,但是有时候我们有多个Navigator的情况下,上面的使用方式就不够用了.比如我们有一个主页面app的Navigator,然后里面有一个匹配好友的功能,这个功能有多个页面,因为匹配好友功能的多个页面实际上是一个完整的流程,所以这些页面需要被放

  • Node.js创建一个Express服务的方法详解

    本文实例讲述了Node.js创建一个Express服务的方法.分享给大家供大家参考,具体如下: 1.创建一个HttpServer服务端 在node.js官网下载好node的Windows版本后一路下一步安装好了node,新建一个server.js文件,开始第一个node文件.首先在文件开头需要使用require包含所需要的模块,然后利用http.createServer创建一个server,并执行回调函数.在回调函数内对请求req进行处理,并返回res结果. 利用url的parse方法将req请

  • 微信小程序 开发MAP(地图)实例详解

    微信小程序 开发MAP(地图)实例详解 在创建MAP(地图)前,请各位小伙伴们认真的去了解微信小程序开发的说明. https://mp.weixin.qq.com/debug/wxadoc/dev/component/map.html#map 了解完MAP(地图)里的属性之后,接下来我们就来创建一个简单的MAP(地图)控件. 第一步:肯定是创建项目.起项目名.项目地址 PS:我这里以index的文件为名 第二步:我们来写 index.wxml 文件的代码 WXML文件代码: <map id=&quo

  • 微信小程序之网络请求简单封装实例详解

    微信小程序之网络请求简单封装实例详解 在微信小程序中实现网络请求相对于Android来说感觉简单很多,我们只需要使用其提供的API就可以解决网络请求问题. 普通HTTPS请求(wx.request) 上传文件(wx.uploadFile) 下载文件(wx.downloadFile) WebSocket通信(wx.connectSocket) 为了数据安全,微信小程序网络请求只支持https,当然各个参数的含义就不在细说,不熟悉的话可以:可以去阅读官方文档的网络请求api,当我们使用request

  • C程序中唯一序列号的生成实例详解

    C程序中唯一序列号的生成实例详解 在实际的软件开发项目中,经常会涉及唯一序列号的生成.本文以一个实际的程序为例,介绍了唯一序列号的生成过程. 本文生成的序列号的样式为:MMDDHHMINSS_XXXXXX. 程序如下: * 修改记录1:// 修改历史记录, 包括修改日期.版本号.修改人及修改内容 * 修改日期: 20140603 * 版 本 号: V1.0 * 修 改 人: Zhou Zhaoxiong * 修改内容: 创建 ***********************************

  • 微信小程序按钮点击跳转页面详解

    微信小程序中,按钮也是<button></button>标签,它通过bindtap属性绑定点击事件: 然后在js里面注册这个回调函数: 回调函数里面通过 wx.navigateTo({ url: '/pages/index/talkPage', }) 跳转到talkPage界面. 注意,html界面要在app.json里面注册: 不注册的话会报错:navigateTo:fail url "pages/index/talkPage" is not in app.j

  • 微信小程序移动拖拽视图-movable-view实例详解

    JS中的sender参数(sender是事件的传值)前提是只有一个touch移动的时候.多个touch需要在 changedTouches 数组中查找 redclcik:function(sender){ wx.showModal({ title: '点击红色', content: '', }) console.log(sender); }, redmove:function(sender){ console.log(sender); // console.log(sender.changedT

  • Python Process创建进程的2种方法详解

    前面介绍了使用 os.fork() 函数实现多进程编程,该方法最明显的缺陷就是不适用于 Windows 系统.本节将介绍一种支持 Python 在 Windows 平台上创建新进程的方法. Python multiprocessing 模块提供了 Process 类,该类可用来在 Windows 平台上创建新进程.和使用 Thread 类创建多线程方法类似,使用 Process 类创建多进程也有以下 2 种方式: 直接创建 Process 类的实例对象,由此就可以创建一个新的进程: 通过继承 P

  • 微信小程序MoxB实现全局状态管理流程详解

    目录 安装 MobX 创建 MobX Store 使用 MobX Store 在 Component 构造器中使用 在 Page 页面中使用 github 地址:https://github.com/wechat-miniprogram/mobx-miniprogram-bindings. 安装 MobX 在小程序根目录下执行 npm install --save mobx-miniprogram mobx-miniprogram-bindings 安装 mobx-miniprogram 和 m

随机推荐