多阶段构建Golang程序Docker镜像

939496716 · · 1153 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

### Docker简介 Docker是基于Linux容器技术(LXC),使用Go语言实现的开源项目,诞生于2013年,遵循Apache2.0协议。Docker自开源后,受到广泛的关注和讨论。 ##### Docker在开发和运维中的优势 * 更快的交付和部署 使用Docker,开发人员可以使用镜像来快速构建一套标准的开发环境,开发完后,测试和运维人员可以直接使用完全相同的环境来部署代码,实现了生产环境的无缝运行。 * 更高效的资源利用 Docker容器的运行不需要额外的虚拟化管理程序支持,它是内核级的虚拟化 ,可以实现更高的性能,同时对资源的额外需求很低。 * 更轻松的迁移和扩展 Docker容器几乎可以在任意的平台上运行,支持主流的操作系统发行版本。这种兼容性让用户可以在不同平台之间轻松地迁移应用。 * 更简单的更新管理 使用Dockerfile,只需要修改一点点配置,就可以替代以往大量的更新工作。并且所有的修改都以增量的方式被分布和更新,从而实现自动化且高效的容器管理。 ##### 首先需要知道以下几个概念 * `Docker镜像` Docker镜像类似于虚拟机镜像,可以将它理解为一个只读的模板。镜像是创建Docker容器的基础。通过版本管理和增量的文件系统,Docker提供了一套十分简单的机制和创建和更新现有的镜像,用户可以直接从网上下载一个已经做好的应用镜像,并直接使用。 * `Docker容器` Docker容器类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用。容器是从镜像创建的应用运行实例。可以将其启动、开始、停止、删除,而这些容器都是彼此相互隔离的,互不可见的。 可以把容器看做一个简易版的Linux系统环境(包括root用户权限、进程空间、用户空间和网络空间)以及运行在其中的应用程序打包而成的盒子。 * `Docker仓库` Docker仓库类似于代码仓库,它是Docker集中存放镜像文件的场所。它的设计理念与Git类似。Docker镜像库分公开仓库和私有仓库。最大的公开仓库是官方提供的Docker Hub。当然,如果不想公开镜像,可以搭建自己的私有仓库。 * `Dockerfile` 一般介绍完以上三个概念就结束了,但我在这里要介绍下Dockerfile,因为镜像的好坏很大程度取决于Dockerfile。Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile来快速创建自定义的镜像。 ### 多阶段构建Golang应用Docker镜像 一般Golang的Dockerfile文件会像这样: ``` # Go语言环境基础镜像 FROM golang:latest # 将源码拷贝到镜像中 COPY server.go /go/release/ # 指定工作目录 WORKDIR /go/release # 编译镜像时,运行 go build 编译生成 app 可执行的二进制文件 RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOARM=6 go build -ldflags '-w -s' -o app server.go # 指定容器运行时入口程序 app ENTRYPOINT ["/go/release/app"] ``` 这种方式构建的Docker镜像体积非常大,构建时间长,占用磁盘空间,部署速度慢。 本篇将使用`多阶段构建(multi-stage builds)`的方式来减少生成的Docker镜像的体积。 > 在`多阶段构建`的过程中,我们在Dockerfile使用多个`FROM`指令,每个`FROM`指令使用不同的基础镜像构成了不同阶段。你可以选择从上一个阶段的产物(一般指生成的文件)复制到下一个阶段,从而确保不会把不需要的东西带到下一阶段。这种方法可以有效减小Docker镜像的大小。[参考官网](https://docs.docker.com/develop/develop-images/multistage-build/) 以[开源项目---gin+vue前后端分离项目](https://github.com/Bingjian-Zhu/gin-vue-admin)为例,介绍Golang应用如何使用`多阶段构建`Docker镜像。 项目结构图 ![](https://img2020.cnblogs.com/blog/1508611/202005/1508611-20200506161502529-1141200427.png) 直接上`Dockerfile` ``` # 构建:使用golang:1.13版本 FROM golang:1.13 as build # 容器环境变量添加,会覆盖默认的变量值 ENV GO111MODULE=on ENV GOPROXY=https://goproxy.cn,direct # 设置工作区 WORKDIR /go/release # 把全部文件添加到/go/release目录 ADD . . # 编译:把cmd/main.go编译成可执行的二进制文件,命名为app RUN GOOS=linux CGO_ENABLED=0 GOARCH=amd64 go build -ldflags="-s -w" -installsuffix cgo -o app cmd/main.go # 运行:使用scratch作为基础镜像 FROM scratch as prod # 在build阶段复制时区到 COPY --from=build /usr/share/zoneinfo/Asia/Shanghai /etc/localtime # 在build阶段复制可执行的go二进制文件app COPY --from=build /go/release/app / # 在build阶段复制配置文件 COPY --from=build /go/release/config ./config # 启动服务 CMD ["/app"] ``` > Dockerfile各指令详细介绍:https://docs.docker.com/engine/reference/builder/#usage 构建阶段,以golang:1.13为基础镜像,把项目编译成Linux x64位系统可执行的二进制文件(命名为app)。运行阶段,把必要的配置文件和app复制到scratch镜像中运行。最后的镜像只包括运行阶段的文件,所以体积很小,只有10多M。 * golang编译知识 ``` GOOS=linux CGO_ENABLED=0 GOARCH=amd64 go build -ldflags="-s -w" -installsuffix cgo -o app cmd/main.go ``` `GOOS`:目标系统为`linux` `CGO_ENABLED`:默认为`1`,启用C语言版本的GO编译器,通过设置成`0`禁用它 `GOARCH`:32位系统为`386`,64位系统为`amd64` `-ldflags`:用于传递每个go工具链接调用的参数。 > * `-s`: 省略符号表和调试信息 > * `-w`: 省略DWARF符号表 `-installsuffix`:在软件包安装的目录中增加后缀标识,用于区分默认版本 `-o`:指定编译后的可执行文件名称 `cmd/main.go`:`main`函数所在路径 ##### scratch镜像 scratch是一个空镜像,只能用于构建其他镜像,比如你要运行一个包含所有依赖的二进制文件,如Golang程序,可以直接使用scratch作为基础镜像。scratch本身是不占空间的,所以使用它构建的镜像大小几乎和二进制文件本身一样大,从而让Golang应用的Docker镜像体积非常小。 参考:https://mp.weixin.qq.com/s/S1Ib08SpQbf1SCbCutUoqQ ### 制作Golang程序Docker镜像 这里直接使用Linux服务器制作Docker镜像,也可以使用Docker for windows在windows上制作Docker镜像。 * 前提:Linux服务器安装`Docker`,`Golang` (1)拉取项目 `go get -x github.com/bingjian-zhu/gin-vue-admin/cmd` (2)修改配置文件 进入项目中`config/config.yml`,修改`database`配置,改成自己的MySQL数据库。`run-mode`运行模式改成`release`。 ![](https://img2020.cnblogs.com/blog/1508611/202005/1508611-20200506190518157-445137270.png) (3)生成Docker镜像 镜像名字为`zhubingjian/gin-vue-admin`,版本`1.0`,不要漏了最后面的`.`; `docker build -t zhubingjian/gin-vue-admin:1.0 .` 其中`zhubingjian`是我`Docker Hub`的账号,想要把镜像上传到自己的`Docker Hub`上,镜像名称需要以`Docker Hub账号`+`/`开头。已经生成的镜像可以通过`tag`修改名称。 运行指令:`docker images` 可以看到我们生成的Docker镜像只有14.3M,非常小。名称为`none`的镜像是多阶段生成过程留下的镜像,可以使用`docker rmi 镜像ID`把它删除掉。 ![](https://img2020.cnblogs.com/blog/1508611/202005/1508611-20200506191619604-1254961137.png) (4)运行镜像 `docker run -d --name gin-vue-admin -p 8000:8000 zhubingjian/gin-vue-admin:1.0` * `-d`:容器以守护进程的方式运行 * `--name`:容器的名字,可以不指定名字 * `-p`:指定宿主机器与容器的端口对应关系, 格式为“宿主端口:容器端口”,如果不指定此项,将无法访问容器里的服务 运行指令:`docker ps -a` 可以看到所有容器,`STATUS`显示`Up 10 seconds`,表示两个意思:一是容器在运行;二是已经运行了10秒。如果显示`Exited 6 days`,则表示已经停止运行6天了。 ![](https://img2020.cnblogs.com/blog/1508611/202005/1508611-20200506192657157-735613331.png) 目前为止,我们已经成功制作Docker镜像且运行了。接下来把前端的`VUE`项目也做成Docker镜像并运行。 ### 制作VUE程序Docker镜像 * 前提:服务器安装`Docker`,`nodejs`,`npm` (1)进入`vue-admin`目录,下载`npm`包 `npm install` (2)修改`vue-admin`目录下的`.env.production`文件,改成自己的后台接口地址 ![](https://img2020.cnblogs.com/blog/1508611/202005/1508611-20200506201813587-694219275.png) (3)发布项目,生成`dist`文件夹 `npm run build:prod` (4)生成Docker镜像 `docker build -t zhubingjian/vue-admin:1.0 .` (5)运行镜像 `docker run -p 80:80 -d --name vue-admin zhubingjian/vue-admin:1.0` > 参考:[Docker 部署 vue 项目](https://juejin.im/post/5cce4b1cf265da0373719819) 最后,在浏览器上打开:http://zbj-home.picp.io 就可以看到程序已经在服务器上跑了。 ### 把镜像推送到Docker Hub上 首先需要注册Docker Hub账号,我注册时候是有坑的,注册系统需要做人机检测,需要翻墙才能完成。官网地址:https://hub.docker.com/ (1)登录Docker Hub `docker login` 然后输入用户名和密码 ![](https://img2020.cnblogs.com/blog/1508611/202005/1508611-20200506203750950-1468271832.png) (2)推送镜像 ``` docker push zhubingjian/gin-vue-admin:1.0 docker push zhubingjian/vue-admin:1.0 ``` ### 总结 本篇主要介绍如何使用多阶段构建Golang程序的Docker镜像,此方法可以精简Docker镜像。 源码地址:https://github.com/Bingjian-Zhu/gin-vue-admin 参考: * http://blog.haohtml.com/archives/19334 * https://blog.csdn.net/weixin_42852772/article/details/82013418 * https://www.jianshu.com/p/4b345a9e768e

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1153 次点击  ∙  2 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传