ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Dockerfile 全景指南:从入门编写dockerfile到生产环境镜像优化实战,一步步带你从啃透制作指令到镜像制作落地!

Dockerfile 全景指南:从入门编写dockerfile到生产环境镜像优化实战,一步步带你从啃透制作指令到镜像制作落地! 文章目录本篇摘要一.镜像制作的原因二.Docker镜像制作的两种方式三.基于快照模式制作C hello world 镜像制作流程基于快照模式的提交镜像总结四.dockerfile镜像制作dockerfile概念为什么需要 Dockerfiledockerfile常见的指令1.FROM指令**2.MAINTAINER指令**3.LABEL指令4.COPY指令5.ENV指令6.WORKDIR指令7.ADD指令8.RUN指令9.CMD指令10.EXPOSE指令11.ENTRYPOINT指令12.ARG 指令13.VOLUME指令14.SHELL指令15.USER指令16.healthcheck指令17.ONBUILD指令18.STOPSIGNAL指令指令总览dockerfile之build介绍**演示URL****演示-f与--no-cache**演示-q与--label演示--network五.dockerfile制作优秀实践六.测试需要代码汇总七.本篇小结本篇摘要本文系统解析 Dockerfile 全指令集与实战技巧涵盖镜像构建原理、多阶段优化、缓存机制及安全实践。通过快照与 Dockerfile 对比详解如何高效封装应用、缩减镜像体积并提供企业级镜像优化方案助力构建生产就绪的容器化应用。一.镜像制作的原因代码封装发布为了将自主编写的应用程序代码直接打包到镜像中实现与镜像一体化的发布和部署。安全合规要求为避免第三方镜像可能存在的安全漏洞或未知风险确保运行环境的安全与可控。功能定制扩展官方镜像无法满足特定需求如为数据库添加审计等额外功能需要通过自定义镜像来实现。内部规范统一遵守公司内部规定需使用自有的操作系统或基础环境作为基准来构建镜像以符合统一的标准和管理流程。二.Docker镜像制作的两种方式制作快照适用于偶尔制作的镜像方法先启动一个基础容器如 Ubuntu进入容器内部手动安装和配置所有所需软件最后将该容器的整个状态打包成一个新镜像。类比类似于给当前系统拍一张“快照”或“备份”。Dockerfile构建适用于经常更新的镜像方法将所有安装和配置步骤编写到一个名为Dockerfile的文本文件中然后使用docker build命令自动构建镜像。优势过程透明、可重复易于版本管理和自动化是推荐的标准做法。三.基于快照模式制作Chello world镜像制作流程基于centos:7原镜像进行把对应的容器启动然后在容器中进行对应操作接着把它commit成镜像下次启动就直接一次性启动执行对应命令这样一个简单的镜像就制作好了。首先对应宿主机进行文件编写启动对应centos:7容器并以bash交互进去把宿主机对应的test文件拷贝过去下面在对应的容器中进行centos 镜像源安装下面安装完gcc开始运行接着把它commit成对应的镜像;下面进行一次性执行容器命令执行完后也是立刻退出了。可以看到对应的commit的过程保留文件系统底层元数据而之前的export就不会。基于快照模式的提交镜像总结可以发现当进行commit进行制作的时候当使用方完全看不到对应的制作过程而且如果想要修改的话又要重头再制作不知道这个镜像到了哪一步而上面操作其实运行容器的时候没有用到gcc倒不如直接把对应的exe拷贝进容器中因此看起来是比较臃肿的。而后面要介绍的Dockerfile就完美的解决了这一点。四.dockerfile镜像制作dockerfile概念Dockerfile 是一个文本脚本文件用于自动化和定义 Docker 镜像的构建过程。镜像的定制就是定制每一层的配置和文件。Dockerfile 中的每一条指令都会对应构建出镜像的一个层级。通过在其中写入一系列的命令例如复制文件、安装软件、配置环境等来描述每一层应当如何被构建。通过执行这个脚本使用docker build命令可以自动地构建出一个符合用户定制需求的、新的 Docker 镜像。Dockerfile 中最后一个 FROM指令决定了最终镜像的根基之前的阶段只是为它服务的临时环境。​如图总而言之Dockerfile 是将手动构建镜像的步骤记录到一个自动化脚本中从而实现镜像构建的流程化、可重复和可管理。为什么需要 Dockerfile官方镜像通常无法直接满足应用需求需要将自己开发的代码打包进去制作成符合要求的自定义应用镜像基于commit的快照模式改造。相比手动执行命令并提交docker commit的不可追溯和易遗漏Dockerfile 能将构建过程自动化确保每次构建的结果一致。使用docker commit制作的是“黑箱镜像”构建步骤不透明。而 Dockerfile 是明文脚本所有操作清晰可见易于理解和二次开发。docker commit容易将运行时产生的临时文件和未清理的依赖打包进镜像导致镜像臃肿。Dockerfile 可以通过多阶段构建等功能分离编译和运行环境产出更标准、体积更小的镜像。制作好对应的镜像然后放到对应仓库后面就可以直接同步push下对应镜像然后实例化出对应的容器在不同的环境进行部署测试等dockerfile常见的指令对应参考docker官方文档1.FROM指令功能FROM指令用于指定构建镜像所依赖的基础镜像后续所有指令均在此基础镜像提供的环境中执行。位置要求必须是 Dockerfile 中首个非注释指令或紧跟在ARG指令之后。镜像拉取若本地不存在指定镜像Docker 会尝试从公共仓库自动拉取若镜像不存在则报错。多阶段构建可通过多次使用FROM指令创建多个镜像或将某一构建阶段作为另一阶段的依赖需配合AS name命名。标签默认值若未指定镜像标签tag默认使用latest标签。语法参数--platform指定目标平台架构如linux/amd64。image基础镜像名称如果是scratch的话就是从空镜像开始制作做出来就是基础镜像。tag/digest使用标签或哈希值精确指定镜像版本。AS name为构建阶段命名便于多阶段构建中引用。演示下在对应目录创建dockerfile文件基于基本镜像centos:7来构建新镜像:进行构建然后这里提示说建议在build的时候进行–platform指定. 是当前目录作为dockefile上下文。创建成功说白了就是搞了个centos:7的副本。启动这个镜像来实例化容器执行一次性命令。2.MAINTAINER指令已废弃的 Docker 指令原用途标注镜像作者信息现建议改用LABEL maintainer作者名语法示例MAINTAINER 姓名邮箱注现使用仅触发警告不影响构建演示下这里提示已经废弃掉了。成功启动可以运行看到对应的author内容发生改变。3.LABEL指令功能用于为 Docker 镜像添加元数据描述信息。格式元数据以键值对keyvalue形式存储。语法LABEL 键值 键值 ...可同时定义多个标签。用途记录作者、版本、描述等镜像信息方便管理。演示下可以看到成功运行。查看镜像详情可以看到对应的labels被添加了。4.COPY指令功能将主机上的文件或目录复制到镜像内部。语法COPY [参数] 源路径 目标路径。参数--chown可设置复制后文件的所属用户和组。--from可从多阶段构建的前一阶段复制文件。规则源路径必须在构建上下文内。复制目录时会递归复制其内容不包括目录本身。复制多个文件或使用通配符时目标路径必须是目录以/结尾。目标路径不存在时会自动创建。演示下首先编写对应dockerfile查看对应的组别有哪些随便启动一个对应的NGINX容器这里可以根据第一个作为不同的组进行chown操作。下面编写对应指令在宿主机制作对应文件。对应镜像制作成功然后去对应的容器的bash下查看。对应的拥有者与从属组更改完成对应的文件内容也发生拷贝覆盖。5.ENV指令作用在镜像里设置环境变量就像设置全局配置。使用设置后后面的指令如RUN,COPY都能用$变量名来使用这个值。写法ENV 变量名值例如ENV APP_HOME/app。演示下编写dockerfile成功打成镜像。下面进入对应容器看下也是成功显示。6.WORKDIR指令核心功能用来设置工作目录相当于cd命令。之后的所有指令如RUN,CMD,COPY,ADD都会在这个目录下执行指定目录不存在就会创建。基本语法WORKDIR /路径/到/目录。路径可以是绝对路径如/app也可以是相对路径。默认目录如果不设置默认的工作目录是容器文件系统的根目录/。相对路径如果使用相对路径如subdir它会基于前一条WORKDIR指令设置的路径。支持变量路径里可以使用之前通过ENV指令定义的环境变量如WORKDIR $APP_HOME。演示下镜像成功构建成功为啥有悬空镜像重复构建同名镜像时Docker会将旧镜像的标签转移给新镜像导致旧镜像变成无标签的状态。。发现对应的工作目录确实变了也就是进入对应的bash就回来到对应工作目录也就是没有指定对应目录默认都会在这个目录操作。7.ADD指令核心功能用于复制文件比COPY功能更强支持自动解压压缩包如.tar和从 URL 下载文件但是url下载后不会自动解压。基本语法ADD [--chown用户:组] 源路径... 目标路径路径包含空格时可以用引号格式。关键参数--chown在复制时可同时修改文件的所有者和所属组如--chownuser:group。路径说明源路径支持使用通配符。目标路径必须是容器内的路径建议使用绝对路径否则会相对于WORKDIR指令设置的目录。演示下对应的nginx下载的官网下面测试下直接url抓过来以及直接tar包拿进来效果首先把对应tar.gz对应的压缩包到当前目录方便cp对于wget直接从网站爬就行下面进行镜像构建发现了对应的url的话只cp对应压缩包进来不进行解压而对应的压缩包cp的话自动解压还发现对于当前目录操作默认当成了对应的工作目录来进行。8.RUN指令核心功能在docker build构建镜像的过程中执行命令例如安装软件、编译代码等。两种语法形式Shell 形式RUN command默认在/bin/sh -c下执行命令支持 Shell 特性如变量替换、通配符*等。Exec 形式RUN [executable, param1, param2]直接执行程序不通过 Shell避免 Shell 解析的歧义格式更清晰不支持 Shell 特性如需使用必须显式调用 Shell如RUN [/bin/bash, -c, your command]。使用场景通常用于安装依赖包、下载编译代码、执行构建脚本等任何需要在构建阶段准备镜像环境的操作。演示下先演示下简单使用把对应的从网站wget下来的压缩包解压到对应目录这里用的包含shell的语法。发现成功解压。下面测试基于ubuntu 解压安转nginx对应exec显示显示shell调用成功对应的nginx安装完成。对应html首页也被覆盖。9.CMD指令核心功能在容器启动时执行命令为容器提供默认的运行程序。与 RUN 的区别RUN在镜像构建时执行用于安装配置CMD在容器运行时执行用于启动应用相当于main函数。语法形式推荐格式CMD [executable, param1, param2]为 ENTRYPOINT 提供参数CMD [param1, param2]Shell 格式CMD command param1 param2重要特性一个 Dockerfile 中可以有多个CMD但只有最后一个会生效。在启动容器时docker run后面跟的命令可以覆盖Dockerfile 中的CMD指令。与entrypoint都出现的时候结合起效果。注意事项使用 JSON 数组格式Exec form时必须使用双引号。演示下基于之前的ubuntu镜像进行让实例化的容器的主进程就去执行启动nginx的前台任务。这里发现对应的cmd变了也就是容器一启动里面的主进程就去执行这个指令了而访问对应8090端口就被映射到容器的80端口nginx就默认部署在80端口上因此看到对应效果。如果没有更改镜像的cmd默认就是bash自然一启动没收到一次性命令就退出来了。10.EXPOSE指令作用只声明容器会用的端口不自动打开端口。本质是给用户的说明文档告诉别人这个镜像里的服务用了哪些端口。用法EXPOSE 端口号或EXPOSE 端口号/协议如EXPOSE 80/tcp。关键运行容器时必须加-p如-p 80:80才能从外部访问。演示下只是声明说是有这个端口并没有完成映射。curl一下发现curl宿主机80端口没有被转发到对应容器80端口故只是声明。11.ENTRYPOINT指令核心功能指定容器启动时的主入口命令让容器像独立应用程序一样运行。两种语法形式Exec 形式推荐ENTRYPOINT [可执行命令, 参数1, 参数2]Shell 形式ENTRYPOINT 命令 参数1 参数2关键注意事项使用 Exec 形式JSON数组时必须使用双引号使用单引号会导致错误。与 CMD 的区别ENTRYPOINT定义的命令通常不会被docker run的命令覆盖而CMD提供的默认参数可以被覆盖。两者常结合使用。演示下基于之前的ubuntu的dockerfile对于cmd配合entrypoint结合使用build后启动发现直接就是前台运行不是bash直接退出说明两者结合使用变成主进程的命令了。查看容器详情可以发现。可以发现这里如果是entrypoint或者两者结合使用的话后面的命令就不能覆盖掉之前的命令给主进程这里是把后面的当成参数传给entrypoint了然后不认识这些参数故报错。如果是cmd模式呢这里可以看到成功打印出来了此时就是把对应的参数给cmd了也就是覆盖cmd原先dockerfile中设置的了直接主进程就执行新的命令了。这里如果使用的是entrypoint那么--entrypoint 命令 -c参数才能发生指令覆盖而cmd本身就会发生覆盖。总结下entrypoint可以结合cmd做entrypoint参数使用然后如果是单entrypoint或者结合使用的那么此时run后面命令就是给entrypoint做参数可能无法识别但是如果是cmd状态run的时候添加参数就是覆盖cmd让主进程执行。12.ARG 指令作用定义构建时可修改的变量类似ENV但仅在docker build阶段有效。语法ARG 变量名[默认值]默认值可选。传参通过docker build --build-arg 变量名值覆盖默认值。作用域从定义处开始生效定义前无法使用即使传参也无效。优先级若ENV和ARG同名ENV的值会覆盖ARG的值也就是只存在于对应dockerfile中不进镜像。用途灵活控制软件版本、路径等构建参数提升Dockerfile可复用性。演示下相当于别名只在对应的dockerfile文件有效。就是对应版本ubuntu。但是如果不想改dockerfile但是想换个版本此时就可以在build的时候借助–build-arg 来修改对应的VERSION这里查看对应镜像版本就是更新后的22.10.总结下如果只希望在dockerfile中起效因此可以使用arg指令比如对应的还有需要动态构建如镜像版本升级等此时arg就能发挥作用。13.VOLUME指令用法VOLUME 挂载点路径直接指定VOLUME [“挂载点路径”]JSON数组格式作用在容器里自动创建备份盘匿名数据卷防止数据丢失。特点备份盘位置由 Docker自动分配用户不能指定主机目录。即使启动命令忘了用-v数据也会存下来。容器删除后备份盘里的数据还在。优先级如果用户启动时用了-v指定目录则以-v为准这个“自动备份盘”就不生效了。典型用途像 MySQL 这类有重要数据的容器必须用它确保数据安全。下面来演示下这路不输入-v也就是默认匿名卷存储在对应的/var/lib/docker/volumes下。确实符合预期并且挂载也是volume。如果加上-v也就是覆盖默认的volume以-v为主把对应宿主机当前目录的文件同步过去了。此时挂载方式也改变了。14.SHELL指令核心功能用于覆盖Docker 容器中执行命令时使用的默认 Shell 程序。默认 ShellLinux 系统默认是[/bin/sh, -c]Windows 系统默认是[cmd, /S, /C]基本语法必须以 JSON 数组格式编写。SHELL [可执行文件, 参数]例如SHELL [/bin/bash, -c]重要特性可以在 Dockerfile 中多次使用。每条SHELL指令都会覆盖之前的所有SHELL指令并影响其后的所有指令。主要用途此指令在Windows 容器中特别有用因为 Windows 上有两种常用的 ShellCMD和PowerShell可以通过该指令进行切换和指定。演示下这里从ubuntu默认的sh切换成bash来详细展示过程。这里可以通过打印出执行过程看出不一样证明构建过程中shell变化了sh–bash。15.USER指令功能用于设置容器运行时或执行后续指令如RUN,CMD的默认用户身份不再默认使用 root 用户以提升安全性。语法支持两种格式用户名/组名USER user[:group]用户ID/组IDUSER UID[:GID]参数user/UID指定用户名或用户 IDgroup/GID可选指定用户组名或组 ID注意事项指定的UID必须是容器内/etc/passwd文件中存在的有效用户 ID否则运行会失败。演示下这里默认是root用户及用户组然后把它设置成nginx进行文件操作然后改回root继续创建mysql再进行文件操作。下面build后进行查看对应容器目录发现用户及用户组确实变了。16.healthcheck指令核心功能用于检查容器内应用服务的健康状态能检测进程虽在运行但服务已不可用如死循环、服务僵死的情况。两种语法形式HEALTHCHECK [OPTIONS] CMD command在容器内运行指定命令来检查健康状况。HEALTHCHECK NONE禁用从基础镜像继承的任何健康检查。关键参数OPTIONS--intervalDURATION检查间隔时间默认30秒。--timeoutDURATION等待命令响应的超时时间默认30秒。--retriesN连续失败多少次才判定为不健康默认3次。--start-periodDURATION容器启动后等待多久开始第一次检查默认0秒。返回值含义(可以通过对应日志详细观看)0成功容器健康。1失败容器不健康。2保留值不使用。主要目的让 Docker 引擎能更智能地监控容器内应用的实际状态而不仅仅是进程是否存在注意健康自定义和运行不是一个状态。演示下下面启动对应容器进行curl自己演示下health正常执行完命令就说明健康。docker ps可以看到从开始检测到健康状态。下面检测下让它出现不健康这使用bash覆盖掉nginx默认的启动命令启动web故此时只是一个shell啥也不干。ps查看到到时间就失败。17.ONBUILD指令也就是延迟触发器作用现在不执行等别人拿我这个镜像当基础去构建时再自动执行我定义的指令。写法ONBUILD Dockerfile指令例如ONBUILD ADD . /app/src。用途专门用来做可复用的基础镜像自动帮后续的“子镜像”完成一些通用操作。演示下第一次发现对应下面没有对应文件。然后复用下上面的镜像发现延迟成功。18.STOPSIGNAL指令核心功能用于设置容器停止时Docker 引擎发送给容器内主进程的系统信号以控制容器的停止方式根据dockerfile里设置的来覆盖掉本身stop优雅退出时候的信号。基本语法STOPSIGNAL 信号。信号可以是数字代号如9。也可以是信号名称如SIGKILL。常见信号SIGTERM (15)默认信号。礼貌地请求进程终止允许其完成清理工作。SIGKILL (9)强制立即终止进程不给进程任何清理的机会。SIGHUP (1)通常用于通知进程重新加载配置。SIGINT (2)模拟键盘CtrlC的中断操作。SIGSTOP (19)暂停进程的执行。主要用途通过发送不同的信号可以更优雅、更可控地停止容器中的应用例如让应用有时间保存状态、完成正在处理的请求后再退出。演示下nginx前台占用宿主机shell启动。stop时候发送对应信号这里显示不是优雅退出收到的是9好信号。下面启动个没被覆盖stop信号的普通nginx镜像这里可以看到优雅的退出。指令总览常见指令清单指令功能描述备注FROM构建镜像基于哪个镜像基础镜像必须掌握MAINTAINER镜像维护者姓名或邮箱地址已废弃被 LABEL 替代LABEL为镜像添加元数据如版本、描述等信息必须掌握COPY拷贝文件或目录到镜像中不支持自动下载或解压必须掌握ADD拷贝文件或目录到镜像中支持 URL 自动下载和压缩包自动解压必须掌握WORKDIR设置镜像内的工作目录后续命令均在此目录下执行必须掌握RUN在构建过程中执行命令如安装软件、配置环境等必须掌握VOLUME声明容器中的挂载点数据卷必须掌握EXPOSE声明容器运行时监听的端口仅声明实际映射需在运行时指定必须掌握ENV设置环境变量供后续指令或容器运行时使用必须掌握CMD指定容器启动时默认执行的命令可被运行时覆盖必须掌握ENTRYPOINT指定容器启动时的程序入口与 CMD 协同或独立使用必须掌握ARG定义构建时可传递的参数仅在构建阶段有效使用较少SHELL指定 RUN、CMD、ENTRYPOINT 使用的默认 shell使用较少USER指定运行容器时的用户名或 UID必须掌握HEALTHCHECK定义容器健康检查方式如检测服务是否就绪必须掌握ONBUILD定义延迟执行的指令仅在以当前镜像为基础镜像构建下一级镜像时触发使用较少STOPSIGNAL覆盖容器停止时发送的系统信号使用较少dockerfile之build介绍功能用于根据Dockerfile文件和构建上下文代码、资源等创建出一个新的 Docker 镜像。语法docker build [OPTIONS] PATH | URL | -常用关键参数-t/--tag为生成的镜像命名和打标签格式name:tag这是最常用的参数。-f指定使用的Dockerfile的路径如果文件名不是默认的Dockerfile或不在上下文根目录时使用。--no-cache禁用缓存从头开始构建确保获取最新依赖。--build-arg设置构建时的变量可传入 Dockerfile 中的ARG指令。-q/--quiet安静模式成功构建后只输出最终的镜像 ID不显示冗长的构建过程。--network设置构建过程中RUN指令的网络模式。--label[]:设置镜像使用的元数据。构建上下文命令最后的路径非常重要它指定了构建时发送给 Docker 守护进程也就是docker客户端给对应服务端发送进行的镜像制作的文件目录通常包含 Dockerfile 和需要复制到镜像中的代码文件。演示URL首先要知道安装了nginx在宿主机上所以访问对应ip自动默认访问80端口也就是nginx主页也就是访问对应ip作为网址自动跑到这个html目录中index.html默认就是80下面配合url方式curl一下成功curl到。网站也是可以的这也就是为啥nginx可以被使用搭建网站原因如这个html里基于url进行dockerfile构建。成功构建。演示-f与–no-cache说是以当前目录为上下文但是找不到对应的dockerfile。下面指明对应dockerfile文件成功构建。对于--no-cache使用的话可以看出如果复杂的镜像构建且无前基础就会变得很慢。演示-q与–label之前在arg指令演示过—build-arg了。成功构建只返回对应对应的id这里写成两个–label来设置多标签。查看镜像对应标签也是成功的。演示–network这里指定了构建过程使用宿主机的网络所以才能https访问到对应的tar包。五.dockerfile制作优秀实践​首先要知道Dockerfile 镜像构建完全由本机的Docker 守护进程daemon负责执行。使用.dockerignore创建此文件来排除构建时不需要的文件避免发送无用数据加速构建过程。多阶段构建将编译和运行环境分离最终镜像只包含运行所需的最小内容大幅减小镜像体积但是最后生成的镜像是以最后一个from为主。利用构建缓存把内容变动少的指令如安装依赖放在 Dockerfile 前面充分利用缓存提升构建速度此时当频繁修改源代码再次build的时候就直接不用一直安装gcc耗时间了。精选基础镜像优先选择官方的轻量级基础镜像如 Alpine、slim 版本避免使用臃肿的全功能系统镜像。合并镜像层尽量将多条RUN、COPY、ADD指令合并成一条减少镜像层数。保持镜像单一功能一个镜像专注于一个用途避免制作大而全的复杂镜像避免镜像融合。固定外部依赖从外部引入数据或依赖时使用明确的版本号和持久化地址确保构建可重复且稳定如果本机不能上网http去远端就出问题了下载。仅安装必要软件包只安装应用运行必需的软件包避免安装任何可有可无的包以最小化镜像体积。六.测试需要代码汇总戳我速看dockerfile等文件七.本篇小结本篇通过对比快照与 Dockerfile 两种镜像构建方式深入剖析了 Dockerfile 核心指令的功能、语法及实战应用场景。从基础镜像选择、多层合并到多阶段构建全面阐述了镜像优化策略。同时结合安全规范与生产实践为开发者提供了从开发到部署的完整容器化解决方案显著提升应用交付效率与运维可靠性。
返回列表