容器技术介绍

容器介绍

容器发展史

早期隔离思想

这一阶段是操作系统级虚拟化萌芽,各BSD、商业Unix各自实现隔离,但没有统一Linux原生方案。

  1. 1979 年:Unix chroot() 系统调用。Unix V7 引入 chroot,修改进程根目录,实现文件系统隔离。仅做目录隔离,没有CPU、内存、网络隔离,是容器最早的技术原型。

    root 破解密码

    /dev/centos/root /mnt/sysroot

    mount -o rw,remount /mnt/sysroot

    chroot /mnt/sysroot/

  2. 1998 年 FreeBSD Jails。FreeBSD 推出 Jails,在 chroot 基础上增加进程、网络隔离,可以在一台主机运行多个独立“虚拟系统”,面向服务隔离,是现代容器思想重要实践。

  3. 2000 年 Solaris Zones。Solaris Zones,操作系统级虚拟化,CPU/内存/网络/文件系统完整隔离,Oracle 商用操作系统容器方案。

Linux 内核关键技术

Namespace做隔离,Cgroups做资源限制,两大基石全部就位,Linux容器底层能力完备。

  1. 2002:Linux 引入 PID Namespace。实现进程ID隔离,容器内部拥有独立PID编号。

  2. 2003:Linux 引入 Network Namespace。网络栈隔离,每个容器独立网卡、IP、路由表。

  3. 2004‑2006:IPC、Mount Namespace陆续并入内核。

  • IPC Namespace:进程间通信隔离
  • Mount Namespace:挂载点隔离,容器可以拥有独立文件挂载视图
  1. 2007:Cgroups(Control Groups)并入Linux内核。由Google工程师开发,实现CPU、内存、IO、网络带宽资源限制。

  2. 2008:User Namespace 开发迭代。实现用户UID/GID隔离,容器内部root不等于宿主机root,解决容器权限安全问题,后续版本逐步完善。

LXC 容器诞生
  1. 2008:LXC(Linux Containers)项目启动。LXC基于Namespace + Cgroups封装,世界上第一个完整Linux用户态容器工具。痛点:没有镜像机制,配置复杂,分发困难,主要面向运维专家。

  2. 2010:CloudFoundry Warden。VMware推出Warden,容器管理服务,做资源隔离与实例生命周期管理。

  3. 2013 dotCloud 内部项目孵化 Docker。dotCloud是一家PaaS云厂商,内部做容器工具,解决LXC镜像、打包分发痛点。

Docker 爆发
  1. 2013‑06:Docker 0.1 正式对外发布。基于LXC,核心创新:镜像分层、Dockerfile、镜像仓库、统一工具链。
    不再只是内核隔离工具,而是完整应用打包分发体系,容器迅速出圈。

  2. 2014‑06:Docker 1.0 正式版发布,生产可用。Docker Hub公共镜像仓库大规模使用。

  3. 2014:Google 对外发布 Borg 论文。Borg是Google内部大规模容器调度系统,是Kubernetes的思想源头;同时Google放出lmctfy容器工具。

  4. 2014年7月:Docker 切换 libcontainer。抛弃LXC,自研 libcontainer,直接调用Linux系统调用,不依赖LXC工具链,容器运行时独立。

  5. 2015‑06:OCI 开放容器基金会成立。Linux基金会主导,Docker、Google、红帽等共同成立OCI(Open Container Initiative),制定容器镜像规范、容器运行时规范,避免容器生态分裂。

Kubernetes崛起
  1. 2015‑07:Kubernetes 1.0发布。Google开源K8s,基于Borg经验,容器集群编排,实现调度、自愈、服务发现、滚动更新。标志容器从单机走向大规模集群。

  2. 2016:runc 正式发布。OCI 标准运行时,libcontainer改名runc,底层真正创建容器的工具;Docker底层调用runc。

  3. 2016:containerd 项目诞生。Docker拆分出containerd,高级容器运行时,管理镜像、容器生命周期,上层对接docker、k8s,下层调用runc。

  4. 2017:Kubernetes 进入CNCF(云原生计算基金会)。K8s移交CNCF托管,成为容器编排事实标准。Docker公司商业受挫,Docker Swarm 编排逐渐边缘化。

  5. 2017‑2018:CRI 容器运行时接口成熟。K8s定义CRI接口,K8s不再强绑定docker;cri‑containerd把containerd适配CRI。

云原生生态成熟
  1. 2019:Kubernetes 1.24正式移除dockershim。K8s不再内置Docker适配,用户直接使用containerd作为K8s默认容器运行时。Docker作为开发工具保留,集群层面不再是首选运行时。

  2. 安全容器发展

  • Kata Containers:轻量级虚拟机,内核隔离,强安全隔离;
  • gVisor:Google,用户态内核,隔离应用与宿主机内核。
  1. 其他OCI兼容运行时。nerdctl(containerd的命令行工具,兼容docker命令)、crun(C语言实现轻量runc替代)广泛使用。

  2. 2020‑2023:Podman + Buildah普及。红帽Podman,无守护进程容器工具,兼容docker命令,原生支持OCI标准。

  3. 2024‑2026:WebAssembly容器、轻量容器兴起。Wasm‑OCI,将Wasm作为容器镜像,极低开销;K8s对Wasm运行时支持增强。

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

什么是容器?

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

传统的虚拟化技术,比如 VMWare, KVM, Xen,目标是创建完整的虚拟机。为了运行应用,除了部署应用本身及其依赖(通常几十 MB),还得安装整个操作系统(几十 GB)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 所有的容器共享同一个 Host OS,这使得容器在体积上要比虚拟机小很多。
  • 启动容器不需要启动整个操作系统,容器部署和启动速度更快,开销更小,也更容易迁移。
  • 容器可以在核心CPU本地运行指令,不需要任何专门的解释机制。与虚拟化相比,这样既不需要指令级模拟,也不需要即时编译。
特性容器虚拟机
启动速度秒级分钟级
性能接近原生较弱
内存代价很小较多
硬盘使用一般为MB一般为GB
运行密度单击支持上千个容器一般几十个
隔离性安全隔离完全隔离
迁移性优秀一般

容器解决的问题

我们来看看软件开发面临着怎样的挑战?

开发人员通常使用多种服务(比如 MQ,Cache,DB)构建和组装应用,而且应用很可能会部署到不同的环境,比如虚拟服务器,私有云和公有云。

一方面应用包含多种服务,这些服务有自己所依赖的库和软件包;另一方面存在多种部署环境,服务在运行时可能需要动态迁移到不同的环境中。这就产生了一个问题:

如何让每种服务能够在所有的部署环境中顺利运行?

于是我们得到了下面这个矩阵:

各种服务和环境通过排列组合产生了一个大矩阵。开发人员在编写代码时需要考虑不同的运行环境,运维人员则需要为不同的服务和平台配置环境。对他们双方来说,这都是一项困难而艰巨的任务。

如何解决这个问题呢?聪明的技术人员从传统的运输行业找到了答案。

几十年前,运输业面临着类似的问题。

每一次运输,货主与承运方都会担心因货物类型的不同而导致损失,比如几个铁桶错误地压在了一堆香蕉上。另一方面,运输过程中需要使用不同的交通工具也让整个过程痛苦不堪:货物先装上车运到码头,卸货,然后装上船,到岸后又卸下船,再装上火车,到达目的地,最后卸货。一半以上的时间花费在装、卸货上,而且搬上搬下还容易损坏货物。

这同样也是一个 NxM 的矩阵。

幸运的是,集装箱的发明解决这个难题。

任何货物,无论钢琴还是保时捷,都被放到各自的集装箱中。集装箱在整个运输过程中都是密封的,只有到达最终目的地才被打开。标准集装箱可以被高效地装卸、重叠和长途运输。现代化的起重机可以自动在卡车、轮船和火车之间移动集装箱。集装箱被誉为运输业与世界贸易最重要的发明。

Docker 将集装箱思想运用到软件打包上,为代码提供了一个基于容器的标准化运输系统。Docker 可以将任何应用及其依赖打包成一个轻量级、可移植、自包含的容器。容器可以运行在几乎所有的操作系统上。

其实,“集装箱” 和 “容器” 对应的英文单词都是 “Container”。“容器” 是国内约定俗成的叫法,可能是因为容器比集装箱更抽象,更适合软件领域的原故吧。


容器的优势

  • 对于开发人员 - Build Once, Run Anywhere

    容器意味着环境隔离和可重复性。开发人员只需为应用创建一次运行环境,然后打包成容器便可在其他机器上运行。另外,容器环境与所在的 Host 环境是隔离的,就像虚拟机一样,但更快更简单。

  • 对于运维人员 - Configure Once, Run Anything

    只需要配置好标准的 runtime 环境,服务器就可以运行任何容器。这使得运维人员的工作变得更高效,一致和可重复。容器消除了开发、测试、生产环境的不一致性。


容器的特性

我们可以看看集装箱思想是如何与 container 各种特性相对应的。

特性集装箱容器
打包对象几乎任何货物任何软件及其依赖
硬件依赖标准形状和接口允许集装箱被装卸到各种交通工具,整个运输过程无需打开容器无需修改便可运行在几乎所有的平台上 – 虚拟机、物理机、公有云、私有云
隔离性集装箱可以重叠起来一起运输,香蕉再也不会被铁桶压烂了资源、网络、库都是隔离的,不会出现依赖问题
自动化标准接口使集装箱很容易自动装卸和移动提供 run, start, stop 等标准化操作,非常适合自动化
高效性无需开箱,可在各种交通工具间快速搬运轻量级,能够快速启动和迁移
职责分工货主只需考虑把什么放到集装箱里;承运方只需关心怎样运输集装箱开发人员只需考虑怎么写代码;运维人员只需关心如何配置基础环境

容器生态系统

大致来看,容器生态系统包含核心技术、平台技术和支持技术。


容器核心技术

容器核心技术包括容器规范、容器 runtime、容器管理工具、容器定义工具、Registry 以及 容器 OS。


容器规范

容器不光是 Docker,还有其他容器,比如 CoreOS 的 rkt。为了保证容器生态的健康发展,保证不同容器之间能够兼容,包含 Docker、CoreOS、Google在内的若干公司共同成立了一个叫 Open Container Initiative(OCI) 的组织,其目是制定开放的容器规范。 目前 OCI 发布了两个规范:

  • runtime spec,runtime 是容器运行的环境。
  • image format spec,image是包含应用程序以及它的依赖库、配置文件、环境变量等打包文件。

有了这两个规范,不同组织和厂商开发的容器能够在不同的 runtime 上运行,确保了容器的可移植性和互操作性。


容器 runtime

runtime 需要跟操作系统 kernel 紧密协作,为容器提供运行环境。

lxc、runc 和 rkt 是目前主流的三种容器 runtime。

  • lxc 是 Linux 上老牌的容器 runtime。Docker 最初也是用 lxc 作为 runtime。
  • runc 是 Docker 自己开发的容器 runtime,符合 oci 规范,也是现在 Docker 的默认 runtime。
  • rkt 是 CoreOS 开发的容器 runtime,符合 oci 规范,因而能够运行 Docker 的容器。

容器管理工具

光有 runtime 还不够,用户得有工具来管理容器啊。容器管理工具对内与 runtime 交互,对外为用户提供 interface,比如 CLI。这就好比除了 JVM,还得提供 java 命令让用户能够启停应用不是。

  • lxd 是 lxc 对应的管理工具。
  • **runc 的管理工具是 docker engine。**docker engine 包含后台 deamon 和 cli 两个部分。我们通常提到 Docker,一般就是指的 docker engine。
  • rkt 的管理工具是 rkt cli。

容器定义工具

容器定义工具允许用户定义容器的内容和属性,这样容器就能够被保存,共享和重建。

  • docker image 是 docker 容器的模板,runtime 依据 docker image 创建容器。
  • dockerfile 是包含若干命令的文本文件,可以通过这些命令创建出 docker image。
  • ACI (App Container Image) 与 docker image 类似,只不过它是由 CoreOS 开发的 rkt 容器的 image 格式。

Registry

容器是通过 image 创建的,需要有一个仓库来统一存放 image,这个仓库就叫做 Registry。

  • 企业可以用 Docker Registry 构建私有的 Registry。
  • Docker Hub(https://hub.docker.com) 是 Docker 为公众提供的托管 Registry,上面有很多现成的 image,为 Docker 用户提供了极大的便利。
  • Quay.io(https://quay.io/)是另一个公共托管 Registry,提供与 Docker Hub 类似的服务。

容器 OS

由于有容器 runtime,几乎所有的 Linux、MAC OS 和 Windows 都可以运行容器。

容器 OS 是专门运行容器的操作系统。与常规 OS 相比,容器 OS 通常体积更小,启动更快。因为是为容器定制的 OS,通常它们运行容器的效率会更高。

目前已经存在不少容器 OS,CoreOS、atomic 和 ubuntu core 是其中的杰出代表。


容器平台技术

容器核心技术使得容器能够在单个 host 上运行。而容器平台技术能够让容器作为集群在分布式环境中运行。

容器平台技术包括容器编排引擎、容器管理平台和基于容器的 PaaS。


容器编排引擎

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

  • 在这种架构下,应用被划分为不同的组件,并以服务的形式运行在各自的容器中,通过 API 对外提供服务。
  • 为了保证应用的高可用,每个组件都可能会运行多个相同的容器。这些容器会组成集群,集群中的容器会根据业务需要被动态地创建、迁移和销毁。

这样一个基于微服务架构的应用系统实际上是一个动态的可伸缩的系统。这就是容器编排引擎。所谓编排,通常包括容器管理、调度、集群定义和服务发现等。通过容器编排引擎,容器被有机的组合成微服务应用,实现业务需求。

当前主流的容器编排引擎:

  • docker swarm 是 Docker 开发的容器编排引擎。
  • kubernetes 是 Google 领导开发的开源容器编排引擎,同时支持 Docker 和 CoreOS 容器。
  • mesos 是一个通用的集群资源调度平台,mesos 与 marathon 一起提供容器编排引擎功能。

容器管理平台

容器管理平台是架构在容器编排引擎之上的一个更为通用的平台。通常容器管理平台能够支持多种编排引擎,抽象了编排引擎的底层实现细节,为用户提供更方便的功能,比如 application catalog 和一键应用部署等。

一、基于 Kubernetes 的平台
1. 开源免费类
  • Rancher:轻量级 K8s 管理平台,支持一键部署、管理多集群,兼容各种环境(云、本地、边缘),适合企业统一管控容器集群。
  • OpenShift:Red Hat 推出的企业级 K8s 发行版,在 K8s 基础上增加了安全、监控、CI/CD 等企业级特性,生态成熟,适合大型企业生产环境。
  • Kubesphere:青云推出的开源容器平台,以 K8s 为内核,提供可视化界面,降低 K8s 使用门槛,支持多租户、DevOps 流水线等功能。
2. 云厂商商业类
  • AWS EKS:亚马逊云的托管 K8s 服务,无缝对接 AWS 生态(存储、负载均衡等),稳定性高,适合用 AWS 云的企业。
  • Azure AKS:微软 Azure 云的托管 K8s 服务,集成 Azure 监控、身份认证等能力,适合微软生态用户。
  • 阿里云 ACK:阿里云的托管 K8s 服务,适配阿里云资源,支持混合云、边缘集群,国内访问速度快,适合国内企业。
二、简化型轻量容器管理平台
  • Portainer:超轻量容器管理 UI,支持管理 Docker 和 K8s,安装简单(单容器部署),界面直观,适合个人测试、小型团队快速管理容器。
  • Docker Desktop:Docker 官方桌面工具(Windows/Mac),内置 K8s 集群,适合开发者本地构建、测试容器应用(个人开发首选)。
  • Lens:K8s IDE,可视化管理 K8s 集群,支持资源编辑、日志查看、监控等,适合开发者高效操作 K8s。

基于容器的 PaaS

基于容器的 PaaS 为微服务应用开发人员和公司提供了开发、部署和管理应用的平台,使用户不必关心底层基础设施而专注于应用的开发。

Deis、Flynn 和 Dokku 都是开源容器 PaaS 的代表。


容器支持技术

容器网络

容器的出现使网络拓扑变得更加动态和复杂。用户需要专门的解决方案来管理容器与容器,容器与其他实体之间的连通性和隔离性。

docker network 是 Docker 原生的网络解决方案。除此之外,我们还可以采用第三方开源解决方案,例如 flannel、weave 和 calico。不同的方案设计和实现方式不同,各有优势和特定,我们可以根据实际需要来选型。


服务发现

动态变化是微服务应用的一大特点。

  • 当负载增加时,集群会自动创建新的容器;

  • 负载减小,多余的容器会被销毁。

  • 容器也会根据 host 的资源使用情况在不同 host 中迁移,容器的 IP 和端口也会随之发生变化。

在这种动态的环境下,必须要有一种机制让 client 能够知道如何访问容器提供的服务。这就是服务发现技术要完成的工作。

服务发现会保存容器集群中所有微服务最新的信息,比如 IP 和端口,并对外提供 API,提供服务查询功能。

etcd、consul 和 zookeeper 是服务发现的典型解决方案。


监控

监控对于基础架构非常重要,而容器的动态特征对监控提出更多挑战。

针对容器环境,已经涌现出很多监控工具和方案。

docker ps/top/stats 是 Docker 原生的命令行监控工具。除了命令行,Docker 也提供了 stats API,用户可以通过 HTTP 请求获取容器的状态信息。

sysdig、cAdvisor/Heapster 和 Weave Scope 是其他开源的容器监控方案。


数据管理

容器经常会在不同的 host 之间迁移,如何保证持久化数据也能够动态迁移,是 Flocker 这类数据管理工具提供的能力。


日志管理

日志为问题排查和事件管理提供了重要依据。

docker logs 是 Docker 原生的日志工具。而 logspout 对日志提供了路由功能,它可以收集不同容器的日志并转发给其他工具进行后处理。


安全性

对于年轻的容器,安全性一直是业界争论的焦点。

OpenSCAP 能够对容器镜像进行扫描,发现潜在的漏洞。

Docker 介绍

Docker 介绍

Docker是基于Go语言实现的开源容器项目,诞生于2013年年初,最初发起者是dotCloud公司。Docker自开源后受到广泛的关注和讨论,逐渐形成了围绕Docker容器的生态体系。由于Docker在业界造成的影响力实在太大,dotCloud公司后来也直接改名为Docker Inc,并专注于 Docker相关技术和产品的开发。

  • Docker提供了各种容器管理工具,可以更简单明了地管理和使用容器。
  • Docker引入分层文件系统构建和高效的镜像机制降低了迁移难度,极大地提升了用户体验。用户操作Docker容器就像操作应用自身一样简单。

可以将Docker容器理解为一种轻量级的沙盒(sandbox)。**每个容器内运行着一个应用,不同的容器相互隔离,容器之间也可以通过网络互相通信。**容器的创建和停止都十分快速,几乎跟创建和终止原生应用一致;另外,容器自身对系统资源的额外需求也十分有限,远远低于传统虚拟机。很多时候,甚至直接把容器当作应用本身也没有任何问题。

Docker 架构

Docker采用C/S(客户端/服务端)架构,整体由三大部分组成:

  • Client客户端
  • Docker Host宿主机(Docker守护进程daemon、镜像Images、容器Containers)
  • Registry镜像仓库。

客户端与Docker守护进程通过Socket通信,完成各类容器操作。


Docker 客户端

Client 客户端就是我们日常执行docker命令的终端,是用户交互入口。

客户端本身不直接做容器创建工作,只是把指令发送给Docker Daemon。

典型命令:

  • docker build:构建镜像,把Dockerfile构建成本地镜像
  • docker pull:从远程镜像仓库拉取镜像到本地
  • docker run:基于本地镜像创建并启动容器

Docker 宿主机

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

Images 镜像

**Docker镜像类似于虚拟机镜像,可以将它理解为一个只读的模板。**例如,一个镜像可以包含一个基本的操作系统环境,里面仅安装了Apache应用程序(或用户需要的其他软件)。可以把它称为一个Apache镜像。镜像是创建Docker容器的基础。通过版本管理和增量的文件系统,Docker提供了一套十分简单的机制创建和更新现有的镜像,用户甚至可以从网上下载一个已经做好的应用镜像,并直接使用。

镜像是只读的模板,相当于容器的安装包/模板,包含应用程序、依赖库、配置文件。

  • 可以通过docker build本地构建生成;
  • 也可以通过docker pull从Registry远程仓库下载到本地;
  • 镜像采用分层存储,多个镜像可以共享底层层,节约磁盘;
  • 镜像本身只读,不能直接运行镜像,必须基于镜像实例化为容器。
Containers 容器

容器是镜像的运行实例。

**Docker容器类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用。**容器是从镜像创建的应用运行实例。可以将其启动、开始、停止、删除,而这些容器都是彼此相互隔离的、互不可见的。可以把容器看做是一个简易版的Linux系统环境(包括root用户权限、进程空间、用户空间和网络空间等)以及运行在其中的应用程序打包而成的盒子。

  • docker run命令,daemon读取本地镜像,在镜像之上增加一层可读写层,生成容器;
  • 一台宿主机可以同时运行多个容器,图中画出4个运行容器;
  • 容器拥有独立隔离环境,本质是宿主机上受Namespace、Cgroups管控的进程;
  • 容器内产生的数据写在读写层,镜像本身不会被修改;容器删除后读写层数据默认丢失。

Registry 镜像仓库

Docker仓库类似于代码仓库,它是Docker集中存放镜像文件的场所。仓库注册服务器存放着很多类镜像,每类镜像包括多个镜像文件,通过不同的标签(tag)来进行区分。例如存放Ubuntu操作系统镜像的分类中可能包括1804、1604、14.04、12.04等不同版本的镜像。

根据所存储的镜像公开分享与否,Docker仓库可以分为:

  • 公开仓库(Public)
  • 私有仓库(Private)

目前,最大的公开仓库是官方提供的Docker Hub,其中存放了数量庞大的镜像供用户下载。国内不少云服务提供商(如时速云、阿里云等)也提供了仓库的本地源,可以提供稳定的国内访问。

当然,用户如果不希望公开分享自己的镜像文件,Docker也支持用户在本地网络内创建一个只能自己访问的私有仓库。当用户创建了自己的镜像之后就可以使用push命令将它上传到指定的公有或者私有仓库。这样用户下次在另外一台机器上使用该镜像时,只需要将其从仓库上pull下来就可以了。

远程镜像仓库,用来存放、分发docker镜像(例如Docker Hub)。

  • 存放各类公开镜像,图示例包含nginx镜像;
  • docker pull:daemon向registry请求,把镜像下载到本地Images;
  • docker push:可以把本地做好的镜像上传到仓库,供其他主机下载使用。

完整交互流程

  1. 用户在Client执行 docker run nginx,将请求发送给 Docker daemon。
  2. daemon访问Registry镜像仓库,下载nginx镜像,保存到本机Images。
  3. daemon读取本地 nginx 镜像,创建容器需要的网络、存储等资源,运行 Container容器。

Docker 版本

Docker 版本3个阶段:

  1. 2013‑2017‑02:语义化 1.x

    格式:主.次.补丁,例:1.13.1

  • 0.1(2013‑06):Docker首次发布,基于LXC
  • 1.0(2014‑06):生产可用,Docker Hub上线
  • 1.12:内置Swarm集群,引入healthcheck
  • 1.13:1.x最后版本,命令行重构
  1. 2017‑03 ~2022‑06:日历版本 CE/EE

    格式:YY.MM.Patch,分社区版CE、企业版EE

  • 17.03:首个日历版本,runc落地
  • 17.05:支持多阶段构建
  • 18.09:底层全面使用containerd
  • 20.10:经典稳定版,支持cgroup v2、rootless,存量环境大量使用
  • 22.06:日历版终点,Compose‑V1废弃
  1. 2023‑02至今:回归语义化23.x+

    格式:主.次.补丁

  • 23.0:默认启用BuildKit构建
  • 24.0/25.0:生产稳定推荐
  • 29.x:最新版本,清理大量老旧接口

搭建学习环境

实验环境

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

安装 Docker

Docker 支持几乎所有的 Linux 发行版,也支持 Mac 和 Windows。各操作系统的安装方法可以访问:https://docs.docker.com/engine/installation/

image-20250531104024825
环境准备

复习:搭建本地仓库。

[root@docker ~ 10:38:53]# mkdir /dvd

[root@docker ~ 10:37:17]# echo '/dev/sr0 /dvd iso9660 defaults 0 0'>> /etc/fstab

root@docker ~ 10:39:20]# mount -a
mount: /dev/sr0 写保护,将以只读方式挂载

# 如果提示如下,则编辑虚拟机:关联对应iso文件
root@docker ~ 10:39:20]# mount -a
mount: /dev/sr0 写保护,将以只读方式挂载


[root@docker ~ 10:39:49]# cd /etc/yum.repos.d/
[root@docker yum.repos.d 10:41:54]# mkdir back

[root@docker yum.repos.d 10:39:57]# mv /etc/yum.repos.d/*repo /etc/yum.repos.d/bak
[root@docker yum.repos.d 10:40:12]# vim dvd.repo
[dvd]
name=local repo from dvd
baseurl=file:///dvd
gpgcheck=0

[root@docker yum.repos.d 10:41:47]# yum clean all

已加载插件:fastestmirror
正在清理软件源: dvd
Cleaning up list of fastest mirrors
Other repos take up 634 M of disk space (use --verbose for details)

[root@docker yum.repos.d 10:43:11]# yum makecache 
已加载插件:fastestmirror
Determining fastest mirrors
dvd                                                                | 3.6 kB  00:00:00     
(1/4): dvd/group_gz                                                | 153 kB  00:00:00     
(2/4): dvd/primary_db                                              | 3.3 MB  00:00:00     
(3/4): dvd/filelists_db                                            | 3.3 MB  00:00:00     
(4/4): dvd/other_db                                                | 1.3 MB  00:00:00     
元数据缓存已建立
# 配置防火墙
## 防火墙不能关闭,部分容器服务需要防火墙的NAT功能。
[root@docker yum.repos.d 10:45:47]# systemctl enable firewalld.service --now
[root@docker yum.repos.d 10:47:18]# firewall-cmd --set-default-zone=trusted

# OS 仓保持默认

# 配置 docker 仓库
[root@docker yum.repos.d 10:50:59]# 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
allinone 部署
安装软件
[root@docker yum.repos.d 10:55:17]# yum install -y docker-ce
# 启动服务
[root@docker yum.repos.d 10:57:25]# systemctl enable docker.service --now
配置镜像加速

目前无法从docker.io仓库直接下载镜像,需要通过国内镜像加速服务器下载。

[root@docker yum.repos.d 11:15:28]# mkdir -p /etc/docker 
[root@docker ~]# tee /etc/docker/daemon.json <<'EOF'
{
  "insecure-registries": ["hub.laoma.cloud"],
  "registry-mirrors": ["http://hub.laoma.cloud","https://docker.m.daocloud.io"]
}
EOF
[root@docker yum.repos.d 11:15:32]# systemctl restart docker

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其他加速站点:华为加速

验证安装
# 查看docker版本
[root@docker yum.repos.d 11:19:22]# docker --version
Docker version 26.1.3, build b72abbb

# 运行第一个容器
[root@docker ~ 11:23:00]# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete 
Digest: sha256:e7c70bb24b462baa86c102610182e3efcb12a04854e8c582838d92970a09f323
Status: Downloaded newer image for hello-world:latest

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

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

其过程可以简单的描述为:

  1. 从 Docker Hub 下载hello-world镜像。
  2. 启动hello-world 容器。
# 运行第二个容器
[root@docker ~ 11:23:29]# 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 
b0ad2a3b9567: Pull complete 
136f1f71f30c: Pull complete 
01f8ace29294: Pull complete 
Digest: sha256:fddc534b7f6bb6197855be559244adb11907d569aae1283db8e6ce8bb8f6f456
Status: Downloaded newer image for httpd:latest
817f24cca3514568f9b7a7cac6f183734077fb74caf4c62502acd2a4d0d29520

其过程可以简单的描述为:

  1. 从 Docker Hub 下载 httpd 镜像。镜像中已经安装好了 Apache HTTP Server。
  2. 启动 httpd 容器,并将容器的 80 端口映射到 host 的 80 端口。

下面我们可以通过浏览器验证容器是否正常工作。在浏览器中输入 http://[your host IP]

# 查看主机ip
[root@docker ~ 11:25:29]# ip -br a
lo               UNKNOWN        127.0.0.1/8 ::1/128 
ens33            UP             10.1.8.130/24 fe80::20c:29ff:fe8c:c39b/64 
virbr0           DOWN           192.168.122.1/24 
virbr0-nic       DOWN           
docker0          UP             172.17.0.1/16 fe80::42:a8ff:fec2:b551/64 
veth7c57cce@if8  UP             fe80::d8ad:99ff:fe96:9148/64 

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

可以访问容器的 http 服务了,第一个容器运行成功!我们轻轻松松就拥有了一个 WEB 服务器。

C/S 分离部署
server
# 安装软件
[root@docker ~ 13:37:21] dnf install -y docker-ce

# 配置服务
[root@docker ~ 13:38:38]# 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 ~ 13:38:50]# systemctl daemon-reload
[root@docker ~ 13:39:47]# systemctl enable docker.service --now

# 验证
[root@docker ~ 13:40:44]# lsof -i :2375
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
dockerd 2565 root    3u  IPv6  76021      0t0  TCP *:2375 (LISTEN)
client 端
# 安装软件
[root@docker ~ 13:50:51]# dnf install -y docker-ce-cli

# 运行容器
[root@docker ~ 14:51:05]# docker -H 10.1.8.130 run hello-world

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

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
 
[root@docker ~ 14:51:21]# 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端。

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 镜像管理

Docker镜像类似于虚拟机镜像,可以将它理解为一个只读的模板。例如,一个镜像可以包含一个基本的操作系统环境,里面仅安装了Apache应用程序(或用户需要的其他软件)。可以把它称为一个Apache镜像。

镜像是创建Docker容器的基础。通过版本管理和增量的文件系统,Docker提供了一套十分简单的机制创建和更新现有的镜像,用户甚至可以从网上下载一个已经做好的应用镜像,并直接使用。

docker 命令帮助信息

更 新man 数据库,查看docker相关命令

[root@docker ~ 14:51:38]# mandb
[root@docker ~ 14:51:51]# man -k docker
docker (1)           - Docker image and container command line interface
docker-attach (1)    - Attach local standard input, output, and error streams to a r...
docker-build (1)     - Build an image from a Dockerfile
docker-builder (1)   - Manage builds
docker-builder-build (1) - Build an image from a Dockerfile
docker-builder-prune (1) - Remove build cache
docker-checkpoint (1) - Manage checkpoints
docker-checkpoint-create (1) - Create a checkpoint from a running container
docker-checkpoint-ls (1) - List checkpoints for a container
docker-checkpoint-rm (1) - Remove a checkpoint
docker-commit (1)    - Create a new image from a container's changes
docker-config (1)    - Manage Docker configs
docker-config-create (1) - Create a config from a file or STDIN
......
[root@docker ~ 14:52:14]# man -k docker|grep search
docker-search (1)    - Search the Docker Hub for images
[root@docker ~ 14:54:37]# man docker-search

search-查找镜像

[root@docker ~ 14:54:52]# docker search --help

Usage:	docker search [OPTIONS] TERM

Search the Docker Hub for images

Options:
  -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print search using a Go template
      --limit int       Max number of search results (default 25)
      --no-trunc        Don't truncate output

示例:搜索所有评价为3星以上的带centos关键字的镜像。

[root@docker ~ 14:55:13]# docker search --filter stars=3 centos
Error response from daemon: Get "https://index.docker.io/v1/search?q=centos&n=25": dial tcp 104.244.43.208:443: connect: connection refused

查询镜像有哪些版本

Docker 本身没有直接查看远程 docker.io(Docker Hub)仓库仓库中某个镜像所有版本的命令,但可以通过以下几种方式实现,核心思路是调用 Docker Hub 的 API 或借助第三方工具:

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

  1. Docker Hub 提供了公开 API 可查询镜像标签(版本),格式如下:
curl -s "https://registry.hub.docker.com/v2/repositories/<镜像名>/tags/" | jq '.results[].name'
  1. 查询具体镜像的版本:

例如,查询官方镜像(如nginx、ubuntu)需在镜像名前加library/:

curl -s "https://registry.hub.docker.com/v2/repositories/library/nginx/tags/" | jq '.results[].name'

例如,查询非官方镜像(如用户 bitnami 发布的mysql)不需在镜像名前加library/:

curl -s "https://registry.hub.docker.com/v2/repositories/bitnami/mysql/tags/" | jq '.results[].name'

**方法 2:**使用第三方工具 docker-search(更便捷,支持搜索和标签查询)

docker-search 是一个简化 Docker Hub 查询的工具,可直接列出镜像的所有标签。

  1. 安装工具(需要 Python 环境):
pip install docker-search
  1. 查询镜像版本:
docker-search tags nginx  # 官方镜像
docker-search tags bitnami/mysql  # 非官方镜像

**方法 3:**通过 Docker Hub 网页端查看(最直观)

直接访问 Docker Hub 官网查询,步骤:

  1. 打开 [Docker Hub](https://hub.docker.com/) 并搜索镜像(如 `nginx`)。
  2. 进入镜像详情页,点击 **Tags** 标签,即可查看所有版本(支持过滤和排序)。

pull-获取镜像

镜像加速

docker image pull命令从docker.io仓库下载镜像,速度比较慢,可以配置优先从国内镜像服务器下载镜像。

[root@docker ~ 15:02:17]# mkdir -p /etc/docker 
[root@docker ~ 15:02:18]# tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://09def58152000fc00ff0c00057bad7e0.mirror.swr.myhuaweicloud.com"]
}
EOF
[root@docker ~ 15:02:45]# systemctl restart docker

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

获取镜像

[root@docker ~ 15:04:53]# docker image pull --help

Usage:	docker image pull [OPTIONS] NAME[:TAG|@DIGEST]

Pull an image or a repository from a registry

Options:
  -a, --all-tags                Download all tagged images in the repository
      --disable-content-trust   Skip image verification (default true)
      --platform string         Set platform if server is multi-platform capable
  -q, --quiet                   Suppress verbose output

严格地讲,镜像的仓库名称中还应该添加仓库地址(即registry,注册服务器)作为前缀,只是我们默认使用的是Docker Hub服务,该前缀可以忽略。

镜像标准命名格式:服务器地址:端口/分类/镜像名:tag

TAG默认是latest。

示例:

[root@docker ~ 15:05:02]# docker image pull centos:8
Using default tag: latest
latest: Pulling from library/centos
3c72a8ed6814: Pull complete 
Digest: sha256:76d24f3ba3317fa945743bb3746fbaf3a0b752f10b10376960de01da70685fbd
Status: Downloaded newer image for centos:latest
docker.io/library/centos:latest

下载过程中可以看出,镜像文件一般由若干层(layer)组成,3c72a8ed6814这样的串是层的唯一id(实际上完整的id包括256比特,由64个十六进制字符组成)。使用docker image pull命令下载时会获取并输出镜像的各层信息。当不同的镜像包括相同的层时,本地仅存储层的一份内容,减小了需要的存储空间。

镜像下载存放到本地位置:/var/lib/docker/StorageDriver

直接从镜像服务器下载

[root@docker ~ 15:06:33]# docker image pull registry.access.redhat.com/ubi8

ls-查看本地镜像列表

[root@docker ~ 15:07:32]# docker image ls --help

Usage:	docker image ls [OPTIONS] [REPOSITORY[:TAG]]

List images

Aliases:
  ls, images, list

Options:
  -a, --all             Show all images (default hides intermediate images)
      --digests         Show digests
  -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print images using a Go template
      --no-trunc        Don't truncate output
  -q, --quiet           Only show numeric IDs

示例:

[root@docker ~ 15:09:34]# 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

# 控制输出列
[root@docker ~ 15:10:02]# docker image ls --format "{{.Repository}}:{{.Tag}}"

tag 用于标明镜像不同版本。一个镜像可以有多个TAG,占用本地的实际空间只有一个镜像。

tag-镜像打标签

[root@docker ~ 15:10:50]# docker image tag --help

Usage:	docker image tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE

示例:

[root@docker ~ 15:11:25]# docker image tag centos:8 myos
[root@docker ~ 15:11:25]# docker image tag centos:8 myos:v1
[root@docker ~ 15:13:06]# 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
myos          latest    5d0da3dc9764   3 years ago    231MB
myos          v1        5d0da3dc9764   3 years ago    231MB

tag 使用最佳实践

借鉴软件版本命名方式能够让用户很好地使用镜像。

一个高效的版本命名方案可以让用户清楚地知道当前使用的是哪个镜像,同时还可以保持足够的灵活性。

每个 repository 可以有多个 tag,而多个 tag 可能对应的是同一个镜像。下面通过例子为大家介绍 Docker 社区普遍使用的 tag 方案。

假设我们现在发布了一个镜像 myimage,版本为 v1.9.1。那么我们可以给镜像打上四个 tag:1.9.1、1.9、1 和 latest。

image-20210617101440573

过了一段时间,我们发布了 v1.9.2。这时可以打上 1.9.2 的 tag,并将 1.9、1 和 latest 从 v1.9.1 移到 v1.9.2。

image-20210617101449747

之后,v2.0.0 发布了。这时可以打上 2.0.0、2.0 和 2 的 tag,并将 latest 移到 v2.0.0。

image-20210617101459730

这种 tag 方案使镜像的版本很直观,用户在选择非常灵活:

  1. myimage:1 始终指向 1 这个分支中最新的镜像。
  2. myimage:1.9 始终指向 1.9.x 中最新的镜像。
  3. myimage:latest 始终指向所有版本中最新的镜像。
  4. 如果想使用特定版本,可以选择 myimage:1.9.1、myimage:1.9.2 或 myimage:2.0.0。

inspect-查看本地镜像详细信息

[root@docker ~ 15:13:11]# docker image inspect --help

Usage:	docker image inspect [OPTIONS] IMAGE [IMAGE...]

Display detailed information on one or more images

Options:
  -f, --format string   Format the output using the given Go template

示例:

[root@docker ~ 15:13:44]# docker image inspect myos
[
    {
        "Id": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6",
        "RepoTags": [
            "centos:8",
            "myos:latest",
            "myos:v1"
        ],
        "RepoDigests": [
            "centos@sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2021-09-15T18:20:05.184694267Z",
        "DockerVersion": "20.10.7",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/bash"
            ],
            "Image": "sha256:f5b050f177fd426be8fe998a8ecf3fb1858d7e26dff4080b29a327d1bd5ba422",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "20210915",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS"
            }
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 231268856,
        "GraphDriver": {
            "Data": {
                "MergedDir": "/var/lib/docker/overlay2/7e78d40a938c39b51b84a87cd56bf1baea6a8fbfd4c252fda16c494b0155cf32/merged",
                "UpperDir": "/var/lib/docker/overlay2/7e78d40a938c39b51b84a87cd56bf1baea6a8fbfd4c252fda16c494b0155cf32/diff",
                "WorkDir": "/var/lib/docker/overlay2/7e78d40a938c39b51b84a87cd56bf1baea6a8fbfd4c252fda16c494b0155cf32/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59"
            ]
        },
        "Metadata": {
            "LastTagTime": "2025-05-31T11:49:08.212335698+08:00"
        }
    }
]

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

history-查看本地镜像分层信息

[root@docker ~ 15:15:00]# docker image history --help

Usage:	docker image history [OPTIONS] IMAGE

Show the history of an image

Options:
      --format string   Pretty-print images using a Go template
  -H, --human           Print sizes and dates in human readable format (default true)
      --no-trunc        Don't truncate output
  -q, --quiet           Only show numeric IDs

示例:

[root@docker ~ 15:15:14]# 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 
# 不压缩输出行
[root@docker ~ 15:15:53]# docker image history myos --no-trunc 
IMAGE                                                                     CREATED       CREATED BY                                                                                                                                                                                                SIZE      COMMENT
sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6   3 years ago   /bin/sh -c #(nop)  CMD ["/bin/bash"]                                                                                                                                                                      0B        
<missing>                                                                 3 years ago   /bin/sh -c #(nop)  LABEL org.label-schema.schema-version=1.0 org.label-schema.name=CentOS Base Image org.label-schema.vendor=CentOS org.label-schema.license=GPLv2 org.label-schema.build-date=20210915   0B        
<missing>                                                                 3 years ago   /bin/sh -c #(nop) ADD file:805cb5e15fb6e0bb0326ca33fd2942e068863ce2a8491bb71522c652f31fb466 in /                                                                                                          231MB   

rm-删除本地镜像

[root@docker ~ 15:16:23]# docker image rm --help

Usage:	docker image rm [OPTIONS] IMAGE [IMAGE...]

Remove one or more images

Aliases:
  rm, rmi, remove

Options:
  -f, --force      Force removal of the image
      --no-prune   Do not delete untagged parents

[root@docker ~]# docker image rm centos

通过标签删除镜像

[root@docker ~ 15:17:02]# docker image rm myos
Untagged: myos:latest

[root@docker ~ 15:18:27]# 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
myos          v1        5d0da3dc9764   3 years ago    231MB

当同一个镜像拥有多个标签的时候,docker image rm命令只是删除该镜像的指定标签,并不影响镜像文件。删除镜像最后一个标签时候,才会删除镜像。

[root@docker ~ 15:19:10]# docker image rm myos:v1 
Untagged: myos:v1

[root@docker ~ 15:19:40]# docker image rm centos:8
Untagged: centos:8
Untagged: centos@sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Deleted: sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6
Deleted: sha256:74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59

[root@docker ~ 15:19:59]# 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

通过 ID 删除镜像

[root@docker ~ 15:28:56]# docker image rm 958373fdd7e8
Untagged: httpd:latest
Untagged: httpd@sha256:09cb4b94edaaa796522c545328b62e9a0db60315c7be9f2b4e02204919926405
Deleted: sha256:958373fdd7e8d15f3df0c9927bcb7d3b565afc6e3ebb1c141defd5341a72fb13
Deleted: sha256:6d06988e4798c5b606b2676489101b613cf645d67add87706687d034f4a9b327
Deleted: sha256:c9fdbab03a0285a8af784fdbf58c75f974034615965a852f4e2e30e5da3ca831
Deleted: sha256:a530aa30f1dcd5de45328983bdd1728346c18710818479eff6769b573006441d
Deleted: sha256:861ae676a017a4a76f6db33be4be9cfb6ab74c405ad2d052f9d1d4ebc85582fb
Deleted: sha256:d705c6f7c9a22dd6b973990683352a383d29e35c72de80aa017cb89764a190aa
Deleted: sha256:ace34d1d784c01e3f9d156687089e8f58f786e23ccd097bdbbf337d6d28b3783

[root@docker ~ 15:29:00]# docker image ls
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    74cc54e27dc4   4 months ago   10.1kB

prune-修剪本地镜像

[root@docker ~ 15:30:24]# docker image prune --help

Usage:	docker image prune [OPTIONS]

Remove unused images

Options:
  -a, --all             Remove all unused images, not just dangling ones
      --filter filter   Provide filter values (e.g. 'until=<timestamp>')
  -f, --force           Do not prompt for confirmation

示例:

[root@docker ~ 15:31:17]# docker pull nginx
[root@docker ~ 15:31:30]# 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
untagged: nginx@sha256:fb39280b7b9eba5727c884a3c7810002e69e8f961cc373b89c92f14961d903a0
deleted: sha256:be69f2940aaf64fdf50c9c99420cbd57e10ee655ec7204df1c407e9af63d0cc1
......
deleted: sha256:3c1060a9ec6601e87cbcb04366f323b6383b7f605153e7df398bc1f843e36141

Total reclaimed space: 117.7MB

[root@docker ~ 15:31:41]# 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

为什么httpd和hello-world没有被删除呢?

因为:这两个镜像被创建的容器使用。

[root@docker ~ 15:32:14]# docker ps -a
CONTAINER ID   IMAGE         COMMAND              CREATED              STATUS                     PORTS                               NAMES
be05a7c31635   httpd         "httpd-foreground"   About a minute ago   Up About a minute          0.0.0.0:80->80/tcp, :::80->80/tcp   gifted_williams
4974ee579b36   hello-world   "/hello"             4 minutes ago        Exited (0) 4 minutes ago                                       keen_kare

save-保存本地镜像为文件

docker默认使用overlay2存储驱动存储镜像。

[root@docker ~ 15:32:56]# docker info|grep 'Storage Driver'
Storage Driver: overlay2

镜像存储在本地/var/lib/docker/overlay2,通过文件系统层面拷贝image,操作复杂。可以使用save命令,将本地镜像保存为单个文件,并分享给他人使用。

[root@docker ~ 15:33:01]# docker image save --help

Usage:	docker image save [OPTIONS] IMAGE [IMAGE...]

Save one or more images to a tar archive (streamed to STDOUT by default)

Options:
  -o, --output string   Write to a file, instead of STDOUT

示例:

[root@docker ~ 15:37:33]# docker save httpd -o httpd.tar
[root@docker ~ 15:37:41]# docker save httpd hello-world -o images.tar
[root@docker ~ 15:37:45]# ls *tar
httpd.tar  images.tar

load-将本地镜像文件导入本地

[root@docker ~ 15:39:27]# docker image load --help

Usage:	docker image load [OPTIONS]

Load an image from a tar archive or STDIN

Options:
  -i, --input string   Read from tar archive file, instead of STDIN
  -q, --quiet          Suppress the load output

示例:删除本地镜像,并导入本地镜像文件

[root@docker ~ 15:39:53]# 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
Error response from daemon: conflict: unable to remove repository reference "hello-world" (must force) - container 4974ee579b36 is using its referenced image 74cc54e27dc4

删除本地正在使用的镜像需要选项-f 或者 --force

[root@docker ~ 15:44:11]# docker image rm httpd hello-world:latest -f
Untagged: httpd:latest
Untagged: httpd@sha256:09cb4b94edaaa796522c545328b62e9a0db60315c7be9f2b4e02204919926405
Untagged: hello-world:latest
Untagged: hello-world@sha256:0b6a027b5cf322f09f6706c754e086a232ec1ddba835c8a15c6cb74ef0d43c29
Deleted: sha256:74cc54e27dc41bb10dc4b2226072d469509f2f22f1a3ce74f4a59661a1d44602

[root@docker ~]# docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
<none>       <none>    958373fdd7e8   4 months ago   148MB
# 让然被容器使用。
# 删除容器后,再删除镜像。

导入镜像

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

[root@docker ~ 15:44:39]# 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

push-将本地镜像推送到服务器

本地镜像本默认推送到docker.io服务器,需要登录才能推送。

[root@docker ~ 15:59:17]#  docker login --help

Usage:	docker login [OPTIONS] [SERVER]

Log in to a Docker registry.
If no server is specified, the default is defined by the daemon.

Options:
  -p, --password string   Password
      --password-stdin    Take the password from stdin
  -u, --username string   Username

示例:

[root@docker ~ 15:59:31]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: mage16196
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

docker.io站点,目前无法访问,会因为登录超时而失败。

docker image push命令语法如下:

[root@docker ~ 16:00:04]# docker image push --help

Usage:	docker image push [OPTIONS] NAME[:TAG]

Push an image or a repository to a registry

Options:
      --disable-content-trust   Skip image signing (default true)

上传的镜像格式:username/image:tag

[root@docker ~ 16:01:36]# docker image tag hello-world:latest mage16196/myhello
[root@docker ~ 16:01:51]# docker image push mage16196/myhello
The push refers to repository [docker.io/mage16196/myhello]
9c27e219663c: Layer already exists 
latest: digest: sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042 size: 525

可以登录到docker hub web界面管理已上传的镜像。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐