干货总结!Dockerfile编写优秀实践

Dockerfile 优秀实践

1. 善用.dockerignore文件

Docker 是CS架构,这就意味着 Client 和 Server 可以在不同的主机上。在构建镜像的时候,Client 会把所有需要的文件打包发送给 Server,这些发送的文件叫做 build context

默认情况下,构建上下文中所有的文件都会被打包发送给 Docker deamon,但是我们可以使用 .dockerignore 来忽略 build context 中的某些路径和文件,从而避免发送不必要的数据内容,从而加快镜像的创建过程,特别是远程构建的时候

When you run a build command, the build client looks for a file named .dockerignore in the root directory of the context. If this file exists, the files and directories that match patterns in the files are removed from the build context before it’s sent to the builder.

如果你有多个 Dockerfile,你可以为每一个 Dockerfile 指定一个 ignore 文件。为了达到这样的目的,我们需要遵循特定的命名规范:" Place your ignore-file in the same directory as the Dockerfile, and prefix the ignore-file with the name of the Dockerfile":

image-20240206164700081

.dockerignore 的忽略规则如下

  • .dockerignore 中的每一行表示一条忽略规则
  • # 开头的行会被视为注释,不会被处理
  • “the root of the context is considered to be both the working and the root directory” 因此 .dockerignore 中 /foo/bar and foo/bar 是等效的,都是以构建上下文的根路径开始
  • 你可以使用 ! 来排除某些文件,即使他们匹配 .dockerignore 文件中的规则。
  • *:匹配任意数量的字符(包括零个)。
  • ?:匹配单个字符。
  • **:匹配任意数量的目录(包括零个)。 **/*.go 会排除 build context 中所有 .go 结尾的文件
  • !:用于排除特定文件或目录,即使它们被之前的模式匹配。

image-20240206190057649

image-20240206190414403

构建镜像后可以发现,/data 目录下只有 file.data,而 file.txt 被忽略了

image-20240206190508316

2.镜像的多阶段构建

https://docs.docker.com/build/building/multi-stage/

构建docker镜像可以有下面两种方式:

  • 将全部组件及其依赖库的编译、测试、打包等流程封装进一个docker镜像中。但是这种方式存在一些问题,比如Dockefile特别长,可维护性降低;镜像的层次多体积大,部署时间长等问题
  • 将每个阶段分散到多个Dockerfile。一个Dockerfile负责将项目及其依赖库编译测试打包好后,然后将运行文件拷贝到运行环境中,这种方式需要我们编写多个Dockerfile以及一些自动化脚本才能将其两个阶段自动整合起来为了解决以上的两个问题,但是Docker17.5版本开始支持多镜像阶段构建,只需要编写一个Dockerfile即可解决上述问题。

通过多步骤创建,可以将编译测试和运行等过程分开,保证最终生成的镜像只包括运行应用所需要的最小化环境。

image-20240207113259299

Dockerfile 多阶段构建的规则如下:

“With multi-stage builds, you use multiple FROM statements in your Dockerfile. Each FROM instruction can use a different base, and each of them begins a new stage of the build. You can selectively copy artifacts from one stage to another, leaving behind everything you don’t want in the final image.”

“When using multi-stage builds, you aren’t limited to copying from stages you created earlier in your Dockerfile. You can use the COPY --from instruction to copy from a separate image. The Docker client pulls the image if necessary and copies the artifact from there”

也就是说,每一个 FROM 都对应着一个 stage 的开始,通过使用 COPY --from 指令,就可以将之前 stage 中的文件拷贝到当前的 stage。

那么 --from 后面的内容是什么?换句话说,如何区分每一个 build stage?你可以用数字表示,第一个 FROM 对应的数字为 0,以此往后递增。但是你可以在 FROM 后面添加 AS <NAME> 给各个阶段命名

image-20240207144728638

完成多阶段构建后,最终镜像只会包含最后一个 stage 的内容,这样我们镜像的空间就可以保证最终生成的镜像只包括运行应用所需要的最小化环境。默认情况会停在最后一个 stage,当然你也可以停在指定的 build stage

例如使用下面的 build 指令中,最后构建阶段会停在名为 “build” 的构建阶段

image-20240207143729556

下面是一个具体的实操,来体会多阶段构建的的优势:

我们的构建目标如下,编写一段 C 语言程序,然后编译成可执行文件:

单阶段构建:

Dockerfile如下所示:

image-20240207150712015

最后的镜像大小如下所示:

image-20240207151530716

多阶段构建:

image-20240207152651158

可以看到占用的空间大大减少

image-20240207152800512

在阶段2中使用体积更小的基础镜像,最终生成镜像的体积会更小

[问题]:

替换为更轻量的镜像 busybox 时遇到这样的问题:

image-20240207200422390

libc, the standard C library, provides the C and POSIX APIs to Linux programs and is an intrinsic part of the Linux system. Most Linux distributions are based on glibc, the GNU C library. However, both Alpine Linux and BusyBox images are based on musl standard C library, which is generally incompatible with glibc.

Consequently, executables that are built on glibc-based distros such as Ubuntu, Debian or Arch Linux, won’t work out of the box on Alpine Linux or BusyBox.

参考解答

3.合理使用缓存

Dockerfile中每一行的指令都会创建一层 “image layer”,这些 layer 就像是 stack 一样, 后来 的“栈”堆在先来的栈“”上

image-20240207224653319

在执行每条指令之前,docker 都会在 cache 中查找是否有可重用的 layer,如果有则会直接重用该层 layer,如果没有,那么之后的 layer 都需要 rebuild,不管之后操作是否相同, layer 的内容是否相同

image-20240207234054836

合理使用cache,要尽量把内容不变,执行成本高的指令放在前面,这样可以尽量复用,如下面这个例子:

image-20240208081707041

上面这个 Dockerfile 并不是高效的,如果本地文件发生修改,COPY . . 以及后面的指令都不能使用缓存,需要重新创建。

因为,我们可以将上面的 COPY 指令一分为二。首先拷贝包管理文件(package.json 和 yarn.lock),然后安装依赖。最后再将项目的源文件(经常修改的部分)拷贝进来,执行 build 命令

image-20240208082147465

经过这样的修改后,只要我们的包管理文件没有发生修改,npm install 这一层的内容是可以使用缓存的,省去了执行 npm install 的时间

下面是一个实操案例,在容器中编写编译运行一段 C 语言代码:

image-20240208083203760

在没有缓存的情况下,我们构建用时 67.3 s

image-20240208084555356

修改 hello.c 的内容后,再次构建。用时 30 多s也不少啊?这是因为我们修改 hello.c 后,COPY 指令以及之后的内容都不能使用缓存,需要重新执行,而之前的指令可以复用缓存,可以看到右边的耗时都是 0s

image-20240208085007455

我们什么都不修改再次构建,在缓存的加持下速度会更快:

image-20240208085305892

4.选择体积较小镜像

基础镜像尽量使用官方镜像,并选择体积较小镜像。容器的核心是应用,大的平台微服务可能几十上百个。选择过大的父镜像(如Ubuntu系统镜像)会造成最终生成应用镜像的臃肿,因此推荐选用瘦身过的应用镜像(如node:slim),或者较为小巧的系统镜像(如alpine、busybox或debian);

5.减少镜像层数

镜像层数越少意味着发生修改时,需要重建的 layers 层数越少,那么你的构建也会越快。如果希望所生成镜像的层数尽量少,可以遵循下面的建议:

  • 尽量合并RUN、ADD和COPY指令。通常情况下,多个RUN指令可以合并为一条RUN指令,并共享同一份缓存;如 apt get update && apt install 尽量写到一行
  • 使用多级构建,从而每个 stage 中都只包含少量的指令
6.推荐使用 exec form

使用 exec form 的优势如下:

  • 直接执行:exec form 直接执行命令,这意味着命令不会被 shell 解析,避免了 shell 解析可能带来的问题
  • 信号传递:使用 exec form 时,Docker 能够正确地将信号(如 SIGTERM)传递给容器中的主进程(PID 1),这对于优雅地停止容器非常重要。在 shell form 中,shell 本身成为 PID 1,这可能导致信号传递不正确。
  • 安全性:由于 exec form 不依赖于 shell,它减少了潜在的安全风险
  • 清晰性:Exec form 使用 JSON 数组格式,使得命令和参数的传递更加清晰,易于理解和维护。
  • 兼容性:Exec form 提供了更好的跨平台兼容性,尤其是在处理 Windows 和 Unix-like 系统时,因为不同系统可能有不同的 shell 和路径分隔符。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2774269.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习的新进展:解析技术演进与应用前景

深度学习的新进展&#xff1a;解析技术演进与应用前景 深度学习&#xff0c;作为人工智能领域的一颗璀璨明珠&#xff0c;一直以来都在不断刷新我们对技术和未来的认知。随着时间的推移&#xff0c;深度学习不断迎来新的进展&#xff0c;这不仅推动了技术的演进&#xff0c;也…

百面嵌入式专栏(面试题)C语言面试题22道

沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们将介绍C语言相关面试题 。 宏定义是在编译的哪个阶段被处理的?答案:宏定义是在编译预处理阶段被处理的。 解读:编译预处理:头文件包含、宏替换、条件编译、去除注释、添加行号。 写一个“标准”宏MIN,这个…

FPGA高端项目:解码索尼IMX327 MIPI相机转USB3.0 UVC 输出,提供FPGA开发板+2套工程源码+技术支持

目录 1、前言免责声明 2、相关方案推荐我这里已有的 MIPI 编解码方案 3、本 MIPI CSI-RX IP 介绍4、个人 FPGA高端图像处理开发板简介5、详细设计方案设计原理框图IMX327 及其配置MIPI CSI RX图像 ISP 处理图像缓存UVC 时序USB3.0输出架构FPGA逻辑设计工程源码架构SDK软件工程源…

2023年ABC123公众号年刊下载(PDF电子书)

Part1 前言 大家好&#xff0c;我是ABC_123。2023年公众号正式更名为"希潭实验室"。除了分享日常红队攻防、渗透测试技术文章之外&#xff0c;重点加强了APT案例分析方面的内容。公众号关注度得到进一步提升&#xff0c;关注人数已达到3万5千人。原计划在2023年编写…

统一身份认证系统架构设计与实践总结

随着互联网的快速发展和应用的普及&#xff0c;人们在各个网站和应用上需要不同的账号和密码进行身份认证。为了解决这个问题&#xff0c;统一身份认证系统应运而生。本文将总结统一身份认证系统的架构设计与实践经验&#xff0c;帮助读者了解如何设计和实现一个高效、安全的统…

2024幻兽帕鲁服务器多少钱一套?

2024年幻兽帕鲁服务器价格表更新&#xff0c;阿里云、腾讯云和华为云Palworld服务器报价大全&#xff0c;4核16G幻兽帕鲁专用服务器阿里云26元、腾讯云32元、华为云26元&#xff0c;阿腾云atengyun.com分享幻兽帕鲁服务器优惠价格表&#xff0c;多配置报价&#xff1a; 幻兽帕鲁…

第三百一十三回

文章目录 1. 概念介绍2. 实现方法2.1 obscureText属性2.2 decoration属性 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何实现倒计时功能"相关的内容&#xff0c;本章回中将介绍如何实现密码输入框.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍…

计划任务功能优化,应用商店上架软件超过100款,1Panel开源面板v1.9.6发布

2024年2月7日&#xff0c;现代化、开源的Linux服务器运维管理面板1Panel正式发布v1.9.6版本。 在v1.9.5和v1.9.6这两个小版本中&#xff0c;1Panel针对计划任务等功能进行了多项优化和Bug修复。此外&#xff0c;1Panel应用商店新增了3款应用&#xff0c;上架精选软件应用超过1…

算法随想录第五十二天打卡|300.最长递增子序列 , 674. 最长连续递增序列 , 718. 最长重复子数组

300.最长递增子序列 今天开始正式子序列系列&#xff0c;本题是比较简单的&#xff0c;感受感受一下子序列题目的思路。 视频讲解&#xff1a;动态规划之子序列问题&#xff0c;元素不连续&#xff01;| LeetCode&#xff1a;300.最长递增子序列_哔哩哔哩_bilibili 代码随想录…

【python】绘制春节烟花

一、Pygame库春节烟花示例 下面是一个使用Pygame实现的简单春节烟花效果的示例代码。请注意&#xff0c;运行下面的代码之前&#xff0c;请确保计算机上已经安装了Pygame库。 import pygame import random import math from pygame.locals import *# 初始化pygame pygame.ini…

基于麻雀优化算法优化XGBoost参数的优化控制策略

目录 一、背景 二、算法流程图 三、附录 一、背景 为提高极端梯度提升&#xff08;Extreme Gradient Boosting, XGBoost&#xff09;集成算法在时间预测、信贷风险预测、工件参数预测、故障诊断预测等方面中的准确性&#xff0c;研究者提出了一种改进的麻雀算法&#xff08;…

【我与Java的成长记】之String类详解

系列文章目录 能看懂文字就能明白系列 C语言笔记传送门 Java笔记传送门 &#x1f31f; 个人主页&#xff1a;古德猫宁- &#x1f308; 信念如阳光&#xff0c;照亮前行的每一步 文章目录 系列文章目录&#x1f308; *信念如阳光&#xff0c;照亮前行的每一步* 前言一、字符串构…

深入浅出:Golang的Crypto/SHA256库实战指南

深入浅出&#xff1a;Golang的Crypto/SHA256库实战指南 介绍crypto/sha256库概览主要功能应用场景库结构和接口实例 基础使用教程字符串哈希化文件哈希化处理大型数据 进阶使用方法增量哈希计算使用Salt增强安全性多线程哈希计算 实际案例分析案例一&#xff1a;安全用户认证系…

【芯片设计- RTL 数字逻辑设计入门 13 -- generate_for 和 for】

文章目录 generate_forverilog codetestbench code仿真波形 for 循环verilog code仿真波形错误小结 generate_for 在某个module中包含了很多相似的连续赋值语句&#xff0c;请使用generata…for语句编写代码&#xff0c;替代该语句&#xff0c;要求不能改变原module的功能。 …

假设检验的过程

假设检验的核心思想是小概率事件在一次实验中不可能发生&#xff0c;假设检验就是利用小概率事件的发生进行反正。学习假设检验&#xff0c;有几个概念不能跳过&#xff0c;原假设、p值 1.原假设 假设检验的基本过程如下&#xff1a; 1&#xff09;做出一个假设H0&#xff0c…

IEC 104电力规约详细解读(三) - 遥信

1.功能简述 遥信&#xff0c;、即状态量&#xff0c;是为了将断路器、隔离开关、中央信号等位置信号上送到监控后台的信息。遥信信息包括&#xff1a;反应电网运行拓扑方式的位置信息。如断路器状态、隔离开关状态&#xff1b;反应一次二次设备工作状况的运行信息&#xff0c;如…

豪掷770亿!华为员工集体“分红大狂欢”:至少14万人受益

豪掷770亿&#xff01;华为员工集体“分红大狂欢”&#xff1a;至少14万人受益 近日&#xff0c;华为宣布了其2023年度分红计划&#xff0c;总金额高达770.85亿元&#xff0c;预计至少将惠及14万员工。这一消息引发了广泛关注和热议&#xff0c;成为业界的一大亮点。作为中国领…

如何构建一个高效的微服务治理闭环管理体系

随着企业业务的快速发展和数字化转型的推进&#xff0c;微服务架构因其高度的灵活性、可扩展性和可维护性而逐渐成为主流。然而&#xff0c;微服务架构的复杂性也带来了诸多治理挑战。为了有效应对这些挑战&#xff0c;构建一个微服务治理闭环至关重要。 1、微服务治理概述 微…

vue的8大生命周期

第072个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使用&#xff0c;computed&a…

L3HCTF 2024

Check in 输入一个1就获得flag