ldc / Docker 入门

Created Mon, 31 Mar 2025 00:00:00 +0000 Modified Thu, 24 Apr 2025 04:32:28 +0000
1601 Words

Docker 是容器技术的基础,而 Kubernetes(k8s)是容器编排系统,因此理解 Docker 的核心概念是学习 k8s 的重要前提。

镜像(Image)

定义

  1. 镜像是只读的模板,包含了运行一个应用所需的所有内容:代码、运行时环境、依赖库、环境变量、配置文件等。
  2. 镜像具有不可变性,镜像一旦构建完成,内容不可修改(如需修改需通过重新构建)。
  3. 镜像采用分层存储结构,每一层是只读的,多个镜像可以共享相同的层,提高存储效率。

分层存储

镜像的分层存储结构是 Docker 的核心设计之一,其原理和优势与容器化技术的轻量、高效特性密切相关。

分层存储的原理

Docker 使用联合文件系统(如 AUFS、Overlay2、DeviceMapper 等)实现分层存储。每个镜像由多个层叠加而成,最上层是容器运行时的可写层。 这些层按顺序堆叠,最终呈现为一个统一的文件系统视图。

假设一个镜像的 Dockerfile 如下:

FROM ubuntu:20.04         # 基础层(Layer 1)
COPY app.py /app/         # 层 2
RUN pip install requests  # 层 3
CMD ["python", "/app/app.py"]
  • 每一条指令生成一个新的只读层。
  • 每个层通过唯一的哈希值标识,如果不同镜像共享相同的层(例如相同的 ubuntu:20.04 基础层),则只需存储一次。

为什么需要分层存储?

  1. 进程轻量化的需求
    • 在微服务架构中,可能同时运行数百个进程,传统虚拟机的镜像是完整的操作系统文件,若每个进程都独立存储完整文件系统,资源浪费严重。 分层存储通过共享和复用层,使得镜像体积显著减少。
  2. 快速迭代的需求
    • 开发过程中需要频繁构建的镜像存在无变化逻辑或资源时,重复构建也是一种计算资源的浪费。 分层存储则可以达成当某一层未变化时复用缓存,提升效率:
      • 更新镜像时,只需修改或添加新的层,无需构建整个镜像。
      • 拉取镜像时,仅需下载本地缺失的层,而非整个镜像。
      • 回滚到旧版本时,只需切换到某个旧层。
      • CI/CD 流水线中,仅传输变化的层,加快部署速度。

容器(Container)

定义

  1. 容器是镜像的运行时实例,基于镜像启动后,会在镜像层之上添加一个可写的容器层用于运行时修改。
  2. 容器是轻量级、临时的、隔离的进程,拥有自己的文件系统、网络和进程空间。

容器隔离

容器的隔离性是容器技术的核心设计之一,它通过操作系统级别的资源隔离,使多个容器在同一主机上独立运行。

容器隔离的原理

Docker 容器的隔离性主要依赖 Linux 内核的两大核心机制:命名空间(Namespaces)控制组(Cgroups)

  1. 命名空间(Namespaces)为进程提供独立的资源视图,使得每个容器拥有自己的隔离环境,包括:
    • PID 命名空间:每个容器内的进程拥有独立的进程 ID(PID),看不到主机或其他容器的进程。
    • Network 命名空间:每个容器拥有独立的网络接口、IP 地址、端口和路由表。
    • Mount 命名空间:容器内的文件系统挂载点独立于主机和其他容器。
    • UTS 命名空间:允许容器拥有独立的主机名和域名。
    • User 命名空间:隔离用户和用户组 ID,提升安全性(避免容器内 root 用户等同于主机 root)。
    • IPC 命名空间:隔离进程间通信(如信号量、共享内存)。
  2. 控制组(Cgroups)用于限制和分配容器使用的硬件资源,避免资源争用:
    • CPU 限制:为容器分配 CPU 配额。
      docker run --cpus=2 <镜像>  # 限制容器最多使用 2 个 CPU 核心
      
    • 内存限制:设置容器的内存使用上限。
      docker run -m 512m <镜像>  # 限制容器内存为 512MB
      
    • 磁盘 I/O 控制:限制容器的读写速率。
    • 设备访问控制:限制容器访问特定硬件设备(如 GPU)。

为什么容器需要隔离?

  1. 在容器化部署出来之前后端就已经存在隔离化的部署方案,那个时候通常是虚拟机,所以容器隔离技术是在保证隔离性前提下的一种替代虚拟机的轻量化方案, 以更低的开销实现类似虚拟机的多环境部署。而隔离部署的目的是为了解决传统部署中,同一主机运行多个应用时不同版本的库或语言运行时可能冲突。
  2. 支持微服务与云原生架构,比如:
    • 弹性伸缩:需要确保扩缩容时新增实例不会与已有服务冲突。
    • 内存泄漏崩溃:资源隔离会限制其影响范围,而新扩容的容器仍能正常提供服务。

仓库(Registry)

私有 Registry 可与 Jenkins、GitLab CI 等 CI/CD 工具集成,实现自动化镜像构建和发布。