基于 GlusterFS 實現 Docker 集群的分布式存儲
以 Docker 為代表的容器技術在云計算領域正扮演著越來越重要的角色,甚至一度被認為是虛擬化技術的替代品。企業級的容器應用常常需要將重要的數據持久化,方便在不同容器間共享。為了能夠持久化數據以及共享容器間的數據,Docker 提出了 Volume 的概念。單機環境的數據卷難以滿足 Docker 集群化的要求,因此需要引入分布式文件系統。目前開源的分布式文件系統有許多,例如 GFS,Ceph,HDFS,FastDFS,GlusterFS 等。GlusterFS 因其部署簡單、擴展性強、高可用等特點,在分布式存儲領域被廣泛使用。本文主要介紹了如何利用 GlusterFS 為 Docker 集群提供可靠的分布式文件存儲。
GlusterFS 分布式文件系統簡介
GlusterFS 概述
GlusterFS (Gluster File System) 是一個開源的分布式文件系統,主要由 Z RESEARCH 公司負責開發。GlusterFS 是 Scale-Out 存儲解決方案 Gluster 的核心,具有強大的橫向擴展能力,通過擴展能夠支持數PB存儲容量和處理數千客戶端。GlusterFS 借助 TCP/IP 或 InfiniBand RDMA 網絡將物理分布的存儲資源聚集在一起,使用單一全局命名空間來管理數據。GlusterFS 基于可堆疊的用戶空間設計,可為各種不同的數據負載提供優異的性能。
GlusterFS 總體架構與組成部分如圖1所示,它主要由存儲服務器(Brick Server)、客戶端以及 NFS/Samba 存儲網關組成。不難發現,GlusterFS 架構中沒有元數據服務器組件,這是其最大的設計這點,對于提升整個系統的性能、可靠性和穩定性都有著決定性的意義。
- GlusterFS 支持 TCP/IP 和 InfiniBand RDMA 高速網絡互聯。
- 客戶端可通過原生 GlusterFS 協議訪問數據,其他沒有運行 GlusterFS 客戶端的終端可通過 NFS/CIFS 標準協議通過存儲網關訪問數據(存儲網關提供彈性卷管理和訪問代理功能)。
- 存儲服務器主要提供基本的數據存儲功能,客戶端彌補了沒有元數據服務器的問題,承擔了更多的功能,包括數據卷管理、I/O 調度、文件定位、數據緩存等功能,利用 FUSE(File system in User Space)模塊將 GlusterFS 掛載到本地文件系統之上,實現 POSIX 兼容的方式來訪問系統數據。
圖1. GlusterFS 總體架構
如圖 1 中 GlusterFS 有非常多的術語,理解這些術語對理解 GlusterFS 的動作機理是非常重要的,表1給出了 GlusterFS 常見的名稱及其解釋。
表1. GlusterFS 常見術語
名稱 | 解釋 |
---|---|
Brick | 最基本的存儲單元,表示為trusted storage pool中輸出的目錄,供客戶端掛載用。 |
Volume | 一個卷。在邏輯上由N個bricks組成。 |
FUSE | Unix-like OS上的可動態加載的模塊,允許用戶不用修改內核即可創建自己的文件系統。 |
Glusterd | Gluster management daemon,要在trusted storage pool中所有的服務器上運行。 |
POSIX | 一個標準,GlusterFS兼容。 |
GlusterFS卷類型
為了滿足不同應用對高性能、高可用的需求,GlusterFS 支持 7 種卷,即 distribute 卷、stripe 卷、replica 卷、distribute stripe 卷、distribute replica 卷、stripe Replica 卷、distribute stripe replica 卷。其實不難看出,GlusterFS 卷類型實際上可以分為 3 種基本卷和 4 種復合卷,每種類型的卷都有其自身的特點和適用場景。
基本卷:
(1) distribute volume 分布式卷
基于 Hash 算法將文件分布到所有 brick server,只是擴大了磁盤空間,不具備容錯能力。由于distribute volume 使用本地文件系統,因此存取效率并沒有提高,相反會因為網絡通信的原因使用效率有所降低,另外本地存儲設備的容量有限制,因此支持超大型文件會有一定難度。圖2 是 distribute volume 示意圖。
圖2. Distribute volume示意圖
(2) stripe volume 條帶卷
類似 RAID0,文件分成數據塊以 Round Robin 方式分布到 brick server 上,并發粒度是數據塊,支持超大文件,大文件的讀寫性能高。圖3 是 stripe volume 示意圖。
圖3. Stripe volume示意圖
(3) replica volume 復制卷
文件同步復制到多個 brick 上,文件級 RAID1,具有容錯能力,寫性能下降,讀性能提升。Replicated 模式,也稱作 AFR(Auto File Replication),相當于 RAID1,即同一文件在多個鏡像存儲節點上保存多份,每個 replicated 子節點有著相同的目錄結構和文件,replica volume 也是在容器存儲中較為推崇的一種。圖4 是 replica volume 示意圖。
圖4 . Replica volume示意圖
復合卷:
(4) distribute stripe volume 分布式條帶卷
Brick server 數量是條帶數的倍數,兼具 distribute 和 stripe 卷的特點。分布式的條帶卷,volume 中 brick 所包含的存儲服務器數必須是 stripe 的倍數(>=2倍),兼顧分布式和條帶式的功能。每個文件分布在四臺共享服務器上,通常用于大文件訪問處理,最少需要 4 臺服務器才能創建分布條帶卷。圖5 是distribute stripe volume 示意圖。
圖5 . Distribute stripe volume 示意圖
(5) distribute replica volume 分布式復制卷
Brick server 數量是鏡像數的倍數,兼具 distribute 和 replica 卷的特點,可以在 2 個或多個節點之間復制數據。分布式的復制卷,volume 中 brick 所包含的存儲服務器數必須是 replica 的倍數(>=2倍),兼顧分布式和復制式的功能。圖6 是 distribute replica volume 示意圖。
圖6 . Distribute replica volume 示意圖
(6) stripe replica volume 條帶復制卷
類似 RAID 10,同時具有條帶卷和復制卷的特點。圖7 是 distribute replica volume 示意圖。
圖7 . Stripe replica volume 示意圖
(7) distribute stripe replica volume:分布式條帶復制卷
三種基本卷的復合卷,通常用于類 Map Reduce 應用。圖8 是 distribute stripe replica volume 示意圖。
圖8 . Distribute stripe replica volume 示意圖
GlusterFS 常用命令
GlusterFS 客戶端提供了非常豐富的命令用來操作節點、卷,表2給出了常用的一些命令。在與容器對接過程中,通過我們需要創建卷、刪除卷,以及設定卷的配額等功能,并且后續這些功能也需要 REST API 化,方便通過HTTP請求的方式來操作卷。
表2. GlusterFS 客戶端常用命令
命令 | 功能 |
---|---|
gluster peer probe | 添加節點 |
gluster peer detach | 移除節點 |
gluster volume create | 創建卷 |
gluster volume start | 啟動卷 |
gluster volume stop | 停止卷 |
gluster volume delete | 刪除卷 |
gluster volume quota enable | 開啟卷配額 |
gluster volume quota enable | 關閉卷配額 |
gluster volume quota limit-usage | 設定卷配額 |
GlusterFS 分布式文件系統安裝與配置
GlusterFS 集群搭建
本文將以 Ubuntu14.04.3 LTS Server 為例安裝 2 個節點的 GlusterFS 集群。每個服務節點需要有一個額外的盤符。具體請參考下面步驟:
清單1. 搭建 GlusterFS 集群
# (1). 格式化磁盤 fdisk /dev/sdb 命令行提示下輸入【m】 輸入命令【n】添加新分區 輸入命令【p】創建主分區 輸入【回車】,選擇默認大小,這樣不浪費空間 輸入【回車】,選擇默認的start cylinder 輸入【w】,保持修改 # (2). 添加gluster源 cat >>/etc/apt/sources.list <<EOF deb http://ppa.launchpad.net/gluster/glusterfs-3.7/ubuntu trusty main deb-src http://ppa.launchpad.net/gluster/glusterfs-3.7/ubuntu trusty main EOF # (3). 安裝glusterfs apt-get install xfsprogs glusterfs-server -y mkfs.xfs -i size=512 /dev/sdb1 mkdir -p /glusterfs/brick #掛載點 echo '/dev/sdb1 /glusterfs/brick xfs defaults 1 2' >> /etc/fstab #設置自動掛載 mount -a && mount gluster volume set all cluster.op-version 30710 # (4). 配置peer gluster peer probe <IP|HOSTNAME> gluster peer status # (5). 當出現下列信息時表示集群搭建成功 gluster peer status Number of Peers: 1 Hostname: 192.168.1.101 Uuid: 8d836e09-f217-488b-971c-be9206a197f6 State: Peer in Cluster (Connected) # (6). 創建Volume gluster volume create <VOLUME_NAME> replica 2 \ node1: /glusterfs/brick/<VOLUME_NAME> \ node2: /glusterfs/brick/<VOLUME_NAME> # (7). 啟動Volume gluster volume start <VOLUME_NAME>
GlusterFS 客戶端配置
清單2. GlusterFS 客戶端配置
# (1). 添加gluster源 cat >>/etc/apt/sources.list <<EOF deb http://ppa.launchpad.net/gluster/glusterfs-3.7/ubuntu trusty main deb-src http://ppa.launchpad.net/gluster/glusterfs-3.7/ubuntu trusty main EOF # (2). 安裝glusterfs client apt-get install glusterfs-client -y # (3). 掛載gluster卷 glusterfs node1:<VOLUME_NAME> /mnt/local-volume
至此,我們就掛載好了GlusterFS集群中的一個Replica類型的卷,所有寫入該卷中的數據都會在集群中有兩份拷貝。
Docker GlusterFS Volume 插件
接下來,我們再來看GlusterFS如何作為Docker的存儲。Docker Volume是一種可以將容器以及容器生產的數據分享開來的數據格式,我們可以使用宿主機的本地存儲作為Volume的提供方,也可以使用Volume Plugin接入許多第三方的存儲。 GitHub就有一個 Docker GlusterFS Volume Plugin ,方便我們將GlusterFS掛載到容器中。具體步驟如下:
清單3. 安裝 Docker GlusterFS Volume 插件
# (1). 獲取docker-volume-glusterfs go get github.com/calavera/docker-volume-glusterfs 考慮到搭建golang環境有一定的復雜性,我們也可以采用golang容器來獲取該應用 # (2). 拷貝docker-volume-glusterfs至/usr/bin cp ./docker-volume-glusterfs /usr/bin chmod 777 /usr/bin/docker-volume-glusterfs # (3). 聲明gluster服務集群 docker-volume-glusterfs -servers node1:node2 # (4). 指定volume docker run --volume-driver glusterfs --volume datastore:/data alpine touch /data/hello 這里的datastore即我們在glusterfs集群中創建的volume,但需要事先手動創建
GlusterFS REST API 服務搭建
上述步驟雖然實現了 GlusterFS 作為 Docker 存儲方案,但 GlusterFS 卷仍需要手動創建。為了自動化地管理 GlusterFS 卷,我們將卷操作封裝成 REST API。 GitHub上的 glusterfs-rest 將 GlusterFS 基礎操作使用 Python 封裝成了 REST API,但是它沒有將 Volume 容量限制等功能封裝起來,而我們項目中這個功能又是必須的,不過稍加修改后就可以實現容量限制的功能。
清單4. 添加 Volume 容量限制功能
# (1). 克隆代碼 git clone https://github.com/aravindavk/glusterfs-rest.git # (2). 修改glusterfs-rest/glusterfsrest/cli/ volume.py create方法 def create(name, bricks, replica=0, stripe=0, transport='tcp', force=False, start_volume=False,limit=False,quota=1): cmd = VOLUME_CMD + ["create", name] if stripe > 0: cmd += ["stripe", str(stripe)] if replica > 0: cmd += ["replica", str(replica)] cmd += ["transport", transport] cmd += bricks if force: cmd += ["force"] # If volume needs to be started, then run create command without # decorator else return create command and status zero true # decorator will take care of running cmd if start_volume: utils.checkstatuszero(cmd) if limit: enable_cmd = VOLUME_CMD + ["quota",name,"enable"] quota_cmd = VOLUME_CMD +["quota",name,"limit-usage","/",str(quota)+"GB"] start(name, force=True) utils.checkstatuszero(enable_cmd) return utils.checkstatuszero(quota_cmd) else: return start(name, force=True) else: return utils.checkstatuszero(cmd) # (3). 修改glusterfs-rest/glusterfsrest/doc/api-1.0.yml Create內容 # ----------------------------------------------------------------------------- # Create Gluster Volume # ----------------------------------------------------------------------------- - title: Create Gluster Volume auth: true url: volume/:name category: volume method: POST params: - name: bricks type: string required: true example: "bricksserver1:/exports/bricks/b1" desc: Comma seperated Brick paths - name: replica type: int required: false example: 1 desc: Replica Count default: 0 - name: stripe type: int required: false example: 1 desc: Stripe Count default: 0 - name: transport type: int required: false example: tcp desc: Transport Type, available types "tcp", "rdma", "tcp,rdma" default: tcp - name: force type: int required: false example: 1 desc: Volume create force default: 0 - name: start type: int required: false example: 1 desc: Start volume after create default: 0 - name: limit type: int required: false example: 1 desc: Limit volume after start default: 0 - name: quota type: int required: false example: 1 desc: Set Quota if limit default: 1 example: | curl -X POST http://admin:secret123@localhost:9000/api/1.0/volume/gv1 -d \ "bricks=bricksserver1:/exports/bricks/b1,bricksserver2:/exports/bricks/b2&start=1&replica=2&limit=1"a=2" response: | Success example: { "data": true, "ok": true } Failure example: { "error": "volume create: gv1: failed: Volume gv1 already exists", "ok": false } # (4). 安裝依賴 apt-get install python-setuptools # (5). 啟動服務 cd glusterfs-rest python setup.py install glusterrest install # (Reinstall also available, sudo glusterrest reinstall) # (6). 拷貝gunicorn cp /usr/local/bin/gunicorn /usr/bin/ chmod 777 /usr/bin/gunicorn # (7). 啟動服務 glusterrest port 80 sudo glusterrest useradd root -g glusterroot -p root glusterrestd
服務啟動后,我們可以通過 http://<node_ip>/ api/1.0/doc 訪問 API 的具體使用方法,主要封裝的 API 見表 3。
表3. Gluster-rest 封裝 API
功能描述 | HTTP請求方法 | URL |
---|---|---|
查看卷列表 | GET | /api/1.0/volumes |
查看單獨卷信息 | GET | /api/1.0/volume/:name |
創建卷 | POST | /api/1.0/volume/:name |
刪除卷 | DELETE | /api/1.0/volume/:name |
啟動卷 | PUT | /api/1.0/volume/:name/start |
停止卷 | PUT | /api/1.0/volume/:name/stop |
重啟卷 | PUT | /api/1.0/volume/:name/restart |
獲取集群節點信息 | GET | /api/1.0/peers |
添加節點 | POST | /api/1.0/peer/:hostname |
刪除節點 | DELETE | /api/1.0/peer/:hostname |
基于 GlusterFS 實現數據持久化案例
接下來,用 MYSQL 數據庫容器來展示 GlusterFS 如何實現數據持久化。
非持久化MYSQL數據庫容器
清單5. 創建非持久化MYSQL 數據庫容器
# (1). 創建mysql_1 docker run --name mysql_1 -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 mysql # (2). 登錄mysql_1 docker exec -it mysql_1 /bin/bash root@4320a6f596fe:/# mysql -uroot # (3). 創建database mysql> create database mydb; Query OK, 1 row affected (0.00 sec) # (4). 列出database mysql>show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mydb | | mysql | | performance_schema | | test | +--------------------+ 5 rows in set (0.00 sec) # (5). 退出mysql及容器 mysql> exit root@4320a6f596fe:/# exit # (6). 刪除容器 docker stop mysql_1 && docker rm mysql_1 # (7). 創建msqyl_2 docker run --name mysql_2 -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 mysql # (8). 登錄mysql_2 docker exec -it mysql_2 /bin/bash root@fe32ea420460:/# mysql -uroot # (9). 列出database mysql>show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | +--------------------+ 4 rows in set (0.00 sec)
這里我們可以看到新創建的容器并沒有包含我們先前創建的 mydb 數據庫,這是因為非執久化的容器所有數據都在內存中,數據會隨著容器的刪除一起刪除。
持久化 MYSQL 數據庫容器
下面我們再用 GlusterFS 卷來實現數據持久化的效果。
清單6. 創建持久化 MYSQL 數據庫容器
# (1). 創建Volume curl -X POST http://root:root@192.168.1.101/api/1.0/volume/gluster_volume -d \ "bricks=bricksserver1:/exports/bricks/gluster_volume,bricksserver2:/exports/bricks/ gluster_volume&start=1&replica=2&limit=1"a=2" # (2). 創建mysql_3 docker run --name mysql_3 --volume-driver glusterfs \ --volume gluster_volume:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 mysql # (3). 登錄mysql_3 docker exec -it mysql_1 /bin/bash root@b3f71265a066:/# mysql -u root # (4). 創建database mysql> create database mydb; Query OK, 1 row affected (0.00 sec) # (5). 列出database mysql>show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mydb | | mysql | | performance_schema | | test | +--------------------+ 5 rows in set (0.00 sec) # (6). 退出mysql及容器 mysql>exit root@b3f71265a066:/# exit # (7). 刪除容器 docker stop mysql_3 && docker rm mysql_3 # (8). 創建msqyl_4 docker run --name mysql_4 --volume-driver glusterfs \ --volume gluster_volume:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 mysql # (9). 登錄mysql_4 docker exec -it mysql_4 /bin/bash root@1aafc1734abb:/# mysql -u root # (10). 列出database Mysql > show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mydb | | mysql | | performance_schema | | test | +--------------------+ 5 rows in set (0.02 sec)
這里我們可以看到新創建的容器包含了之前創建的數據庫 mydb,也就實現了我們說的數據持久化效果。
小結
GlusterFS 作為一種開源分布式存儲組件,具有非常強大的擴展能力,同時也提供了非常豐富的卷類型,能夠輕松實現PB級的數據存儲。本文基于 docker glusterfs volume 插件和 gluster-rest API 封裝,實現了容器的集群分布式存儲功能。Docker 本身提供了本地存儲的方案,但無法跨越主機,因此容器一旦被銷毀后,如果不是落在先前的宿主機上運行也就意味著數據丟失。本文實現的 GlusterFS 存儲方案,卷信息不隨 Docker 宿主機的變更而發生變化,因此能夠方便實現 Docker 集群的橫向擴展。本文為 Docker 集群提供持久化的功能,例如關系型數據、文件服務等,提供了非常有價值的參考。
來自:http://www.ibm.com/developerworks/cn/opensource/os-cn-glusterfs-docker-volume/index.html?ca=drs-