Dockerfile 编写推荐
一、导读
本文主要介绍在编写 docker 镜像的时候一些需要注意的事项和推荐的做法。
虽然 Dockerfile 简化了镜像构建的过程,并且把这个过程可以进行版本控制,但是不正当的
Dockerfile 使用也会导致很多问题。
- docker 镜像太大。如果你经常使用镜像或者构建镜像,一定会遇到那种很大的镜像,甚至有些能达到 2G 以上
- docker 镜像的构建时间过长。每个 build 都会耗费很长时间,对于需要经常构建镜像(比如单元测试)的地方这可能是个大问题
- 重复劳动。多次镜像构建之间大部分内容都是完全一样而且重复的,但是每次都要做一遍,浪费时间和资源
希望读者能够对 docker 镜像有一定的了解,阅读这篇文章至少需要一下前提知识
- 了解 docker 的基础概念,运行过容器
- 熟悉 docker 镜像的基础知识,知道镜像的分层结构
- 最好是负责过某个 docker 镜像的构建(使用 docker build 命令创建过自己的镜像)
- Dockerfile 和镜像构建
Dockerfile 是由一个个指令组成的,每个指令都对应着最终镜像的一层。每行的第一个单词就是命令,后面所有的字符串是这个命令的参数,关于 Dockerfile 支持的命令以及它们的用法,可以参考官方文档,这里不再赘述。
当运行 docker build 命令的时候,整个的构建过程是这样的:
a. 读取 Dockerfile 文件发送到 docker daemon
b. 读取当前目录的所有文件(context),发送到 docker daemon
c. 对 Dockerfile 进行解析,处理成命令加上对应参数的结构
d. 按照顺序循环遍历所有的命令,对每个命令调用对应的处理函数进行处理
e. 每个命令(除了 FROM)都会在一个容器执行,执行的结果会生成一个新的镜像,为最后生成的镜像打上标签
二、编写 Dockerfile 的一些最佳实践
1.使用统一的 base 镜像
有些文章讲优化镜像会提倡使用尽量小的基础镜像,目前集团操作系统一级提供统一的基础镜像,一些BU也根据自己的技术规范定义了BU级的基础镜像,一般的应用只需要FROM自己BU提供的基础镜像即可,因为基础镜像只需要下载一次可以共享,并不会造成太多的存储空间浪费。它的好处是这些镜像的生态比较完整,方便我们安装软件,除了问题方便调试。
2.动静分离
经常变化的内容和基本不会变化的内容要分开,把不怎么变化的内容放在下层,创建出来不同基础镜像供上层使用。比如可以创建各种语言的基础镜像,这些镜像包含了最基本的语言库,每个组可以在上面继续构建应用级别的镜像。
3.最小原则:只安装必需的东西
很多人构建镜像的时候,都有一种冲动——把可能用到的东西都打包到镜像中。要遏制这种想法,镜像中应该只包含必需的东西,任何可以有也可以没有的东西都不要放到里面。因为镜像的扩展很容易,而且运行容器的时候也很方便地对其进行修改。这样可以保证镜像尽可能小,构建的时候尽可能快,也保证未来的更快传输、更省网络资源。
4.一个原则:每个镜像只有一个功能
不要在容器里运行多个不同功能的进程,每个镜像中只安装一个应用的软件包和文件,需要交互的程序通过 容器之间的网络进行交流。这样可以保证模块化,不同的应用可以分开维护和升级,也能减小单个镜像的大小。
5.使用更少的层
虽然看起来把不同的命令尽量分开来,写在多个命令中容易阅读和理解。但是这样会导致出现太多的镜像层,而不好管理和分析镜像,而且镜像的层是有限的。尽量把相关的内容放到同一个层,使用换行符进行分割,这样可以进一步减小镜像大小,并且方便查看镜像历史。
6.减少每层的内容
尽管只安装必须的内容,在这个过程中也可能会产生额外的内容或者临时文件,我们要尽量让每层安装的东西保持最小。
比如使用 --no-install-recommends 参数告诉 apt-get 不要安装推荐的软件包
7.不要在 Dockerfile 中单独修改文件的权限
因为 docker 镜像是分层的,任何修改都会新增一个层,修改文件或者目录权限也是如此。如果有一个命令单独修改大文件或者目录的权限,会把这些文件复制一份,这样很容易导致镜像很大。
解决方案也很简单,要么在添加到 Dockerfile 之前就把文件的权限和用户设置好,要么在容器启动脚本(entrypoint)做这些修改,或者拷贝文件和修改权限放在一起做(这样最终也只是增加一层)。
8.利用 cache 来加快构建速度
如果 Docker 发现某个层已经存在了,它会直接使用已经存在的层,而不会重新运行一次。如果你连续运行 docker build 多次,会发现第二次运行很快就结束了。
不过从 1.10 版本开始,Content Addressable Storage 的引入导致缓存功能的实效,目前引入了 --cache-from 参数可以手动指定一个镜像来使用它的缓存。
反之,如果想要缓存失效(禁用此层及后面层的缓存),可以在对应层前加LABEL语句:
LABEL key=value ,每次修改value的值,使得缓存失效。
9.版本控制和自动构建
最好把 Dockerfile 和对应的应用代码一起放到版本控制中,然后能够自动构建镜像。这样的好处是可以追踪各个版本镜像的内容,方便了解不同镜像有什么区别,对于调试和回滚都有好处。
另外,如果运行镜像的参数或者环境变量很多,也要有对应的文档给予说明,并且文档要随着 Dockerfile 变化而更新,这样任何人都能参考着文档很容易地使用镜像,而不是下载了镜像不知道怎么用。
10.使用一个.dockerignore文件
在大部分情况下,最好的做法是将每一个Dockerfile文件放到一个空的文件夹里。接着,把构建Dockerfile所需的文件添加到这个文件下。为了提高构建的效率,你可以在这个文夹下添加一个.dockerignore 文件来排除那些没用的文件和文件夹。这个文件支持类似 .gitignore 文件那样的排除模式。关于如何创建它,可以移步到dockerignore 文件。
相关文章:
Dockerfile 编写推荐
一、导读 本文主要介绍在编写 docker 镜像的时候一些需要注意的事项和推荐的做法。 虽然 Dockerfile 简化了镜像构建的过程,并且把这个过程可以进行版本控制,但是不正当的 Dockerfile 使用也会导致很多问题。 docker 镜像太大。如果你经常使用镜像或者…...
【抽象代数】1.2. 半群与群
群的定义 群非空集合二元运算性质 定义1. 设 为一个非空集合,上有二元运算,满足结合律,则称或为一个半群。 定义2. 设 为半群,若元素 满足 ,则称 为 的左幺元(右幺元:)&#…...
Django中实现简单易用的分页工具
如何在Django中实现简单易用的分页工具?📚 嗨,小伙伴们!今天我们来看看如何在 Django 中实现一个超简单的分页工具。无论你是在处理博客文章、产品列表,还是用户评论,当数据量一大时,分页显得尤…...
「软件设计模式」装饰者模式(Decorator)
深入解析装饰者模式:动态扩展功能的艺术(C实现) 一、模式思想与应用场景 1.1 模式定义 装饰者模式(Decorator Pattern)是一种结构型设计模式,它通过将对象放入包含行为的特殊封装对象中,动态地…...
CI/CD(二)docker-compose安装Jenkins
1、docker-compose.yml version: 3.8services:jenkins:image: jenkins/jenkins:lts # 使用官方的 Jenkins LTS 镜像container_name: jenkinsuser: root # 如果需要以 root 用户运行ports:- "8080:8080" # Jenkins Web 界面端口- "50000:50000" # 用于 Jen…...
OpenCV机器学习(1)人工神经网络 - 多层感知器类cv::ml::ANN_MLP
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::ml::ANN_MLP 是 OpenCV 库中的一部分,用于实现人工神经网络 - 多层感知器(Artificial Neural Network - Multi-Layer…...
ProxySQL构建PolarDB-X标准版高可用路由服务三节点集群
ProxySQL构建PolarDB-X标准版高可用路由服务三节点集群 一、PolarDB-X标准版主备集群搭建 三台机器上传 polardbx 包,包可以从官网https://openpolardb.com/download获取,这里提供离线rpm。 1、上传 polardbx 安装包 到 /opt目录下 rpm -ivh t-pol…...
15.1 Process(进程)类
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 通常开发时想要获得进程是比较困难的事,必须要调用CreateToolhelpSnapshot、ProcessFirst、ProcessNext等API或者诸如 Zw…...
elasticsearch8 linux版以服务的方式启动
1.创建系统服务文件 对于使用 systemd 作为系统初始化系统的 Linux 发行版(如 CentOS 7 及以上、Ubuntu 16.04 及以上),需要创建一个 systemd 服务文件。以 root 用户或具有 sudo 权限的用户身份执行以下操作: sudo vim /etc/sy…...
小米 R3G 路由器刷机教程(Pandavan)
小米 R3G 路由器刷机教程(Pandavan) 一、前言 小米 R3G 路由器以其高性价比和稳定的性能备受用户青睐。然而,原厂固件的功能相对有限,难以满足高级用户的个性化需求。刷机不仅可以解锁路由器的潜能,还能通过第三方固…...
某大型业务系统技术栈介绍【应对面试】
微服务架构【图】 微服务架构【概念】 微服务架构,是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。在微服务架构中,服务与服务之间通信时,通常是…...
【区块链】零知识证明基础概念详解
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 零知识证明基础概念详解引言1. 零知识证明的定义与特性1.1 基本定义1.2 三个核心…...
建筑行业安全技能竞赛流程方案
一、比赛时间: 6月23日8:30分准时到场;9:00-10:00理论考试;10:10-12:00现场隐患答疑;12:00-13:30午餐;下午13:30-15:30现场…...
数据结构:图;邻接矩阵和邻接表
邻接矩阵: 1.概念: 邻接矩阵是图的存储结构之一,通过二维数组表示顶点间的连接关系。 2.具体例子 : 一.无向图邻接矩阵示例: 示例图(顶点:A、B、C,边:A-B、B-C&…...
DeepSeek-R1论文阅读及蒸馏模型部署
DeepSeek-R1论文阅读及蒸馏模型部署 文章目录 DeepSeek-R1论文阅读及蒸馏模型部署摘要Abstract一、DeepSeek-R1论文1. 论文摘要2. 引言3. DeepSeek-R1-Zero的方法3.1 强化学习算法3.2 奖励建模3.3 训练模版3.4 DeepSeek-R1-Zero的性能、自进化过程和顿悟时刻 4. DeepSeek-R1&am…...
OpenEuler学习笔记(三十三):在 OpenEuler 上搭建 OpenGauss 数据库环境
在 OpenEuler 上搭建 OpenGauss 数据库环境需要按照以下步骤进行。OpenGauss 是华为开源的一款高性能关系型数据库,支持高并发、高可用性和分布式部署。 1. 环境准备 确保你的 OpenEuler 系统满足以下要求: 操作系统:OpenEuler 20.03 LTS 或…...
[C++]多态详解
目录 一、多态的概念 二、静态的多态 三、动态的多态 3.1多态的定义 3.2虚函数 四、虚函数的重写(覆盖) 4.1虚函数 4.2三同 4.3两种特殊情况 (1)协变 (2)析构函数的重写 五、C11中的final和over…...
调用DeepSeek API接口:实现智能数据挖掘与分析
调用DeepSeek API接口:实现智能数据挖掘与分析 在当今数据驱动的时代,企业和开发者越来越依赖高效的数据挖掘与分析工具来获取有价值的洞察。DeepSeek作为一款先进的智能数据挖掘平台,提供了强大的API接口,帮助用户轻松集成其功能到自己的应用中。本文将详细介绍如何调用D…...
ffmpeg-cli-wrapper操作ffmpeg的工具
学习链接 ffmpeg-cli-wrapper - 内部封装了操作ffmpeg命令的java类库,它提供了一些类和方法,可以方便地构建和执行 ffmpeg 命令,而不需要直接操作字符串或进程。并且支持异步执行和进度监听 springboot-ffmpeg-m3u8-convertor - gitee代码 …...
【Qt】QObject类的主要功能
在 Qt 中,QObject 类是所有 Qt 对象的基类,提供了许多基础功能,使得 Qt 的对象系统能够有效地工作。它为其他类提供了核心的机制,比如信号和槽机制、对象树结构、内存管理等。 QObject 类的主要功能: 信号和槽机制&am…...
Arm Cortex-R82处理器架构与关键系统寄存器解析
1. Cortex-R82处理器架构概述Arm Cortex-R82是Armv8-R架构下的高性能实时处理器,专为需要确定性响应的关键任务系统设计。与常见的Cortex-A系列不同,R系列在保留内存管理单元(MMU)的同时,强化了实时性和安全性特性。AArch64作为其64位执行状态…...
通过Python快速编写脚本调用Taotoken提供的多种大模型
通过Python快速编写脚本调用Taotoken提供的多种大模型 1. 环境准备 开始前请确保已安装Python 3.7或更高版本。推荐使用虚拟环境管理依赖,可通过以下命令创建并激活虚拟环境: python -m venv taotoken-env source taotoken-env/bin/activate # Linux…...
树莓派Zero 2W到手后,我踩过的第一个坑:新版系统SSH连接失败全记录与解决
树莓派Zero 2W新版系统SSH连接失败深度排障指南 拿到树莓派Zero 2W的兴奋感还没持续多久,就被SSH连接失败的红色提示浇了盆冷水。作为2021年发布的最新款超紧凑型开发板,Zero 2W凭借其四核处理器和WiFi/BLE模块成为物联网项目的理想选择。但当我按照三年…...
深入解析libclang的多维数组处理
深入解析libclang的多维数组处理 在C++编程中,多维数组是一个常见的概念。然而,通过libclang来解析这些数组的维度信息却并非那么直观。本文将详细介绍如何使用Python的libclang绑定来解析C++结构体中的多维数组,并展示如何获取每个维度的具体大小。 C++中的多维数组 首先…...
紧急!某城商行因Docker调试误操作导致T+0清算中断——这份《金融容器调试熔断 checklist》已获央行金融科技中心内部推荐
更多请点击: https://intelliparadigm.com 第一章:金融容器调试事故的根源与警示 在高并发、强一致性的金融核心系统中,容器化部署虽提升了弹性与交付效率,却也放大了调试环节的脆弱性。一次看似常规的 kubectl exec -it payment…...
微信聊天记录数据主权实践:WeChatMsg本地导出工具技术解析
微信聊天记录数据主权实践:WeChatMsg本地导出工具技术解析 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/W…...
TB6600驱动器共阴共阳接法傻傻分不清?一张图搞定STM32与42步进电机的接线避坑指南
TB6600驱动器共阴共阳接法全解析:STM32与42步进电机高效连接实战 第一次拿到TB6600驱动器和42步进电机时,面对DIR、DIR-、PUL、PUL-这些接口,我完全懵了。更让人头疼的是,网上关于共阴和共阳接法的说法五花八门,有的教…...
QQ聊天记录解密终极指南:全平台数据库密钥提取完整方案
QQ聊天记录解密终极指南:全平台数据库密钥提取完整方案 【免费下载链接】qq-win-db-key 全平台 QQ 聊天数据库解密 项目地址: https://gitcode.com/gh_mirrors/qq/qq-win-db-key 你是否曾因更换设备而无法查看珍贵的QQ聊天记录?或者想要备份多年的…...
AI工具搭建自动化视频生成字符串拼接
从字符串拼接说起:聊聊AI工具搭建自动化视频生成的那些事 前阵子帮一个做自媒体朋友调试脚本,他每天要生成几十段短视频字幕,每段都需要把文案逐字逐句拼到视频模板里。他原本的做法是手动复制粘贴文案,再手动调整时间轴ÿ…...
3D场景生成中的遮挡感知与布局优化技术
1. 项目概述:当3D场景学会"看穿"遮挡物在3D内容生成领域,我们常常遇到这样的困境:当需要生成复杂室内场景时,传统模型会因家具间的相互遮挡而出现布局混乱——沙发可能半嵌在墙里,餐桌上的花瓶悬浮在半空。这…...
