容器数据持久化
容器数据管理
容器写数据原理:
- Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层
- 基于写实复制(cow),只读层的内容需要修改时,把文件复制到读写层,在读写层进行修改,而只读层的数据没有修改,但此时还是在容器内部的数据持久化,容器删除修改后的数据也删除,但使用volume可以将数据存在宿主机
容器的数据管理:
Docker镜像是分层设计的,镜像层是只读的,通过镜像启动的容器添加了一层可读写的文件系统,用户写入的数据都保存在这一层中
容器的数据分层目录:
- LowerDir: image镜像层,容器基于哪个镜像运行的,只读层
- UpperDir: 容器的上层(读写层),容器变化的数据存放在此处
- MergedDir: 容器的文件系统,使用Union-FS(联合文件系统)将lowerdir和upperdir合并完成后给容器使用,最终呈现给用户的统一视图,也就是容器中的根文件系统
- WorkDir: 容器在宿主机的工作目录,挂载后内容会被清空,且在使用过程中其内容用户不可见
查看分层数据目录: docker inspect n1 |grep -A 5 Data
哪些数据需要持久化:
有状态协议就是就通信双方要记住双方,并且共享一些信息。而无状态协议的通信每次都是独立的,与上一次的通信没什么关系
"状态”可以理解为“记忆”,有状态对应有记忆,无状态对应无记忆
数据持久化方式:
如果要将写入到容器的数据永久保存,则需要将容器中的数据保存到宿主机的指定目录
两种方式:
- 数据卷(Data Volume),直接将宿主机目录挂载到容器的指定目录,推荐使用
- 数据卷容器(Data Volume Containe),间接使用宿主机空间,数据卷容器是将物理机的目录挂载到一个专门的数据卷容器(做服务器),其他容器通过数据卷容器读写宿主机的数据,此方法不常用
数据卷:
数据卷使用场景:
- 数据库
- 日志输出
- 静态web页面
- 应用配置文件
- 多容器间目录或文件共享
数据卷特点:
- 数据卷是目录或文件,且可以在多个容器之间共同使用。实现同期之间共享和重用
- 对数据卷更改数据在所有容器里面会立即更新
- 数据卷的数据可以持久化保存,删除容器后仍然存在
- 在容器里面写入数据不会影响到镜像
- 依赖于宿主机目录,宿主机出问题,容器会受影响,当宿主机较多时,不方便统一管理
- 匿名和命名数据卷在容器启动时初始化,如果宿主机目录有数据,容器内也能看到数据
数据卷使用方法:
三种方法:
- 指定文件映射: 运行时指定宿主机的具体路径和容器路径的挂载关系
- 匿名卷: 只指定容器内目录路径充当挂载点,docker自动指定宿主机的路径进行挂载,把容器内的目录存下来,存在哪不管,由docker决定宿主机存储位置
- 命名卷: 指定数据卷的名称和容器路径的挂载关系
用法:
创建数据卷:
docker run -v [host-src:]container-dest[:选项]
选项:
ro 从容器内对数据卷是只读,默认为可读可写
rw 容器对此数据卷可读写
删除数据卷:
docker rm -v 只能删除匿名卷
docker volume rm `docker volume ls -q` 删除所有卷
docker volume命令:
docker volume cmd [选项] 卷
cmd命令:
create 创卷卷
inspect 显示详细信息
-f string 指定显示内容
ls
-q 只显示卷名
-f 内容 过滤显示
prune 清理空间
-f 强制删除
rm 删除卷
-f 强制删除
使用数据卷方法
方式1:指定映射关系
-v <宿主机绝对路径目录/文件>:<容器目录/文件>[:ro]
方式2:指定容器内路径,宿主机路径自动生成:/var/lib/docker/volumes/<卷ID>/_data目录
-v <容器内路径>
方式3:数据卷名和容器路径,固定的存放在/var/lib/docker/volumes/<卷名>/_data
-v <卷名>:<容器目录路径> 自动生成卷
docker volume create 卷名 手动创建卷
docker run -d -P 80 --name ngx1 -v vol1:/data/html nginx
指定物理机和容器目录映射方式:
例:本地网页,给nginx容器使用
mkdir /data/web
echo "nginx web v1" > /data/web/index.html
docker run -dp 81:80 -v /data/web:/opt/nginx/html --name n1 hj-ngx-ctos8:v3
docker run -dp 82:80 -v /data/web:/opt/nginx/html --name n2 hj-ngx-ctos8:v3
例:mysql容器,数据库持久化
mkdir /data/mysql
tee env.list <<EOF
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=hj
MYSQL_USER=hj
MYSQL_PASSWORD=123456
EOF
cat /root/mysql <<eof
[mysqld]
skip-name-resolve
bin-log
eof
docker pull mysql:5.7.30
docker run -dp 3306:3306 -v /data/mysql:/var/lib/mysql -v /root/mysql:/etc/mysql/conf.d/ --env-file=/opt/env.list --name sql mysql:5.7.30
匿名卷:
宿主机随机生成目录
docker run -dp 80:80 -v /usr/share/nginx/html --name n1 nginx
docker rm -fv n1 删除容器时删除卷,-v只能用来删除匿名卷
命名数据卷:
就是把匿名卷随机生成的卷id变成指定卷名
docker volume create hj_vol
docker volume ls
#当数据卷不存在时,直接指定会自动创建
docker run -dp 80:80 -v hj_vol:/opt/nginx/html --name n1 hj-ngx-ctos8:v3
容器卷:
由于匿名卷不能多个容器共同使用,但基于容器卷方式,可以将一个数据卷提供给多个容器使用
A容器做服务器,他使用一个数据卷
B和C容器做客户端,她们使用A容器的数据卷
注意:
- B、C容器除了创建时需要依赖A容器,创建成功后就不在依赖
- 如A容器停止状态时,D容器还是能基于A的数据卷创建;但是A容器被删除了,D容器就无法基于A创建
- 当B、C、D容器都创建且运行成功后,A容器被删除并不会影响其他的使用
docker run命令实现:
指定数据卷的容器
docker run --volumes-from 容器主机
为nginx做共享容器卷:
1)A容器
docker run -d --name ctos -v /data/web:/opt/nginx/html centos tail -f /etc/hosts
2)B和C容器
docker run -dp 80:80 --name n1 --volumes-from ctos hj-ngx-ctos8:v3
docker run -dp 81:80 --name n2 --volumes-from ctos hj-ngx-ctos8:v3
docker inspect n1|grep -A 8 Mounts 查看卷挂载
使用匿名卷时,做数据持久化:
匿名卷时不方便查询物理机的存储位置,此时可以再开一个容器,这个容器也是使用共享容器卷,但再指定一个本地数据卷,把容器卷的内容保存在自己的数据卷
1)A容器用匿名卷
docker run -dt --name al -v /data alpine tail -f /etc/hosts
2)B容器做数据持久备份
docker run -it --rm --name bak -v /opt/bak:/bak --volumes-from al centos tar czvf /bak/bak.tgz /data/
3)模拟A容器数据丢失
docker exec -it al sh
rm -rf /data
4)用B容器的备份恢复数据
docker run -it --rm --name bak -v /opt/bak:/bak --volumes-from al centos sh -c 'tar xzvf /bak/bak.tgz -C /'