极兔一面:Dockerfile如何优化?注意:千万不要只说减少层数
说在前面
在40岁老架构师 尼恩的读者交流群(50+)中,面试题是一个非常、非常高频的交流话题。
最近,有小伙伴面试极兔时,遇到一个面试题:
如果优化 Dockerfile?
小伙伴没有回答好,只是提到了减少镜像层数。
一般来说,面试的小伙伴,大部分都会说
- 使用更小的基础镜像, 比如
alpine
. - 减少镜像层数, 比如 使用
&&
符号将命令链接起来。 - 给基础镜像打上 安全补丁。
但这些,其实都是单点的优化。优化 Dockerfile 的核心是 合理分层、构建一个精良的基础镜像。
这里尼恩给大家做一下系统化、体系化的梳理,使得大家可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”。
也一并把这个题目以及参考答案,收入咱们的 《尼恩Java面试宝典》V46版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。
注:本文以 PDF 持续更新,最新尼恩 架构笔记、面试题 的PDF文件,请从这里获取:码云
为什么要优化镜像
首先,回到起点。为啥要优化 镜像?优化镜像的好处是:
- 一个小镜像有什么好处: 分发更快,存储更少,加载更快。
- 镜像臃肿带来了什么问题: 存储过多,分发更慢且浪费带宽更多。
镜像的构成
其次,来看看镜像的构成。从两个维度来看:
- 俯瞰镜像: 就是一个删减版的操作系统。
- 侧看镜像: 由一层层的
layer
堆叠而成
那么问题来了
应该如何优化镜像?
举个例子 docker build
- Dockerfile v1
# v1
FROM nginx:1.15-alpine
RUN echo "hello"
RUN echo "demo best practise"
ENTRYPOINT [ "/bin/sh" ]
- Dockerfile v2
# v2
FROM nginx:1.15-alpine
RUN echo "hello"
RUN echo "demo best practise"
ENTRYPOINT [ "/bin/sh" ]
1st build
全新构建
# docker build -t demo:0.0.1 .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM nginx:1.15-alpine---> 9a2868cac230
Step 2/4 : RUN echo "hello"---> Running in d301b4b3ed55
hello
Removing intermediate container d301b4b3ed55---> 6dd2a7773bbc
Step 3/4 : RUN echo "demo best practise"---> Running in e3084037668e
demo best practise
Removing intermediate container e3084037668e---> 4588ecf9837a
Step 4/4 : ENTRYPOINT [ "/bin/sh" ]---> Running in d63f460347ff
Removing intermediate container d63f460347ff---> 77b52d828f21
Successfully built 77b52d828f21
Successfully tagged demo:0.0.1
2nd build
Dockerfile 与 1st build
完全一致, 命令仅修改 build tag , 从 0.0.1
到 0.0.2
# docker build -t demo:0.0.2 .
Sending build context to Docker daemon 4.096kB
Step 1/4 : FROM nginx:1.15-alpine---> 9a2868cac230
Step 2/4 : RUN echo "hello"---> Using cache---> 6dd2a7773bbc
Step 3/4 : RUN echo "demo best practise"---> Using cache---> 4588ecf9837a
Step 4/4 : ENTRYPOINT [ "/bin/sh" ]---> Using cache---> 77b52d828f21
Successfully built 77b52d828f21
Successfully tagged demo:0.0.2
可以看到,
- 每层 layer 都使用 cache (
---> Using cache
) ,并未重新构建。 - 我们可以通过
docker image ls |grep demo
看到,demo:0.0.1
与demo:0.0.2
的 layer hash 是相同。
所以从根本上来说, 这两个镜像就是同一个镜像,虽然都是 build 出来的。
3rd build
这次, 我们将Dockerfile 02的 第三层 RUN echo "demo best practise"
变更为 RUN echo "demo best practise 02"
docker build -t demo:0.0.3 .
Sending build context to Docker daemon 4.608kB
Step 1/4 : FROM nginx:1.15-alpine---> 9a2868cac230
Step 2/4 : RUN echo "hello"---> Using cache---> 6dd2a7773bbc
Step 3/4 : RUN echo "demo best practise 02"---> Running in c55f94e217bd
demo best practise 02
Removing intermediate container c55f94e217bd---> 46992ea04f49
Step 4/4 : ENTRYPOINT [ "/bin/sh" ]---> Running in f176830cf445
Removing intermediate container f176830cf445---> 2e2043b7f3cb
Successfully built 2e2043b7f3cb
Successfully tagged demo:0.0.3
可以看到 ,
- 第二层仍然使用
cache
- 但是第三层已经生成了新的 hash 了
- 虽然第四层的操作没有变更,但是由于上层的镜像已经变化了,所以第四层本身也发生了变化。
注意: 每层在
build
的时候都是依赖于上册---> Running in f176830cf445
。
4th build
第四次构建, 这次使用 --no-cache
不使用缓存, 模拟在另一台电脑上进行 build 。
# docker build -t demo:0.0.4 --no-cache .
Sending build context to Docker daemon 5.632kB
Step 1/4 : FROM nginx:1.15-alpine---> 9a2868cac230
Step 2/4 : RUN echo "hello"---> Running in 7ecbed95c4cd
hello
Removing intermediate container 7ecbed95c4cd---> a1c998781f2e
Step 3/4 : RUN echo "demo best practise 02"---> Running in e90dae9440c2
demo best practise 02
Removing intermediate container e90dae9440c2---> 09bf3b4238b8
Step 4/4 : ENTRYPOINT [ "/bin/sh" ]---> Running in 2ec19670cb14
Removing intermediate container 2ec19670cb14---> 9a552fa08f73
Successfully built 9a552fa08f73
Successfully tagged demo:0.0.4
可以看到,
- 虽然和
3rd build
使用的Dockerfile
相同, 但由于没有缓存,每一层都是重新 build 的。 - 虽然
demo:0.0.3
和demo:0.0.4
在功能上是一致的。但是 他们的 layer 不同, 从根本上来说,他们是不同的镜像。
结论
1. 合理分层、构建一个精良的基础镜像
- 一个相对固定的
build
环境 - 善用
cache
- 构建
自己的基础镜像
:其中就包括了
a. 安全补丁
b. 权限限制
c. 基础库依赖安装
d. 等…
2. 精简为美:一屋不扫何以扫天下
- 使用
.dockerignore
保持context
干净 - 容器镜像环境清理
a. 缓存清理
b.multi stage build
尼恩提示:以上答案,所包含的技术细节比较多,具体请参见《尼恩Java面试宝典》最新版。
参考文献
docker storage driver
: https://docs.docker.com/storage/storagedriver/dockerfile best practices
: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/multi-stage
: https://docs.docker.com/develop/develop-images/multistage-build/
推荐阅读:
《响应式圣经:10W字,实现Spring响应式编程自由》
《全链路异步,让你的 SpringCloud 性能优化10倍+》
《Linux命令大全:2W多字,一次实现Linux自由》
《网易二面:CPU狂飙900%,该怎么处理?》
《阿里二面:千万级、亿级数据,如何性能优化? 教科书级 答案来了》
《峰值21WQps、亿级DAU,小游戏《羊了个羊》是怎么架构的?》
《场景题:假设10W人突访,你的系统如何做到不 雪崩?》
《2个大厂 100亿级 超大流量 红包 架构方案》
《Nginx面试题(史上最全 + 持续更新)》
《K8S面试题(史上最全 + 持续更新)》
《操作系统面试题(史上最全、持续更新)》
《Docker面试题(史上最全 + 持续更新)》
《Springcloud gateway 底层原理、核心实战 (史上最全)》
《Flux、Mono、Reactor 实战(史上最全)》
《sentinel (史上最全)》
《Nacos (史上最全)》
《TCP协议详解 (史上最全)》
《分库分表 Sharding-JDBC 底层原理、核心实战(史上最全)》
《clickhouse 超底层原理 + 高可用实操 (史上最全)》
《nacos高可用(图解+秒懂+史上最全)》
《队列之王: Disruptor 原理、架构、源码 一文穿透》
《环形队列、 条带环形队列 Striped-RingBuffer (史上最全)》
《一文搞定:SpringBoot、SLF4j、Log4j、Logback、Netty之间混乱关系(史上最全)》
《单例模式(史上最全)》
《红黑树( 图解 + 秒懂 + 史上最全)》
《分布式事务 (秒懂)》
《缓存之王:Caffeine 源码、架构、原理(史上最全,10W字 超级长文)》
《缓存之王:Caffeine 的使用(史上最全)》
《Java Agent 探针、字节码增强 ByteBuddy(史上最全)》
《Docker原理(图解+秒懂+史上最全)》
《Redis分布式锁(图解 - 秒懂 - 史上最全)》
《Zookeeper 分布式锁 - 图解 - 秒懂》
《Zookeeper Curator 事件监听 - 10分钟看懂》
《Netty 粘包 拆包 | 史上最全解读》
《Netty 100万级高并发服务器配置》
《Springcloud 高并发 配置 (一文全懂)》
相关文章:

极兔一面:Dockerfile如何优化?注意:千万不要只说减少层数
说在前面 在40岁老架构师 尼恩的读者交流群(50)中,面试题是一个非常、非常高频的交流话题。 最近,有小伙伴面试极兔时,遇到一个面试题: 如果优化 Dockerfile? 小伙伴没有回答好,只是提到了减少镜像层数。…...

SpringBoot+Vue实现酒店客房管理系统
文末获取源码 开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7/8.0 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9 浏…...

自适应多因素认证:构建不可破解的企业安全防线|身份云研究院
打开本文意味着你理解信息安全的重要性,并且希望获取行业最佳实践来保护你所在组织的信息安全。本文将带你了解多因素认证(MFA:Multi-Factor-Authentication)对于企业信息安全的重要性以及实施方法。 多因素认证(MFA&…...
阶段二8_集合ArrayList_学生管理系统_详细步骤
一.学生管理系统案例 1.需求: 针对目前我们的所学内容,完成一个综合案例:学生管理系统! 该系统主要功能如下: 1.添加学生:通过键盘录入学生信息,添加到集合中 2.删除学生:通过键盘录…...

一篇解决Linux 中的负载高低和 CPU 开销并不完全对应
负载是查看 Linux 服务器运行状态时很常用的一个性能指标。在观察线上服务器运行状况的时候,我们也是经常把负载找出来看一看。在线上请求压力过大的时候,经常是也伴随着负载的飙高。 但是负载的原理你真的理解了吗?我来列举几个问题&#x…...

关于IDM下载器,提示:一个假冒的序列号被用来注册……idea项目文件路径报红
关于IDM下载器,提示:一个假冒的序列号被用来注册……到C:\Windows\System32\drivers\etc 修改目录下面的hosts文件(如果没有修改的权限就右键属性hosts文件修改user的权限为完全控制),在hosts里面增加以下内容…...

JVM - 高效并发
目录 Java内存模型和内存间的交互操作 Java内存模型 内存间的交互操作 内存间交互操作的规则 volatile特性 多线程中的可见性 volatile 指令重排原理和规则 指令重排 指令重排的基本规则 多线程中的有序性 线程安全处理 锁优化 锁优化之自旋锁与自适应自旋 锁优…...

中小学智慧校园电子班牌系统源码 Saas云平台模式
智慧电子班牌区别于传统电子班牌,智慧校园电子班牌系统更加注重老师和学生的沟通交流和及时数据交互。学校为每个教室配置一台智能电子班牌,一般安装于教室门口,用来实时显示学校通知、班级通知,可设置集中分布式管理,…...

记录一次服务器被攻击的经历
突然收到阿里云发过来的异常登陆的信息: 于是,急忙打开电脑查看对应的ECS服务器的记录: 发现服务器的cpu占用率异常飙升,所以可以大概断定服务器已经被非法入侵了。 通过自己的账号登陆后,发现sshd服务有异常的链接存…...
Python解题 - CSDN周赛第29期 - 争抢糖豆
本期问哥是志在必得,这本算法书我已经觊觎许久,而之前两次因为种种原因未能如愿。因此,问哥这几天花了不少时间,把所有之前在每日一练做过的题目重新梳理了一遍。苦心人,天不负,感谢官方大大! 第…...

C代码中访问链接脚本中的符号
一、目的在之前的《GNU LD脚本命令语言(一)》、《GNU LD脚本命令语言(二)》我们介绍了GNU链接脚本的知识点,基本上对链接脚本中的SECTION、REGION、以及加载地址与执行地址的关系等内容有了一定的了解。本篇主要讲解链…...

MySQL 8:MySQL索引
索引就是通过一定的算法建立数据模型,用于快速查找某一列中具有特定值的行。如果没有索引,MySQL 必须从第一条记录开始读取整个表,直到找到相关的表。表越大,查询数据所花费的时间就越多。如果表中查询的列有索引,MySQ…...

JVM详解
一,JVM 1,JVM区域划分 类装载器,运行时数据区,字节码执行引擎 2,JVM内存模型(运行时数据区) 由本地方法栈,虚拟机栈,堆,方法区,和程序计数器组成。…...

MySQL数据库调优————索引数据结构
B-TREE B-TREE数据结构 B-TREE特性 根节点的子结点个数2 < X < m,m是树的阶 假设m 3,则根节点可有2-3个孩子 中间节点的子节点个数m/2 < y < m 假设m 3,中间节点至少有2个孩子,最多3个孩子 每个中间节点包含n个关…...

visual studio 改变界面语言
在使用visual studio 2019 时,开始是英文界面,后面变成了中文界面。但是看视频教学时有的是英文界面,我就想回到英文界面,所以有切换界面语言的需要。其实操作很简单:工具-> 选项 打开界面在界面里选择环境…...
2023.2.16每日一题——1250. 检查「好数组」
每日一题题目描述解题核心解法一:数论题目描述 题目链接:1250. 检查「好数组」 给你一个正整数数组 nums,你需要从中任选一些子集,然后将子集中每一个数乘以一个 任意整数,并求出他们的和。 假如该和结果为 1&#x…...

亿级高并发电商项目-- 实战篇 --万达商城项目 八(安装FastDFS、安装Nginx、文件服务模块、文件上传功能、商品功能与秒杀商品等功能)
专栏:高并发---分布式项目 👏作者简介:大家好,我是小童,Java开发工程师,CSDN博客博主,Java领域新星创作者 📕系列专栏:前端、Java、Java中间件大全、微信小程序、微信支…...

Viper捐款7000万韩元,合计人民币是多少钱?
Viper捐款7000万韩元,合计人民币是多少钱? #2023LCK春季赛##英雄联盟# #Viper捐款7000万韩元# Viper向大田东区捐款 7000 万,成为大田荣誉协会 105 号会员。Viper选手从 2019 年开始一直向大田东区捐款,但是他不希望这件事被公开…...

前端vue实现系统拦截跳转外链并进入跳转询问界面
跳转询问界面如下图所示: 给自己挖坑的实现方式,最终解决方案请看最底下 思路:正常情况下我们有2种方式跳转外链 第一种非a标签,我们手动添加事件进行跳转 <div class"dingdan public-padding p-item" click&quo…...
【Linux】Shell(Bash)单引号、双引号、不加引号和反引号用法和区别详解
简要总结 不加引号:不会将含有空格的字符串视为一个整体输出, 如果内容中有变量等,会先把变量解析出结果,然后在输出最终内容来,如果字符串中带有空格等特殊字符,则不能完整的输出,需要改加双引号ÿ…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...