20 KiB
05.Docker数据管理
05.Docker数据管理
1. Docker数据管理
2. 数据管理
2.1 UnionFS(联合文件系统)
Docker 中的 UnionFS(联合文件系统)是一种分层、轻量级且高性能的文件系统,其核心功能是将多个目录内容联合挂载到同一个目录下,形成一个统一的文件系统视图。以下是其主要特点和作用:
2.1.1 核心特点
- 分层存储:UnionFS 可以将不同层次的文件和目录合并成单一的目录树。在 Docker 中,每一层可以代表一个镜像层,最低层通常是只读的基础镜像层,上面的层是可写的容器层。
- 写时复制(Copy-on-Write, CoW):当容器需要修改一个文件时,UnionFS 不会直接更改底层只读镜像中的文件,而是将更改写入到一个可写的上层。这样,原始镜像层保持不变,可以被多个容器共享。
- 隔离性:由于底层的只读镜像层保持不变,每个容器看到的是一个完整的文件系统视图,包括它们的改动,但这些改动仅存在于它们自己的可写层中。
- 性能优化:UnionFS 通过仅对发生更改的文件进行操作,以及通过页面缓存共享等机制,减少了磁盘 I/O 操作,加快了容器启动时间。
2.1.2 在 Docker 中的应用
- 镜像分层:Docker 镜像是由多个只读层叠加而成的,每一层都代表了镜像构建过程中的一个状态。UnionFS 将这些层联合起来,形成一个完整的文件系统。
- 容器运行时的文件系统:当启动一个容器时,Docker 会在镜像的最顶层添加一个新的可写层。容器的所有写操作都在这个可写层中进行,而不会影响到镜像的只读层。
- 镜像继承与共享:由于镜像的分层结构,新的镜像可以基于已有的镜像构建,只需添加新的层即可。同时,多个容器可以共享同一个镜像的只读层,极大地节省了磁盘空间。
2.1.3 常见的 UnionFS 实现
虽然 UnionFS 是一个理念,但 Linux 内核中有多种具体的实现方式,Docker 默认使用的是 Overlay2。Overlay2 是一种先进的联合文件系统实现,具有更好的性能和一些先进的功能,如页面缓存共享。
2.2 镜像层与可写层
在 Docker 中,镜像层和容器可写层是基于联合文件系统(UnionFS)实现的关键概念。它们共同构成了容器的文件系统结构,使得 Docker 能够高效地管理和运行容器。以下是对镜像层和容器可写层的详细解释:
2.2.1 一、镜像层
镜像层是 Docker 镜像的组成部分,每个镜像由多个只读层组成,这些层是不可修改的。
-
镜像层的生成
-
当你构建一个 Docker 镜像时,Dockerfile 中的每一条指令(如
RUN
、COPY
、ADD
等)都会生成一个新的镜像层。 -
例如,一个简单的 Dockerfile 如下:
FROM ubuntu:20.04 RUN apt-get update && apt-get install -y nginx COPY ./my_nginx.conf /etc/nginx/nginx.conf
- 第一层是基础镜像层,如
ubuntu:20.04
,这是从 Docker Hub 拉取的预构建镜像。 - 第二层是通过
RUN
指令安装 Nginx 生成的层,包含了安装过程中产生的所有文件和目录变化。 - 第三层是通过
COPY
指令将本地的my_nginx.conf
文件复制到镜像中的/etc/nginx/nginx.conf
位置生成的层。
- 第一层是基础镜像层,如
-
每一层都是基于前一层构建的,新的层只包含与前一层的差异部分。
-
-
镜像层的特点
- 只读性:镜像层是只读的,一旦创建就不能修改。如果需要修改镜像层中的内容,必须通过构建新的镜像层来实现。
- 共享性:多个容器可以共享同一个镜像层,因为镜像层是不可变的,这大大节省了磁盘空间。
- 不可变性:镜像层的不可变性保证了镜像的一致性和可重复性,无论在什么环境下运行,基于同一镜像启动的容器都具有相同的文件系统结构。
-
镜像层的作用
- 构建高效:通过分层构建,Docker 可以缓存中间层,避免重复构建相同的操作。例如,如果基础镜像层和安装 Nginx 的层已经构建过,再次构建时可以直接使用缓存的层,而不是重新执行命令。
- 节省空间:多个容器可以共享镜像层,减少了磁盘空间的占用。例如,10 个基于同一个基础镜像的容器,只需要存储一份基础镜像层,而不是每份都单独存储。
- 便于分发:镜像层的结构使得镜像可以方便地分发和共享。用户可以从 Docker Hub 等镜像仓库拉取镜像,而无需关心镜像的具体构建过程。
2.2.2 二、容器可写层
容器可写层是容器运行时特有的一个层,它是可写的,用于存储容器运行时产生的所有变更。
- 容器可写层的生成
- 当你启动一个容器时,Docker 会在镜像的最顶层添加一个新的可写层。这个可写层是容器独有的,用于存储容器运行时的文件系统变更。
- 例如,如果你在容器中创建了一个新文件、修改了一个现有文件或删除了一个文件,这些操作都会反映在容器可写层中,而不会影响到镜像层。
- 容器可写层的特点
- 可写性:容器可写层是可写的,容器运行时的所有文件系统操作(如创建、修改、删除文件)都在这个层中进行。
- 独立性:每个容器都有自己的可写层,容器之间的可写层是隔离的。一个容器的变更不会影响到其他容器。
- 临时性:容器可写层的内容在容器被删除时也会被删除。如果需要持久化数据,需要将数据存储在外部存储(如卷)中。
- 容器可写层的作用
- 隔离性:容器可写层保证了容器之间的隔离性。每个容器在自己的可写层中进行操作,不会影响到其他容器或镜像层。
- 灵活性:容器可写层允许容器在运行时动态地修改文件系统,而不会影响到镜像的原始状态。这使得容器可以灵活地运行各种应用程序。
- 数据持久化:虽然容器可写层的内容在容器删除时会被删除,但你可以通过挂载卷(Volumes)将数据持久化到宿主机或其他存储设备中,从而实现数据的持久化存储。
2.2.3 三、镜像层与容器可写层的关系
镜像层和容器可写层通过联合文件系统(UnionFS)联合起来,形成了容器的完整文件系统视图。
- 联合挂载
- Docker 使用联合文件系统将镜像层和容器可写层联合挂载到同一个目录下。从容器的角度来看,它看到的是一个完整的文件系统,包含了镜像层和容器可写层的内容。
- 例如,当你在容器中访问一个文件时,Docker 会先在容器可写层中查找该文件。如果找不到,就会在镜像层中查找。如果在镜像层中找到了文件,就会将该文件的内容返回给容器。
- 写时复制(Copy-on-Write)
- 当容器需要修改一个文件时,Docker 会使用写时复制机制。具体来说,Docker 会将文件从镜像层复制到容器可写层,然后在可写层中进行修改。这样,镜像层保持不变,而容器可写层存储了修改后的文件。
- 例如,假设镜像层中有一个文件
/etc/nginx/nginx.conf
,容器需要修改这个文件。Docker 会将该文件从镜像层复制到容器可写层,然后在可写层中进行修改。从容器的角度来看,它看到的是修改后的文件,而镜像层中的文件保持不变。
- 删除操作
- 当容器删除一个文件时,Docker 会在容器可写层中记录一个删除操作,而不是真正删除镜像层中的文件。这样,镜像层保持不变,而容器可写层记录了文件的删除状态。
- 例如,假设容器删除了一个文件
/etc/nginx/nginx.conf
,Docker 会在容器可写层中记录一个删除标记。从容器的角度来看,该文件已经被删除,而镜像层中的文件仍然存在。
2.2.4 总结
- 镜像层:是 Docker 镜像的组成部分,是只读的、不可变的,多个容器可以共享镜像层。镜像层通过分层构建,提高了构建效率、节省了磁盘空间,并保证了镜像的一致性和可重复性。
- 容器可写层:是容器运行时的可写层,用于存储容器运行时的文件系统变更。容器可写层是独立的、可写的、临时的,保证了容器之间的隔离性和运行时的灵活性。
- 联合文件系统(UnionFS):将镜像层和容器可写层联合挂载,形成了容器的完整文件系统视图。通过写时复制机制,Docker 在不影响镜像层的情况下,允许容器在可写层中进行文件系统操作。
2.3 查看镜像的详细信息
2.3.1 一、查看镜像数据信息
[root@localhost nginx]# docker inspect nginx_games:v1
"Architecture": "amd64",
"Os": "linux",
"Size": 685997316,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/ilm8ifbi2gcrqg156w7kbu22f/diff:/var/lib/docker/overlay2/u51fr5eul9csiwghxmnm1acsi/diff:/var/lib/docker/overlay2/lo6sgoxbliga9l2qqqxcu2tvp/diff:/var/lib/docker/overlay2/bi4orr0yujicfufabnw7u8tym/diff:/var/lib/docker/overlay2/e51d5c1c74a99e1b1e41980bb9270fcba562976e40ae7dbf65ff585689a783d2/diff",
"MergedDir": "/var/lib/docker/overlay2/talgtlohecyw3kt8d8idpzw4g/merged",
"UpperDir": "/var/lib/docker/overlay2/talgtlohecyw3kt8d8idpzw4g/diff",
"WorkDir": "/var/lib/docker/overlay2/talgtlohecyw3kt8d8idpzw4g/work"
LoweDir:image镜像层本身(只读)
UpperDir:容器的上层读写层
MergeDir:容器的文件系统,使用Union FS(联合文件系统)将镜像层和容器层合并给容器使用
WorkDir:容器在宿主机的工作目录
2.3.2 二、查看镜像层构建过程
[root@localhost nginx]# docker history nginx_games:v1
IMAGE CREATED CREATED BY SIZE COMMENT
9c86d96dfba0 25 hours ago CMD ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0
<missing> 25 hours ago EXPOSE map[443/tcp:{} 80/tcp:{}] 0B buildkit.dockerfile.v0
<missing> 25 hours ago ADD games.tar.gz /usr/local/nginx/html/ # bu… 164MB buildkit.dockerfile.v0
<missing> 25 hours ago RUN /bin/sh -c useradd -s /sbin/nologin ngin… 297kB buildkit.dockerfile.v0
<missing> 25 hours ago RUN /bin/sh -c cd /usr/local/src/nginx-1.22.… 16.6MB buildkit.dockerfile.v0
<missing> 25 hours ago ADD nginx-1.22.0.tar.gz /usr/local/src/ # bu… 6.46MB buildkit.dockerfile.v0
<missing> 25 hours ago RUN /bin/sh -c yum install -y vim wget unzip… 323MB buildkit.dockerfile.v0
<missing> 25 hours ago MAINTAINER Eagle_nls 2898485992@qq.com 0B buildkit.dockerfile.v0
<missing> 16 months ago CMD ["/bin/bash"] 0B buildkit.dockerfile.v0
<missing> 16 months ago ADD layer.tar.xz / # buildkit 176MB buildkit.dockerfile.v0
如果想要缩小所构建镜像的大小,我们可以尝试少创建镜像层,在一层中多做一些事情,尽可能减少RUN命令
3. 数据卷
3.1 什么是数据卷?
数据卷实际上就是宿主机上的目录或者是文件,可以被直接mount到容器当中使用。
实际生产环境中,需要针对不同类型的服务、不同类型的数据存储要求做相应的规划,最终保证服务的可扩展性、稳定性以及数据的安全性。
3.2 数据卷案例
- 创建目录并准备页面
[root@docker-server1 ~]# mkdir -p /data/web
[root@docker-server1 ~]# echo 'eaglslab nginx test!' > /data/web/index.html
[root@docker-server1 ~]# cat /data/web/index.html
eaglslab nginx test
- 启动两个容器并验证数据
[root@docker-server1 ~]# docker run -d -it --name web1 -v /data/web/:/usr/share/nginx/html/ -p 8080:80 nginx
588c494dc9098e0a43e15bce3162c34676dd981609edc32d46bf4beb59b9cf19
[root@docker-server1 ~]# docker run -d -it --name web2 -v /data/web/:/usr/share/nginx/html/ -p 8081:80 nginx
ff6b3731a9ba3e0f91d2c8d89bb6573eb5e5a9b840163bc1122a9e5678d108b7
[root@docker-server1 ~]# curl 192.168.175.10:8080
eaglslab nginx test!
[root@docker-server1 ~]# curl 192.168.175.10:8081
eaglslab nginx test!
[root@docker-server1 ~]# echo 'hello world!' > /data/web/index.html
[root@docker-server1 ~]# curl 192.168.175.10:8080
hello world!
[root@docker-server1 ~]# curl 192.168.175.10:8081
hello world!
- 进入到容器内测试写入数据
[root@docker-server1 ~]# docker exec -it web1 bash
root@588c494dc909:/# echo 'docker test!' > /usr/share/nginx/html/index.html
[root@docker-server1 ~]# curl 192.168.175.10:8080
docker test!
[root@docker-server1 ~]# curl 192.168.175.10:8081
docker test!
- 尝试只读挂载
# 删除容器的时候不会删除宿主机的目录
[root@docker-server1 ~]# docker rm -fv web1
web1
[root@docker-server1 ~]# docker rm -fv web2
web2
[root@docker-server1 ~]# cat /data/web/index.html
docker test!
# 通过只读方式挂载以后,在容器内部是不允许修改数据的
[root@docker-server1 ~]# docker run -d -it --name web1 -v /data/web/:/usr/share/nginx/html/:ro -p 8080:80 nginx
a395b27958ca0cdcf52a86bd17813dcbcda4ed774895adcc99e85fc114ab84ff
[root@docker-server1 ~]# docker exec -it web1 bash
root@a395b27958ca:/# echo 123 > /usr/share/nginx/html/index.html
bash: /usr/share/nginx/html/index.html: Read-only file system
- 文件挂载
[root@docker-server1 ~]# docker run -d -it --name web2 -v /data/web/index.html:/usr/share/nginx/html/index.html:ro -p 8081:80 nginx
4b34c957372d314cdb0f85d7e2c65b095615adfe3051ae6b4266b7bacd50f374
[root@docker-server1 ~]# curl 192.168.175.10:8081
docker test!
3.3 数据卷特点
- 数据卷是宿主机的目录或者文件,并且可以在多个容器之间共同使用
- 在宿主机对数据卷更改数据后会在所有容器里面会立即更新
- 数据卷的数据可以持久保存,即使删除使用该数据卷卷的容器也不影响
- 在容器里面写入数据不会影响到镜像本身(隔离性)。
- 需要挂载多个目录或者文件的时候可以使用多个-v参数指定
- 数据卷使用场景包括日志输出、静态web页面、应用配置文件、多容器间目录或文件共享
3.4 数据卷容器
3.4.1 什么是数据卷容器
数据卷容器是一个普通的容器,专门用于提供数据卷供其他容器挂载。它允许用户创建一个专门用于数据存储的容器,并将其数据卷挂载到其他容器中。数据卷容器的主要用途是将数据卷的生命周期与应用容器分离,使数据可以在容器之间共享和持久化。
3.4.2 数据卷容器的用途
- 数据持久化:数据卷容器可以确保数据即使在容器被删除后也不会丢失。例如,对于数据库应用,数据卷容器可以持久化数据库文件,避免因容器删除而导致数据丢失。
- 数据共享:多个容器可以通过挂载同一个数据卷容器来共享数据。这在多容器应用中非常有用,例如在微服务架构中,多个服务容器可以共享数据库数据。
- 备份与恢复:数据卷容器可以用于备份和恢复数据。通过将数据卷容器中的数据卷备份到宿主机或其他存储设备,可以在需要时恢复数据。
- 迁移数据:数据卷容器可以方便地迁移数据。通过将数据卷容器中的数据卷迁移到其他主机,可以快速实现数据的迁移。
3.4.3 数据卷容器与本地数据挂载的区别
特性 | 数据卷容器 | 本地数据挂载 |
---|---|---|
目录来源 | Docker 自动创建的目录 | 宿主机上已存在的目录 |
适用场景 | 数据持久化、容器间共享数据 | 开发调试、快速文件同步 |
容器间共享 | 支持 | 不支持 |
宿主机文件系统依赖 | 无依赖 | 依赖宿主机文件系统 |
数据持久化 | 数据卷的生命周期独立于容器,即使容器被删除,数据卷仍然存在 | 如果容器被删除,挂载的目录和文件仍然存在,但需要手动管理 |
数据初始化 | 如果宿主机没有对应的文件,数据卷容器会自动将容器运行所需的文件复制到数据卷中 | 如果宿主机没有对应的文件,容器可能会因缺少运行所需的文件而出错 |
数据覆盖 | 数据卷中的数据会覆盖容器内的数据 | 容器内的数据会覆盖宿主机上的数据 |
3.4.4 实例演示
- 先启动一个卷容器Server
[root@docker-server1 ~]# docker run -d --name nginx-web -v /data/web/:/usr/share/nginx/html/:ro -p 8081:80 nginx
- 启动两个客户端容器
[root@docker-server1 ~]# docker run -d --name web1 -p 8082:80 --volumes-from nginx-web nginx:latest
ac22faa405ec07c065042465cd7f9d456be891effdd5d13d9571b96ef9c550f7
[root@docker-server1 ~]# docker run -d --name web2 -p 8083:80 --volumes-from nginx-web nginx:latest
e084845475b01dedfdae7362f6fbece7b5ab57ff6289c8c9bf08251f5ba448ed
- 访问测试
[root@docker-server1 ~]# curl 192.168.175.10:8081
docker test!
[root@docker-server1 ~]# curl 192.168.175.10:8082
docker test!
[root@docker-server1 ~]# curl 192.168.175.10:8083
docker test!
- 停止卷容器可以创建新容器
[root@docker-server1 ~]# docker stop nginx-web
nginx-web
[root@docker-server1 ~]# docker run -d -it --name web3 -p 8084:80 --volumes-from nginx-web nginx:latest
6ebd95c132ee1a9e4b43d1849efc628ca7185187a59d70b3816ff16dd47b6e8e
[root@docker-server1 ~]# curl 192.168.175.10:8084
docker test!
- 删除卷容器之后不可以再创建新容器
[root@docker-server1 ~]# docker rm -fv nginx-web
nginx-web
[root@docker-server1 ~]# docker run -d -it --name web4 -p 8085:80 --volumes-from nginx-web nginx:latest
docker: Error response from daemon: No such container: nginx-web.
See 'docker run --help'.
# 但是之前已经创建好的容器不会有任何影响
[root@docker-server1 ~]# curl 192.168.175.10:8082
docker test!
3.4.5 总结
在当前环境下,即使把提供卷的容器Server删除,已经运行的容器Client依然可以使用挂载的卷,因为容器是通过挂载的方式访问数据的,但是无法创建新的卷容器客户端,但是再把卷容器Server创建后即可正常创建卷容器client,此方式可以用于线上共享数据目录等环境,因为即使数据卷容器被删除了,其他已经运行的容器依然可以挂载使用
数据卷容器可以作为共享的方式为其他容器提供文件共享,可以在容器生成中启动一个实例挂载本地的目录,然后其他的容器分别挂载此容器的目录,即可保证各个容器之间的数据一致性。