菜单

容器化

相关源文件

本页面提供了关于容器化概念、工具和实践的全面概述,以及它们与 DevOps 工作流程的关系。它涵盖了容器基础知识、镜像管理、容器创建和运行、网络、存储以及安全最佳实践。有关容器编排的特定信息,请参阅Kubernetes 管理

容器基础

容器是轻量级、可移植且隔离的环境,用于打包应用程序及其依赖项。它们能够实现从开发到生产环境中一致的部署。

来源: topics/containers/README.md91-100

什么是容器?

容器是一个隔离的执行环境,具有可配置的隔离和资源限制。根据开放容器倡议(OCI),容器将软件组件及其所有依赖项封装在一个自描述和可移植的格式中,允许任何兼容的运行时在没有额外依赖项的情况下运行它。

容器的关键特征

  • 共享宿主系统的内核
  • 使用 Linux 命名空间和 cgroups 进行隔离
  • 轻量级(与虚拟机相比)
  • 跨不同环境可移植
  • 快速启动,本质上是短暂的

来源: topics/containers/README.md65-73 topics/containers/README.md78-80

容器与虚拟机对比

功能容器虚拟机
隔离性操作系统级虚拟化硬件虚拟化
内核与宿主共享每个虚拟机单独
启动时间分钟
资源开销
安全良好更好
可移植性优秀有限

容器在以下情况下是理想的选择

  • 轻量级、快速启动的环境
  • 运行同一应用程序的多个实例
  • 开发和生产环境中一致的环境

虚拟机在以下情况下更适合

  • 完整的操作系统隔离和安全性
  • 运行需要独立操作系统全部资源和功能的应用程序

来源: topics/containers/README.md91-113

容器使用的 Linux 内核功能

容器利用多种 Linux 内核功能来提供隔离

  • 命名空间 (Namespaces):隔离系统资源,使其仅对命名空间内的进程可用
  • 控制组 (cgroups):限制和核算进程组的资源使用
  • SELinux:保护进程的访问控制机制
  • Seccomp:限制进程使用系统调用和文件描述符能力的安全性机制

来源: topics/containers/README.md805-827

容器镜像

容器镜像是一个轻量级、独立、可执行的包,包含运行应用程序所需的一切:代码、运行时、库、环境变量和配置文件。

镜像结构

容器镜像由多个只读层组成。关键特性

  • 每一层代表前一层发生的更改
  • 层是不可变的(不可更改)
  • 层具有基于内容的哈希 ID
  • 多个镜像可以共享公共层
  • 当容器运行时,顶部会添加一个薄的可写层

来源: topics/containers/README.md304-310 topics/containers/README.md1017-1023

镜像与容器

镜像是一个只读模板,包含应用程序代码和依赖项。容器是镜像的一个运行实例,带有一个额外的可写层。

图片容器
只读镜像之上的读写层
模板/蓝图运行实例
存储在注册表中运行在宿主上
不可变。可变状态
可与其他容器共享拥有自己的文件系统状态

来源: topics/containers/README.md83-88 topics/containers/README.md1017-1023

镜像注册表和仓库

  • 注册表 (Registry):存储和分发容器镜像的服务(例如,Docker Hub,Quay.io)
  • 仓库 (Repository):具有相同名称但不同标签的相关镜像的集合
  • 标签 (Tag):附加到仓库中镜像的标签,通常表示版本

来源: topics/containers/README.md518-522 topics/containers/README.md525-528

容器运行时和引擎

容器运行时架构

容器实现通常包含多个组件

  1. 客户端 (Client):用于用户交互的命令行界面
  2. 守护进程/引擎 (Daemon/Engine):处理 API 请求、构建、网络等的上层组件
  3. 容器运行时 (Container Runtime):管理容器生命周期 (containerd)
  4. 低级运行时 (Low-level Runtime):与 Linux 内核功能接口 (runc)

来源: topics/containers/README.md886-899 topics/containers/README.md902-909 topics/containers/README.md912-923

OCI 标准

开放容器倡议(OCI)是一个开放的治理结构,旨在标准化容器格式和运行时。OCI 维护以下规范:

  • 镜像规范 (Image Spec):定义容器镜像的构建和结构方式
  • 运行时规范 (Runtime Spec):定义容器运行时应如何运行

符合 OCI 的容器必须支持基本操作:创建、启动、停止、删除和查询状态。

来源: topics/containers/README.md1240-1248 topics/containers/README.md1251-1254

使用容器

容器生命周期

容器生命周期中的基本操作包括

  1. 从镜像创建容器
  2. 启动容器以运行应用程序
  3. 任务完成后停止容器
  4. 移除容器以清理资源

来源: topics/containers/README.md147-156 topics/containers/README.md177-185

基本容器命令

操作命令示例
运行容器podman run ubuntu
列出正在运行的容器podman container ls
列出所有容器podman container ls -a
在容器中执行命令podman container exec -it [容器] bash
停止容器podman container stop [容器]
移除容器podman container rm [容器]
在后台运行podman container run -d [镜像]
映射端口podman run -p 8080:80 [镜像]

来源: topics/containers/README.md138-219

构建容器镜像

Containerfile/Dockerfile

Containerfile(或 Docker 的 Dockerfile)是一个文本文件,其中包含构建容器镜像的说明。每条指令都会在镜像中创建一个新层。

常用指令包括

  • FROM:指定基础镜像
  • RUN:在容器中执行命令
  • COPY/ADD:将文件从宿主复制到容器
  • WORKDIR:设置工作目录
  • EXPOSE:记录容器监听的端口
  • ENV:设置环境变量
  • USER:指定运行容器的用户
  • CMD/ENTRYPOINT:定义要运行的默认命令

来源: topics/containers/README.md615-618 topics/containers/README.md628-635

镜像构建过程

使用 podman builddocker build 构建镜像时

  1. 为每个指令创建一个临时容器
  2. 在容器中执行该指令
  3. 将结果保存为新的镜像层
  4. 移除临时容器
  5. 对每个指令重复此过程

构建缓存

  • 之前构建的层会被缓存
  • 如果指令及其上下文未发生变化,则使用缓存
  • 当指令或其上下文发生变化时,会发生缓存失效

来源: topics/containers/README.md418-425 topics/containers/README.md428-439

多阶段构建

多阶段构建允许你在 Containerfile 中使用多个 FROM 语句,每个 FROM 语句都开启一个新的构建阶段。这使你能够

  1. 在一个阶段中构建应用程序,包含所有必需的构建工具
  2. 仅将应用程序的工件复制到一个干净的最终镜像中
  3. 生成更小的镜像,无需不必要的构建工具

来源: topics/containers/README.md1060-1073

镜像优化最佳实践

  • 在 FROM 指令中使用特定标签
  • 合并相关的 RUN 指令以减少层数
  • 清理包安装后的残留
  • 使用 .dockerignore 排除不必要的文件
  • 尽可能使用更小的基础镜像
  • 实现多阶段构建
  • 将频繁更改的指令放在文件靠后的位置
  • 设置正确的 USER 以避免以 root 用户运行

来源: topics/containers/README.md452-458 topics/containers/README.md638-645

容器网络

容器网络支持通信

  • 在同一主机上的容器之间
  • 容器和主机之间
  • 容器和外部网络之间

关键网络概念

  • 容器网络模型 (CNM):由 Docker 使用
  • 容器网络接口 (CNI):由 Kubernetes 和其他平台使用
  • 网络:对端点集合进行分组和隔离
  • 端点:用于连接的虚拟网络接口
  • 沙盒:具有接口、路由表等的隔离网络栈

来源: topics/containers/README.md1090-1098 topics/containers/README.md1104-1120

网络类型

网络类型描述用例
桥接将容器桥接到主机的默认网络大多数独立容器
主机容器共享主机的网络命名空间最大性能,无隔离
容器没有网络访问权限最大安全隔离
Overlay多主机网络容器编排
Macvlan容器在物理网络上获得 MAC 地址遗留应用程序

端口映射

使容器服务可以从主机或外部网络访问

podman run -d --name apache1 -p 8080:80 httpd

这会将容器中的端口 80 映射到主机上的端口 8080。

来源: topics/containers/README.md212-218

容器存储

存储类型

容器提供不同的存储选项

  1. 临时存储:可写容器层中的默认存储

    • 容器被移除时消失
    • 由存储驱动程序管理
    • 不适用于持久化数据
  2. 持久化存储:

    • :由容器引擎管理
    • 绑定挂载:从主机挂载到容器的目录或文件
    • tmpfs 挂载:仅存储在主机内存中

来源: topics/containers/README.md754-767 topics/containers/README.md771-796

管理持久化数据

创建和使用卷

podman volume create my_volume
podman run -v my_volume:/path/in/container image_name

挂载主机目录

podman run -v /host/path:/container/path image_name

来源: topics/containers/README.md771-796

容器安全

安全最佳实践

关键安全建议

  • 仅在容器中安装必要的软件包
  • 尽可能不要以 root 用户运行容器
  • 尽可能将卷和容器文件系统设置为只读
  • 绝不要使用 --privileged 标志运行容器
  • 使用安全扫描工具检查容器镜像
  • 设置资源限制以防止拒绝服务攻击
  • 保持主机系统更新和安全

来源: topics/containers/README.md1140-1147 topics/containers/README.md1151-1155

无根容器

无根容器在主机上无需 root 权限即可运行,从而提供额外的安全优势

  • 降低了容器被攻破时的攻击面
  • 强制执行最小权限原则
  • 防止权限升级攻击

使用无根容器时的注意事项

  • 无法绑定到低于 1024 的端口
  • 与某些系统功能的集成受限
  • 某些命令可能无法正常工作
  • 网络处理方式不同(通常通过 Slirp)
  • 特殊的 FUSE-OverlayFS 等文件系统驱动

来源: topics/containers/README.md1198-1203 topics/containers/README.md1206-1217 topics/containers/README.md1219-1234

生产环境中的容器

生产注意事项

生产容器的最佳实践

  • 使用特定的镜像标签(而不是 latest
  • 实现适当的健康检查
  • 设置适当的重启策略
  • 使用资源限制
  • 实施监控和日志记录
  • 确保组件之间连接的安全
  • 对于复杂的部署,考虑容器编排

来源: topics/containers/README.md1162-1178

重启策略

重启策略决定了容器如何从故障中恢复

  • no:从不重启容器(默认)
  • always:如果容器停止,则始终重启它
  • unless-stopped:除非显式停止,否则重启
  • on-failure:仅在非零退出代码时重启

这些策略为容器提供了基本的自我修复能力。

来源: topics/containers/README.md1182-1193

总结

容器化是现代 DevOps 实践中的一项基本技术,它提供了一种标准化的方式来打包、分发和运行包含其依赖项的应用程序。通过理解容器基础知识、镜像管理、网络、存储和安全最佳实践,团队可以在其开发和部署工作流中有效地利用容器。

有关生产环境中更高级的容器管理,请考虑使用 Kubernetes 管理 来探索容器编排。