docker学习 打包软体

1. 从容器构建镜像的手动流程

  • 核心工作流
    1. 从现有镜像创建并启动一个容器。
    2. 在容器的文件系统中进行改动(如安装软件、添加文件)。
    3. 使用 docker commit 提交改动,生成一个包含新文件层的新镜像。
  • 审计改动:使用 docker diff 命令可以查看容器相对于其基础镜像的文件系统变化。输出结果包括:
    • A (Added):新增文件。
    • C (Changed):修改的文件。
    • D (Deleted):删除的文件。
  • 提交选项docker commit 允许设置作者(-a)、提交信息(-m)以及环境变量、工作目录等元数据属性。

2. 深入理解镜像与分层结构

镜像并非一个单一文件,而是由多个只读层堆叠而成的集合。

  • 联合文件系统 (UFS):Docker 利用 UFS 将多层文件系统挂载为一个统一的视图。容器对镜像层的任何改动都会记录在最顶层的“可写层”中。
  • 写时复制 (Copy-on-Write):当修改底层的文件时,Docker 会先将该文件复制到顶层再进行修改。
  • 体积限制与层级限制
    • 删除文件并不减小体积:在新的层中删除底层文件,只是在顶层标记该文件不可见,底层文件依然存在于镜像中,因此镜像总大小反而可能增加。
    • 层数限制:某些联合文件系统(如 AUFS)有最大层数限制(如42层)。

3. 导出与导入扁平化文件系统

为了减小镜像体积或去除构建历史,可以使用导出功能。

  • docker export:将容器的整个文件系统压缩成一个 tar 归档文件,它会丢弃所有的分层历史和元数据,仅保留当前状态。
  • docker import:将 tar 归档文件重新导入为一个单层镜像
  • 优点:可以创建一个非常小的、不含冗余历史的“扁平镜像”。

4. 镜像标签与版本控制最佳实践

  • 仓库与标签:仓库(Repository)是镜像的命名桶,而标签(Tag)则指向特定的层 ID。
  • latest 标签的陷阱latest 标签是一个“移动的目标”,它并不总是指向最稳定的版本,过度依赖它会导致生产环境的版本不一致。
  • 最佳实践
    • 为镜像分配具体的版本号标签(如 1.9.1),并在更新时移动主版本标签(如 1.9)以指向最新的补丁版本。
    • 保持软件版本与镜像版本的一致性,利用细粒度的重叠标签体系。

比喻理解: 镜像的手动构建就像是在制作一本剪贴报。每一页代表一个镜像层,你在一页上写的字或贴的照片(即 docker diff 记录的 A、C、D)都被永久保存。如果你想“删掉”第一页的一个错别字,你只能在第二页贴一张白纸盖住它,但第一页的字其实还在报本里,所以报本只会越来越厚。而 docker export 就像是用复印机把整本报纸印成了一张平整的纸,历史痕迹不见了,虽然变薄了,但你也无法再翻看之前的修改记录了。