背景特征平台项目中的Zeppelin需要文件系统作数据持久化,当时国内采用的NFS作为存储,NFS能以文件系统方式方式去使用。特征平台项目部署到海外,海外只有S对象存储,如果自建NFS存储需要解决部署维护、服务高可用等问题其稳定性肯定不受保证,所以还是决定采用S。只不过AWS官方只提供了SDK或CLI等方式去使用,并没有使用文件系统一样操作sbucket的方法,如果修改数据访问方式去以SDK操作对象存储操作S是比较麻烦,另外一个原因是Zeppelin基于文件目录做git的本地版本管理,如果直接对接S就没有了版本管理能力,怎么样不修改数据访问方式而且能够以文件目录挂载的方式去使用s了?通过调研发现国内的云厂商阿里云OSS、腾讯云COS、开源的ceph对象存储都提供有FUSE方式去实现对象存储到文件目录的挂载。S作为对象存储的通用标杆也应该支持这样的操作,最终找到了sfs-fuse/sfs-fuse这个仓库,可以让你像普通文件系统一样挂载S,并能够在K8S上计算节点把S当系统文件一样进行使用。FUSE、SFS介绍用户态文件系统(filesysteminuserspace,简称FUSE),它能使用户在无需编辑和编译内核代码的情况下,创建用户自定义的文件系统。文件系统是操作系统的重要组成部分,一般在内核层面实现对于文件系统的支持,而通常内核态的代码难以调试,生产率较低。在用户态空间实现文件系统能够极大幅度的提高生产效率,简化为实现新的文件系统的工作量。FUSE主要包含两个部分,内核FUSE模块(Linux从.6.14版本开始支持)和用户态Libfuse库。SFS就是基于FUSE的文件系统,允许Linux和MacOsX挂载S的存储桶在本地文件系统,Sfs能够保持对象原来的格式,SFS是POSIX的大子集,包括读/写文件、目录、符号链接、模式、uid/gid和扩展属性,与AmazonS、Google云存储和其他基于S的对象存储兼容。使用fuse将s挂载bucket挂载到K8SPOD中可以像访问本地磁盘一样访问数据,而且数据并不会在本地同步影响本地磁盘容量,挂载后,任何POD无需密钥就可以可以从该目录去读取、写入数据。FUSE基本原理fuse实现了一个对文件系统访问的回调。fuse主要分为内核FUSE模块和用户态Libfuse库两部分。其中用户态的库为程序开发提供接口,也是我们实际开发时用的接口,我们通过这些接口将请求处理功能注册到fuse中。内核态模块是具体的数据流程的功能实现,它截获文件的访问请求,然后调用用户态注册的函数进行处理。fuse处理流程图如上图所示,其中fuse_user是开发的用户态的文件系统程序,该程序启动的时候会将自己开发的接口注册到fuse中,比如读写文件的接口,遍历目录的接口等。同时,通过该程序在系统某个路径挂载fuse文件系统,比如/tmp/file_on_fuse_fs。此时如果在该目录中有相关操作时,请求会经过VFS到fuse的内核模块(图中步骤1),fuse内核模块根据请求类型,调用用户态应用注册的函数(图中步骤),然后将处理结果通过VFS返回给系统调用(步骤)SFS实施方案比较直观的方案就是在K8S集群所有的计算节点都安装好SFS所依赖的软件,然后挂载sbucket到所有计算节点上。这种方式比较麻烦在于:首先所有计算节点都需要安装sf客户端、其次拷贝s认证信息到机器上,接下来要手动执行挂载命令,这还没完还需要设置挂载操作开机启动,避免机器重启后需要手动运行挂载命令。如上图所示,每个计算节点都需要重复安装、拷贝、执行、设置这个操作流程,这一系统操作将带来极大的运维成本。大概二三年前在大厂部署K8S对象存储,当时给K8S计算机点挂载cephfs就是这么操作的,这一连串操作下来那个过程是非常酸爽而且面对大集群通常会遇到有的节点会漏掉这个操作步骤,经常会导致调度到这个节点的任务因为找不到文件目录而报错。在做特征平台时,海外需要挂载S,从K8S集群安装部署运维到S服务挂载都需要了解,基于对K8S更加深入的了解,发现一个更加简单和自动化的方法,其方法主要是利用docker容器共享宿主机mountnamespace。通过此功能可以把宿主机目录挂载到容器中,容器中执行sfs挂载到对应宿主机目录完成sbucket文件挂载。通过K8SDaemonSet对象在所有计算节点启动一个pod去执行同样的操作。这样8s计算所有计算节点都就都挂载了S对象存储。之后基于K8S创建的pod就可以通过挂载宿主机目录去使用S的bucket。经历过那一系列重复操作到现在只需要把sfs及依赖打包到镜像,利用K8Sdaemonset自动为每个计算节点都运行一个pod去完成挂载操作,才发现这简直不要太美妙,从此无论机器扩容都可以喝着咖啡泡着茶看着K8S集群创建POD自动完成节点文件挂载操作。这一系统简单示意图如下所示:SFS实践步骤整体流程创建镜像:将sfs-fuse等依赖统一打包到镜像中,镜像中包含挂载fsbucket启动脚本操作编写K8SConfigmap对象,加入sfs-fuse挂载所需要的动态配置编写K8SDaemonSets对象,最终实现计算节点sbucket文件的挂载操作第一步:构建镜像:
FROMalpine:latestENVMNT_POINT/var/sENVIAM_ROLE=noneENVS_REGIONVOLUME/var/sARGSFS_VERSION=v1.89RUNapk--updateaddbashfuselibcurllibxmllibstdc++libgccalpine-sdkautomakeautoconflibxml-devfuse-devcurl-devgit;\gitclone