docker镜像瘦身思路
docker镜像瘦身思路
一、简介
docker镜像太大,带来了以下几个问题:
- 存储开销
这块影响其实不算很大,因为对服务器磁盘来说,15GB的存储空间并不算大,除非用户服务器的磁盘空间很紧张
- 部署时间
这块影响真的很大,交付件zip包太大,导致用户部署该产品时,花费的时间变长,客户现场中反馈部署时间超过1.5小时,这严重影响用户的体验,降低满意度
- 性能不稳定
如果客户的服务器规格不够(特别是磁盘读写性能不够),会增大部署失败的概率。
二、瘦身思路
以下思路是我在该任务中尝试使用用于镜像瘦身的方法,均可以不同程度的降低DOcker镜像的尺寸。
- 清理Docker镜像中的无用安装包
在Dockerfile构建Docker镜像过程中,有可能引入临时文件,比如:安装包i、文件压缩包。这些临时文件忘记清理,导致占据了一定的尺寸,有必要对其进行清理。
如下Dockerfile:
FROM xxxx/xxxx-jdk:1.0.0RUN apt-get update && apt-get install -y git maven
mysql-client nodejs nodejs-legacy python-pip graphviz npm unzip
Dockerfile里面经常安装很多工具,安装完后,需要及时删除安装包缓存
(alpine) apk del openssh vim:删除包及其依赖包
(Ubuntu) Apt-get clean:删除所有已下载的包文件
(centos) Yum clean all: yum 会把下载的软件包和header存储在cache中,而不自动删除。如果觉得占用磁盘空间,可以使用yum clean指令进行清除,更精确 的用法是yum clean headers清除header,yum clean packages清除下载的rpm包,yum clean all一全部清除
上面的dockerfile中在安装工具后应该执行下: && apt-get clean && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y git maven
mysql-client nodejs nodejs-legacy python-pip graphviz npm unzip && apt-get clean && rm -rf /var/lib/apt/lists/*
实例:
FROM centos:7
RUN yum update -y
RUN yum install -y wget unzip socat java-1.8.0-openjdk-headless
# Set permissions
RUN yum clean all
EXPOSE 8486
修改:将黄色标示的部分改写成如下,大小从691Mb下降到583Mb
RUN yum update -y && yum install -y wget unzip socat java-1.8.0-openjdk-headless && yum clean all
- 避免不必要的工具安装
有的Dockerfile中安装了很多工具,这个工具的加在一起尺寸比较大,这块需要挨个排查:客户环境下,需不需要安装该工具?很多工具其实是面向开发使用的,而用户根本不会使用,那么就没有必要在客户环境上使用安装这么工具的镜像,应该仔细排除工具的必要性,会给镜像瘦身带来比较大的收益。比如, dockerfile中安装了JDK。 这个有些情况下,完全没必要,实际上可能jre就能搞定。
总之,能不安装,就不安装;能少安装,就少安装;能用轻量级的工具,尽量用轻量级的工具!!!
- 多阶段构建
Docker多阶段构建是17.05以后引入的新特性,旨在解决编译、构建复杂和镜像大小的问题。对于多阶段构建,可以在Dockerfile中使用多个FROM语句。每个FROM指令可以使用不同的基础,并且每个指令都开始一个新的构建。您可以选择性地将工件从一个阶段复制到另一个阶段,从而在最终image中只留下您想要的内容。
如下图所示为多阶段构建的使用示例:
把多个Dockerfile合并在一块,每个Dockerfile单独作为一个“阶段”,“阶段”之间可以互相联系,让后一个阶段构建可以使用前一个阶段构建的产物,形成一条构建阶段的chain,最终结果仅产生一个image,避免产生冗余的多个临时images或临时容器对象。
1)多阶段构建使用之前
针对多阶段构建的特点,分析我们产品里面的dockerfile,如下面所示,该操作的目的是将tar包拷贝值容器内的路径下,并解压、执行后续操作。然而COPY层具有一定的大小,只起到临时层的作用。(特别是这个tar包足足几百MB!)。
FROM xxxx:${project.version}COPY karaf-${ccsdk.opendaylight.version}.tar.gz /tmp/
RUN mkdir /opt/opendaylight \
&& tar zxvf /tmp/karaf-${ccsdk.opendaylight.version}.tar.gz --directory /opt/opendaylight \&& rm -rf /tmp/karaf-${ccsdk.opendaylight.version}.tar.gz \
&& mv /opt/opendaylight/karaf-${ccsdk.opendaylight.version} /opt/opendaylight/current && mkdir -p /opt/opendaylight/current && ln -s /opt/opendaylight/current /opt/opendaylight/karaf-${ccsdk.opendaylight.version}
RUN mkdir -p /opt/opendaylight/current/system/org/mariadb/jdbc/mariadb-java-client/${ccsdk.mariadb-connector-java.version}
COPY mariadb-java-client-${ccsdk.mariadb-connector-java.version}.jar /opt/opendaylight/current/system/org/mariadb/jdbc/mariadb-java-client/${ccsdk.mariadb-connector-java.version}
EXPOSE 8181
2) 使用多阶段构建
使用多阶段构建,修改后的dockerfile如下图所示,修改实现将第一阶段拷贝并解压好的文件复制过来即可,少了拷贝tar包的环节,这样使得最终形成的镜像中镜像层数得到有效的降低,也一定程度上降低了镜像尺寸。
FROM xxxx:${project.version} as baseFirst
COPY karaf-${ccsdk.opendaylight.version}.tar.gz /tmp/
RUN mkdir /opt/opendaylight \
&& tar zxvf /tmp/karaf-${ccsdk.opendaylight.version}.tar.gz --directory /opt/opendaylight \&& rm -rf /tmp/karaf-${ccsdk.opendaylight.version}.tar.gz \
&& mv /opt/opendaylight/karaf-${ccsdk.opendaylight.version} /opt/opendaylight/current FROM xxxxxe:${project.version} as baseSecondRUN mkdir -p /opt/opendaylight/current && ln -s /opt/opendaylight/current /opt/opendaylight/karaf-${ccsdk.opendaylight.version}
COPY --from=baseFirst /opt/opendaylight/current /opt/opendaylight/current
RUN mkdir -p /opt/opendaylight/current/system/org/mariadb/jdbc/mariadb-java-client/${ccsdk.mariadb-connector-java.version}
COPY mariadb-java-client-${ccsdk.mariadb-connector-java.version}.jar /opt/opendaylight/current/system/org/mariadb/jdbc/mariadb-java-client/${ccsdk.mariadb-connector-java.version}
EXPOSE 8181
- Copy和赋权同时执行
FROM ubuntu:16.04
# Copy APIKeys
COPY ./messageservice/ /tmp/zookeeper/gerrit ------A
EXPOSE 2181 2888 3888
B------> RUN useradd $ZK_USER && [ `id -u $ZK_USER` -eq 1000 ] && [ `id -g $ZK_USER` -eq 1000 ] && chown -R $ZK_USER:$ZK_USER /opt/$ZK_DIST/ /opt/zookeeper/ /var/lib/ /var/log/ /tmp/zookeeper/
USER $ZK_USER
问题排查如下:A处copy的文件700MB太大,很多文件没用到
B处给/tmp/zookeeper添加属组和属主,该层也很大
修改:使用 COPY –chown=1000:1000 ./messageservice/ /tmp/zookeeper/gerrit, 镜像大小从1.4GB 下降到700Mb
- 镜像层的复用
这一块修改得当的话,得到的收益是最大的!!!最大的!!!最大的!!!
我们知道docker镜像具有层级结构,如果很多镜像具有相同的层,则这些相同的层就能得到复用(把多个镜像生成一个tar),docker不会保存两份相同放入层文件,通过提高层得复用能显著降低整体的镜像尺寸。比如常见方法有:替换统一的基础镜像、创建出统一的基础镜像、调整层的顺序等等。这里东西没有整理,就不上图了,可以自行脑补,查阅资料即可
我这边经过这一步调整后,zip产品包从11.45GB下降到6.96GB
最终zip包从15GB下降到7GB
docker镜像瘦身思路的更多相关文章
- 三个技巧帮助Docker镜像瘦身
在构建Docker容器时,应该尽量想办法获得体积更小的镜像,因为传输和部署体积较小的镜像速度更快. 但RUN语句总是会创建一个新层,而且在生成镜像之前还需要使用很多中间文件,在这种情况下,该如何获得体 ...
- Docker系列之镜像瘦身(五)
前言 本节我们来讲讲在我们在构建镜像过程中不出问题,同时使得最后所构建的镜像文件大小尽可能最小,温馨提示:文中大图均可点击放大查看详细信息. 缓存(cache) Docker的优势之一在于提供了缓存, ...
- Docker容器镜像瘦身的三个小窍门(转)
[转自:http://dockone.io/article/8174] 在构建Docker容器时,我们应尽可能减小镜像的大小.使用共享层的镜像尺寸越小,其传输和部署速度越快. 不过在每个RUN语句都会 ...
- iOS内置图片瘦身思路整理
一.前言 前段时间注意到我们APP的包大小超过100MB了,所以随口跟老板说了下能否采用字体文件(.ttf)替代PNG图片,老板对应用瘦身很感兴趣因此让我做下技术调研.这篇文章主要是将我们的各个技术方 ...
- docker nginx-php容器镜像瘦身优化
1. 在安装好php环境的容器,参考上面贴出的链接那篇文章的部分,做好基础工作: #创建工作目录 mkdir /rootfs #进入工作目录 cd /rootfs #创建基础目录 mkdir -p b ...
- 我可以减肥失败,但我的 Docker 镜像一定要瘦身成功!
作者|徐伟 来源|尔达 Erda 公众号 简介 容器镜像类似于虚拟机镜像,封装了程序的运行环境,保证了运行环境的一致性,使得我们可以一次创建任意场景部署运行.镜像构建的方式有两种,一种是通过 do ...
- iOS控制器瘦身-面向超类编程
今天写这篇文章的目的,是提供一种思路,来帮助大家解决控制器非常臃肿的问题,对控制器瘦身. 滴滴 老司机要开车了 如果手边有项目,不妨打开工程看一下你的控制器代码有多少行,是不是非常多?再看一下tabl ...
- Docker之Alpine制作jre镜像(瘦身)+自定义镜像上传阿里云
alpine制作jdk镜像 alpine Linux简介 1.Alpine Linux是一个轻型Linux发行版,它不同于通常的Linux发行版,Alpine采用了musl libc 和 BusyBo ...
- Spring Boot打包瘦身 Docker 使用全过程 动态配置、日志记录配置
springBoot打包的时候代码和jar包打包在同一个jar包里面,会导致jar包非常庞大,在不能连接内网的时候调试代码,每次只改动了java代码就需要把所有的jar包一起上传,导致传输文件浪费了很 ...
随机推荐
- Redis数据迁移同步工具(redis-shake)
前言 最近线上一台自建redis服务的服务器频繁报警,内存使用率有点高,这是一台配置比较简陋(2C8G)的机子了,近期也打算准备抛弃它了.抛弃之前需对原先的数据进行迁移,全量数据,增量数据都需要考虑, ...
- SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'xxx' already exists
字面意思 xxx表已存在. 在使用laravel 写同步结构的时候 最好习惯性写个if语句判定是否存在 // 判断数据表是否存在 Schema::hasTable('table'); // 判断数据 ...
- 在 Linux 系统中如何管理 systemd 服务
在上一篇文章<Linux的运行等级与目标>中,我介绍过 Linux 用 systemd 来取代 init 作为系统的初始化进程.尽管这一改变引来了很多争议,但大多数发行版,包括 RedHa ...
- 数据库-第八章 数据库编程-8.4 ODBC编程
ODBC编程 一.ODBC概述 二.ODBC工作原理概述 1.用户应用程序 2.ODBC驱动程序管理器 3.数据库驱动程序 4.数据源管理 5.小结 三.ODBC API基础 1.函数概述 2.句柄及 ...
- 一文说通Dotnet Core的中间件
前几天,公众号后台有朋友在问Core的中间件,所以专门抽时间整理了这样一篇文章. 一.前言 中间件(Middleware)最初是一个机械上的概念,说的是两个不同的运动结构中间的连接件.后来这个概念 ...
- Java实现 蓝桥杯 算法提高VIP 摆花 dp 记忆搜索 2种做法 多重背包
题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号.为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时 ...
- C# winform 学习(三)
目标 1.windows程序简介 2.窗体的常用属性和事件 3.显示消息框 4.多窗体应用 一.程序简介 1.特点:所见即所得,通过事件实现用户与界面的交互 2.程序结构 1)窗体文件(每个窗体至少有 ...
- Java实现 蓝桥杯VIP 算法训练 求完数
问题描述 如果一个自然数的所有小于自身的因子之和等于该数,则称为完数.设计算法,打印1-9999之间的所有完数. 样例输出 与上面的样例输入对应的输出. 例: 数据规模和约定 1-9999 publi ...
- Java实现蓝桥杯模拟元音单词的验证
问题描述 小明对类似于 hello 这种单词非常感兴趣,这种单词可以正好分为四段,第一段由一个或多个辅音字母组成,第二段由一个或多个元音字母组成,第三段由一个或多个辅音字母组成,第四段由一个或多个元音 ...
- Java实现 LeetCode 207 课程表
207. 课程表 现在你总共有 n 门课需要选,记为 0 到 n-1. 在选修某些课程之前需要一些先修课程. 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1] ...