Docker日渐成为生产环境中越来越重要的基础架构,除了传统的轻负载、无状态应用,逐步也开始走入类似于DB的环境。随之而来的是对容器数据持久化要求越来越多。
Docker自身提供了多种数据持久化的方案,例如Bind Mount、Docker Managed Volume、Data-packed Volume Container等。无论哪种方式,都要依赖Docker宿主机的存储,当宿主机出现故障、Docker需要漂移时,会出现持久化数据无法访问的情况。
要解决此问题,需要将Docker使用的持久化存储从宿主机独立出来提供给Docker使用。NAS恰好可以满足此需求;而在Azure上的files storage提供了基于SMB2、3的NAS访问,可以作为Docker的持久化存储的目标。
配置环境
Docker主机
在Azure创建一台Centos 7.4作为宿主机,登陆后安装Docker软件:sudo yum install -y docker*
启动Docker服务:sudo systemctl start docker
运行一个httpd的Docker,将宿主机端口80映射给该Docker:sudo docker run -d -p 80:80 httpd
访问Docker提供的httpd服务,正常:
共享存储
创建一个通用存储账号,并在其下创建Files Storage:
点击Connect并记下linux下的连接命令:
Tips:记住将命令中的[mount point]更换为实际加载点。很多次被询问为什么执行不成功发现是这里没修改
Docker加载共享存储
Blind Mount
Blind Mount是Docker原生提供的将宿主机存储映射给Docker的方式,通过-v参数指定原卷和目标卷。
共享存储挂载给宿主机后,可以作为主机存储资源映射给Docker。下边测试这种方案是否可行。
在宿主机建立挂载点/mnt/smb,并挂载Files Storage:sudo mkdir /mnt/smb
sudo mount -t cifs //dockersto.file.core.windows.net/docker /mnt/smb -o vers=3.0,username=dockersto,password=8XOUIi+lUsSsKXrSKU6SVOgTuPxaPb9pbPiNoHNdUYRbkLPbcVX85ynk7wWmB5zZIILjnvEs3OTn7XDuBYWgpg==,dir_mode=0777,file_mode=0777,sec=ntlmssp
检查挂载情况可看到成功挂载:
运行一个Centos的Docker,并通过-v参数将宿主机的/mnt/smb映射给Docker里的/mnt:sudo docker run -it -v /mnt/smb:/mnt centos
由于使用了-it参数,所以登录后自动进入Docker的sh环境。
检查Docker里的存储挂载情况:
可以看到共享的Files Storage通过宿主机映射到了Docker指定的目录/mnt。
在该目录下创建一个文件(由于权限问题,先将宿主机的selinux禁用才能成功):
检查Azure Files Storage,可以看到创建的文件:
Docker直接挂载
Docker里也可以直接执行mount指令挂载共享存储。
启动一个没有主机映射的Docker:sudo docker run -it centos
直接在Docker里mount共享存储:
出现权限错误。
这是由于安全管理造成,需要在运行Docker时用–privileged=true提升Docker的权限:sudo docker run -it --privileged=true centos
重新运行Docker后挂载共享存储:
因为Centos的Docker镜像里没有cifs文件系统支持,需要手工安装:yum install -y cifs*
再次执行mount命令,顺利挂载:
可以看到,无论是宿主机挂载映射给Docker还是Docker里直接挂载,都可以实现将共享存储作为Docker持久化存储,避免因为宿主机原因导致的数据丢失。
文件系统兼容问题
在Docker里执行mount命令检查,可以看到无论哪种方式,Docker并不改变文件系统类型,通过Files Storage映射到Docker仍然是CIFS的文件系统:
CIFS和NFS作为非结构化文件系统,只能用作文件类型数据保存,一般不能用作结构化数据(如数据库)等存放位置。但是随着数据库发展,也慢慢开始支持共享文件系统。
SQL Server
SQL Server有明确官方说明,从2012开始支持SMB(CIFS):
并且SQL2017已经开始退出官方的Docker版本,正好可以直接用来测试:sudo docker run -e 'ACCEPT_EULA=Y' -e 'MSSQL_SA_PASSWORD=Password123!' -p 1402:1433 -v /mnt/smb/:/var/opt/mssql --privileged=true --name sql01 -d microsoft/mssql-server-linux
如上命令从Docker Hub下载MS SQL的官方镜像运行,并将/mnt/smb(Files Storage加载点)映射给Docker作为/var/opt/mssql(数据库目录)。
检查运行结果:
成功执行。
检查Azure Files Storage,可以看到已生成SQL的文件夹:
Oracle
Oracle官方文档明确说明不支持CIFS:
在Docker Hub里有非官方的Oracle DB镜像:
首先测试用宿主机本地目录作为Docker内oracle目录,可正常运行:
再将/mnt/smb作为Docker内oracle目录,可以看到运行后马上退出:
通过-it参数进入Docker内部可以看到,错误原因是文件系统不支持:
MySQL
MySQL也提供了官方Docker镜像,测试如下:
MySQL正常运行并创建了相关文件。
但是MySQL在运行前需要对目录做初始化,所以目录必须为空,不能有任何文件或文件夹。
不同软件对文件系统有不同要求。对于不支持CIFS的软件,没法用此方式实现数据持久化。
对kernel的兼容性问题
从Docker与虚拟化技术的对比可以看出:
虚拟化是从底层开始一步步实现,而Docker则是使用的宿主机kernel:
那么,问题来了,如果Linux软件有kernel版本要求,那么是由宿主机的kernel版本决定还是Docker里的Linux发行版本决定?
还是以Azure Files Storage为例,使用了SMB v2、3;而CentOS 7以下版本由于kernel限制只支持SMB v1.x。
CentOS 7作为宿主机,运行CentOS 6是否可以挂载Azure Files Storage?或者反之是否可以?
CentOS 7宿主机
在CentOS 7宿主机运行CentOS 6的Docker:
检查/etc/redhat-release文件确认版本:
由于CentOS 6的Docker不带mount、cifs等,所以需要手工安装:yum install -y mount* cifs*
执行mount命令顺利挂载:
CentOS 6宿主机
创建一台CentOS 6的虚机,挂载Azure Files Storage,可以看到由于兼容性问题报错:
CentOS 6不原生支持Docker,所以安装Docker需要通过Fedora EPEL仓库来进行。依次执行如下指令安装:sudo rpm -ivh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
sudo yum install -y docker-io
安装完成启动Dockeer服务并检查:
下载运行CentOS 7的Docker:
在Docker里安装cifs的支持:
挂载共享存储:
和宿主机同样错误,说明也有kernel兼容性问题。
通过SMB挂载的测试可以看出,在Docker里运行软件,和宿主机kernel的兼容性有关;如果是kernel版本比较敏感的应用,为了避免和底层kernel兼容性导致的不确定因素,还是建议使用主机虚拟化。