3.docker镜像与仓库
Docker 学习笔记 (三):理解镜像与仓库
1. 什么是 Docker 镜像?(Docker Images Deep Dive)
在前两章中,我们使用了 hello-world 镜像。但镜像本质上是什么?
1.1 镜像的本质
镜像是一个只读的模板 (Read-only Template),它包含了运行应用程序所需的一切:
- 代码 (Application Code)
- 运行时环境 (Runtime Environment):如 Node.js, Python。
- 依赖库 (Libraries & Dependencies)
- 配置文件 (Configuration)
- 基础操作系统 (Base Layer):如 Alpine, Ubuntu (通常是裁剪版)。
你可以把它想象成应用程序的“DNA”或者“快照 (Snapshot)”,一旦创建,其中的内容就是不可变的。
1.2 分层架构 (Layered Architecture)
Docker 镜像不是一个单一的大文件,而是由多层 (Layers) 组成的。
- 结构:每一层通常对应
Dockerfile中的一条指令。 - 优势:这种分层机制使得存储和传输非常高效。例如,如果多个镜像都使用
Ubuntu作为基础镜像,那么宿主机只需要存储一份Ubuntu的层,所有容器都可以共享它。
2. 镜像仓库 (Container Registries)
镜像构建好后,需要一个地方存储和分发,这就是镜像仓库。
2.1 核心作用
- 协作 (Collaboration):团队成员之间共享镜像。
- 版本控制 (Versioning):通过 Tag (标签) 追踪不同版本的镜像,方便回滚和更新。
- 安全性 (Security):企业级仓库通常提供漏洞扫描和访问控制。
- 自动化 (Automation):与 CI/CD 流水线集成,自动构建和推送。
2.2 仓库类型
- 公共仓库 (Public Registries):如 Docker Hub,对所有人开放,拥有海量开源软件镜像。
- 私有仓库 (Private Registries):用于存储专有软件或敏感数据。
- SaaS 服务:如 Docker Hub Private Repos, Quay.io。
- 自托管 (Self-Hosted):如 Harbor, JFrog Artifactory。
- 云厂商服务:AWS ECR, Google GCR, Azure ACR。
3. 编写 Dockerfile (Building Images)
手动安装环境太麻烦且不可复现。Dockerfile 是构建镜像的脚本文件,体现了 “Infrastructure as Code” 的理念。
3.1 核心指令解析
一个典型的 Dockerfile 结构如下:
1 | # 1. 指定基础镜像 (Base Image) |
- FROM: 每一份 Dockerfile 的起点。尽量选择轻量级的镜像(如
alpine版本)。 - WORKDIR: 相当于
cd,后续命令都会在这个目录下执行。 - COPY: 将宿主机的文件复制到容器内部。
- RUN: 在构建镜像时执行的命令(如安装软件、解压文件)。每执行一次
RUN就会建立一个新的层。 - CMD: 在启动容器时默认执行的命令。
3.2 构建与上下文
构建命令通常为:
1 | docker build -t my-app:v1 . |
注意最后的 .,它代表构建上下文 (Build Context)。Docker 客户端会将该目录下的所有文件发送给 Docker Daemon 进行构建。
4. 镜像优化与最佳实践 (Advanced Topics)
4.1 使用 .dockerignore
类似于 .gitignore。构建时,我们不应该把本地的 node_modules、日志文件、临时文件发送给 Docker Daemon。使用 .dockerignore 可以显著减小构建上下文的大小,加快构建速度并提高安全性。
4.2 多阶段构建 (Multistage Builds)
这是一个高级技巧,用于优化镜像体积。
- 问题:编译 Go 或 Java 应用需要安装大量的编译器和工具 (SDK),但运行只需要一个二进制文件。如果把 SDK 都打包进最终镜像,体积会非常大。
- 解决:使用多阶段构建。
- Stage 1 (Build): 包含编译器,负责编译代码。
- Stage 2 (Run): 仅包含基础 OS。
- 操作:从 Stage 1 复制编译好的产物到 Stage 2。最终镜像只包含 Stage 2 的内容,体积极小。
4.3 Distroless 镜像
这是一种为了安全性极致优化的镜像。
- 特点:不包含 Shell (bash/sh)、包管理器 (apt/apk) 等任何多余工具。
- 优势:体积微小,攻击面极小(黑客即使利用漏洞进入容器,也没有 Shell 可以执行命令)。
- 挑战:由于没有 Shell,调试 (Debug) 会变得非常困难。