使用Azure Files Storage实现Docker数据持久化及其他

  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兼容性导致的不确定因素,还是建议使用主机虚拟化。