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

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

3天内不再提示

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

马哥Linux运维 来源:CSDN技术社区 作者:Scoful 2022-06-23 10:49 次阅读

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

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

使用的项目源码地址 (https://github.com/scoful/kingProject)

本地直接编译打一个linux运行包

set GOOS=linuxset GOARCH=amd64go build main.go

d5260a4c-f231-11ec-ba43-dac502259ad0.png

结果是22M

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

Dockerfile文件内容

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

编译镜像后查询结果如下:

d5333776-f231-11ec-ba43-dac502259ad0.png

结果是941M,基本跟基础镜像golang的大小一致,而且因为没有预先编译,等到运行的时候再编译并拉取依赖包,run起来很慢

3. 编译后的镜像 1.14G

Dockerfile文件内容# 基础镜像,基于golang最新镜像构建FROM golang# 作者MAINTAINER scoful# 全局工作目录WORKDIR $GOPATH/kingProject# 把运行Dockerfile文件的当前目录所有文件复制到目标目录COPY . $GOPATH/kingProject# 环境变量#  用于代理下载go项目依赖的包ENV GOPROXY https://goproxy.cn,direct# 编译RUN GOOS=linux GOARCH=amd64 go build main.go# 需暴露的端口EXPOSE 8888# 可外挂的目录VOLUME ["/go/kingProject/config","/go/kingProject/log"]# docker run命令触发的真实命令(相当于直接运行编译后的可运行文件)ENTRYPOINT ["./main"]

d545119e-f231-11ec-ba43-dac502259ad0.png

结果是1.14G,更大了,因为加上了编译过程中拉取的包,但是预先编译,所以直接run,速度很快

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

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

Dockerfile文件内容

# 基础镜像,基于golang的alpine版本镜像构建FROM golang:alpine# 作者MAINTAINER scoful# 全局工作目录WORKDIR $GOPATH/kingProject# 把运行Dockerfile文件的当前目录所有文件复制到目标目录COPY . $GOPATH/kingProject# 环境变量#  用于代理下载go项目依赖的包ENV GOPROXY https://goproxy.cn,direct# 编译RUN GOOS=linux GOARCH=amd64 go build main.go# 需暴露的端口EXPOSE 8888# 可外挂的目录VOLUME ["/go/kingProject/config","/go/kingProject/log"]# docker run命令触发的真实命令(相当于直接运行编译后的可运行文件)ENTRYPOINT ["./main"]

d554eeac-f231-11ec-ba43-dac502259ad0.png

结果是517M,比1.14G减少了650.36M,直接降了56%,而且run一样很快

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

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

Dockerfile文件内容

# 基础镜像,基于golang的alpine镜像构建--编译阶段FROM golang:alpine AS builder# 作者MAINTAINER scoful# 全局工作目录WORKDIR /go/kingProject# 把运行Dockerfile文件的当前目录所有文件复制到目标目录COPY . /go/kingProject# 环境变量#  用于代理下载go项目依赖的包ENV GOPROXY https://goproxy.cn,direct# 编译,关闭CGO,防止编译后的文件有动态链接,而alpine镜像里有些c库没有,直接没有文件的错误RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build main.go

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

d5674264-f231-11ec-ba43-dac502259ad0.png

结果是28.4M,比517M减少了488.6M,再降95%,那个533M是第一级构建生成的

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

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

Dockerfile文件内容

# 基础镜像,基于golang的alpine镜像构建--编译阶段FROM golang:alpine AS builder# 作者MAINTAINER scoful# 全局工作目录WORKDIR /go/kingProject# 把运行Dockerfile文件的当前目录所有文件复制到目标目录COPY . /go/kingProject# 环境变量#  用于代理下载go项目依赖的包ENV GOPROXY https://goproxy.cn,direct# 编译,关闭CGO,防止编译后的文件有动态链接,而alpine镜像里有些c库没有,直接没有文件的错误RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build main.go



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

d5721edc-f231-11ec-ba43-dac502259ad0.png

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

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

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

Dockerfile文件内容

# 基础镜像,基于golang的alpine镜像构建--编译阶段FROM golang:alpine AS builder# 作者MAINTAINER scoful# 全局工作目录WORKDIR /go/kingProject# 把运行Dockerfile文件的当前目录所有文件复制到目标目录COPY . /go/kingProject# 环境变量#  用于代理下载go项目依赖的包ENV GOPROXY https://goproxy.cn,direct# 编译,关闭CGO,防止编译后的文件有动态链接,而alpine镜像里有些c库没有,直接没有文件的错误RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-w -s" main.go

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

d58ca888-f231-11ec-ba43-dac502259ad0.png

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

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

Dockerfile文件内容

# 基础镜像,基于golang的alpine镜像构建--编译阶段FROM golang:alpine AS builder# 作者MAINTAINER scoful# 全局工作目录WORKDIR /go/kingProject# 把运行Dockerfile文件的当前目录所有文件复制到目标目录COPY . /go/kingProject# 环境变量#  用于代理下载go项目依赖的包ENV GOPROXY https://goproxy.cn,direct# 编译,关闭CGO,防止编译后的文件有动态链接,而alpine镜像里有些c库没有,直接没有文件的错误RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-w -s" main.goRUN echo "https://mirrors.aliyun.com/alpine/v3.8/main/" > /etc/apk/repositories     && echo "https://mirrors.aliyun.com/alpine/v3.8/community/" >> /etc/apk/repositories     && apk add --no-cache tzdata     && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime      && echo Asia/Shanghai > /etc/timezone     && apk del tzdata

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

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

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

Dockerfile文件内容

# 基础镜像,基于golang的alpine镜像构建--编译阶段FROM golang:alpine AS builder# 作者MAINTAINER scoful# 全局工作目录WORKDIR /go/kingProject# 把运行Dockerfile文件的当前目录所有文件复制到目标目录COPY . /go/kingProject# 环境变量#  用于代理下载go项目依赖的包ENV GOPROXY https://goproxy.cn,direct# 编译,关闭CGO,防止编译后的文件有动态链接,而alpine镜像里有些c库没有,直接没有文件的错误RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-w -s" main.go

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

over,Enjoy!!!

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

文章出处:【微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

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

    关注

    87

    文章

    11292

    浏览量

    209323
  • 镜像
    +关注

    关注

    0

    文章

    164

    浏览量

    10707
  • Docker
    +关注

    关注

    0

    文章

    457

    浏览量

    11846

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

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    怎么构建docker镜像仓库软件

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

    【Milk-V Duo 开发板免费体验】2、SDK编译环境的Docker镜像制作教程

    开始学习制作docker镜像 准备工作:安装docker(百度很多教程,没啥好说,不废话),然后将附件里的压缩包解压缩到任意目录,在命令行中进入该目录下。 编制制作脚本
    发表于 08-24 20:23

    Docker上的Alpine Linux镜像建立

    如何建立你自己的Docker镜像2016-03-18 14:33 Alpine Linux的什么是Docker社区所钟爱?轻量级容器意味着更多的计算资源。Alpine Linux的确是轻型
    发表于 10-12 11:52 0次下载

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

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

    Docker—简介与镜像用法

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

    Heroku-Docker Docker镜像的Heroku​项目

    ./oschina_soft/heroku-docker.zip
    发表于 05-11 09:46 0次下载
    Heroku-<b class='flag-5'>Docker</b> <b class='flag-5'>Docker</b><b class='flag-5'>镜像</b>的Heroku​<b class='flag-5'>项目</b>

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

    【导读】go 项目怎么 docker 镜像体积减小
    的头像 发表于 06-12 15:07 1408次阅读

    Docker镜像的详细讲解

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

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

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

    减少docker镜像大小的方法

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

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

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

    Dockerfile定义Docker镜像的构建过程

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

    如何在Windows系统上设置Docker镜像

    在使用 Docker 进行镜像下载和构建时,由于众所周知的原因,国内用户可能会遇到下载速度慢或者无法连接的问题。为了解决这个问题,我们可以使用国内的镜像源来加速下载速度。本文将介绍如何在 Windows 系统上设置
    的头像 发表于 10-24 16:55 5951次阅读

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

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

    手动构建Docker镜像的方法

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