系统架构与设计(7)- Kubernetes 的共享存储
计算机存储系统由存放程序和数据的各类存储设备及有关的软件构成,是计算机系统的重要组成部分,用于存放程序和数据。
存储系统分为内存储器和外存储器,两者按一定的结构,有机地组织在一起。存储器一般分为以下几种:高速缓冲存储器、主存储器、辅助存储器。这里所提到的存储主要是指应用层面所需要的存储,即辅助存储器。
1. 存储的发展历程
第一个阶段:存储与主机的共存阶段,主机箱内有 CPU,内存,磁盘等设备;
第二个阶段:依旧是存储和主机共存的阶段,但是主机内可以安装多个磁盘,并能组建简单的 RAID;
第三个阶段:实现了存储和主机的分离,主机和存储之间使用 SCSI 线缆,但一般只能给一台主机使用,灵活性比较低,而且 SCSI 线缆比较短,在传输距离上也是个硬伤;
第四个阶段:为了实现多主机共享访问存储和扩展传输距离,底层使用 FC 交换机或者以太网交换机,实现存储的共享,但上层的协议依然是 SCSI,底层传送的协议利用 FC 或 IP 协议,实现了存储交换式网络;
2. 基于存储设备的分类
基于存储设备的分类,目前主流有三种类型: DAS、NAS 和 SAN .
1) 直连附属存储(Direct-Attached Storage,DAS)
DAS 是存储的设备只用于独立的一台服务器连接,很难把存储共享与其它主机(刀片应该可以实现的)存储设备是直接连接到服务器的主板总线,所以速度较快,比一般的 ISCSI 传输速度快。
DAS 在成本上比较低廉,性能比较稳定,但直连式存储需要依赖服务器主机的操作系统进行数据的 I/O 读写和存储设备管理,数据的备份和恢复,需要占用服务器主机的资源,包括 CPU 和系统 I/O 等。在 DAS 中服务器与存储交互过程一般如下:
2) 网络附属存储 (Network Attached Storage,NAS)
通过网络把文件服务器共享出的目录挂载到本地使用,服务器在工作中会把内存中的要存储的数据转换为网络 I/O 传递到文件服务器,服务器和文件服务器之间是属于文件系统 I/O 级别,服务器不用去关心这些数据要存放在哪些磁盘的哪些扇区,目前常见的协议有:NFS、CIFS 等。在 NAS 中服务器与存储的交互过程通常如下图:
3) 存储区域网络 (Storage Area Network,SAN)
通过光纤交换机或者以太网交换机把服务器和存储设备连接在一起,实现多服务器共享访问或使用一个存储阵列或集群存储。SAN 中服务器和存储间是属于块级别 I/O。 SAN 分为:
(1) FC SAN:需要服务器配备 FC HBA 卡 连接到 FC 交换机,存储也通过 FC HBA 卡连接到 FC 交换机,FC 的传输速度应能达到 1.2GB/S 甚至更高。这种架构造价较高,但速度和稳定性较高。
(2) IP SAN: 通过以太网卡和以太网交换机,把服务器和存储之间连接起来,让服务器通过 IP 网络把数据存储到存储设备上,目前以有万兆网络,但尚未普及,IP SAN 造价低廉,传输灵活,但速度和稳定性可能与 FC SAN 还要差一截。
3. 基于存储方式的分类
1) 块存储
块存储一般体现形式是卷或者硬盘(比如 Windows 里的 C 盘),数据是按字节来访问的,对于块存储而言,对里面存的数据内容和格式是完全一无所知的。
传统的文件系统,是直接访问存储数据的硬件介质的。介质不关心也无法去关心这些数据的组织方式以及结构,因此用的是最简单粗暴的组织方式:所有数据按照固定的大小分块,每一块赋予一个用于寻址的编号。
以大家比较熟悉的机械硬盘为例,一块就是一个扇区,老式硬盘是 512 字节大小,新硬盘是 4K 字节大小。老式硬盘用柱面-磁头-扇区号(CHS,Cylinder-Head-Sector)组成的编号进行寻址,现代硬盘用一个逻辑块编号寻址(LBA,Logical Block Addressing)。所以,硬盘往往又叫块设备(Block Device),除了硬盘还有其它块设备,例如不同规格的软盘,各种规格的光盘,磁带等。
至于哪些块组成一个文件,哪些块记录的是目录/子目录信息,这是文件系统的事情。不同的文件系统有不同的组织结构,这个就不展开了。为了方便管理,硬盘这样的块设备通常可以划分为多个逻辑块设备,也就是我们熟悉的硬盘分区(Partition)。反过来,单个介质的容量、性能有限,可以通过某些技术手段把多个物理块设备组合成一个逻辑块设备,例如各种级别的 RAID,JBOD,某些操作系统的卷管理系统(Volume Manager)如 Windows 的动态磁 盘、Linux 的 LVM 等。
块设备的使用对象除了传统的文件系统以及一些专用的管理工具软件如备份软件、分区软件外,还有一些支持直接读写块设备的软件如数据库等,但一般用户很少这样使用。
在网络存储中,服务器把本地的一个逻辑块设备 -- 底层可能是一个物理块设备的一部分,也可能是多个物理块设备的组合,又或者多个物理块设备的组合中的一部分,甚至是一个本地文件系统上的一个文件 -- 通过某种协议模拟成一个块设备,远程的客户端(可以是一台物理主机,也可以是虚拟机,某个回答所说的块设备是给虚拟机用是错误的)使用相同的协议把这个逻辑块设备作为一个本地存储介质来使用,划分分区,格式化自己的文件系统等等。这就是块存储,比较常见的块存储协议是 iSCSI。
2) 文件存储
文件存储的用户是自然人,最容易理解。计算机中所有的数据都是 0 和 1,存储在硬件介质上的一连串的 0/1 组合对我们来说完全无法去分辨以及管理。因此我们用 “文件” 这个概念对这些数据进行组织,所有用于同一用途的数据,按照不同应用程序要求的结构方式组成不同类型的文件(通常用不同的后缀来指代不同的类型),然后我们给每一个文件起一个方便理解记忆的名字。
当文件很多的时候,我们按照某种划分方式给这些文件分组,每一组文件放在同一个目录(或者叫文件夹)里面,当然我们也需要给这些目录起一个容易理解和记忆的名字。而且目录下面除了文件还可以有下一级目录(称之为子目录或者子文件夹),所有的文件、目录形成一个树状结构。我们最常用的 Windows 系统中,打开资源管理器就可以看到以这种方式组织起来的无数个文件和目录。
为了方便查找,从根节点开始逐级目录往下,一直到文件本身,把这些目录、子目录、文件的名字用特殊的字符(例如 Windows/DOS 用“\”,类 Unix 系统用 “/” )拼接起来,这样的一串字符称之为路径,例如 Linux 中的 “/etc/systemd/system.conf” 或者 Windows 中的 “C:\Windows\System32\taskmgr.exe” 。人类用路径作为唯一标识来访问具体的文件。而由作为自然人的程序员所编写的各种软件程序,绝大部分也使用这种方式来访问文件。
把存储介质上的数据组织成目录-子目录-文件这种形式的数据结构,用于从这个结构中寻找、添加、修改、删除文件的程序,以及用于维护这个结构的程序,组成的系统有一个专用的名字:文件系统(File System)。文件系统有很多,常见的有 Windows 的 FAT/FAT32/NTFS,Linux 的 EXT2/EXT3/EXT4/XFS/BtrFS 等。
在网络存储中,底层数据并非存储在本地的存储介质,而是另外一台服务器上,不同的客户端都可以用类似文件系统的方式访问这台服务器上的文件,这样的系统叫网络文件系统(Network File System),常见的网络文件系统有Windows 网络的 CIFS(也叫SMB)、类 Unix 系统网络的NFS等。而文件存储除了网络文件系统外,FTP、HTTP 其实也算是文件存储的某种特殊实现,都是可以通过某个 url 来访问一个文件。
3) 对象存储
之所以出现对象存储这种东西,是为了克服块存储与文件存储各自的缺点,发扬各自的优点。简单来说块存储读写快,不利于共享,文件存储读写慢,利于共享。能否弄一个读写块,利于共享的存储出来呢?于是就有了对象存储。
一个文件包含了属性(术语:metadata,元数据,例如该文件的大小、修改时间、存储路径等)以及内容(数据)。
像 FAT32 这种文件系统,是直接将一份文件与 metadata 一起存储的,存储过程先将文件按照文件系统的最小块大小来打散(例如 4M 的文件,假设文件系统要求一个块 4K,那么就将文件打散称为 1000 个小块),再写进硬盘里,过程中没有区分数据和 metadata 的。而每个块最后会告知你下一个要读取的块地址,然后一直这样顺序的按图索骥,最后完成整份文件的所有块的读取。
这种情况下读写速率很慢,因为就算你有 100 个机械臂在读写,但是由于你只有读取到第一个块,才能知道下一个块在哪里,其实相当于只能有 1 个机械臂在实际工作。
而对象存储则将元数据独立出来了,控制节点叫元数据服务器(服务器 + 对象存储管理软件),里面主要负责存储对象的属性(主要是对象的数据被打散存放到了那几台分布式服务器中的信息)而其他负责存储数据的分布式服务器叫做 OSD,主要负责存储文件的数据部分。当用户访问对象,会先访问元数据服务器,元数据服务器只负责反馈对象存储在哪里 OSD,假设反馈文件 A 存储在 B、C、D 三台 OSD,那么用户就会再次直接访问 3 台 OSD 服务器去读取数据。
这时候由于是 3 台 OSD 同时对外传输数据,所以传输的速度就会加快了,当 OSD 服务器数量越多,这种读写速度的提升就越大,通过此种方式,实现了读写快的目的。另一方面,对象存储软件是有专门的文件系统的,所以 OSD 对外又相当于文件服务器,那么就不存在共享方面的困难了,也解决了文件共享方面的问题。
所以对象存储的出现,很好的结合了块存储和文件存储的优点。
为什么对象存储兼具块存储和文件存储的好处,还要使用块存储和文件存储呢?
(1) 有一类应用是需要存储直接裸盘映射的,例如数据库。因为数据需要存储楼盘映射给自己后,再根据自己的数据库文件系统来对裸盘进行格式化的,所以是不能够采用其他已经被格式化为某种文件系统的存储的。此类应用更合适使用块存储。
(2) 对象存储的成本比起普通的文件存储还要较高,需要购买专门的对象存储软件以及大容量硬盘。如果对数据量要求不是海量,只是为了做文件共享的时候,直接用文件存储的形式好了,性价比高。
4. 共享存储
这里的共享存储,指的是基于文件系统的共享存储,多台服务器读写同一个存储设备的同一个分区,或者说系统允许多个用户 (进程) 共享同一份文件。
文件系统的共享存储,可以理解为共享文件夹或文件,包含共享文件夹或文件的共享协议、传输协议、访问权限等信息,而且共享行为一般发生在局域网内或远程网络之间。
网络主机之间共享文件,必然会涉及到文件传输协议、文件共享协议等,这里我们先了解一下常用的文件传输协议和文件共享协议。
1) FTP/TFTP/FTPS
FTP(File Transfer Protocol) 是 TCP/IP 协议簇中的一员,是 1971 年发展起来的文件传输协议,作为标准网络协议出现它包含两个部分实现,一个是 FTP Server,一个是 FTP Client,其中 Server 用来存储文件,Client 供客户机使用以访问远程资源。
默认情况下,FTP 使用 TCP 20 和 TCP 21 两个端口传输数据,TCP 20 用于数据传输,TCP 21 用于控制信息传输。而是否使用 20 端口传输数据与 FTP 传输模式有关,如果 FTP 主动模式,那么数据传输端口就是 20,如果采用的被动模式,那最终传输数据的端口由 FTP 的服务器和客户机协商决定。
FTP 的缺点:数据传输模式不够合理,工作方式设计不合理,与防火墙工作不协调,安全认证策略不完善,相对而言整个传输过程效率也低下。
FTPS(FTP over SSL/TLS),是一种安全的 FTP,添加了传输层安全(TLS)和安全套接层(SSL)的加密协议。尽管在数据传输方面加固了安全,但 FTP 的底层设计依然还是没有改变,所以直到现在应用也不够广泛。偶尔在内网中会有部署的 FTP 服务,但大家也更倾向于使用 samba, nfs, http, webdav 这些协议共享文件。
2) SCP/SFTP
SCP(Secure Copy) 和 SFTP(Secure File Transfer Protocol) 都基于 SSH(Secure SHell) 协议,OpenSSH 是 SSH 协议的一个开源实现,一些嵌入式设备可以通过 dropbear 建立 ssh 连接,dropbear 也实现了 SSH 协议的基础功能。
SCP 用来进行远程文件复制,并且整个复制过程是加密的。数据传输使用 ssh tunnel,并且使用和 ssh 相同的认证方式,提供相同的安全保证。密码认证或密钥对 (key-pair)验证。
SFTP 与 FTP 有着几乎一样的语法和功能。SFTP 为 SSH 的一部分,是一种传输文件到服务器的安全方式。在 SSH 软件包中,已经包含了一个叫作 SFTP 的安全文件传输子系统,SFTP 本身没有单独的守护进程,它必须使用 sshd 守护进程(端口号默认是22)来完成相应的连接操作,所以从某种意义上来说,SFTP 并不像一个服务器程序,而更像是一个客户端程序。
SFTP 同样是使用加密传输认证信息和传输的数据,所以,使用 SFTP 是安全的。但是,正由于这种传输方式使用了加密/解密技术,所以比起普通 FTP,开销大得多,传输效率低得多。如果用户对网络安全性要求更高,则可以使用 SFTP 代替 FTP。
SCP 和 SFTP 的比较:
(1) 两者都基于 SSH,但是传输效率和安全性上也有区别;
(2) SCP 不支持断点续传,一次 timeout 就得重来,而 SFTP 支持;
(3) SCP 不检查传输的数据包,效率更高但安全性更低;
(4) SCP 单次传输不支持 4Gib 以上文件,适合小文件传输,速度更快。SFTP 适合更大文件,安全性更高的传输场景;
3) HTTP/HTTPS
HTTP(HyperText Transfer Protocol)即超文本传输协议,我们都不陌生了,通过 http 共享文件可以很简单,比如使用 nginx 标准模块 Auto Index 可以很快创建一个可以共享的文件服务器,效率也非常之高。
HTTPS(HTTP over SSL/TLS),加密后的 http 流量,目前正是主流 Web 交互的方式。
4) MTP
MTP(Media Transfer Protocol) 媒体传输协议,是基于 PTP(Picture Transfer Protocol) 协议的扩展,主要用于传输媒体文件,其中有价值的应用就是同步 DRM 文件的 license。
MTP 既可以实现在 USB 协议上,也可以实现在 TCP/IP 协议上,它属于上层的应用协议,而不关心底层传输协议。目前大部分设备的应用都是基于 USB 协议。在 Android 设备上应用广泛,使用 USB A cable 连接 Windows PC 和 Android 设备,默认的文件传输协议就是 MTP,但除此之外,内网文件的传输很少应用到此协议。
5) SMB/CIFS/SAMBA
SMB(Server Message Block) 通信协议是微软和英特尔在 1987 年制定的协议,主要是作为 Microsoft 网络的通讯协议,它是当今世上网络文件系统协议两极之一的存在。
SMB 使用了 NetBIOS 的 API。另外,它是一个开放性的协议,允许了协议扩展,这使得它可以变得更大而且复杂;大约有 65 个最上层的作业,而每个作业都超过 120 个函数,甚至 Windows NT 自己也没有全部支持到,后来~~著名的微软改名部门~~又把 SMB 重新设计了一套新的实现: CIFS(Common Internet File System) 协议,并且加入了许多新的特色功能。
一开始微软设计的 SMB 不支持在 Linux 上运行,著名黑客、技术大牛安德鲁·垂鸠 (Andrew Tridgell) 通过逆向工程,于 1992 年在澳洲国立大学(ANU)开发了第一版的 Samba Unix 软件,实现了 SMB/CIFS 兼容协议,并命名为 Samba,通过该程序实现了 Windows 和 Linux 之间的文件共享。 Debian 上的软件包名称就是 samba,OpenWrt 中一般有 samba36-server 和 samba4-server (版本 4,性能更强,更新的一个版本)。
SMB 是 C/S (Client and Server) 类型协议,客户机可以访问服务器上的共享文件系统、打印机及其他资源。更进阶一点,通过设置 "NetBIOS over TCP/IP",Samba 不但能与局域网络主机分享资源,还能与全世界的电脑分享资源,但一般很少这样使用。
SMB 的优点之一是兼容性特别好,在各平台都获得了广泛支持,包括 Windows、Linux、macOS、Android、iOS、iPadOS,甚至一些嵌入式系统比如 OpenWrt,挂载访问都很方便。另外 SMB 也是各种电视、电视盒子默认支持的协议,这些电视和盒子通过 SMB 访问服务器端的资源可以达到播放电影、音乐、访问图片和预览普通文件的目的。
另外 SMB 提供端到端加密、安全性高,配置选项丰富,支持 ACL(Access Control List) 并支持多种用户认证方式。
不过 SMB 的缺点也是最令极客们诟病的,是传输效率稍低,速度不太稳定,受机器网络和硬件资源波动较大。
简而言之,SMB 协议是在局域网上用于服务器文件访问和打印的协议。CIFS 可以看做是应用程序协议如文件传输协议和超文本传输协议的一个实现。
6) NFS
NFS(Network File System),即网络文件系统,是 FreeBSD 支持的文件系统中的一种。NFS 允许一个系统在网络上与它人共享目录和文件。通过使用 NFS,用户和程序可以像访问本地文件一样访问远端系统上的文件。它由 Sun 公司(已被 Oracle 收购)开发,于 1984 年发布,最新版本 NFSv4.2 于 2016 年发布。NFS 基于开放网络运算远程过程调用(ONC RPC)协议:一个开放、标准的 RFC 协议,任何人或组织都可以依据标准实现它。
NFS 通常使用在 Unix 操作系统上(比如 Solaris、AIX 及 HP-UX)和其他类 Unix 操作系统(例如 Linux 及 FreeBSD),同时在 macOS 和 Windows 系统也提供了 NFS 实现。不过在 Windows 系统上挂载 NFS 共享目录时,由于 Windows 自带的 NFS 客户端长久以来不支持 UTF-8,会致中文文件和目录显示为乱码。
NFS 的优点是 kernel 直接支持,部署简单、运行稳定,协议简单、传输效率高。
NFS 的缺点是没有加密授权等功能,仅依靠 IP 地址或主机名来决定用户能否挂载共享目录,对具体目录和文件无法进行 ACL 控制(NFSv4 以前)。通常的做法是通过 Kerberos 对 NFS 进行认证及加密,不过部署配置比较麻烦。
7) rsync
rsync 全称 remote synchronize,即 "远程同步",是 Liunx/Unix 下的一个远程数据同步工具。它可通过 LAN/WAN 快速同步多台主机间的文件和目录,并适当利用 rsync 算法(差分编码)以减少数据的传输,即可做到增量传输/备份。严格来说,rsync 算不上底层的文件传输/共享协议,但是本文为了介绍的尽量全面还是提一下。
在常驻模式(daemon mode)下,rsync 默认监听 TCP 端口 873,以原生 rsync 传输协议或者透过远程 shell 如 RSH 或者 SSH 提供文件。SSH 模式下,rsync 客户端执行程序必须同时在本地和远程机器上安装。
rsync 首度发布于 1996 年 6 月 19 日。原始作者为安德鲁·垂鸠(Andrew Tridgell)(很巧的是,又是这个大神)与保罗·麦可拉斯(Paul Mackerras)。
rsync 现在应用广泛,使用起来也非常方便易用,效率也高,最初设计就是替代 SCP 的。既能在本地用于数据拷贝、移动(可用来替代 Linux cp 和 mv 命令),也能做增量备份存储。通过 SSH 实现远程复制也非常好用。
类似于 rsync 的工具,还有 rclone、robocopy、freefilesync 等。
5. Kubernetes 的共享存储
Kubernetes 是分布式容器集群,如何在多个 Pod 之间或多个 Node 之间进行数据存储和共享是非常重要的问题。
Kubernetes 引入了持久存储卷(PersistentVolume,PV),满足持久化数据的要求,可以将数据将永久保存,支持多种第三方的存储系统。
1) 持久存储卷(PersistentVolume,PV)
PersistentVolume(PV) 是集群中由管理员配置的一段网络存储,它是从存储设备中的空间创建出一个存储资源。集群中的资源就像节点(Node)一样都是一种集群资源,可以从远程的 NFS 或分布式对象存储系统中创建得来(PV 存储空间大小、访问方式)。
PV 类似于卷(Volume)的卷插件,并且它独立于使用它的任何单个 Pod 的生命周期。
2) 持久存储卷请求(PersistentVolumeClaim,PVC)
PersistentVolumeClaim(PVC)是用户存储的请求。PVC 的使用逻辑:在 Pod 中定义一个存储卷(该存储卷类型为 PVC),定义的时候直按指定大小,PVC 必须与对应的 PV 建立关系,PVC 会根据定义去 PV 申请,而 PV 是由存储空间创建出来的。PV 和 PVC 是 K8s 抽象出来的持久存储资源。
虽然 PVC 允许用户使用抽象存储资源,但是常见的需求是,用户需要根据不同的需求去创建 PV,用于不同的场景。而此时需要集群管理员提供不同需求的 PV,而不仅仅是 PV 的大小和访问模式,但又不需要用户了解这些卷的实现细节。对于这样的需求,此时可以采用 StorageClass 资源。
3) Kubernetes 支持的 PV 类型
AWSElasticBlockStore:AWS 公有云提供的 ElasticBlockStore;
AzureFile:Azure 公有云提供的 File;
AzureDisk:Azure 公有云提供的 Disk;
CephFS:一种开源共享存储系统;
FC(FibreChannel):光纤存储设备;
FlexVolume:一种插件式的存储机制;
Flocker:一种开源共享存储系统;
GCEPersistentDisk:GCE 公有云提供的 PersistentDisk;
Glusterfs:一种开源共享存储系统;
HostPath:宿主机目录,仅用于单机测试;
iSCSI:iSCSI 存储设备;
Local:本地存储设备,从 Kubernetes1.7 版本引入,到 1.14 版本时更新为稳定版,目前可以通过指定块(Block)设备提供 LocalPV,或通过社区开发的 sig-storage-local-static-provisioner 插件(https://github.com/kubernetes-sigs/sigstorage-local-static-provisioner)来管理 LocalPV 的生命周期;
NFS:网络文件系统;
PortworxVolumes:Portworx 提供的存储服务;
QuobyteVolumes:Quobyte 提供的存储服务;
RBD(CephBlockDevice):Ceph 块存储;
ScaleIOVolumes:DellEMC 的存储设备;
StorageOS:StorageOS 提供的存储服务;
VsphereVolume:VMWare 提供的存储系统;
4) Kubernetes 集群使用 NFS
在 Kubernetes 使用的过程中,有很多数据需要持久化保存。Kubernetes 本身不能实现这样的功能,所以需要提供外部存储来实现。
NFS 网络文件系统,可以实现 Linux/Unix 主机之间的文件共享,能良好支持 PV 静态和动态创建等功能,是一种不错的持久化保存方式。
kubernetes 使用 NFS 共享存储的两种方式:
(1) 手动方式静态创建所需要的 PV 和 PVC;
(2) 通过创建 PVC 动态地创建对应 PV,无需手动创建 PV;