0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

go项目怎么让docker镜像体积减小

Linux爱好者 来源:CSDN技术社区 作者:Scoful 2022-06-12 15:07 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

【导读】go 项目怎么让 docker 镜像体积减小?本文做了详细介绍。

1. 直接编译得到运行文件 22M

使用的项目源码地址 (https://github.com/scoful/kingProject)
本地直接编译打一个linux运行包

setGOOS=linux
setGOARCH=amd64
gobuildmain.go

2e4bbe54-de7e-11ec-ba43-dac502259ad0.png
结果是22M

2. 不编译直接运行的镜像 941M

Dockerfile文件内容

#基础镜像,基于golang最新镜像构建
FROMgolang
#作者
MAINTAINERscoful
#全局工作目录
WORKDIR$GOPATH/kingProject
#把运行Dockerfile文件的当前目录所有文件复制到目标目录
COPY.$GOPATH/kingProject
#环境变量
#用于代理下载go项目依赖的包
ENVGOPROXYhttps://goproxy.cn,direct
#需暴露的端口
EXPOSE8888
#可外挂的目录
VOLUME["/go/kingProject/config","/go/kingProject/log"]
#dockerrun命令触发的真实命令(相当于不编译打包,源代码直接运行)
ENTRYPOINT["go","run","main.go"]

编译镜像后查询结果如下:
2e8b729c-de7e-11ec-ba43-dac502259ad0.png
结果是941M,基本跟基础镜像golang的大小一致,而且因为没有预先编译,等到运行的时候再编译并拉取依赖包,run起来很慢

3. 编译后的镜像 1.14G

Dockerfile文件内容

#基础镜像,基于golang最新镜像构建
FROMgolang
#作者
MAINTAINERscoful
#全局工作目录
WORKDIR$GOPATH/kingProject
#把运行Dockerfile文件的当前目录所有文件复制到目标目录
COPY.$GOPATH/kingProject
#环境变量
#用于代理下载go项目依赖的包
ENVGOPROXYhttps://goproxy.cn,direct
#编译
RUNGOOS=linuxGOARCH=amd64gobuildmain.go
#需暴露的端口
EXPOSE8888
#可外挂的目录
VOLUME["/go/kingProject/config","/go/kingProject/log"]
#dockerrun命令触发的真实命令(相当于直接运行编译后的可运行文件)
ENTRYPOINT["./main"]

2ebd80a2-de7e-11ec-ba43-dac502259ad0.png
结果是1.14G,更大了,因为加上了编译过程中拉取的包,但是预先编译,所以直接run,速度很快

4. 优化:使用alpine版本的基础镜像 517M

优化的方向:如果一个镜像在https://hub.docker.com/里能搜到有alpine版本,尽量用alpine版本,相当于是官方提供的最小化可用版本

Dockerfile文件内容

#基础镜像,基于golang的alpine版本镜像构建
FROMgolang:alpine
#作者
MAINTAINERscoful
#全局工作目录
WORKDIR$GOPATH/kingProject
#把运行Dockerfile文件的当前目录所有文件复制到目标目录
COPY.$GOPATH/kingProject
#环境变量
#用于代理下载go项目依赖的包
ENVGOPROXYhttps://goproxy.cn,direct
#编译
RUNGOOS=linuxGOARCH=amd64gobuildmain.go
#需暴露的端口
EXPOSE8888
#可外挂的目录
VOLUME["/go/kingProject/config","/go/kingProject/log"]
#dockerrun命令触发的真实命令(相当于直接运行编译后的可运行文件)
ENTRYPOINT["./main"]

2f090216-de7e-11ec-ba43-dac502259ad0.png
结果是517M,比1.14G减少了650.36M,直接降了56%,而且run一样很快

5. 再优化:使用多级构建的镜像 28.4M

再优化的方向:go项目其实只是在build的阶段需要go环境,run的时候是不需要的,那build完后go环境用个alpine版本就行

Dockerfile文件内容

#基础镜像,基于golang的alpine镜像构建--编译阶段
FROMgolang:alpineASbuilder
#作者
MAINTAINERscoful
#全局工作目录
WORKDIR/go/kingProject
#把运行Dockerfile文件的当前目录所有文件复制到目标目录
COPY./go/kingProject
#环境变量
#用于代理下载go项目依赖的包
ENVGOPROXYhttps://goproxy.cn,direct
#编译,关闭CGO,防止编译后的文件有动态链接,而alpine镜像里有些c库没有,直接没有文件的错误
RUNGOOS=linuxGOARCH=amd64CGO_ENABLED=0gobuildmain.go

#使用alpine这个轻量级镜像为基础镜像--运行阶段
FROMalpineASrunner
#全局工作目录
WORKDIR/go/kingProject
#复制编译阶段编译出来的运行文件到目标目录
COPY--from=builder/go/kingProject/main.
#复制编译阶段里的config文件夹到目标目录
COPY--from=builder/go/kingProject/config./config
#需暴露的端口
EXPOSE8888
#可外挂的目录
VOLUME["/go/kingProject/config","/go/kingProject/log"]
#dockerrun命令触发的真实命令(相当于直接运行编译后的可运行文件)
ENTRYPOINT["./main"]

2f609cb0-de7e-11ec-ba43-dac502259ad0.png
结果是28.4M,比517M减少了488.6M,再降95%,那个533M是第一级构建生成的

6. 再再优化:使用多级构建+scratch基础镜像 22.8M

再再优化的方向:再极端一点,第二级构建的时候用个空镜像来当基础镜像

Dockerfile文件内容

#基础镜像,基于golang的alpine镜像构建--编译阶段
FROMgolang:alpineASbuilder
#作者
MAINTAINERscoful
#全局工作目录
WORKDIR/go/kingProject
#把运行Dockerfile文件的当前目录所有文件复制到目标目录
COPY./go/kingProject
#环境变量
#用于代理下载go项目依赖的包
ENVGOPROXYhttps://goproxy.cn,direct
#编译,关闭CGO,防止编译后的文件有动态链接,而alpine镜像里有些c库没有,直接没有文件的错误
RUNGOOS=linuxGOARCH=amd64CGO_ENABLED=0gobuildmain.go


#使用scratch这个空镜像为基础镜像--运行阶段
FROMscratchASrunner
#全局工作目录
WORKDIR/go/kingProject
#复制编译阶段编译出来的运行文件到目标目录
COPY--from=builder/go/kingProject/main.
#复制编译阶段里的config文件夹到目标目录
COPY--from=builder/go/kingProject/config./config
#需暴露的端口
EXPOSE8888
#可外挂的目录
VOLUME["/go/kingProject/config","/go/kingProject/log"]
#dockerrun命令触发的真实命令(相当于直接运行编译后的可运行文件)
ENTRYPOINT["./main"]

2f7a2306-de7e-11ec-ba43-dac502259ad0.png
结果是22.8M,已经约等于不用镜像直接编译出的可执行文件大小了,比28.4M减少了5.6M,再降20%,但用scratch当基础镜像的坏处是没法exec进入容器内部,因为真的就是空镜像,啥都没有,啥都不支持

7. 再再再优化:go编译命令去掉冗余输出 16.3M

再再再优化的方向:再再极端一点,go编译的时候,加上参数-ldflags="-w -s",直接去掉一些冗余输出内容

Dockerfile文件内容

#基础镜像,基于golang的alpine镜像构建--编译阶段
FROMgolang:alpineASbuilder
#作者
MAINTAINERscoful
#全局工作目录
WORKDIR/go/kingProject
#把运行Dockerfile文件的当前目录所有文件复制到目标目录
COPY./go/kingProject
#环境变量
#用于代理下载go项目依赖的包
ENVGOPROXYhttps://goproxy.cn,direct
#编译,关闭CGO,防止编译后的文件有动态链接,而alpine镜像里有些c库没有,直接没有文件的错误
RUNGOOS=linuxGOARCH=amd64CGO_ENABLED=0gobuild-ldflags="-w-s"main.go


#使用scratch这个空镜像为基础镜像--运行阶段
FROMscratchASrunner
#全局工作目录
WORKDIR/go/kingProject
#复制编译阶段编译出来的运行文件到目标目录
COPY--from=builder/go/kingProject/main.
#复制编译阶段里的config文件夹到目标目录
COPY--from=builder/go/kingProject/config./config
#需暴露的端口
EXPOSE8888
#可外挂的目录
VOLUME["/go/kingProject/config","/go/kingProject/log"]
#dockerrun命令触发的真实命令(相当于直接运行编译后的可运行文件)
ENTRYPOINT["./main"]

2f9e1b08-de7e-11ec-ba43-dac502259ad0.png
结果是16.3M,看似比不用镜像直接编译出的可执行文件还小,那是因为直接编译没有加上这个参数,如果加上大小还是差不多的,比22.8M减少了6.5M,再降29%,好了,降无可降了,用1.14G来对比的话,减少了1.12G,足足降了99%,鹅妹子嘤!

8. 最终版:顺便解决时区问题 16.3M

Dockerfile文件内容

#基础镜像,基于golang的alpine镜像构建--编译阶段
FROMgolang:alpineASbuilder
#作者
MAINTAINERscoful
#全局工作目录
WORKDIR/go/kingProject
#把运行Dockerfile文件的当前目录所有文件复制到目标目录
COPY./go/kingProject
#环境变量
#用于代理下载go项目依赖的包
ENVGOPROXYhttps://goproxy.cn,direct
#编译,关闭CGO,防止编译后的文件有动态链接,而alpine镜像里有些c库没有,直接没有文件的错误
RUNGOOS=linuxGOARCH=amd64CGO_ENABLED=0gobuild-ldflags="-w-s"main.go
RUNecho"https://mirrors.aliyun.com/alpine/v3.8/main/">/etc/apk/repositories
&&echo"https://mirrors.aliyun.com/alpine/v3.8/community/">>/etc/apk/repositories
&&apkadd--no-cachetzdata
&&cp/usr/share/zoneinfo/Asia/Shanghai/etc/localtime
&&echoAsia/Shanghai>/etc/timezone
&&apkdeltzdata

#使用scratch这个空镜像为基础镜像--运行阶段
FROMscratchASrunner
#全局工作目录
WORKDIR/go/kingProject
#复制编译阶段编译出来的运行文件到目标目录
COPY--from=builder/go/kingProject/main.
#复制编译阶段里的config文件夹到目标目录
COPY--from=builder/go/kingProject/config./config
#复制编译阶段里的时区文件到目标目录
COPY--from=builder/etc/localtime/etc/localtime
COPY--from=builder/etc/timezone/etc/timezone
#需暴露的端口
EXPOSE8888
#可外挂的目录
VOLUME["/go/kingProject/config","/go/kingProject/log"]
#dockerrun命令触发的真实命令(相当于直接运行编译后的可运行文件)
ENTRYPOINT["./main"]

9. 最最推荐使用版:多级+alpine 21.9M

综上所述,scratch镜像有它的缺陷,是一个真的空镜像,不支持很多命令,比如cp,sh等,如果要进入容器内部查东西,都进不去,不适合真实情况,所以还是推荐alpine镜像,很小5M多,可以接受。

Dockerfile文件内容

#基础镜像,基于golang的alpine镜像构建--编译阶段
FROMgolang:alpineASbuilder
#作者
MAINTAINERscoful
#全局工作目录
WORKDIR/go/kingProject
#把运行Dockerfile文件的当前目录所有文件复制到目标目录
COPY./go/kingProject
#环境变量
#用于代理下载go项目依赖的包
ENVGOPROXYhttps://goproxy.cn,direct
#编译,关闭CGO,防止编译后的文件有动态链接,而alpine镜像里有些c库没有,直接没有文件的错误
RUNGOOS=linuxGOARCH=amd64CGO_ENABLED=0gobuild-ldflags="-w-s"main.go


#使用alpine这个轻量级镜像为基础镜像--运行阶段
FROMalpineASrunner
#全局工作目录
WORKDIR/go/kingProject
#复制编译阶段编译出来的运行文件到目标目录
COPY--from=builder/go/kingProject/main.
#复制编译阶段里的config文件夹到目标目录
COPY--from=builder/go/kingProject/config./config
#将时区设置为东八区
RUNecho"https://mirrors.aliyun.com/alpine/v3.8/main/">/etc/apk/repositories
&&echo"https://mirrors.aliyun.com/alpine/v3.8/community/">>/etc/apk/repositories
&&apkadd--no-cachetzdata
&&cp/usr/share/zoneinfo/Asia/Shanghai/etc/localtime
&&echoAsia/Shanghai>/etc/timezone
&&apkdeltzdata
#需暴露的端口
EXPOSE8888
#可外挂的目录
VOLUME["/go/kingProject/config","/go/kingProject/log"]
#dockerrun命令触发的真实命令(相当于直接运行编译后的可运行文件)
ENTRYPOINT["./main"]

over,Enjoy!!!

原文标题:给 go 项目打最小 docker 镜像,足足降低 99%

文章出处:【微信公众号:Linux爱好者】欢迎添加关注!文章转载请注明出处。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编译
    +关注

    关注

    0

    文章

    688

    浏览量

    34949
  • 镜像
    +关注

    关注

    0

    文章

    178

    浏览量

    11548
  • Docker
    +关注

    关注

    0

    文章

    526

    浏览量

    14022

原文标题:给 go 项目打最小 docker 镜像,足足降低 99%

文章出处:【微信号:LinuxHub,微信公众号:Linux爱好者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    怎么构建docker镜像仓库软件

    Docker Registry】用docker registry 镜像搭建私有测试仓库
    发表于 08-13 11:03

    浅析Docker镜像本地存储机制及容器启动原理

    Docker 镜像不是一个单一的文件,而是有多层构成。我们可通过 docker images 获取本地的镜像列表及对应的元信息, 接着可通过dock
    发表于 10-19 14:17 2808次阅读

    Docker—简介与镜像用法

    阿里云官方镜像站: ​​https://developer.aliyun.com/mirror/?utm_content=g_1000303593​​ ​ 一、容器简介 Docker是管理容器的引擎
    发表于 11-25 16:28 925次阅读
    <b class='flag-5'>Docker</b>—简介与<b class='flag-5'>镜像</b>用法

    go项目怎么docker镜像体积减小

    go 项目怎么 docker 镜像体积减小?本文做
    的头像 发表于 06-23 10:49 1634次阅读

    Docker镜像的详细讲解

    本文是对 Docker 镜像的详细讲解,讲解了如何安装 Docker、配置 Docker 镜像加速以及操作
    的头像 发表于 08-02 10:00 2892次阅读

    从零开始学习制作、以及使用Tina的Docker编译镜像

    学习制作、以及使用Tina的Docker编译镜像
    的头像 发表于 08-28 11:45 3144次阅读
    从零开始学习制作、以及使用Tina的<b class='flag-5'>Docker</b>编译<b class='flag-5'>镜像</b>

    减少docker镜像大小的方法

    Docker 是一种容器引擎,可以在容器内运行一段代码。Docker 镜像是在任何地方运行您的应用程序而无需担心应用程序依赖性的方式。
    的头像 发表于 05-15 11:13 1552次阅读
    减少<b class='flag-5'>docker</b><b class='flag-5'>镜像</b>大小的方法

    docker 搜索镜像,docker查看镜像详细信息(docker下载镜像命令)

    Docker Hub是集中管理的Docker镜像注册中心。通过Docker 用户可以在注册中心搜索、下载和使用CLI命令行工具中的镜像。以下
    的头像 发表于 07-19 09:46 2745次阅读

    Dockerfile定义Docker镜像的构建过程

    了解Dockerfile Dockerfile 是一个文本文件,用于定义 Docker 镜像的构建过程。它以指令的形式描述了如何构建镜像,从基础镜像开始逐步添加配置、文件和依赖,最终形
    的头像 发表于 09-30 10:22 3218次阅读

    构建docker镜像应该遵循哪些原则

    构建 Docker 镜像时,应遵循以下原则: 单一职责:每个镜像应只包含一个应用或服务,避免将多个应用或服务放在同一个镜像中。这样可以确保镜像
    的头像 发表于 11-23 09:41 1879次阅读

    手动构建Docker镜像的方法

    不推荐使用docker commit命令,而应该使用更灵活、更强大的dockerfile来构建docker镜像
    的头像 发表于 08-05 15:30 1316次阅读
    手动构建<b class='flag-5'>Docker</b><b class='flag-5'>镜像</b>的方法

    Dockerfile镜像制作与Docker-Compose容器编排

    Dockerfile镜像制作 docker/podman中, 镜像是容器的基础,每次执行docker run的时候都会指定哪个基本镜像作为容
    的头像 发表于 01-07 11:01 1145次阅读
    Dockerfile<b class='flag-5'>镜像</b>制作与<b class='flag-5'>Docker</b>-Compose容器编排

    Docker-镜像的分层-busybox镜像制作

    目录 知识点1:镜像的分层 示例:进入 docker hub查看Jenkins的Dockerfile 知识点2:base镜像 知识点3:scratch镜像 scratch
    的头像 发表于 01-15 10:44 1007次阅读
    <b class='flag-5'>Docker</b>-<b class='flag-5'>镜像</b>的分层-busybox<b class='flag-5'>镜像</b>制作

    docker-proxy镜像加速仓库

    自建多平台容器镜像代理服务,支持 Docker Hub, GitHub, Google, k8s, Quay, Microsoft 等镜像仓库。
    的头像 发表于 03-06 16:06 796次阅读
    <b class='flag-5'>docker</b>-proxy<b class='flag-5'>镜像</b>加速仓库

    基于Docker镜像逆向生成Dockerfile

    在本文中, 我们将通过理解Docker镜像如何存储数据, 以及如何使用工具查看镜像方方面面的信息来逆向工程一个Docker镜像; 以及如何使
    的头像 发表于 03-10 09:45 1217次阅读
    基于<b class='flag-5'>Docker</b><b class='flag-5'>镜像</b>逆向生成Dockerfile