Docker 入门:容器技术与 Docker 基础

Docker 入门:容器技术与 Docker 基础


本篇学习路线

复制代码
为什么要容器(问题) → 容器是什么(概念) → 靠什么实现(原理) → 怎么发展到今天(历史)
→ 生态全貌 → Docker 架构 → 安装上手 → 镜像管理(第一个核心技能)

文章目录

  • [Docker 入门:容器技术与 Docker 基础](#Docker 入门:容器技术与 Docker 基础)
  • 一、为什么要容器?从一个真实的困境讲起
    • [1.1 软件开发的"矩阵难题"](#1.1 软件开发的"矩阵难题")
    • [1.2 集装箱的启示](#1.2 集装箱的启示)
      • [集装箱思想 → 容器特性对照【重点】](#集装箱思想 → 容器特性对照【重点】)
    • [1.3 容器对开发/运维分别意味着什么【重点】](#1.3 容器对开发/运维分别意味着什么【重点】)
  • 二、容器到底是什么?
    • [2.1 定义【重点】](#2.1 定义【重点】)
    • [2.2 容器 vs 虚拟机:一张图看懂【重点】](#2.2 容器 vs 虚拟机:一张图看懂【重点】)
      • [容器 vs 虚拟机对比表【重点,常考】](#容器 vs 虚拟机对比表【重点,常考】)
    • [2.3 背景知识:容器之前的虚拟化方案](#2.3 背景知识:容器之前的虚拟化方案)
  • 三、容器靠什么实现?两大内核基石【难点,务必理解】
  • 四、容器发展简史【重点,了解来龙去脉】
      • [4.1 一条主线看懂 40 年](#4.1 一条主线看懂 40 年)
      • [4.2 各阶段详细脉络(知识点全表)](#4.2 各阶段详细脉络(知识点全表))
      • [4.3 极简时间轴(建议背下来)【重点】](#4.3 极简时间轴(建议背下来)【重点】)
  • 五、容器生态系统全貌
    • [5.1 容器核心技术(六要素)](#5.1 容器核心技术(六要素))
      • [① 容器规范(OCI)](#① 容器规范(OCI))
      • [② 容器 runtime(运行时)](#② 容器 runtime(运行时))
      • [③ 容器管理工具](#③ 容器管理工具)
      • [④ 容器定义工具](#④ 容器定义工具)
      • [⑤ Registry(镜像仓库)【重点】](#⑤ Registry(镜像仓库)【重点】)
      • [⑥ 容器 OS](#⑥ 容器 OS)
    • [5.2 容器平台技术(从单机到集群)](#5.2 容器平台技术(从单机到集群))
      • [① 容器编排引擎【重点】](#① 容器编排引擎【重点】)
      • [② 容器管理平台](#② 容器管理平台)
      • [③ 基于容器的 PaaS](#③ 基于容器的 PaaS)
    • [5.3 容器支持技术(周边保障)](#5.3 容器支持技术(周边保障))
  • [六、Docker 是什么?](#六、Docker 是什么?)
    • [6.1 定义【重点】](#6.1 定义【重点】)
    • [6.2 Docker 架构【重点 + 难点】](#6.2 Docker 架构【重点 + 难点】)
      • [① Client 客户端](#① Client 客户端)
      • [② Docker Host 宿主机](#② Docker Host 宿主机)
      • [③ Registry 镜像仓库](#③ Registry 镜像仓库)
      • [④ 一次 `docker run nginx` 的完整流程【重点,考试常考】](#④ 一次 docker run nginx 的完整流程【重点,考试常考】)
    • [6.3 Docker 版本演变【了解】](#6.3 Docker 版本演变【了解】)
  • [七、动手:安装 Docker 并跑起第一个容器](#七、动手:安装 Docker 并跑起第一个容器)
    • [7.1 实验环境](#7.1 实验环境)
    • [7.2 环境准备:搭建本地 yum 仓库(复习)](#7.2 环境准备:搭建本地 yum 仓库(复习))
    • [7.3 防火墙与 Docker 仓库](#7.3 防火墙与 Docker 仓库)
    • [7.4 安装并启动(allinone 部署)](#7.4 安装并启动(allinone 部署))
    • [7.5 配置镜像加速【重点,国内必做】](#7.5 配置镜像加速【重点,国内必做】)
    • [7.6 验证:跑起前两个容器](#7.6 验证:跑起前两个容器)
    • [7.7 C/S 分离部署【难点:亲手验证 Docker 是 C/S 架构】](#7.7 C/S 分离部署【难点:亲手验证 Docker 是 C/S 架构】)
    • [7.8 Docker 对 Windows 的支持](#7.8 Docker 对 Windows 的支持)
  • [八、Docker 镜像管理(第一个核心技能)](#八、Docker 镜像管理(第一个核心技能))
    • [8.0 先学会查帮助](#8.0 先学会查帮助)
    • [8.1 search------查找镜像](#8.1 search——查找镜像)
    • [8.2 pull------下载镜像【重点】](#8.2 pull——下载镜像【重点】)
    • [8.3 ls------查看本地镜像列表](#8.3 ls——查看本地镜像列表)
    • [8.4 tag------给镜像打标签](#8.4 tag——给镜像打标签)
      • [tag 的最佳实践:滚动版本号方案【重点】](#tag 的最佳实践:滚动版本号方案【重点】)
    • [8.5 inspect------查看镜像详细信息](#8.5 inspect——查看镜像详细信息)
    • [8.6 history------查看镜像的"分层历史"](#8.6 history——查看镜像的"分层历史")
    • [8.7 rm------删除镜像【重点 + 易错】](#8.7 rm——删除镜像【重点 + 易错】)
    • [8.8 prune------批量清理镜像](#8.8 prune——批量清理镜像)
    • [8.9 save / load------镜像的离线导出与导入【重点】](#8.9 save / load——镜像的离线导出与导入【重点】)
    • [8.10 push------把本地镜像推送到仓库](#8.10 push——把本地镜像推送到仓库)
  • 本篇知识自测清单

一、为什么要容器?从一个真实的困境讲起

1.1 软件开发的"矩阵难题"

现代应用很少是"一个程序跑起来"这么简单:

  • 一个应用往往由多种服务组装而成:消息队列(MQ)、缓存(Cache)、数据库(DB)......每个服务都有自己的依赖库、软件包、配置;
  • 应用还要部署到多种环境:虚拟服务器、私有云、公有云......

于是产生了一个核心矛盾------如何让每种服务在所有环境里都顺利运行?

服务 × 环境,排列组合,形成一个 N×M 的大矩阵:
#mermaid-svg-x0jHabgV6wD5xXyW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-x0jHabgV6wD5xXyW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-x0jHabgV6wD5xXyW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-x0jHabgV6wD5xXyW .error-icon{fill:#552222;}#mermaid-svg-x0jHabgV6wD5xXyW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-x0jHabgV6wD5xXyW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-x0jHabgV6wD5xXyW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-x0jHabgV6wD5xXyW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-x0jHabgV6wD5xXyW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-x0jHabgV6wD5xXyW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-x0jHabgV6wD5xXyW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-x0jHabgV6wD5xXyW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-x0jHabgV6wD5xXyW .marker.cross{stroke:#333333;}#mermaid-svg-x0jHabgV6wD5xXyW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-x0jHabgV6wD5xXyW p{margin:0;}#mermaid-svg-x0jHabgV6wD5xXyW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-x0jHabgV6wD5xXyW .cluster-label text{fill:#333;}#mermaid-svg-x0jHabgV6wD5xXyW .cluster-label span{color:#333;}#mermaid-svg-x0jHabgV6wD5xXyW .cluster-label span p{background-color:transparent;}#mermaid-svg-x0jHabgV6wD5xXyW .label text,#mermaid-svg-x0jHabgV6wD5xXyW span{fill:#333;color:#333;}#mermaid-svg-x0jHabgV6wD5xXyW .node rect,#mermaid-svg-x0jHabgV6wD5xXyW .node circle,#mermaid-svg-x0jHabgV6wD5xXyW .node ellipse,#mermaid-svg-x0jHabgV6wD5xXyW .node polygon,#mermaid-svg-x0jHabgV6wD5xXyW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-x0jHabgV6wD5xXyW .rough-node .label text,#mermaid-svg-x0jHabgV6wD5xXyW .node .label text,#mermaid-svg-x0jHabgV6wD5xXyW .image-shape .label,#mermaid-svg-x0jHabgV6wD5xXyW .icon-shape .label{text-anchor:middle;}#mermaid-svg-x0jHabgV6wD5xXyW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-x0jHabgV6wD5xXyW .rough-node .label,#mermaid-svg-x0jHabgV6wD5xXyW .node .label,#mermaid-svg-x0jHabgV6wD5xXyW .image-shape .label,#mermaid-svg-x0jHabgV6wD5xXyW .icon-shape .label{text-align:center;}#mermaid-svg-x0jHabgV6wD5xXyW .node.clickable{cursor:pointer;}#mermaid-svg-x0jHabgV6wD5xXyW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-x0jHabgV6wD5xXyW .arrowheadPath{fill:#333333;}#mermaid-svg-x0jHabgV6wD5xXyW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-x0jHabgV6wD5xXyW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-x0jHabgV6wD5xXyW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-x0jHabgV6wD5xXyW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-x0jHabgV6wD5xXyW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-x0jHabgV6wD5xXyW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-x0jHabgV6wD5xXyW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-x0jHabgV6wD5xXyW .cluster text{fill:#333;}#mermaid-svg-x0jHabgV6wD5xXyW .cluster span{color:#333;}#mermaid-svg-x0jHabgV6wD5xXyW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-x0jHabgV6wD5xXyW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-x0jHabgV6wD5xXyW rect.text{fill:none;stroke-width:0;}#mermaid-svg-x0jHabgV6wD5xXyW .icon-shape,#mermaid-svg-x0jHabgV6wD5xXyW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-x0jHabgV6wD5xXyW .icon-shape p,#mermaid-svg-x0jHabgV6wD5xXyW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-x0jHabgV6wD5xXyW .icon-shape .label rect,#mermaid-svg-x0jHabgV6wD5xXyW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-x0jHabgV6wD5xXyW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-x0jHabgV6wD5xXyW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-x0jHabgV6wD5xXyW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 要部署到多种环境
应用包含多种服务
MQ 服务
Cache 服务
DB 服务
虚拟服务器
私有云
公有云

对开发人员:写代码要考虑不同运行环境;对运维人员:要为每种服务 × 每种平台配置环境。双方都是灾难。

典型场景你一定见过:"在我电脑上明明能跑啊?"------开发环境好好的,一到测试/生产环境就报"缺依赖库"、"版本不对"、"配置丢了"。这就是环境不一致问题。

1.2 集装箱的启示

几十年前,运输业遇到过一模一样的问题:

  • 不同货物混装会互相损坏(铁桶压坏香蕉);
  • 货物要在卡车、轮船、火车之间反复装卸,一半以上时间花在装/卸货上,还容易损坏货物。

这同样是一个 N×M 矩阵(货物 × 交通工具)。

集装箱的发明解决了这一切:任何货物装进标准集装箱,全程密封、只在目的地开箱;标准化的接口让集装箱在卡车、轮船、火车之间高效转运,无需开箱。集装箱被誉为运输业与世界贸易最重要的发明。

Docker 做的事,就是把"集装箱思想"搬到软件领域:把任何应用连同它的依赖打包成一个轻量级、可移植、自包含的"集装箱"(容器),可以在几乎所有操作系统上运行。

"集装箱"和"容器"的英文都是 Container。"容器"是国内软件领域约定俗成的叫法。

集装箱思想 → 容器特性对照【重点】

特性 集装箱 容器
打包对象 几乎任何货物 任何软件及其依赖
硬件依赖 标准形状接口,可装卸到任何交通工具,全程不开箱 无需修改即可运行在几乎所有平台(虚拟机、物理机、公有云、私有云)
隔离性 集装箱可堆叠运输,货物互不干扰 资源、网络、库都是隔离的,不会出现依赖冲突
自动化 标准接口便于自动装卸 提供 run/start/stop 等标准化操作,适合自动化
高效性 无需开箱即可快速转运 轻量级,能快速启动和迁移
职责分工 货主只管装什么,承运方只管怎么运 开发只管写代码,运维只管配基础环境

1.3 容器对开发/运维分别意味着什么【重点】

两个口号记住容器的好处:

  • 对开发人员 ------Build Once, Run Anywhere(一次构建,到处运行):只需为应用创建一次运行环境,打包成容器后可在任何机器上运行;容器环境与宿主机隔离,像虚拟机一样隔离,但更快更简单。
  • 对运维人员 ------Configure Once, Run Anything(一次配置,运行一切):只需配好标准的 runtime 环境,服务器就能运行任何容器;开发、测试、生产环境高度一致,工作变得高效、可重复。

二、容器到底是什么?

2.1 定义【重点】

容器 = 操作系统级虚拟化技术 :在同一台宿主机操作系统之上,把应用程序 + 依赖库 + 配置文件 + 环境变量打包在一起,形成相互隔离的运行环境。

关键词"操作系统级":容器不需要携带一个完整的操作系统,它直接共享宿主机的 OS 内核,只打包"应用 + 它需要的环境"。

2.2 容器 vs 虚拟机:一张图看懂【重点】

传统虚拟化(VMware、KVM、Xen)的目标是创建完整的虚拟机。为了运行一个几十 MB 的应用,你得先在虚拟机里装一套几十 GB 的操作系统。

虚拟机架构------每个应用背一个完整 OS:
#mermaid-svg-pdLDh0RbnNMGevgR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pdLDh0RbnNMGevgR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pdLDh0RbnNMGevgR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pdLDh0RbnNMGevgR .error-icon{fill:#552222;}#mermaid-svg-pdLDh0RbnNMGevgR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pdLDh0RbnNMGevgR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pdLDh0RbnNMGevgR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pdLDh0RbnNMGevgR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pdLDh0RbnNMGevgR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pdLDh0RbnNMGevgR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pdLDh0RbnNMGevgR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pdLDh0RbnNMGevgR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pdLDh0RbnNMGevgR .marker.cross{stroke:#333333;}#mermaid-svg-pdLDh0RbnNMGevgR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pdLDh0RbnNMGevgR p{margin:0;}#mermaid-svg-pdLDh0RbnNMGevgR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-pdLDh0RbnNMGevgR .cluster-label text{fill:#333;}#mermaid-svg-pdLDh0RbnNMGevgR .cluster-label span{color:#333;}#mermaid-svg-pdLDh0RbnNMGevgR .cluster-label span p{background-color:transparent;}#mermaid-svg-pdLDh0RbnNMGevgR .label text,#mermaid-svg-pdLDh0RbnNMGevgR span{fill:#333;color:#333;}#mermaid-svg-pdLDh0RbnNMGevgR .node rect,#mermaid-svg-pdLDh0RbnNMGevgR .node circle,#mermaid-svg-pdLDh0RbnNMGevgR .node ellipse,#mermaid-svg-pdLDh0RbnNMGevgR .node polygon,#mermaid-svg-pdLDh0RbnNMGevgR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pdLDh0RbnNMGevgR .rough-node .label text,#mermaid-svg-pdLDh0RbnNMGevgR .node .label text,#mermaid-svg-pdLDh0RbnNMGevgR .image-shape .label,#mermaid-svg-pdLDh0RbnNMGevgR .icon-shape .label{text-anchor:middle;}#mermaid-svg-pdLDh0RbnNMGevgR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-pdLDh0RbnNMGevgR .rough-node .label,#mermaid-svg-pdLDh0RbnNMGevgR .node .label,#mermaid-svg-pdLDh0RbnNMGevgR .image-shape .label,#mermaid-svg-pdLDh0RbnNMGevgR .icon-shape .label{text-align:center;}#mermaid-svg-pdLDh0RbnNMGevgR .node.clickable{cursor:pointer;}#mermaid-svg-pdLDh0RbnNMGevgR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-pdLDh0RbnNMGevgR .arrowheadPath{fill:#333333;}#mermaid-svg-pdLDh0RbnNMGevgR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pdLDh0RbnNMGevgR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pdLDh0RbnNMGevgR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pdLDh0RbnNMGevgR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pdLDh0RbnNMGevgR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pdLDh0RbnNMGevgR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-pdLDh0RbnNMGevgR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pdLDh0RbnNMGevgR .cluster text{fill:#333;}#mermaid-svg-pdLDh0RbnNMGevgR .cluster span{color:#333;}#mermaid-svg-pdLDh0RbnNMGevgR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-pdLDh0RbnNMGevgR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pdLDh0RbnNMGevgR rect.text{fill:none;stroke-width:0;}#mermaid-svg-pdLDh0RbnNMGevgR .icon-shape,#mermaid-svg-pdLDh0RbnNMGevgR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pdLDh0RbnNMGevgR .icon-shape p,#mermaid-svg-pdLDh0RbnNMGevgR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-pdLDh0RbnNMGevgR .icon-shape .label rect,#mermaid-svg-pdLDh0RbnNMGevgR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pdLDh0RbnNMGevgR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-pdLDh0RbnNMGevgR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-pdLDh0RbnNMGevgR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 应用A
来宾操作系统

(几十GB)
应用B
来宾操作系统

(几十GB)
Hypervisor 虚拟化层
宿主机操作系统
物理硬件

容器架构------所有容器共享同一个宿主机 OS 内核:
#mermaid-svg-PnGV2OgMGunqpUnu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PnGV2OgMGunqpUnu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PnGV2OgMGunqpUnu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PnGV2OgMGunqpUnu .error-icon{fill:#552222;}#mermaid-svg-PnGV2OgMGunqpUnu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PnGV2OgMGunqpUnu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PnGV2OgMGunqpUnu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PnGV2OgMGunqpUnu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PnGV2OgMGunqpUnu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PnGV2OgMGunqpUnu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PnGV2OgMGunqpUnu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PnGV2OgMGunqpUnu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PnGV2OgMGunqpUnu .marker.cross{stroke:#333333;}#mermaid-svg-PnGV2OgMGunqpUnu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PnGV2OgMGunqpUnu p{margin:0;}#mermaid-svg-PnGV2OgMGunqpUnu .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PnGV2OgMGunqpUnu .cluster-label text{fill:#333;}#mermaid-svg-PnGV2OgMGunqpUnu .cluster-label span{color:#333;}#mermaid-svg-PnGV2OgMGunqpUnu .cluster-label span p{background-color:transparent;}#mermaid-svg-PnGV2OgMGunqpUnu .label text,#mermaid-svg-PnGV2OgMGunqpUnu span{fill:#333;color:#333;}#mermaid-svg-PnGV2OgMGunqpUnu .node rect,#mermaid-svg-PnGV2OgMGunqpUnu .node circle,#mermaid-svg-PnGV2OgMGunqpUnu .node ellipse,#mermaid-svg-PnGV2OgMGunqpUnu .node polygon,#mermaid-svg-PnGV2OgMGunqpUnu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PnGV2OgMGunqpUnu .rough-node .label text,#mermaid-svg-PnGV2OgMGunqpUnu .node .label text,#mermaid-svg-PnGV2OgMGunqpUnu .image-shape .label,#mermaid-svg-PnGV2OgMGunqpUnu .icon-shape .label{text-anchor:middle;}#mermaid-svg-PnGV2OgMGunqpUnu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PnGV2OgMGunqpUnu .rough-node .label,#mermaid-svg-PnGV2OgMGunqpUnu .node .label,#mermaid-svg-PnGV2OgMGunqpUnu .image-shape .label,#mermaid-svg-PnGV2OgMGunqpUnu .icon-shape .label{text-align:center;}#mermaid-svg-PnGV2OgMGunqpUnu .node.clickable{cursor:pointer;}#mermaid-svg-PnGV2OgMGunqpUnu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PnGV2OgMGunqpUnu .arrowheadPath{fill:#333333;}#mermaid-svg-PnGV2OgMGunqpUnu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PnGV2OgMGunqpUnu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PnGV2OgMGunqpUnu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PnGV2OgMGunqpUnu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PnGV2OgMGunqpUnu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PnGV2OgMGunqpUnu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PnGV2OgMGunqpUnu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PnGV2OgMGunqpUnu .cluster text{fill:#333;}#mermaid-svg-PnGV2OgMGunqpUnu .cluster span{color:#333;}#mermaid-svg-PnGV2OgMGunqpUnu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PnGV2OgMGunqpUnu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PnGV2OgMGunqpUnu rect.text{fill:none;stroke-width:0;}#mermaid-svg-PnGV2OgMGunqpUnu .icon-shape,#mermaid-svg-PnGV2OgMGunqpUnu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PnGV2OgMGunqpUnu .icon-shape p,#mermaid-svg-PnGV2OgMGunqpUnu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PnGV2OgMGunqpUnu .icon-shape .label rect,#mermaid-svg-PnGV2OgMGunqpUnu .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PnGV2OgMGunqpUnu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PnGV2OgMGunqpUnu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PnGV2OgMGunqpUnu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 应用A + 环境
共享宿主机

操作系统内核
应用B + 环境
应用C + 环境
宿主机操作系统
物理硬件

由此带来三个关键特点:

  1. 所有容器共享同一个 Host OS,所以体积远小于虚拟机;
  2. 启动容器不需要启动整个操作系统------部署和启动速度更快、开销更小、更容易迁移;
  3. 容器内程序直接在 CPU 上本地运行指令,不需要虚拟化那套"指令级模拟"或"即时编译",所以性能接近原生。

容器 vs 虚拟机对比表【重点,常考】

特性 容器 虚拟机
启动速度 秒级 分钟级
性能 接近原生 较弱
内存代价 很小 较多
硬盘使用 一般为 MB 一般为 GB
运行密度 单机支持上千个容器 一般几十个
隔离性 安全隔离 完全隔离
迁移性 优秀 一般

注意"隔离性"一栏:虚拟机是完全隔离 (各自独立内核),容器只是安全隔离(共享内核,靠内核机制隔离)------这也是容器比虚拟机轻的原因,同时是容器隔离性弱于虚拟机的原因。

2.3 背景知识:容器之前的虚拟化方案

学习容器前,先了解业界曾经/正在使用的虚拟化方案(本课程前情提要):

方案 说明
VMware Workstation 个人桌面级虚拟机软件
KVM + oVirt KVM 是 Linux 内核自带的虚拟化技术;oVirt 用于集中管理多台 KVM 虚拟主机
VMware ESXi + vCenter 企业级裸金属虚拟化 + 集中管理平台
OpenStack(nova 组件) 开源私有云平台;nova 是计算核心,包含 nova-api、nova-scheduler、nova-compute

它们解决的是"一台物理机当多台用"的问题;容器解决的则是"应用打包与环境一致性"问题,二者定位不同。


三、容器靠什么实现?两大内核基石【难点,务必理解】

容器不是凭空出现的魔法,它完全依赖 Linux 内核提供的两个机制:

Namespace(命名空间)负责"隔离"------让容器之间互相看不见;
Cgroups(控制组)负责"限制"------让容器之间互相不抢占。

Namespace:让容器"各自为政"

Namespace 隔离什么 效果
PID 进程编号 容器内有自己的 PID 1、PID 2......看不到宿主机进程
Network 网络栈 每个容器有独立的网卡、IP、路由表
IPC 进程间通信 容器间信号量、共享内存互不干扰
Mount 挂载点 容器有独立的文件系统挂载视图
User 用户 UID/GID 容器内的 root ≠ 宿主机的 root,解决容器权限安全问题
UTS 主机名 容器可有独立的主机名(如 -h myos)

Cgroups:给容器"上配额"

由 Google 工程师开发,能对容器的 CPU、内存、IO、网络带宽做限制------容器 A 再忙也不能吃光宿主机资源。

记住这个等式(贯穿整个 Docker 学习):

容器 = 应用 + 环境打包 +(Namespace 隔离 + Cgroups 资源限制)

容器本质上是宿主机上受管控的普通进程,而不是虚拟机。


四、容器发展简史【重点,了解来龙去脉】

4.1 一条主线看懂 40 年

#mermaid-svg-7QR4bLi8lBlksKyJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7QR4bLi8lBlksKyJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7QR4bLi8lBlksKyJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7QR4bLi8lBlksKyJ .error-icon{fill:#552222;}#mermaid-svg-7QR4bLi8lBlksKyJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7QR4bLi8lBlksKyJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7QR4bLi8lBlksKyJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7QR4bLi8lBlksKyJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7QR4bLi8lBlksKyJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7QR4bLi8lBlksKyJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7QR4bLi8lBlksKyJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7QR4bLi8lBlksKyJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7QR4bLi8lBlksKyJ .marker.cross{stroke:#333333;}#mermaid-svg-7QR4bLi8lBlksKyJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7QR4bLi8lBlksKyJ p{margin:0;}#mermaid-svg-7QR4bLi8lBlksKyJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7QR4bLi8lBlksKyJ .cluster-label text{fill:#333;}#mermaid-svg-7QR4bLi8lBlksKyJ .cluster-label span{color:#333;}#mermaid-svg-7QR4bLi8lBlksKyJ .cluster-label span p{background-color:transparent;}#mermaid-svg-7QR4bLi8lBlksKyJ .label text,#mermaid-svg-7QR4bLi8lBlksKyJ span{fill:#333;color:#333;}#mermaid-svg-7QR4bLi8lBlksKyJ .node rect,#mermaid-svg-7QR4bLi8lBlksKyJ .node circle,#mermaid-svg-7QR4bLi8lBlksKyJ .node ellipse,#mermaid-svg-7QR4bLi8lBlksKyJ .node polygon,#mermaid-svg-7QR4bLi8lBlksKyJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7QR4bLi8lBlksKyJ .rough-node .label text,#mermaid-svg-7QR4bLi8lBlksKyJ .node .label text,#mermaid-svg-7QR4bLi8lBlksKyJ .image-shape .label,#mermaid-svg-7QR4bLi8lBlksKyJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-7QR4bLi8lBlksKyJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7QR4bLi8lBlksKyJ .rough-node .label,#mermaid-svg-7QR4bLi8lBlksKyJ .node .label,#mermaid-svg-7QR4bLi8lBlksKyJ .image-shape .label,#mermaid-svg-7QR4bLi8lBlksKyJ .icon-shape .label{text-align:center;}#mermaid-svg-7QR4bLi8lBlksKyJ .node.clickable{cursor:pointer;}#mermaid-svg-7QR4bLi8lBlksKyJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7QR4bLi8lBlksKyJ .arrowheadPath{fill:#333333;}#mermaid-svg-7QR4bLi8lBlksKyJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7QR4bLi8lBlksKyJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7QR4bLi8lBlksKyJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7QR4bLi8lBlksKyJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7QR4bLi8lBlksKyJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7QR4bLi8lBlksKyJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7QR4bLi8lBlksKyJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7QR4bLi8lBlksKyJ .cluster text{fill:#333;}#mermaid-svg-7QR4bLi8lBlksKyJ .cluster span{color:#333;}#mermaid-svg-7QR4bLi8lBlksKyJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7QR4bLi8lBlksKyJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7QR4bLi8lBlksKyJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-7QR4bLi8lBlksKyJ .icon-shape,#mermaid-svg-7QR4bLi8lBlksKyJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7QR4bLi8lBlksKyJ .icon-shape p,#mermaid-svg-7QR4bLi8lBlksKyJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7QR4bLi8lBlksKyJ .icon-shape .label rect,#mermaid-svg-7QR4bLi8lBlksKyJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7QR4bLi8lBlksKyJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7QR4bLi8lBlksKyJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7QR4bLi8lBlksKyJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1979

chroot

文件系统隔离
1998-2000

Jails / Zones

完整OS级隔离
2002-2008

Namespace + Cgroups

陆续进入 Linux 内核
2008

LXC

第一个Linux容器工具
2013

Docker

镜像+Dockerfile 容器大众化
2015

OCI标准 + K8s 1.0

标准化+集群编排
2016至今

runc/containerd/CRI

云原生生态成熟

4.2 各阶段详细脉络(知识点全表)

阶段一:早期隔离思想(各 Unix 系统各自实现,Linux 尚无原生方案)

时间 事件 要点
1979 Unix V7 引入 chroot() 系统调用 修改进程根目录,实现文件系统隔离;只有目录隔离,没有 CPU/内存/网络隔离,是容器最早的技术原型
1998 FreeBSD Jails 在 chroot 基础上增加进程、网络隔离,一台主机可跑多个独立"虚拟系统",现代容器思想的重要实践
2000 Solaris Zones 操作系统级虚拟化,CPU/内存/网络/文件系统完整隔离(Oracle 商用方案)

知识拓展:chroot 至今仍有个经典用途------破解 Linux root 密码 (救援模式挂载真实根后 chroot 进去改密码):

bash 复制代码
/dev/centos/root   /mnt/sysroot
mount -o rw,remount /mnt/sysroot
chroot /mnt/sysroot/

阶段二:Linux 内核关键技术就位(容器底层能力逐渐完备)

时间 技术 作用
2002 PID Namespace 进内核 进程 ID 隔离
2003 Network Namespace 进内核 网络栈隔离
2004--2006 IPC、Mount Namespace 陆续合入 进程间通信隔离、挂载点隔离
2007 Cgroups 合入 Linux 内核 CPU/内存/IO/网络带宽资源限制(Google 工程师开发)
2008 User Namespace 开始开发迭代 UID/GID 隔离,容器内 root ≠ 宿主机 root;后续版本逐步完善

阶段三:LXC 容器诞生

时间 事件
2008 **LXC(Linux Containers)**项目启动:基于 Namespace + Cgroups 封装,世界上第一个完整的 Linux 用户态容器工具。痛点:没有镜像机制、配置复杂、分发困难,主要面向运维专家
2010 VMware 推出 CloudFoundry Warden:容器管理服务,做资源隔离与实例生命周期管理
2013 PaaS 云厂商 dotCloud 内部孵化 Docker,专门解决 LXC 的镜像、打包、分发痛点

阶段四:Docker 爆发

时间 事件 意义
2013-06 Docker 0.1 发布(基于 LXC) 核心创新:镜像分层、Dockerfile、镜像仓库、统一工具链 ------容器不再只是隔离工具,而是完整的应用打包分发体系,迅速出圈
2014-06 Docker 1.0 发布 宣布生产可用;Docker Hub 公共镜像仓库大规模使用
2014 Google 发布 Borg 论文 Borg 是 Google 内部大规模容器调度系统,是 Kubernetes 的思想源头;同期 Google 放出 lmctfy 容器工具
2014-07 Docker 切换到自研 libcontainer 抛弃 LXC,直接调用 Linux 系统调用,不依赖 LXC 工具链,容器运行时走向独立
2015-06 OCI(Open Container Initiative)成立 Linux 基金会主导,Docker、Google、红帽等共同成立,制定容器镜像规范 + 容器运行时规范,避免容器生态分裂

阶段五:Kubernetes 崛起与运行时分层

时间 事件 意义
2015-07 Kubernetes 1.0 发布 Google 基于 Borg 经验开源 K8s,实现调度、自愈、服务发现、滚动更新------容器从单机走向大规模集群
2016 runc 发布 libcontainer 改名 runc,OCI 标准运行时,底层真正创建容器的工具,Docker 底层调用它
2016 containerd 诞生 Docker 拆分出的高级容器运行时,管理镜像和容器生命周期;上层对接 docker/k8s,下层调用 runc
2017 K8s 移交 CNCF(云原生计算基金会)托管 K8s 成为容器编排事实标准;Docker 公司商业受挫,其编排引擎 Docker Swarm 逐渐边缘化
2017--2018 CRI(容器运行时接口)成熟 K8s 定义 CRI 接口,不再强绑定 Docker;cri-containerd 把 containerd 适配进 CRI

阶段六:云原生生态成熟

  • K8s 移除 dockershim:K8s 不再内置 Docker 适配层,containerd 成为 K8s 默认容器运行时;Docker 保留为开发工具,在集群层面不再是首选运行时。
  • 安全容器:Kata Containers(轻量级虚拟机、内核隔离、强安全隔离)、gVisor(Google 用户态内核,把应用与宿主机内核隔开)。
  • 其他 OCI 兼容运行时:nerdctl(containerd 的命令行工具,兼容 docker 命令)、crun(C 语言实现的轻量 runc 替代品)。
  • 2020--2023 :红帽 Podman + Buildah 普及------无守护进程、兼容 docker 命令、原生支持 OCI 标准。
  • 2024--2026:WebAssembly 容器兴起(Wasm-OCI,把 Wasm 当镜像,开销极低),K8s 对 Wasm 运行时支持增强。

4.3 极简时间轴(建议背下来)【重点】

时间 里程碑 核心价值
1979 Unix chroot 文件系统隔离原型
1998 FreeBSD Jails 完整 OS 级隔离雏形
2007 Linux Cgroups 合入内核 资源限制基石
2008 LXC 项目诞生 第一个 Linux 容器工具
2013 Docker 发布 镜像 + Dockerfile,容器大众化
2015 OCI 成立;K8s 1.0 标准化 + 集群编排时代开启
2016 runc、containerd 分层容器运行时架构
2017 K8s 移交 CNCF K8s 成为编排事实标准
2022 K8s 彻底移除 dockershim containerd 成为 K8s 默认运行时
2023 至今 Wasm 容器、安全容器 轻量、强隔离新方向

【难点补充】为什么 runc、containerd 这一层很重要?可以把容器运行时想象成"厨房分工":

  • runc:真正点火的厨师(创建/销毁单个容器);
  • containerd:厨房主管(管理镜像、容器生命周期、日志);
  • docker/k8s :点菜的前台(面向用户的界面)。
    K8s 通过 CRI 标准接口"点菜",所以换不换 Docker 它都无所谓。

五、容器生态系统全貌

容器不只是 Docker 一个工具,而是一整片生态。分三层看:核心技术 (单机能跑容器)、平台技术 (集群规模编排)、支持技术(周边保障)。

5.1 容器核心技术(六要素)

① 容器规范(OCI)

容器不只有 Docker(还有 CoreOS 的 rkt 等)。为保证不同容器互相兼容,Docker、CoreOS、Google 等公司共同成立 OCI,发布了两个规范:

  • runtime spec:容器运行环境规范(runtime 是容器运行的环境);
  • image format spec:镜像格式规范(image = 应用 + 依赖库 + 配置 + 环境变量的打包文件)。

有了规范,不同组织/厂商的容器可以在不同 runtime 上运行------可移植性和互操作性。

② 容器 runtime(运行时)

runtime 与操作系统内核紧密协作,为容器提供运行环境。主流三种:

runtime 说明
lxc Linux 老牌 runtime,Docker 最初就用它
runc Docker 自研 ,符合 OCI 规范,现在 Docker 的默认 runtime
rkt CoreOS 开发,符合 OCI 规范,因此也能运行 Docker 的容器

③ 容器管理工具

光有 runtime 不够------用户需要工具来操作容器。管理工具对内与 runtime 交互,对外给用户提供 CLI。

类比:有了 JVM 还不行,还得有 java 命令让你能启动程序。

runtime 管理工具
lxc lxd
runc docker engine(含后台 daemon + CLI 两部分;我们平时说的 "Docker" 就是指它)
rkt rkt cli

④ 容器定义工具

用来定义容器的内容和属性,让容器能被保存、共享、重建:

  • docker image:Docker 容器的模板,runtime 依据它创建容器;
  • dockerfile:包含若干命令的文本文件,通过这些命令能构建出 docker image(后面课程的重点);
  • ACI(App Container Image):CoreOS 为 rkt 开发的镜像格式,与 docker image 类似。

⑤ Registry(镜像仓库)【重点】

容器由 image 创建,image 需要统一存放的地方------就是 Registry:

  • 企业可以用 Docker Registry 搭建私有仓库;
  • Docker Hub(https://hub.docker.com):官方公共托管仓库,有大量现成镜像,对用户极其方便;
  • Quay.io(https://quay.io):另一个公共托管仓库。

⑥ 容器 OS

因为有容器 runtime,几乎所有的 Linux、macOS、Windows 都能跑容器。容器 OS 是专门为运行容器定制的操作系统:体积更小、启动更快、运行容器效率更高。代表:CoreOS、atomic、ubuntu core。

5.2 容器平台技术(从单机到集群)

核心技术只解决"单机跑容器";平台技术让容器作为集群在分布式环境运行。

① 容器编排引擎【重点】

基于容器的应用一般采用微服务架构:

  • 应用被拆分成不同组件,各自以服务形式跑在容器里,通过 API 对外提供服务;
  • 为了高可用,每个组件可能跑多个相同容器组成集群,容器根据业务动态创建、迁移、销毁。

这样一个动态可伸缩的系统,靠人工管理不现实------这就是**编排(Orchestration)**要干的事:容器管理、调度、集群定义、服务发现。主流引擎:

  • Docker Swarm:Docker 自家编排引擎;
  • Kubernetes:Google 主导的开源编排引擎,同时支持 Docker 和 CoreOS 容器(当前事实标准);
  • Mesos :通用集群资源调度平台,与 marathon 配合提供编排功能。

② 容器管理平台

架在编排引擎之上的更通用平台,通常支持多种编排引擎、屏蔽底层细节,提供应用目录、一键部署等便利功能。

基于 Kubernetes 的平台:

平台 特点
Rancher(开源免费) 轻量级 K8s 管理平台,一键部署、管理多集群,兼容云/本地/边缘环境,适合企业统一管控
OpenShift(开源免费) Red Hat 企业级 K8s 发行版,增加安全、监控、CI/CD 等企业级特性,生态成熟,适合大型企业生产
Kubesphere(开源免费) 青云开源容器平台,以 K8s 为内核,提供可视化界面降低使用门槛,支持多租户、DevOps 流水线
AWS EKS(商业托管) 亚马逊云托管 K8s,无缝对接 AWS 生态(存储、负载均衡),稳定性高
Azure AKS(商业托管) 微软云托管 K8s,集成 Azure 监控、身份认证
阿里云 ACK(商业托管) 适配阿里云资源,支持混合云、边缘集群,国内访问快,适合国内企业

简化型轻量管理平台:

平台 特点
Portainer 超轻量容器管理 UI,支持 Docker 和 K8s,单容器即可部署,界面直观,适合个人测试、小团队
Docker Desktop Docker 官方桌面工具(Windows/Mac),内置 K8s,个人本地开发首选
Lens K8s IDE,可视化管集群:资源编辑、日志查看、监控

③ 基于容器的 PaaS

为微服务开发提供开发、部署、管理平台,用户不用关心底层基础设施、专注写应用。代表(均为开源):Deis、Flynn、Dokku。

5.3 容器支持技术(周边保障)

领域 为什么需要 代表方案
容器网络 容器让网络拓扑更动态复杂,需要专门方案管理容器间、容器与外部的连通性和隔离性 docker network(Docker 原生);flannel、weave、calico(第三方开源,各有优劣,按需选型)
服务发现 微服务动态变化:负载增→自动建容器,负载降→销毁容器;容器还会迁移,IP/端口随时变。client 必须有办法"找到"服务。服务发现保存所有微服务最新的 IP/端口信息,对外提供查询 API etcd、consul、zookeeper
监控 容器的动态特征对监控提出更高挑战 docker ps/top/stats(原生命令行)+ stats API(HTTP 获取容器状态);sysdig、cAdvisor/Heapster、Weave Scope(开源方案)
数据管理 容器常在不同 host 间迁移,持久化数据也要能动态跟着走 Flocker
日志管理 日志是问题排查和事件管理的重要依据 docker logs(原生);logspout(日志路由:收集各容器日志并转发给其他工具后处理)
安全性 容器年轻,安全性一直是业界争论焦点 OpenSCAP(对容器镜像做扫描,发现潜在漏洞)

六、Docker 是什么?

6.1 定义【重点】

  • Docker 是基于 Go 语言 实现的开源容器项目,2013 年初 诞生,最初发起者是 dotCloud 公司。开源后广受关注,围绕它形成了完整生态;由于影响力太大,dotCloud 干脆改名 Docker Inc,专注 Docker 相关技术。
  • Docker 的两大贡献:
    1. 提供了各种容器管理工具------管理和使用容器变得简单明了;
    2. 引入分层文件系统构建和高效的镜像机制------迁移难度大幅降低,用户体验极好,操作容器就像操作应用本身。
  • 可以把 Docker 容器理解为一种轻量级的沙盒(sandbox) :每个容器里运行一个应用,不同容器相互隔离,也可以通过网络互相通信。创建/停止容器非常快,几乎和创建/终止原生应用一致;资源额外开销远低于虚拟机------很多时候直接把容器当作应用本身也没问题。

6.2 Docker 架构【重点 + 难点】

Docker 采用 C/S(客户端/服务端)架构 ,客户端与 Docker 守护进程通过 Socket 通信:
#mermaid-svg-u3bPQo1pRflbVJXt{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-u3bPQo1pRflbVJXt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-u3bPQo1pRflbVJXt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-u3bPQo1pRflbVJXt .error-icon{fill:#552222;}#mermaid-svg-u3bPQo1pRflbVJXt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-u3bPQo1pRflbVJXt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-u3bPQo1pRflbVJXt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-u3bPQo1pRflbVJXt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-u3bPQo1pRflbVJXt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-u3bPQo1pRflbVJXt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-u3bPQo1pRflbVJXt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-u3bPQo1pRflbVJXt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-u3bPQo1pRflbVJXt .marker.cross{stroke:#333333;}#mermaid-svg-u3bPQo1pRflbVJXt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-u3bPQo1pRflbVJXt p{margin:0;}#mermaid-svg-u3bPQo1pRflbVJXt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-u3bPQo1pRflbVJXt .cluster-label text{fill:#333;}#mermaid-svg-u3bPQo1pRflbVJXt .cluster-label span{color:#333;}#mermaid-svg-u3bPQo1pRflbVJXt .cluster-label span p{background-color:transparent;}#mermaid-svg-u3bPQo1pRflbVJXt .label text,#mermaid-svg-u3bPQo1pRflbVJXt span{fill:#333;color:#333;}#mermaid-svg-u3bPQo1pRflbVJXt .node rect,#mermaid-svg-u3bPQo1pRflbVJXt .node circle,#mermaid-svg-u3bPQo1pRflbVJXt .node ellipse,#mermaid-svg-u3bPQo1pRflbVJXt .node polygon,#mermaid-svg-u3bPQo1pRflbVJXt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-u3bPQo1pRflbVJXt .rough-node .label text,#mermaid-svg-u3bPQo1pRflbVJXt .node .label text,#mermaid-svg-u3bPQo1pRflbVJXt .image-shape .label,#mermaid-svg-u3bPQo1pRflbVJXt .icon-shape .label{text-anchor:middle;}#mermaid-svg-u3bPQo1pRflbVJXt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-u3bPQo1pRflbVJXt .rough-node .label,#mermaid-svg-u3bPQo1pRflbVJXt .node .label,#mermaid-svg-u3bPQo1pRflbVJXt .image-shape .label,#mermaid-svg-u3bPQo1pRflbVJXt .icon-shape .label{text-align:center;}#mermaid-svg-u3bPQo1pRflbVJXt .node.clickable{cursor:pointer;}#mermaid-svg-u3bPQo1pRflbVJXt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-u3bPQo1pRflbVJXt .arrowheadPath{fill:#333333;}#mermaid-svg-u3bPQo1pRflbVJXt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-u3bPQo1pRflbVJXt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-u3bPQo1pRflbVJXt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-u3bPQo1pRflbVJXt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-u3bPQo1pRflbVJXt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-u3bPQo1pRflbVJXt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-u3bPQo1pRflbVJXt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-u3bPQo1pRflbVJXt .cluster text{fill:#333;}#mermaid-svg-u3bPQo1pRflbVJXt .cluster span{color:#333;}#mermaid-svg-u3bPQo1pRflbVJXt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-u3bPQo1pRflbVJXt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-u3bPQo1pRflbVJXt rect.text{fill:none;stroke-width:0;}#mermaid-svg-u3bPQo1pRflbVJXt .icon-shape,#mermaid-svg-u3bPQo1pRflbVJXt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-u3bPQo1pRflbVJXt .icon-shape p,#mermaid-svg-u3bPQo1pRflbVJXt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-u3bPQo1pRflbVJXt .icon-shape .label rect,#mermaid-svg-u3bPQo1pRflbVJXt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-u3bPQo1pRflbVJXt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-u3bPQo1pRflbVJXt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-u3bPQo1pRflbVJXt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} docker run 等命令
Socket 通信,只发指令
pull 下载 / push 上传
基于镜像创建实例
用户
Client 客户端

(docker 命令行)
Docker Daemon 守护进程

(宿主机上,真正干活)
Images 镜像

(只读模板)
Containers 容器

(镜像 + 可读写层)
Registry 镜像仓库

Docker Hub 等

三大部分逐一拆解:

① Client 客户端

  • 就是我们敲 docker 命令的终端,用户交互入口;
  • 关键理解【难点】:客户端不直接做容器创建工作,只是把指令发送给 Docker Daemon(真正干活的在服务端);
  • 典型命令:docker build(构建镜像)、docker pull(拉取镜像)、docker run(基于镜像创建并启动容器)。

② Docker Host 宿主机

宿主机上运行核心组件 Docker daemon(守护进程)------整个架构的服务端,后台常驻进程,真正处理所有 docker 请求:镜像构建、拉取,容器创建、启停、销毁。宿主机内管理两大资源:

Images 镜像【重点】

  • 镜像 = 只读的模板(类比:虚拟机镜像 / 类 / 菜谱),是创建容器的基础,包含应用程序、依赖库、配置文件、环境变量。例如"一个基础 OS 环境 + 只装了 Apache"就是一个 Apache 镜像。
  • 获取方式:docker build 本地构建,或 docker pull 从 Registry 下载;甚至可以从网上下载现成的应用镜像直接用。
  • 通过版本管理和增量的文件系统,Docker 提供了简单的机制创建和更新镜像。
  • 分层存储:镜像由多个只读层叠出来,多个镜像可共享底层(pull 时会看到一层层下载)------节约磁盘。
  • 关键限制:镜像只读,不能直接运行,必须基于它实例化成容器。

Containers 容器【重点】

  • 容器 = 镜像的运行实例(类比:类 → 实例 / 菜谱 → 炒出来的菜),是一个轻量级沙盒。
  • docker run 时 daemon 读取本地镜像,在只读镜像层之上叠加一层可读写层,生成容器:

#mermaid-svg-xbV3inFUF7vTlc6y{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xbV3inFUF7vTlc6y .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xbV3inFUF7vTlc6y .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xbV3inFUF7vTlc6y .error-icon{fill:#552222;}#mermaid-svg-xbV3inFUF7vTlc6y .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xbV3inFUF7vTlc6y .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xbV3inFUF7vTlc6y .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xbV3inFUF7vTlc6y .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xbV3inFUF7vTlc6y .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xbV3inFUF7vTlc6y .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xbV3inFUF7vTlc6y .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xbV3inFUF7vTlc6y .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xbV3inFUF7vTlc6y .marker.cross{stroke:#333333;}#mermaid-svg-xbV3inFUF7vTlc6y svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xbV3inFUF7vTlc6y p{margin:0;}#mermaid-svg-xbV3inFUF7vTlc6y .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xbV3inFUF7vTlc6y .cluster-label text{fill:#333;}#mermaid-svg-xbV3inFUF7vTlc6y .cluster-label span{color:#333;}#mermaid-svg-xbV3inFUF7vTlc6y .cluster-label span p{background-color:transparent;}#mermaid-svg-xbV3inFUF7vTlc6y .label text,#mermaid-svg-xbV3inFUF7vTlc6y span{fill:#333;color:#333;}#mermaid-svg-xbV3inFUF7vTlc6y .node rect,#mermaid-svg-xbV3inFUF7vTlc6y .node circle,#mermaid-svg-xbV3inFUF7vTlc6y .node ellipse,#mermaid-svg-xbV3inFUF7vTlc6y .node polygon,#mermaid-svg-xbV3inFUF7vTlc6y .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xbV3inFUF7vTlc6y .rough-node .label text,#mermaid-svg-xbV3inFUF7vTlc6y .node .label text,#mermaid-svg-xbV3inFUF7vTlc6y .image-shape .label,#mermaid-svg-xbV3inFUF7vTlc6y .icon-shape .label{text-anchor:middle;}#mermaid-svg-xbV3inFUF7vTlc6y .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xbV3inFUF7vTlc6y .rough-node .label,#mermaid-svg-xbV3inFUF7vTlc6y .node .label,#mermaid-svg-xbV3inFUF7vTlc6y .image-shape .label,#mermaid-svg-xbV3inFUF7vTlc6y .icon-shape .label{text-align:center;}#mermaid-svg-xbV3inFUF7vTlc6y .node.clickable{cursor:pointer;}#mermaid-svg-xbV3inFUF7vTlc6y .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xbV3inFUF7vTlc6y .arrowheadPath{fill:#333333;}#mermaid-svg-xbV3inFUF7vTlc6y .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xbV3inFUF7vTlc6y .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xbV3inFUF7vTlc6y .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xbV3inFUF7vTlc6y .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xbV3inFUF7vTlc6y .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xbV3inFUF7vTlc6y .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xbV3inFUF7vTlc6y .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xbV3inFUF7vTlc6y .cluster text{fill:#333;}#mermaid-svg-xbV3inFUF7vTlc6y .cluster span{color:#333;}#mermaid-svg-xbV3inFUF7vTlc6y div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xbV3inFUF7vTlc6y .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xbV3inFUF7vTlc6y rect.text{fill:none;stroke-width:0;}#mermaid-svg-xbV3inFUF7vTlc6y .icon-shape,#mermaid-svg-xbV3inFUF7vTlc6y .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xbV3inFUF7vTlc6y .icon-shape p,#mermaid-svg-xbV3inFUF7vTlc6y .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xbV3inFUF7vTlc6y .icon-shape .label rect,#mermaid-svg-xbV3inFUF7vTlc6y .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xbV3inFUF7vTlc6y .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xbV3inFUF7vTlc6y .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xbV3inFUF7vTlc6y :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 可读写层(容器新产生的数据写在这里)
镜像层(只读,永不修改)

  • 一台宿主机可同时运行多个容器,各自隔离;容器本质 = 宿主机上受 Namespace、Cgroups 管控的进程(对应第三节的两大内核基石)。
  • 可以把容器看成"简易版 Linux 环境(root 权限、进程空间、用户空间、网络空间)+ 应用"打包成的盒子,可启动、停止、删除,彼此隔离互不可见。
  • 【难点】数据归宿:容器内新产生的数据写可读写层 ,镜像本身不受影响;容器删除后,可读写层数据默认丢失(第三篇会专门讲数据卷来解决这个问题)。

③ Registry 镜像仓库

  • 类似代码仓库,集中存放镜像。一个仓库(repository)对应一类镜像,用**标签(tag)**区分版本------例如 Ubuntu 仓库里有 18.04、16.04、14.04、12.04 等版本。
  • 按公开与否分:公开仓库(Public) ------最大的是官方 Docker Hub ;国内云商(时速云、阿里云等)提供本地源,国内访问稳定。私有仓库(Private)------本地网络内自建,仅自己访问。
  • 工作方式:docker pull 让 daemon 从 Registry 下载镜像到本地;做好镜像后用 docker push 上传到仓库,下次在其他机器上 pull 下来就能用。

④ 一次 docker run nginx 的完整流程【重点,考试常考】

#mermaid-svg-Jk1rRpp2EXxqPllr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Jk1rRpp2EXxqPllr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Jk1rRpp2EXxqPllr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Jk1rRpp2EXxqPllr .error-icon{fill:#552222;}#mermaid-svg-Jk1rRpp2EXxqPllr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Jk1rRpp2EXxqPllr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Jk1rRpp2EXxqPllr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Jk1rRpp2EXxqPllr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Jk1rRpp2EXxqPllr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Jk1rRpp2EXxqPllr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Jk1rRpp2EXxqPllr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Jk1rRpp2EXxqPllr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Jk1rRpp2EXxqPllr .marker.cross{stroke:#333333;}#mermaid-svg-Jk1rRpp2EXxqPllr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Jk1rRpp2EXxqPllr p{margin:0;}#mermaid-svg-Jk1rRpp2EXxqPllr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Jk1rRpp2EXxqPllr .cluster-label text{fill:#333;}#mermaid-svg-Jk1rRpp2EXxqPllr .cluster-label span{color:#333;}#mermaid-svg-Jk1rRpp2EXxqPllr .cluster-label span p{background-color:transparent;}#mermaid-svg-Jk1rRpp2EXxqPllr .label text,#mermaid-svg-Jk1rRpp2EXxqPllr span{fill:#333;color:#333;}#mermaid-svg-Jk1rRpp2EXxqPllr .node rect,#mermaid-svg-Jk1rRpp2EXxqPllr .node circle,#mermaid-svg-Jk1rRpp2EXxqPllr .node ellipse,#mermaid-svg-Jk1rRpp2EXxqPllr .node polygon,#mermaid-svg-Jk1rRpp2EXxqPllr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Jk1rRpp2EXxqPllr .rough-node .label text,#mermaid-svg-Jk1rRpp2EXxqPllr .node .label text,#mermaid-svg-Jk1rRpp2EXxqPllr .image-shape .label,#mermaid-svg-Jk1rRpp2EXxqPllr .icon-shape .label{text-anchor:middle;}#mermaid-svg-Jk1rRpp2EXxqPllr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Jk1rRpp2EXxqPllr .rough-node .label,#mermaid-svg-Jk1rRpp2EXxqPllr .node .label,#mermaid-svg-Jk1rRpp2EXxqPllr .image-shape .label,#mermaid-svg-Jk1rRpp2EXxqPllr .icon-shape .label{text-align:center;}#mermaid-svg-Jk1rRpp2EXxqPllr .node.clickable{cursor:pointer;}#mermaid-svg-Jk1rRpp2EXxqPllr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Jk1rRpp2EXxqPllr .arrowheadPath{fill:#333333;}#mermaid-svg-Jk1rRpp2EXxqPllr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Jk1rRpp2EXxqPllr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Jk1rRpp2EXxqPllr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Jk1rRpp2EXxqPllr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Jk1rRpp2EXxqPllr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Jk1rRpp2EXxqPllr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Jk1rRpp2EXxqPllr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Jk1rRpp2EXxqPllr .cluster text{fill:#333;}#mermaid-svg-Jk1rRpp2EXxqPllr .cluster span{color:#333;}#mermaid-svg-Jk1rRpp2EXxqPllr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Jk1rRpp2EXxqPllr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Jk1rRpp2EXxqPllr rect.text{fill:none;stroke-width:0;}#mermaid-svg-Jk1rRpp2EXxqPllr .icon-shape,#mermaid-svg-Jk1rRpp2EXxqPllr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Jk1rRpp2EXxqPllr .icon-shape p,#mermaid-svg-Jk1rRpp2EXxqPllr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Jk1rRpp2EXxqPllr .icon-shape .label rect,#mermaid-svg-Jk1rRpp2EXxqPllr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Jk1rRpp2EXxqPllr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Jk1rRpp2EXxqPllr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Jk1rRpp2EXxqPllr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 没有
有

  1. 用户在 Client 执行 docker run nginx
  2. 请求通过 Socket 发给 Daemon
  3. 本地有 nginx 镜像吗?
  4. 访问 Registry 下载镜像,存到本地 Images
  5. Daemon 读取本地镜像
  6. 创建容器需要的网络/存储等资源,运行 Container

6.3 Docker 版本演变【了解】

阶段 时间 版本格式 关键节点
语义化 1.x 2013--2017.02 主.次.补丁(如 1.13.1) 0.1(2013-06 首发版,基于 LXC);1.0(2014-06 生产可用,Docker Hub 上线);1.12(内置 Swarm 集群,引入 healthcheck);1.13(1.x 最后版本,命令行重构)
日历版本 CE/EE 2017.03--2022.06 YY.MM.Patch,分社区版 CE / 企业版 EE 17.03(首个日历版,runc 落地);17.05(支持多阶段构建);18.09(底层全面使用 containerd);20.10(经典稳定版,支持 cgroup v2、rootless,存量环境大量使用);22.06(日历版终点,Compose-V1 废弃)
回归语义化 23.x+ 2023.02 至今 主.次.补丁 23.0(默认启用 BuildKit 构建);24.0/25.0(生产稳定推荐);29.x(最新版,清理大量老旧接口)

七、动手:安装 Docker 并跑起第一个容器

7.1 实验环境

  1. 操作系统:CentOS 7(最小化安装)
  2. 容器 runtime:runc
  3. 管理工具:Docker Engine

Docker 支持几乎所有 Linux 发行版,也支持 Mac 和 Windows。各系统安装方法见官方文档:https://docs.docker.com/engine/installation/

7.2 环境准备:搭建本地 yum 仓库(复习)

bash 复制代码
[root@docker ~]# mkdir /dvd
[root@docker ~]# cp /etc/fstab /etc/fstab.bak      # 养成好习惯:改配置前先备份
[root@docker ~]# echo '/dev/sr0 /dvd iso9660 defaults 0 0'>> /etc/fstab

[root@docker ~]# mount /dvd
mount: /dev/sr0 写保护,将以只读方式挂载
[root@docker ~]# ls /dvd
CentOS_BuildTag  EULA  images    LiveOS    repodata  ...
EFI  GPL  isolinux  Packages  RPM-GPG-KEY-CentOS-7 ...

# 如果提示"在 /dev/sr0 上找不到媒体":编辑虚拟机设置,关联对应的 iso 文件

# 屏蔽其他源,只保留本地 dvd 源
[root@docker ~]# mkdir /etc/yum.repos.d/bak
[root@docker ~]# mv /etc/yum.repos.d/*repo /etc/yum.repos.d/bak
[root@docker ~]# vim /etc/yum.repos.d/dvd.repo
[dvd]
name=local repo from dvd
baseurl=file:///dvd
gpgcheck=0

# 重建缓存
[root@docker ~]# yum clean all
[root@docker ~]# yum makecache

7.3 防火墙与 Docker 仓库

bash 复制代码
# 【重点】防火墙不能关闭!部分容器服务需要防火墙的 NAT 功能。
# 把默认 zone 设为 trusted(信任所有),既保留 NAT 能力又不拦截流量
[root@docker ~]# systemctl enable firewalld.service --now
[root@docker ~]# firewall-cmd --set-default-zone=trusted

# 配置 docker-ce 的 yum 仓库(用华为云镜像源)
[root@docker ~]# cat > /etc/yum.repos.d/docker-ce.repo <<'EOF'
[docker-ce-stable]
name=Docker CE Stable - $basearch
baseurl=https://mirrors.huaweicloud.com/docker-ce/linux/centos/7/$basearch/stable
enabled=1
gpgcheck=0
EOF

7.4 安装并启动(allinone 部署)

bash 复制代码
[root@docker ~]# yum install -y docker-ce
# 启动服务并设置开机自启
[root@docker ~]# systemctl enable docker.service --now

7.5 配置镜像加速【重点,国内必做】

目前国内无法直连 docker.io 仓库,必须配置国内镜像加速服务器,否则 pull 会超时失败:

bash 复制代码
[root@docker ~]# mkdir -p /etc/docker 
[root@docker ~]# tee /etc/docker/daemon.json <<'EOF'
{
  "insecure-registries": ["hub.hero.cloud"],    # 自己搭建的局域网私有仓库
  "registry-mirrors": ["http://hub.hero.cloud","https://docker.m.daocloud.io"]
}
EOF
[root@docker ~]# systemctl restart docker

【补充】这两个配置项的区别(初学者容易混):

  • registry-mirrors:拉取 docker.io 官方镜像时优先走这些加速站;
  • insecure-registries:声明 hub.laoma.cloud 是可信任的 HTTP 私有仓库 (未加密 Registry),允许与其通信。
    其他可用加速站点:华为云加速

7.6 验证:跑起前两个容器

bash 复制代码
# 查看版本,能出版本号说明 daemon 正常
[root@docker ~]# docker --version
Docker version 26.1.3, build b72abbb

# 第一个容器:hello-world(Docker 官方的"安装成功"测试镜像)
[root@docker ~]# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete 
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

过程拆解(对照 6.2 节架构图理解):① 从 Docker Hub 下载 hello-world 镜像;② 启动 hello-world 容器(输出欢迎信息后容器自动退出------应用跑完了,容器就结束使命了)。

bash 复制代码
# 第二个容器:httpd(Apache Web 服务器)
[root@docker ~]# docker run -d -p 80:80 httpd
Unable to find image 'httpd:latest' locally
latest: Pulling from library/httpd
852e50cd189d: Pull complete    ← 一层一层下载(镜像分层!)
67d51c33d390: Pull complete 
......
817f24cca3514568f9b7a7cac6f183734077fb74caf4c62502acd2a4d0d29520   ← 最后输出容器 ID

过程拆解:① 下载 httpd 镜像(里面已装好 Apache HTTP Server);② 启动容器,-p 80:80 把容器的 80 端口映射到宿主机的 80 端口 (第三篇网络管理详讲);-d 让它在后台跑。

验证------宿主机 IP 是 10.1.8.130:

bash 复制代码
[root@docker ~]# ip -br a
ens33            UP             10.1.8.130/24 ...
docker0          UP             172.17.0.1/16 ...    ← Docker 自动创建的网桥,第三篇会讲

[root@docker ~]# curl 10.1.8.130
<html><body><h1>It works!</h1></body></html>

浏览器访问 http://10.1.8.130 看到 "It works!"------两条命令就拥有了一台 Web 服务器,这就是容器的高效。

7.7 C/S 分离部署【难点:亲手验证 Docker 是 C/S 架构】

既然 Client 只发指令、Daemon 才干活,那它们完全可以不在同一台机器上。实验:让 client 机器远程操控 server 机器的 Docker。

server 端(10.1.8.130)------让 daemon 监听 TCP 2375 端口:

bash 复制代码
[root@docker ~]# dnf install -y docker-ce

# 修改服务配置,让 daemon 额外监听 tcp://0.0.0.0:2375
[root@docker ~]# vim /usr/lib/systemd/system/docker.service
# 在 ExecStart 参数最后添加 -H tcp://0.0.0.0:2375
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375

[root@docker ~]# systemctl daemon-reload
[root@docker ~]# systemctl enable docker.service --now

# 验证端口已监听
[root@docker ~]# lsof -i :2375
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
dockerd 2565 root    3u  IPv6  76021      0t0  TCP *:2375 (LISTEN)

client 端 ------只装命令行工具,用 -H 指定远程 server:

bash 复制代码
[root@client ~]# dnf install -y docker-ce-cli

# 通过 -H 指定 server 地址执行命令
[root@client ~]# docker -H 10.1.8.130 run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
......

[root@client ~]# docker -H 10.1.8.130 images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
httpd               latest              0a30f4c29d25        2 weeks ago         138MB
hello-world         latest              bf756fb1ae65        11 months ago       13.3kB

结论【考试点】 :client 只做管理,image 和 container 都存储在 server 端------client 机器上并没有装 daemon,也没有镜像。

7.8 Docker 对 Windows 的支持

Docker Engine 可通过 Docker Desktop 在 Windows、macOS、Linux 上使用。Windows 版 Docker Desktop 需运行在 WSL(Windows Subsystem for Linux) 或 Hyper-V 两种架构之上。详见:https://docs.docker.com/desktop/setup/install/windows-install/


八、Docker 镜像管理(第一个核心技能)

镜像 = 只读模板 = 容器的"出生证明"。本节按实际使用顺序:查(search)→ 下(pull)→ 看(ls/inspect/history)→ 改名(tag)→ 删(rm/prune)→ 离线传(save/load)→ 上传(push)。

8.0 先学会查帮助

任何 docker 命令都可以用 --help 或 man 手册查用法:

bash 复制代码
[root@docker ~]# mandb                     # 更新 man 数据库
[root@docker ~]# man -k docker             # 列出所有 docker 相关手册
docker (1)           - Docker image and container command line interface
docker-build (1)     - Build an image from a Dockerfile
docker-search (1)    - Search the Docker Hub for images
......
[root@docker ~]# man -k docker|grep search    # 配合 grep 精确找
[root@docker ~]# man docker-search             # 查看详细手册

8.1 search------查找镜像

bash 复制代码
docker search [OPTIONS] TERM
# -f/--filter 过滤条件;--format 格式化;--limit 结果数量(默认25);--no-trunc 不截断

示例:搜索 3 星以上、带 centos 关键字的镜像:

bash 复制代码
[root@docker ~]# docker search --filter stars=3 centos
Error response from daemon: ... connection refused

(国内环境直连 docker.io 的搜索接口会失败,属正常现象。)

查询镜像有哪些版本(tag)【重点,实操常需要】

Docker 没有直接列出远程仓库某镜像所有版本的命令,但有三种替代方法:

方法 1:curl 调用 Docker Hub API(推荐,无需装工具)

bash 复制代码
# 通用格式
curl -s "https://registry.hub.docker.com/v2/repositories/<镜像名>/tags/" | jq '.results[].name'

# 官方镜像(nginx、ubuntu 等)要在名字前加 library/
curl -s "https://registry.hub.docker.com/v2/repositories/library/nginx/tags/" | jq '.results[].name'

# 非官方镜像(如用户 bitnami 发布的 mysql)直接写"用户名/镜像名"
curl -s "https://registry.hub.docker.com/v2/repositories/bitnami/mysql/tags/" | jq '.results[].name'

方法 2:第三方工具 docker-search

bash 复制代码
pip install docker-search
docker-search tags nginx            # 官方镜像
docker-search tags bitnami/mysql    # 非官方镜像

方法 3:Docker Hub 网页端(最直观)

打开 https://hub.docker.com/ → 搜索镜像(如 nginx)→ 进入详情页 → 点 Tags 标签,即可查看所有版本(支持过滤和排序)。

查询 Harbor 私有仓库的镜像版本

Harbor 提供 REST API(这就是 7.5 节 insecure-registries 里 hub.laoma.cloud 的身份):

bash 复制代码
# 查询项目清单
curl -s "http://hub.laoma.cloud/api/v2.0/projects" | jq -r '.[].name'

# 查询项目下有哪些镜像
curl -s "http://hub.laoma.cloud/api/v2.0/projects/library/repositories" | jq -r '.[].name'

# 查询特定镜像的标签
curl -s "http://hub.laoma.cloud/api/v2.0/projects/library/repositories/nginx/artifacts" | jq -r '.[].tags[].name' | sort -V

# 需要认证时用 -u 指定 用户名:密码
curl -s -u student:Student123 "http://hub.laoma.cloud/api/v2.0/projects/library/repositories/nginx/artifacts" | jq -r '.[].tags[].name' | sort -V

8.2 pull------下载镜像【重点】

bash 复制代码
docker image pull [OPTIONS] NAME[:TAG|@DIGEST]
# -a 下载该仓库所有标签;--platform 指定平台;-q 静默输出

镜像标准命名格式【重点】:

复制代码
服务器地址:端口/分类/镜像名:tag
例:registry.access.redhat.com/ubi8
例:docker.io/library/centos:8
  • 默认使用 Docker Hub,所以"服务器地址"前缀通常省略不写;
  • 不写 tag 时默认是 latest。
bash 复制代码
# 省略前缀,从 Docker Hub(实际走加速器)下载
[root@docker ~]# docker image pull centos:8
latest: Pulling from library/centos
3c72a8ed6814: Pull complete          ← 注意!下载是按"层"进行的
Digest: sha256:76d24f3ba3317fa945743bb3746fbaf3a0b752f10b10376960de01da70685fbd
Status: Downloaded newer image for centos:latest
docker.io/library/centos:latest

# 写完整服务器地址 → 直接从该镜像服务器下载
[root@docker ~]# docker image pull registry.access.redhat.com/ubi8

观察"分层"【难点】 :3c72a8ed6814 这样的串是层(layer)的唯一 ID(完整 ID 是 256 位、64 个十六进制字符,这里显示的是简写)。

为什么要分层?当不同的镜像包含相同的层时,本地只存一份。例如 centos:8 和某基于 centos:8 构建的镜像,底层完全复用------这就是 Docker 节约磁盘的秘诀,也是"分层文件系统"的含义。

镜像下载后存放在本地:/var/lib/docker/<存储驱动>(本环境是 overlay2)。

8.3 ls------查看本地镜像列表

bash 复制代码
docker image ls [OPTIONS] [REPOSITORY[:TAG]]     # 别名:ls / images / list
# -a 显示全部(含中间层);--digests 显示摘要;-f 过滤;--format 格式化;-q 只显示ID;--no-trunc 不截断
bash 复制代码
[root@docker ~]# docker image ls
REPOSITORY                        TAG       IMAGE ID       CREATED        SIZE
httpd                             latest    958373fdd7e8   4 months ago   148MB
hello-world                       latest    74cc54e27dc4   4 months ago   10.1kB
centos                            8         5d0da3dc9764   3 years ago    231MB

# 用 Go 模板控制输出列
[root@docker ~]# docker image ls --format "{{.Repository}}:{{.Tag}}"

【补充】各列含义:REPOSITORY 仓库名、TAG 版本标签、IMAGE ID 镜像唯一 ID(显示前 12 位)、CREATED 构建时间、SIZE 体积。

一个镜像可以有多个 TAG,但本地只占一份实际空间(见下一节 tag 命令)。

8.4 tag------给镜像打标签

bash 复制代码
docker image tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
# 不改变镜像本身,只是给同一个 IMAGE ID 起了别名
bash 复制代码
[root@docker ~]# docker image tag centos:8 myos       # 起名 myos,tag 省略 = latest
[root@docker ~]# docker image tag centos:8 myos:v1    # 再起一个带版本号的名字

[root@docker ~]# docker image ls
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
centos        8         5d0da3dc9764   3 years ago    231MB
myos          latest    5d0da3dc9764   3 years ago    231MB   ┐
myos          v1        5d0da3dc9764   3 years ago    231MB   ┘ 三个"名字",同一个 IMAGE ID、同一份空间

tag 的最佳实践:滚动版本号方案【重点】

Docker 社区通用方案------发布一个版本时同时打 4 个标签。以发布 v1.9.1 为例:

tag 指向
1.9.1 锁定这个具体版本
1.9 指向 1.9.x 中最新的
1 指向 1.x 中最新的
latest 指向所有版本中最新的

之后发布 v1.9.2:新打 1.9.2,并把 1.9、1、latest 从 v1.9.1 移动到 v1.9.2 ;再发布 v2.0.0:新打 2.0.0、2.0、2,并把 latest 移到 v2.0.0。
#mermaid-svg-TlolOmvZwKCluoWC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TlolOmvZwKCluoWC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TlolOmvZwKCluoWC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TlolOmvZwKCluoWC .error-icon{fill:#552222;}#mermaid-svg-TlolOmvZwKCluoWC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TlolOmvZwKCluoWC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TlolOmvZwKCluoWC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TlolOmvZwKCluoWC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TlolOmvZwKCluoWC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TlolOmvZwKCluoWC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TlolOmvZwKCluoWC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TlolOmvZwKCluoWC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TlolOmvZwKCluoWC .marker.cross{stroke:#333333;}#mermaid-svg-TlolOmvZwKCluoWC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TlolOmvZwKCluoWC p{margin:0;}#mermaid-svg-TlolOmvZwKCluoWC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-TlolOmvZwKCluoWC .cluster-label text{fill:#333;}#mermaid-svg-TlolOmvZwKCluoWC .cluster-label span{color:#333;}#mermaid-svg-TlolOmvZwKCluoWC .cluster-label span p{background-color:transparent;}#mermaid-svg-TlolOmvZwKCluoWC .label text,#mermaid-svg-TlolOmvZwKCluoWC span{fill:#333;color:#333;}#mermaid-svg-TlolOmvZwKCluoWC .node rect,#mermaid-svg-TlolOmvZwKCluoWC .node circle,#mermaid-svg-TlolOmvZwKCluoWC .node ellipse,#mermaid-svg-TlolOmvZwKCluoWC .node polygon,#mermaid-svg-TlolOmvZwKCluoWC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TlolOmvZwKCluoWC .rough-node .label text,#mermaid-svg-TlolOmvZwKCluoWC .node .label text,#mermaid-svg-TlolOmvZwKCluoWC .image-shape .label,#mermaid-svg-TlolOmvZwKCluoWC .icon-shape .label{text-anchor:middle;}#mermaid-svg-TlolOmvZwKCluoWC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TlolOmvZwKCluoWC .rough-node .label,#mermaid-svg-TlolOmvZwKCluoWC .node .label,#mermaid-svg-TlolOmvZwKCluoWC .image-shape .label,#mermaid-svg-TlolOmvZwKCluoWC .icon-shape .label{text-align:center;}#mermaid-svg-TlolOmvZwKCluoWC .node.clickable{cursor:pointer;}#mermaid-svg-TlolOmvZwKCluoWC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TlolOmvZwKCluoWC .arrowheadPath{fill:#333333;}#mermaid-svg-TlolOmvZwKCluoWC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TlolOmvZwKCluoWC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TlolOmvZwKCluoWC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TlolOmvZwKCluoWC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TlolOmvZwKCluoWC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TlolOmvZwKCluoWC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TlolOmvZwKCluoWC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TlolOmvZwKCluoWC .cluster text{fill:#333;}#mermaid-svg-TlolOmvZwKCluoWC .cluster span{color:#333;}#mermaid-svg-TlolOmvZwKCluoWC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TlolOmvZwKCluoWC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TlolOmvZwKCluoWC rect.text{fill:none;stroke-width:0;}#mermaid-svg-TlolOmvZwKCluoWC .icon-shape,#mermaid-svg-TlolOmvZwKCluoWC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TlolOmvZwKCluoWC .icon-shape p,#mermaid-svg-TlolOmvZwKCluoWC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TlolOmvZwKCluoWC .icon-shape .label rect,#mermaid-svg-TlolOmvZwKCluoWC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TlolOmvZwKCluoWC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TlolOmvZwKCluoWC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TlolOmvZwKCluoWC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 版本更新
大版本更新
v2.0.0 发布
2.0.0
2.0 / 2 / latest 移到这里
v1.9.2 发布
1.9.2
1.9 / 1 / latest 移到这里
v1.9.1 发布
1.9.1
1.9 / 1 / latest 指向它

用户因此获得灵活性:

  1. myimage:1 始终是 1 分支最新版;2. myimage:1.9 始终是 1.9.x 最新版;3. myimage:latest 始终是最新版;4. 要锁死版本就用 myimage:1.9.1。

8.5 inspect------查看镜像详细信息

bash 复制代码
docker image inspect [OPTIONS] IMAGE [IMAGE...]
# -f/--format:用 Go 模板提取特定字段

docker image inspect myos 输出一个 JSON 数组,重点看这些字段:

字段 含义
Id 镜像完整 ID(sha256:...)
RepoTags 该镜像的所有标签(如 centos:8、myos:latest、myos:v1 都在列)
RepoDigests 仓库摘要(从哪个仓库以什么摘要拉来的)
Created / DockerVersion 构建时间 / 构建所用 Docker 版本
Config 环境变量 Env、默认命令 Cmd、标签 Labels 等配置
Architecture / Os 架构(amd64)/ 操作系统(linux)
GraphDriver 存储驱动(overlay2)及各层目录路径
RootFS.Layers 镜像的分层列表

用 -f 提取单个字段(脚本中很常用):

bash 复制代码
[root@docker ~]# docker image inspect myos -f '{{.Architecture}}'
amd64
[root@docker ~]# docker image inspect myos -f '{{.Os}}'
linux

8.6 history------查看镜像的"分层历史"

bash 复制代码
docker image history [OPTIONS] IMAGE
# --format 格式化;-H 人类可读(默认);--no-trunc 不截断;-q 只显示 ID
bash 复制代码
[root@docker ~]# docker image history myos
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
5d0da3dc9764   3 years ago   /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B        
<missing>      3 years ago   /bin/sh -c #(nop)  LABEL org.label-schema.sc...   0B        
<missing>      3 years ago   /bin/sh -c #(nop)  ADD file:805cb5e15fb6e0bb0...   231MB 

# --no-trunc 查看完整命令(上面被截断了)
[root@docker ~]# docker image history myos --no-trunc

每一行 = 构建镜像时执行的一步 = 一层。这个镜像:第 1 层 ADD 进来 231MB 的根文件系统,第 2 层打了 LABEL(0B,只是元数据),第 3 层设置了默认 CMD(0B)。history 是理解"镜像分层"最直观的工具。

8.7 rm------删除镜像【重点 + 易错】

bash 复制代码
docker image rm [OPTIONS] IMAGE [IMAGE...]     # 别名:rm / rmi / remove
# -f 强制删除;--no-prune 不删除未打标签的父层

核心规则【考试点】:一个镜像有多个标签时,rm 一次只删一个标签;删到最后一个标签才真正删除镜像。

bash 复制代码
# myos 有 latest 和 v1 两个标签 → 只删掉一个标签,镜像还在
[root@docker ~]# docker image rm myos
Untagged: myos:latest

[root@docker ~]# docker image ls
REPOSITORY    TAG       IMAGE ID       SIZE
myos          v1        5d0da3dc9764   231MB     ← 还在
centos        8         5d0da3dc9764   231MB

# 删除最后一个标签 → 镜像本体和它的所有层被删除
[root@docker ~]# docker image rm myos:v1
Untagged: myos:v1
[root@docker ~]# docker image rm centos:8
Untagged: centos:8
Untagged: centos@sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Deleted: sha256:5d0da3dc9764...    ← 注意 Deleted 了多个层
Deleted: sha256:74ddd0ec08fa...

按 ID 删除(会自动删掉该镜像的所有标签和所有层):

bash 复制代码
[root@docker ~]# docker image rm 958373fdd7e8    # 删除 httpd
Untagged: httpd:latest
Deleted: sha256:958373fdd7e8...(多个层依次删除)

8.8 prune------批量清理镜像

bash 复制代码
docker image prune [OPTIONS]
# -a 删除所有"没有被容器使用"的镜像(不加 -a 只删悬空镜像 dangling);--filter 过滤(如 until=时间);-f 免确认
bash 复制代码
[root@docker ~]# docker pull nginx
[root@docker ~]# docker image prune -a <<< "y"
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] Deleted Images:
untagged: nginx:latest
......
Total reclaimed space: 117.7MB

思考:为什么 httpd 和 hello-world 没有被删掉?

因为这两个镜像正被容器使用着(哪怕是已退出的容器也算):

bash 复制代码
[root@docker ~]# docker ps -a
CONTAINER ID   IMAGE         COMMAND              STATUS                     PORTS      NAMES
be05a7c31635   httpd         "httpd-foreground"   Up About a minute          80->80     gifted_williams
4974ee579b36   hello-world   "/hello"             Exited (0) 4 minutes ago              keen_kare

【难点】这是 Docker 的保护机制:容器(即使已退出)会"引用"它基于的镜像,被引用的镜像不许删。想彻底删除,必须先删掉(或强制删除)相关容器。

8.9 save / load------镜像的离线导出与导入【重点】

Docker 默认用 overlay2 存储驱动(docker info | grep 'Storage Driver' 可查看),镜像实际存储在 /var/lib/docker/overlay2 的分层目录里,直接拷贝这些文件非常复杂。正确姿势是用 save/load:

bash 复制代码
# save:把本地镜像打包成 tar 文件(可一次打包多个镜像)
docker image save [OPTIONS] IMAGE [IMAGE...]     # -o 输出到文件

[root@docker ~]# docker save httpd -o httpd.tar
[root@docker ~]# docker save httpd hello-world -o images.tar
[root@docker ~]# ls *tar
httpd.tar  images.tar

# load:从 tar 文件导入镜像
docker image load [OPTIONS]     # -i 指定输入文件;-q 静默

[root@docker ~]# docker image load -i images.tar 
Loaded image: httpd:latest
Loaded image: hello-world:latest

配合"被容器引用就删不掉"的知识,看一个删除实验:

bash 复制代码
# 直接删正在被使用的镜像 → 报错
[root@docker ~]# docker image rm httpd hello-world
Error response from daemon: conflict: unable to remove repository reference "httpd" (must force) - container be05a7c31635 is using its referenced image 958373fdd7e8

# 加 -f 强制删除 → 标签删掉了,但镜像显示为 <none>(仍被容器占用着)
[root@docker ~]# docker image rm httpd hello-world:latest -f
Untagged: httpd:latest
......
[root@docker ~]# docker image ls
REPOSITORY   TAG       IMAGE ID       SIZE
<none>       <none>    958373fdd7e8   148MB     ← 镜像本体还在
# 结论:要真正释放空间,需删除容器后再删镜像

8.10 push------把本地镜像推送到仓库

本地镜像默认推送到 docker.io,推送前必须先登录:

bash 复制代码
docker login [OPTIONS] [SERVER]
# -u 用户名;-p 密码;--password-stdin 从标准输入读密码(更安全)

[root@docker ~]# docker login
Login with your Docker ID to push and pull images from Docker Hub. ...
Username: mage16196
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.   ← 提示:密码明文存在本地
Login Succeeded

(注:docker.io 国内目前无法访问,实际登录会超时失败。)

推送格式要求【考试点】:镜像名必须符合 username/image:tag------Docker 靠镜像名前缀判断该推到哪个账户下,所以要先 tag 再 push:

bash 复制代码
# 第一步:把镜像 tag 成 "自己用户名/镜像名" 的格式
[root@docker ~]# docker image tag hello-world:latest mage16196/myhello

# 第二步:推送
[root@docker ~]# docker image push mage16196/myhello
The push refers to repository [docker.io/mage16196/myhello]
9c27e219663c: Layer already exists       ← 底层和官方 hello-world 相同,直接复用(分层的好处又体现了一次)
latest: digest: sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042 size: 525

推送成功后可登录 Docker Hub 网页端管理已上传的镜像。


本篇知识自测清单

看完本篇,你应该能不假思索地回答:

  1. 容器解决了什么问题?(N×M 矩阵 / 环境不一致,集装箱类比)
  2. 容器和虚拟机的本质区别?(共享内核 vs 各带内核,对比表 7 项)
  3. 容器靠哪两大内核技术实现?分别负责什么?(Namespace 隔离 / Cgroups 限制)
  4. Docker 架构三大部分?谁真正干活?(Client / Host(daemon+镜像+容器) / Registry;daemon 干活)
  5. 镜像和容器的关系?(只读模板 vs 运行实例 + 可读写层)
  6. 镜像为什么分层?好处?(不同镜像共享相同层,省磁盘)
  7. 删除多标签镜像的规则?(删标签,直到最后一个才删本体)
  8. 为什么有的镜像删不掉?(被容器引用)
  9. save 和 pull/push 的适用场景?(离线分发 vs 在线仓库)
  10. 三条必会命令:docker run hello-world、docker image pull、docker image ls。
相关推荐
文丑颜不良啊3 小时前
LeetCode2481~2500题目解析
java·leetcode
Flynn Liang4 小时前
同一需求三套写法:用 Spring AI、LangChain4j、AgentScope Java 各实现一个带工具调用的 RAG 助手(实战对比)
java·人工智能·大模型·架构设计·spring ai·langchain4j·agentscope
聪明的笨猪猪4 小时前
实际工程问题:AI 生成 Spring Cache(@Cacheable / @CachePut / @CacheEvict)缓存注解踩坑
java·经验分享·面试·ai编程
愿有所息5 小时前
记一次 ARM64 + JDK8 上 fastjson2 的诡异数据错乱
java
秋饼5 小时前
MCP 2026-07-28 无状态协议大改版:Spring AI 2.1 多轮往返请求与网关路由落地
java·ai·技术分享·后端开发
xbzb6 小时前
镜像到底存在哪:/var/lib/docker 的四级映射与 daemon.json 配置
docker·容器·json·镜像·daemon.json·四级
阿里云云原生6 小时前
生产更可信,订阅更耐用丨Higress 社区进展报告
云原生
SL_staff6 小时前
JVS-BI 实战:业务人员如何用零代码 ELT + 可视化配置构建实时经营分析闭环
java·spring·全栈
SL_staff7 小时前
企业AI落地难?JVS-AI渐进式实践:安全可控、小切口验证、标准化沉淀与规模化复制
java·开源·aigc