从业务数据的角度看,容器可以分为两类:无状态(stateless)容器和有状态(stateful)容器。
无状态是指容器在运行过程中不需要保存数据,每次访问的结果不依赖上一次访问,比如提供静态页面的 web 服务器。
有状态是指容器需要保存数据,而且数据会发生变化,访问的结果依赖之前请求的处理结果,最典型的就是数据库服务器。
简单来讲,状态(state)就是数据,如果容器需要处理并存储数据,它就是有状态的,反之则无状态。
Docker 是如何实现这个跨主机管理 data volume 方案的呢?
答案是 volume driver。
data volume 都是由 driver 管理的,创建 volume 时如果不特别指定,将使用 local
类型的 driver,即从 Docker Host 的本地目录中分配存储空间。如果要支持跨主机的 volume,则需要使用第三方 driver。
目前已经有很多可用的 driver,比如使用 Azure File Storage 的 driver,使用 GlusterFS 的 driver,完整的列表可参考 https://docs.docker.com/engine/extend/legacy_plugins/#volume-plugins
Rex-Ray driver,其原因是:
Rex-Ray 是开源的,而且社区活跃。
支持多种 backend,VirtualBox 的 Virtual Media、Amazon EBS、Ceph RBD、OpenStack Cinder 等。
支持多种操作系统,Ubuntu、CentOS、RHEL 和 CoreOS。
支持多种容器编排引擎,Docker Swarm、Kubernetes 和 Mesos。
Rex-Ray 安装使用方法非常简单
virtualbox平台虚拟机
docker1和docker2主机上操作
【1】Installation REX-Ray
curl -sSL https://rexray.io/install | sh -
【2】然后两台虚拟机创建并编辑 REX-Ray 的配置文件 /etc/rexray/config.yml
libstorage:
service: virtualbox
virtualbox:
endpoint: http://192.168.51.11:18083
volumePath: C:\share
controllerName: SATA
# libstorage-service 1 使用Virtualbox的Virtual media作为backend,提供data volue,生产环境中使用 ceph RBD 等
# virtualbox-endpoint 1 实验环境中提供backend 的地址
# virtualbox-volumePtah: 1 实验环境中提供backed的目录
# virtualbox-controllerName:1 controller 的名字
【3】在VirtualBox宿主机上启动vboxwebsrv服务
C:\Program Files\Oracle\VirtualBox\VBoxWebSrv.exe -H 0.0.0.0
【4】关闭 VirtualBox 的登录认证:
C:\Program Files\Oracle\VirtualBox\VBoxManage.exe setproperty websrvauthlibrary null
【5】在关机状态下修改虚拟机 docker1和 docker2 的 Storage 配置
1.关闭虚拟机docker1和docker2
2.删除IDE存储介质,保留SATA存储介质
3.设置SATA controller 的 port 数量的最大值 为 30
【6】开启docker1和docker2, 运行rexray volume ls 测试 Rex-Ray 是否能够正常工作
root@docker1:~# rexray volume ls
ID Name Status Size
c2b3c553-dc43-4df1-8a72-faa26a9ee861 docker1.vmdk attached 20
cec5b10d-8bc1-4326-bb9b-e3add075f3f1 docker2.vmdk unavailable 20
root@docker2:~# rexray volume ls
ID Name Status Size
c2b3c553-dc43-4df1-8a72-faa26a9ee861 docker1.vmdk unavailable 20
cec5b10d-8bc1-4326-bb9b-e3add075f3f1 docker2.vmdk attached 20
列表中的 volume 是当前 VirtualBox 所有的虚拟磁盘。准备就绪,当前实验环境如下图所示:
创建和使用 Rex-Ray volume
在 docker1 或 docker2 上执行如下命令创建 volume
rexray volume create --size 2 'c:\share\mysqldata'
--size 指定创建volume的大小,单位GB
或者
docker volume create --driver rexray --name=mysqldata --opt=size=2
最后是创建volume的绝对路径,因为 \ 是特殊字符,需要用单引号引起来
root@docker1:~# rexray volume create --size 2 'c:\share\mysqldata'
ID Name Status Size
cd335365-dea0-4e22-95ce-daa0258595e8 mysqldata available 2
root@docker1:~# rexray volume ls
ID Name Status Size
c2b3c553-dc43-4df1-8a72-faa26a9ee861 docker1.vmdk attached 20
cec5b10d-8bc1-4326-bb9b-e3add075f3f1 docker2.vmdk unavailable 20
cd335365-dea0-4e22-95ce-daa0258595e8 mysqldata available 2
root@docker1:~# docker volume ls
DRIVER VOLUME NAME
rexray docker1.vmdk
rexray docker2.vmdk
rexray mysqldata
volume mysqldata
创建成功,大小为 2GB。在 VirtualBox 宿主机中也能看到 mysqldata
创建mysql容器并使用Rex-Ray volume
root@docker1:~# docker run --name mydb_on_docker1 -v mysqldata:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=passw0rd -d mysql
-v mysqldata:/var/lib/mysql
将之前创建的 volume mount 到 MySQL 的数据目录。
root@docker1:~# docker volume inspect mysqldata
[
{
"CreatedAt": "0001-01-01T00:00:00Z",
"Driver": "rexray",
"Labels": null,
"Mountpoint": "",
"Name": "mysqldata",
"Options": null,
"Scope": "global",
"Status": {
"availabilityZone": "",
"fields": null,
"iops": 0,
"name": "mysqldata",
"server": "virtualbox",
"service": "virtualbox",
"size": 2,
"type": "HardDisk"
}
}
]
root@docker1:~# docker inspect mydb_on_docker1 | jq .[0].Mounts
[
{
"Type": "volume",
"Name": "mysqldata",
"Source": "",
"Destination": "/var/lib/mysql",
"Driver": "rexray",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
/var/lib/libstorage/volumes/mysqldata/data
被 mount 到了容器的目录 /var/lib/mysql
,这样 Rex-Ray volume mysqldata
就已经 mount 到了容器 mydb_on_docker1
。
下图可以看到 Rex-Ray volume mysqldata 已经挂载到docker1 上
当前实验拓扑如下图所示:
更新数据库
按照如下步骤更新 MySQL 数据:
① 进入容器 mydb_on_docker1。
② 登录数据库,输入容器启动时由环境变量 MYSQL_ROOT_PASSWORD 指定的密码。
③ 切换到数据库 mysql。
④ 创建数据库表 my_id。
⑤ 插入一条数据。
⑥ 确认数据已经写入。
执行 docker rm -f mydb_on_docker1
删除容器。
docker1上的容器已经被销毁了,将在 docker2 上创建新容器并重新使用 volume mysqldata。
最后可以看到,mysqldata 自动从docker1 上卸载了
在docker2上创建一个mysql容器,使用上面的 Rex-Ray volume mysqldata
root@docker2:~# docker run --name mydb_on_docker2 -v mysqldata:/var/lib/mysql -d mysql
本次docker run 不需要指定passwd ,新容器也使用相同的卷 mysqldata
,不过这次不需要指定环境变量 MYSQL_ROOT_PASSWORD
,因为密码已经保存到 mysqldata
里面了。
现在 Rex-Ray volume mysqldata
已经挂载到 docker2:
root@docker2:~# docker volume inspect mysqldata
[
{
"CreatedAt": "0001-01-01T00:00:00Z",
"Driver": "rexray",
"Labels": null,
"Mountpoint": "",
"Name": "mysqldata",
"Options": null,
"Scope": "global",
"Status": {
"availabilityZone": "",
"fields": null,
"iops": 0,
"name": "mysqldata",
"server": "virtualbox",
"service": "virtualbox",
"size": 2,
"type": "HardDisk"
}
}
]
root@docker2:~# docker inspect mydb_on_docker2 | jq .[0].Mounts
[
{
"Type": "volume",
"Name": "mysqldata",
"Source": "",
"Destination": "/var/lib/mysql",
"Driver": "rexray",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
登录数据库查看在docker1上新建的表和数据是否还在
① 进入到容器 mydb_on_docker2。
② 登录数据库,密码与 mydb_on_docker1 一致。
③ 切换到数据库 mysql。
④ 确认之前由 mydb_on_docker1 创建的表和写入的数据完好无损
当前实验拓扑如下:
Rex-Ray 可以提供跨主机的volume,起生命周期不依赖 Docker Host 和容器。是stateful 容器理想的数据存储方式。
如何使用其他storage provider 的 volume driver ,部署和配合 storage provider 会有所不同,不过 Docker 在使用 volume 的方式是一样的:
1、通过 docker volume create --driver 创建volume
2、创建容器时使用 -v 指定上一步中创建的volume
报错:
电脑ip变了,但rexray配置文件(/etc/rexray/config.yml)中服务端口用的ip仍然是之前的ip,可能是这个问题
修改配置文件如下(将endpoint中的ip改为现在宿主机的ip):