209 lines
10 KiB
Markdown
209 lines
10 KiB
Markdown
### 一、镜像概述
|
||
|
||
Docker 镜像包含运行应用程序所需的所有内容:代码、运行时、库、环境变量和配置文件。镜像是构建 Docker 容器的蓝图。它们是分层的,每一层都代表一个镜像构建的指令。当你创建一个新的镜像时,你会在一个基础镜像之上添加一个新的层,这个基础镜像可能是一个操作系统(如 Ubuntu 或 CentOS),也可能是另一个已经包含了额外组件的镜像。每当你在镜像上执行一个操作(如安装软件包或修改文件),Docker 都会在镜像的顶部添加一个新的层
|
||
|
||
|
||
|
||
### 二、镜像核心技术——联合文件系统 Union File System
|
||
|
||
联合文件系统允许多个不同的文件系统被叠加在一起,形成单个文件系统。每一层都可以添加变更,而不影响其他层。广泛应用于 Linux 发行版中的 Live CD、Docker 镜像等场景。常见的联合文件系统有 AUFS、OverlayFS、Btrfs 等
|
||
|
||
联合文件系统的原理是将多个目录(称为分支)叠加在一起,这样就可以合并它们的内容。用户在访问文件或目录时,实际上是在访问一个由这些分支叠加而成的统一视图。下面是一些关键特点和工作原理:
|
||
|
||
- **分层结构:**在 UnionFS 中,每个分支都可以看作是一个层,层与层之间可以是只读或者可写的。这些层从下往上叠加,形成一个统一的文件系统。最下面的层通常是只读的,而最上面的层是可写的
|
||
- **只读和可写层:**只读层包含不变的数据,而可写层通常用于存储变更。这种结构使得基础数据(只读层)在多个应用中被重复利用,而不需要复制,从而节省空间
|
||
- **Copy-On-Write(COW):**这是 UnionFS 的一种核心策略。当需要对文件进行修改时,如果该文件处于只读层,则首先会将该文件复制到最上面的可写层,然后再进行修改。这个过程称为“写时复制”,意味着只有在需要修改时,文件的副本才会被创建
|
||
- **文件和目录的合并视图:**从用户的角度来看,叠加在一起的所有层就像是一个普通的文件系统。如果多个层中包含了相同的文件或目录,UnionFS 按照一定的优先级规则(通常是最上面的层优先)来决定哪个版本对用户可见
|
||
- **删除和修改:**当删除或修改一个文件时,UnionFS 会在可写层创建一个特殊的标记(白板或删除标记),表示该文件在这个层被删除或修改了。即使底层的只读分支中仍然存在这个文件的原始版本,用户也看不到
|
||
- **透明性:**对于最终用户和应用程序来说,UnionFS 提供了一个透明的文件系统接口,使得它们无需关心底层的分层和叠加细节
|
||
|
||
### 三、镜像核心技术——写时复制 Copy On Write
|
||
|
||
一种优化策略,用于在容器中管理文件系统的写入操作
|
||
|
||
#### 基本原理
|
||
|
||
1. **初始状态:** 当容器启动时,文件系统的各个层次被堆叠在一起,形成一个联合文件系统。这些层次中的每一个层都是只读的
|
||
2. **写操作触发:** 当容器需要对文件系统进行写操作时,例如创建、修改或删除文件,"Copy-On-Write"被触发
|
||
3. **创建副本:** 联合文件系统不直接在底层文件系统上执行写操作。相反,它在顶层的可写层创建一个被写入的文件或目录的副本
|
||
4. **仅在需要时复制:** 副本的创建是按需进行的,只有在写入操作发生时才会复制相关的文件或目录。直到写入操作发生,原始文件系统层仍然是只读的
|
||
|
||
#### 优势与好处
|
||
|
||
1. **避免污染底层层次:** "Copy-On-Write"策略确保了底层文件系统层不会被写入,因此原始镜像或者其他容器共享的底层层次不会被修改。这有助于维护原始镜像的不变性
|
||
2. **节省存储空间:** 由于只有在写入操作发生时才会创建副本,"Copy-On-Write"减少了对存储空间的需求。多个容器可以共享相同的底层层次,只需保存它们各自的修改,而不必复制整个文件系统
|
||
3. **快速创建副本:** 由于只有在需要时才复制文件,"Copy-On-Write"使得容器可以快速创建修改,而不需要复制整个文件系统,提高了性能和效率
|
||
4. **隔离写入操作:** "Copy-On-Write"确保了容器之间的文件写入操作是相互隔离的。每个容器都有自己的写入层,使得它们可以独立地对文件系统进行修改,而不会相互影响
|
||
|
||
### 四、镜像制作
|
||
|
||
#### 技术
|
||
|
||
1. **Dockerfile:** Docker 使用 Dockerfile 来定义和描述镜像的构建步骤。Dockerfile 是一个文本文件,包含了从基础镜像开始,逐步添加、配置和操作的指令,最终构建出一个新的镜像。
|
||
2. **基础镜像:** 基础镜像是构建其他镜像的起点,它通常包含了操作系统和基本的运行时环境。选择适当的基础镜像对于镜像的性能和大小都有影响。
|
||
3. **Docker CLI:** Docker 命令行工具是与 Docker 引擎进行交互的主要方式。通过 Docker CLI,可以执行构建、运行、推送等操作,对 Docker 镜像进行管理。
|
||
4. **Docker Hub:** Docker Hub 是一个中央仓库,用于存储和分享 Docker 镜像。用户可以将自己构建的镜像推送到 Docker Hub,也可以从 Docker Hub 拉取公共镜像
|
||
|
||
#### 流程
|
||
|
||
1. **创建 Dockerfile:** 首先,通过创建一个 Dockerfile 来定义镜像的构建步骤。Dockerfile 包含了一系列指令,例如基础镜像的选择、软件的安装、配置文件的添加等
|
||
|
||
```dockerfile
|
||
FROM base_image:tag
|
||
RUN apt-get update && apt-get install -y software
|
||
COPY local-files /app
|
||
```
|
||
|
||
2. **构建镜像:** 使用 `docker build` 命令执行 Dockerfile 中定义的构建步骤。这将会逐步执行每个指令,生成一个新的 Docker 镜像
|
||
|
||
```bash
|
||
docker build -t my_custom_image:tag .
|
||
```
|
||
|
||
3. **运行容器:** 可以使用 `docker run` 命令基于刚刚构建的镜像启动容器。在容器中,你可以测试和验证构建的应用程序或服务
|
||
|
||
```bash
|
||
docker run -it my_custom_image:tag
|
||
```
|
||
|
||
4. **推送到仓库:** 如果你想分享或备份你的镜像,可以使用 `docker push` 命令将镜像推送到 Docker Hub 或其他容器仓库
|
||
|
||
```bash
|
||
docker push my_custom_image:tag
|
||
```
|
||
|
||
5. 持续集成(可选):** 对于大型项目或团队,可以考虑将 Docker 镜像的构建过程整合到持续集成(CI)流程中,确保代码变更触发自动的构建和测试
|
||
|
||
#### Dockerfile编写关键指令
|
||
|
||
1. **FROM:** 指定基础镜像,所有其他指令都基于该镜像。
|
||
|
||
```dockerfile
|
||
FROM ubuntu:20.04
|
||
```
|
||
|
||
2. **LABEL:** 为镜像添加元数据,通常用于提供版本、描述等信息。
|
||
|
||
```dockerfile
|
||
LABEL maintainer="your-name"
|
||
```
|
||
|
||
3. **RUN:** 在镜像中执行命令,用于安装软件包、配置环境等。
|
||
|
||
```dockerfile
|
||
RUN apt-get update && apt-get install -y software
|
||
```
|
||
|
||
4. **COPY:** 将文件从主机复制到镜像中。
|
||
|
||
```dockerfile
|
||
COPY local-files /app
|
||
```
|
||
|
||
5. **ADD:** 类似于 COPY,但可以处理 URL 和解压缩 tar 文件。
|
||
|
||
```dockerfile
|
||
ADD https://example.com/file.tar.gz /app
|
||
```
|
||
|
||
6. **WORKDIR:** 设置工作目录,后续的相对路径都相对于该目录。
|
||
|
||
```dockerfile
|
||
WORKDIR /app
|
||
```
|
||
|
||
7. **ENV:** 设置环境变量。
|
||
|
||
```dockerfile
|
||
ENV MY_VARIABLE=my-value
|
||
```
|
||
|
||
8. **EXPOSE:** 声明容器运行时监听的网络端口。
|
||
|
||
```dockerfile
|
||
EXPOSE 80
|
||
```
|
||
|
||
9. **CMD:** 指定容器启动时要运行的命令。可以有多个 CMD,但只有最后一个生效。
|
||
|
||
```dockerfile
|
||
CMD ["executable", "param1", "param2"]
|
||
```
|
||
|
||
10. **ENTRYPOINT:** 指定容器启动时要运行的命令,与 CMD 结合使用。CMD 提供默认参数。
|
||
|
||
```dockerfile
|
||
ENTRYPOINT ["executable", "param1", "param2"]
|
||
```
|
||
|
||
11. **VOLUME:** 创建挂载点,用于持久化存储或与其他容器共享数据。
|
||
|
||
```dockerfile
|
||
VOLUME /data
|
||
```
|
||
|
||
12. **USER:** 设置运行时的用户名或 UID。
|
||
|
||
```dockerfile
|
||
USER username
|
||
```
|
||
|
||
13. **ARG:** 定义构建时的参数,可通过 `docker build` 命令传递。
|
||
|
||
```dockerfile
|
||
ARG version=latest
|
||
```
|
||
|
||
|
||
|
||
### 五、镜像存储与分发
|
||
|
||
#### 存储方式:
|
||
|
||
1. **本地文件系统:**
|
||
- Docker 镜像可以直接存储在本地文件系统上。这适用于开发和测试阶段,以及在单机环境中使用。
|
||
2. **Docker Hub 和其他 Registry:**
|
||
- Docker Hub 是 Docker 官方提供的中央镜像仓库,允许用户将镜像上传至其中,并从中下载。私有仓库(如 Harbor、Amazon ECR、Azure Container Registry 等)也提供了类似的功能,适用于企业内部或有特殊需求的场景。
|
||
3. **Docker Volume:**
|
||
- Docker Volume 用于持久化存储容器数据,但也可以用来存储镜像。这种方式适用于需要在容器之间共享数据的场景,但并不是首选的镜像存储方式。
|
||
4. **分布式存储系统:**
|
||
- 在某些场景中,可以使用分布式存储系统(如 Ceph、GlusterFS、NFS 等)来存储 Docker 镜像。这种方式允许多个 Docker 主机共享相同的存储,提供高可用性和扩展性。
|
||
|
||
#### 分发方式:
|
||
|
||
1. **Docker Push 和 Pull:**
|
||
|
||
使用 `docker push` 命令将本地构建的镜像上传到 Docker Hub 或其他 Registry,并使用 `docker pull` 命令在其他机器上下载镜像。这是最常见的分发方式。
|
||
|
||
```bash
|
||
# 将镜像推送至 Docker Hub
|
||
docker push username/repository:tag
|
||
|
||
# 在其他机器上拉取镜像
|
||
docker pull username/repository:tag
|
||
```
|
||
|
||
**Docker Save 和 Load:**
|
||
|
||
使用 `docker save` 命令将镜像保存为 tar 文件,然后通过 `docker load` 命令在其他机器上加载。这种方式适用于离线环境或需要手动迁移镜像的情况。
|
||
|
||
```bash
|
||
# 将镜像保存为 tar 文件
|
||
docker save -o image.tar username/repository:tag
|
||
|
||
# 在其他机器上加载镜像
|
||
docker load -i image.tar
|
||
```
|
||
|
||
**导出和导入容器快照:**
|
||
|
||
使用 `docker export` 命令导出容器快照,然后使用 `docker import` 命令导入为镜像。这种方式适用于将容器快照分享给其他人。
|
||
|
||
```bash
|
||
# 导出容器快照
|
||
docker export container_id > container.tar
|
||
|
||
# 导入为镜像
|
||
cat container.tar | docker import - username/repository:tag
|
||
```
|