ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

90DaysOfDevOps Day 45:剖析一个 Docker Image —— 从分层结构到 Dockerfile 构建与推送全流程

90DaysOfDevOps Day 45:剖析一个 Docker Image —— 从分层结构到 Dockerfile 构建与推送全流程 文档/教程【免费下载链接】90DaysOfDevOpsThis repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.项目地址https://gitcode.com/gh_mirrors/90/90DaysOfDevOps点击查看免费下载本文以 90DaysOfDevOps 项目 Day 45 文档2022/vi/Days/day45.md为核心系统讲解 Docker Image 的内部结构分层、容器层、父镜像与 manifest、两种镜像构建方式并基于仓库内真实存在的 Dockerfile 与配套目录演示docker build、容器内验证、inspect与推送 DockerHub 的完整实操链路。读完本文你将能独立写出自己的 Dockerfile、理解镜像分层对构建效率的影响并把自制镜像发布到远程仓库。Docker Image 是什么只读模板与可移植载体Docker image 是一个只读模板其中包含一组创建容器的指令可在 Docker 平台上运行。它的核心价值在于把应用程序与预配置好的服务环境打包在一起既可供个人私有使用也可以公开共享给其他 Docker 用户。对于任何第一次接触 Docker 的人而言镜像就是一切的起点。前一节Day 44中我们已经演示过如何使用 Docker Desktop 结合 DockerHub 拉取并运行官方验证过的镜像而 Day 45 要解决的关键问题是当我们需要自己的镜像时该如何构建如果只是手动进入 Ubuntu 容器、安装所需软件并提交那么一旦容器被关闭或删除所有软件更新和安装都会消失——不存在可重复的版本。这在演示功能时没问题但无法支撑在多个环境间传输镜像、每次运行容器都自带同一套软件的诉求。镜像的内部解剖Layer、容器层与 Manifest每个文件都是 Layer层构成一个 Docker 镜像的每一层文件都被称为一个layer层。这些 layer 以阶段方式一层层堆叠每一层都依赖其正下方的层。层的顺序对镜像生命周期管理的效率至关重要应把最常变化的层放在栈的尽可能高处原因在于当你修改镜像中的某一层时Docker 不仅会重建该层还会重建所有基于它构建的上层。因此改动最上层的层重建整个镜像所需的工作量最小。Container Layer运行时可写层每次 Docker 从镜像启动一个容器正如昨天所做都会额外添加一个可写层writeable layer称为container layer容器层。它记录容器运行期间的全部变更。这一层是正在运行的容器与原始镜像之间唯一的区别。任意数量的同源容器都可以共享对同一底层镜像的访问同时各自保持独立状态。回到 Ubuntu 镜像的例子可以多次运行同一个命令第一个容器安装pinta第二个容器安装figlet——两个应用、用途不同、体积不同。每个部署的容器共享同一个镜像但不共享状态删除容器后这些状态也随之消失。Parent Image父镜像除 Ubuntu 外DockerHub 及第三方仓库还提供了大量开箱即用的容器镜像。这些镜像通常被称为parent image父镜像基础镜像它是所有其他层得以构建的地基为容器环境提供最基本的构件。Manifest镜像的描述文件除了组成镜像的一组独立 layer 文件外Docker 镜像还包含一个额外的manifest文件。它本质上是镜像的JSON 格式描述包含镜像标签tag、数字签名以及针对不同宿主平台如何配置容器的详细信息。可以说manifest 把一堆层文件升级为一个完整的、可寻址、可校验的镜像实体。创建 Docker 镜像的两种方式方式一docker commit临时快照法第一种方式是即席操作挑选基础镜像启动容器安装所有想要的软件与依赖然后执行docker commit 容器名此时本地docker images中以及 Docker Desktop 的 Images 标签页里就会出现该镜像的本地副本。这种方法非常简单快捷非常适合测试、排障、验证依赖等场景。但作者明确不建议在生产中采用它生命周期管理极其困难且需要大量手工配置与再配置。它只适合理解流程而 Dockerfile 方式才更贴合真实世界中企业级容器部署的诉求。方式二Dockerfile可重复构建法我们推荐的构建方式是编写Dockerfile。它提供了一种干净、紧凑、可重复的镜像创建方法生命周期管理容易得多也便于集成进CI/CD持续集成与持续交付流程——代价是比第一种方式稍复杂一些。一个 Dockerfile 本质上是一个三步过程创建 Dockerfile 文件 → 按需添加指令 → 执行构建。Dockerfile 常用指令速查表以下是构建 Dockerfile 时最常用、也最可能用到的指令完整保留自原文档指令用途FROM指定父基础镜像。WORKDIR为 Dockerfile 中后续的任何命令设置工作目录。RUN运行命令用于安装容器所需的任何应用与软件包。COPY从特定位置复制文件或目录到镜像中。ADD功能同 COPY但额外支持处理远程 URL 以及解压压缩文件。ENTRYPOINT容器启动时总会执行的命令若未指定默认是/bin/sh -c。CMD传递给 entrypoint 的参数若未设置 ENTRYPOINT默认/bin/sh -c则 CMD 就是容器实际执行的命令。EXPOSE定义从哪个端口访问容器应用。LABEL为镜像添加元数据。动手构建仓库内的真实 Dockerfile 与 .dockerignore本仓库在 2022/Days/Containers 目录下保存了 Day 45 实践用的全部文件读者可以直接对照查看、复现练习。与.gitignore类似我们还会在构建目录中准备一个.dockerignore文件用来列出那些在 Docker 构建过程中产生、但希望从最终构建产物中排除的文件。始终牢记容器的哲学就是紧凑、快速、零冗余。原文档给出如下极简 Dockerfile 布局即 2022/Days/Containers/Dockerfile 的早期版本# Use the official Ubuntu 18.04 as base FROM ubuntu:18.04 # Install nginx and curl RUN apt-get update apt-get upgrade -y RUN apt-get install -y nginx curl RUN rm -rf /var/lib/apt/lists/*而仓库中最终落盘的 Dockerfile 又在此基础上做了安全加固——创建非 root 用户并以该用户身份运行这是镜像构建中非常重要的最佳实践可有效降低容器提权风险# Use the official Ubuntu 18.04 as base FROM ubuntu:18.04 # Install nginx and curl RUN apt-get update apt-get upgrade -y #RUN apt-get install -y nginx curl #RUN rm -rf /var/lib/apt/lists/* RUN groupadd -g 1000 basicuser useradd -r -u 1000 -g basicuser basicuser USER basicuser从源码结构可以看出FROM指定基础镜像RUN负责执行更新与软件安装注释掉的apt-get install行保留了调试痕迹而groupadd/useraddUSER组合则完成了最小权限运行的安全加固。在终端中进入该目录后执行构建命令docker build -t 90daysofdevops:0.1 .其中-t用于指定镜像名称与标签tag。执行后终端会输出逐层构建的日志构建完成后再用docker images即可看到新生成的镜像运行与验证容器内检查、Inspect 与推送 DockerHub运行镜像并验证软件可用性镜像构建完成后既可以用 Docker Desktop 启动容器也可以用 Docker CLI。作者在 Docker Desktop 中启动了一个容器进入容器 CLI 后可以看到curl已经可用Docker Desktop 的镜像操作菜单Docker Desktop 的 UI 还支持对这个新镜像做更多操作例如Inspect、Pull、Push to Hub、Remove、RUN其中Inspect可以看到镜像的历史构建记录——几乎就是 Dockerfile 里那些我们希望在容器中执行的指令和代码行这正是分层构建的直接体现也印证了每条 Dockerfile 指令产生一层的机制为什么 Pull 会失败Push 却可以镜像列表里的Pull 选项此时必然失败——因为这个镜像还没有托管在任何远程仓库找不到可拉取的位置。但我们有Push to Hub选项可以把镜像推送到 DockerHub。这里有一个关键细节之前使用的docker build -t 90daysofdevops:0.1 .在推送环节是不能直接复用的。若要推送构建命令必须带上 DockerHub 用户名前缀docker build -t {{username}}/{{imagename}}:{{version}} .推送完成后回到自己的 DockerHub 仓库就能看到刚推送的新镜像此时 Docker Desktop 里的Pull标签页就可以真正使用了仓库佐证镜像分层与 compose 的组合使用Day 45 聚焦镜像构建但同一 2022/Days/Containers 目录还给出了镜像/容器组合使用的进阶示例可作为镜像生态的延伸佐证elasticsearch-logstash-kibana/docker-compose.yml基于elasticsearch:7.16.1、logstash:7.16.1、kibana:7.16.1三个官方镜像编排 ELK 单节点集群演示了镜像 tag 选择、端口映射9200/9300/5000/5044/9600/5601、healthcheck用curl探测localhost:9200/_cluster/health、depends_on依赖关系与 bridge 网络其配套说明见 elasticsearch-logstash-kibana/README.md。my_wordpress/docker-compose.yaml组合mysql:5.7与wordpress:latest镜像展示通过命名卷持久化容器状态db_data、wordpress_data——这正是 Day 45 强调的容器层可写但随容器销毁而消失问题的标准解法。这些 compose 文件中的image:字段全部指向 DockerHub 上的官方基础镜像与 Day 45 讨论的parent image 层模型一脉相承。小结通过 Day 45 的剖析可以提炼出镜像构建的四条核心结论镜像 只读模板 分层结构每一条 Dockerfile 指令生成一层改动上层比改动下层重建成本更低容器层是镜像与运行容器间唯一的差异容器状态可写但生命周期短暂持久化要靠卷volumeDockerfile 优于docker commit前者可重复、易管理、便于接入 CI/CD是企业级部署的正道推送必须带用户名前缀docker build -t {{username}}/{{imagename}}:{{version}} .否则无法在 DockerHub 上定位与复用。下一节将在此基础上进一步深入容器化实践衔接内容见 2022/vi/Days/day46.md。赞分享文档/教程【免费下载链接】90DaysOfDevOpsThis repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.项目地址https://gitcode.com/gh_mirrors/90/90DaysOfDevOps点击查看免费下载相关推荐90DaysOfDevOps 实战Docker 镜像解剖与 Dockerfile 构建指南Day 4590DaysOfDevOps 实战Docker 镜像解剖与 Dockerfile 构建指南Day 45 本篇是 90DaysOfDevOps 开源学习计划文档/教程90DaysOfDevOps深入剖析 Docker 镜像结构 —— 从分层原理到 Dockerfile 构建实战90DaysOfDevOps深入剖析 Docker 镜像结构 —— 从分层原理到 Dockerfile 构建实战 镜像Image是 Docker 一切操作文档/教程90DaysOfDevOps 第 45 天深入剖析 Docker 镜像的结构与 Dockerfile 实战90DaysOfDevOps 第 45 天深入剖析 Docker 镜像的结构与 Dockerfile 实战 本文是 90DaysOfDevOps 系列第 45文档/教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表