基于 GlusterFS 實現 Docker 集群的分布式存儲

lucita 7年前發布 | 30K 次閱讀 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 總體架構

基于 GlusterFS 實現 Docker 集群的分布式存儲

如圖 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示意圖

基于 GlusterFS 實現 Docker 集群的分布式存儲

(2) stripe volume 條帶卷

類似 RAID0,文件分成數據塊以 Round Robin 方式分布到 brick server 上,并發粒度是數據塊,支持超大文件,大文件的讀寫性能高。圖3 是 stripe volume 示意圖。

圖3. Stripe volume示意圖

基于 GlusterFS 實現 Docker 集群的分布式存儲

(3) replica volume 復制卷

文件同步復制到多個 brick 上,文件級 RAID1,具有容錯能力,寫性能下降,讀性能提升。Replicated 模式,也稱作 AFR(Auto File Replication),相當于 RAID1,即同一文件在多個鏡像存儲節點上保存多份,每個 replicated 子節點有著相同的目錄結構和文件,replica volume 也是在容器存儲中較為推崇的一種。圖4 是 replica volume 示意圖。

圖4 . Replica volume示意圖

基于 GlusterFS 實現 Docker 集群的分布式存儲

復合卷:

(4) distribute stripe volume 分布式條帶卷

Brick server 數量是條帶數的倍數,兼具 distribute 和 stripe 卷的特點。分布式的條帶卷,volume 中 brick 所包含的存儲服務器數必須是 stripe 的倍數(>=2倍),兼顧分布式和條帶式的功能。每個文件分布在四臺共享服務器上,通常用于大文件訪問處理,最少需要 4 臺服務器才能創建分布條帶卷。圖5 是distribute stripe volume 示意圖。

圖5 . Distribute stripe volume 示意圖

基于 GlusterFS 實現 Docker 集群的分布式存儲

(5) distribute replica volume 分布式復制卷

Brick server 數量是鏡像數的倍數,兼具 distribute 和 replica 卷的特點,可以在 2 個或多個節點之間復制數據。分布式的復制卷,volume 中 brick 所包含的存儲服務器數必須是 replica 的倍數(>=2倍),兼顧分布式和復制式的功能。圖6 是 distribute replica volume 示意圖。

圖6 . Distribute replica volume 示意圖

基于 GlusterFS 實現 Docker 集群的分布式存儲

(6) stripe replica volume 條帶復制卷

類似 RAID 10,同時具有條帶卷和復制卷的特點。圖7 是 distribute replica volume 示意圖。

圖7 . Stripe replica volume 示意圖

基于 GlusterFS 實現 Docker 集群的分布式存儲

(7) distribute stripe replica volume:分布式條帶復制卷

三種基本卷的復合卷,通常用于類 Map Reduce 應用。圖8 是 distribute stripe replica volume 示意圖。

圖8 . Distribute stripe replica volume 示意圖

基于 GlusterFS 實現 Docker 集群的分布式存儲

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&quota=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&quota=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-

 

 本文由用戶 lucita 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!