Docker镜像与容器
镜像
Docker镜像基于Union File System实现,包含了相关依赖和基础环境,是在文件系统中依次挂载的一系列镜像层。
每层镜像层都包括了对上一层镜像的修改。其内部实现机制是写时复制(Copy on Write)。
写时复制
写时复制(Copy on Write,COW)是一种计算机编程技术,用于优化数据的复制操作。常常用于对象或数组的拷贝中。
当涉及到复制数据时,传统的方法是直接复制整个数据,这会占用大量的内存和处理时间。相反,COW技术延迟了复制操作,只有在需要修改原始数据时才会执行实际的复制操作。其思想在很多方面都有所体现,比如前端的懒加载,git等。
当容器中的应用程序对文件系统进行修改时,Docker会通过UFS将修改后的文件复制到容器的独立层中,只有在需要修改原始数据时才会执行实际的操作,而不是直接修改基础镜像。
不同于常见虚拟化在初始化时从镜像中拷贝整个文件系统,写时复制的运行时复制机制,使得Docker的启动速度达到秒级。
固定的流程
固定是稳定的别名。
Docker镜像的一系列操作依赖Docker本身。必须通过Docker进行Import、Export和Build等操作,而不能像虚拟机一样能够通过网络个人或组织提供的不同源的iso文件导入,不能单独恢复。失去了部分灵活性带来的是流程的稳定性。
Docker会对每一个有修改的镜像层生成一个64位的HashCode,保证其在全球范围内唯一,也就是我们通过docker images看到的镜像ID(前12位)。这种ID区分镜像层的方法使得层与层之间得以区分解耦,达到一种复用的效果。比如以较为底层的技术组成的一层镜像可以作为其它多个上层应用镜像的公用子层镜像,类似于公用一个地基,但实际上是分离的。其带来的是更低的储存空间占用,这种地空间占用也是Docker的优势之一。
命名
Docker镜像命名形式: username/repository:tag
64位的hash code当然不适合来在应用层运用,就像32位的IP地址一样,我们实际应用往往是输入一个方便记忆和理解的域名,然后通过DNS解析映射到这个IP地址上。Docker的Hash Code当然可以指定唯一的镜像,但我们需要更便捷直观的别名映射。
如果镜像路径中不包含username字段(无标记用户),则这个镜像就是Docker官方镜像。
镜像的repository字段的取名一般就是软件名称,当然也可以是其它名称,但这样做的辨别效果并不好。
镜像的tag字段则对应软件中的版本号、依赖环境,构建方式等信息。如果不显式地输入tag,则默认为atest。
容器
这部分切换到容器方面。
生命周期

Docker容器生命周期有五部分。简便记忆,可以将其简单理解为一个软件的”安装—使用—删除“的这么一个过程
- Created
- Running
- Paused
- Stopped
- Deleted
主进程
容器的声明周期同主进程表里。主进程就是PID为1的进程。主进程启动,容器启动;主进程关闭,容器关闭;反之亦然。
PID(Process Identifier)
PID是操作系统分配给每个正在运行的进程的唯一标识符。
每个进程都有一个唯一的PID,而且在任何给定时间内,同一操作系统中的不同进程不能有相同的PID。
通过使用PID,操作系统可以同时管理和协调多个并发的进程,从而实现有效的多任务处理和资源利用。
PID主要作用有以下几点
进程管理:操作系统使用PID来跟踪和管理运行中的进程。PID允许操作系统在多任务环境中识别、管理和控制不同的进程。
进程间通信:在进程间通信(IPC)中,PID用于标识和定位目标进程,使得进程可以相互通信、交换数据以及协调操作。
资源分配:操作系统使用PID来管理和分配进程所需的资源,例如内存、处理器时间、文件和设备访问权限等。PID允许操作系统为每个进程提供适当的资源配额和权限。
错误诊断:在错误诊断和故障排除过程中,PID可以帮助确定哪些进程可能导致系统故障或性能问题。通过监视和分析具有特定PID的进程,可以更容易地定位和解决问题。
这也就能说明为什么Docker不推荐一个容器里塞进多个程序运行:一个容器只有一个PID,如果一个容器塞了很多程序就难以对程序进行追踪和定位。
也就是为什么“容器即应用”是最佳实践。