typora/note/devops/docker/底层原理2——镜像.md
2024-12-12 10:48:55 +08:00

209 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

### 一、镜像概述
Docker 镜像包含运行应用程序所需的所有内容:代码、运行时、库、环境变量和配置文件。镜像是构建 Docker 容器的蓝图。它们是分层的,每一层都代表一个镜像构建的指令。当你创建一个新的镜像时,你会在一个基础镜像之上添加一个新的层,这个基础镜像可能是一个操作系统(如 Ubuntu 或 CentOS也可能是另一个已经包含了额外组件的镜像。每当你在镜像上执行一个操作如安装软件包或修改文件Docker 都会在镜像的顶部添加一个新的层
### 二、镜像核心技术——联合文件系统 Union File System
联合文件系统允许多个不同的文件系统被叠加在一起,形成单个文件系统。每一层都可以添加变更,而不影响其他层。广泛应用于 Linux 发行版中的 Live CD、Docker 镜像等场景。常见的联合文件系统有 AUFS、OverlayFS、Btrfs 等
联合文件系统的原理是将多个目录(称为分支)叠加在一起,这样就可以合并它们的内容。用户在访问文件或目录时,实际上是在访问一个由这些分支叠加而成的统一视图。下面是一些关键特点和工作原理:
- **分层结构:**在 UnionFS 中,每个分支都可以看作是一个层,层与层之间可以是只读或者可写的。这些层从下往上叠加,形成一个统一的文件系统。最下面的层通常是只读的,而最上面的层是可写的
- **只读和可写层:**只读层包含不变的数据,而可写层通常用于存储变更。这种结构使得基础数据(只读层)在多个应用中被重复利用,而不需要复制,从而节省空间
- **Copy-On-WriteCOW**这是 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
```