はじめに
三番煎じ(そんな日本語はないが)ですが、Kubenetesを使うこととなり、Kubenetesがサポートする分散ファイルシステムのGlusterFSを動かしてみます。ぐぐったら、多くの方が検証されていたので驚きました。CockroachDBと比較すると天と地の差があります...
その他、HDFSとは違ってマスターレスな構成のため、どのノードが落ちても大丈夫なのは非常に良いと思いました。でも、デメリットは何だろう。小さい大量のファイルを扱う場合、NFSより性能が悪くなるところなのですかね。
という訳で、CentOS、Docker、GlusterFSの組み合わせを選択します。
環境
Docker 17.06.2-ce
CentOS 7.4
GlusterFS 3.10.5
トポロジー
Docker環境ですので、Gluster層とStorage層に分けました。Glusterサーバーにデータを格納してしまうと、コンテナとデータが疎結合ではなくなり、Dockerのメリットであるポータビリティー性が悪くなります。
1. 事前準備
-1.1. HostOSの作成と起動
boot2dockerを使います。デスクトップにあるアイコンをダブルクリックし、Docker Quick Start Terminalを起動します。いつも通りクジラで出てきます。
## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\_______/
docker is configured to use the default machine with IP 192.168.99.100
For help getting started, check out the docs at https://docs.docker.com
-1.2. CentOS7イメージのダウンロード
あ、CentOS6は200MBオーバーだったのに、CentOS7は200MBアンダーになっています。CentOS7で、不要なモジュールを削除したのかな。
$ docker pull centos:centos7
centos7: Pulling from library/centos
(省略)
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos centos7 196e0ce0c9fb 6 days ago 196.6 MB
-1.3. Failed to get D-Bus connection: Operation not permittedへの対応
CentOS7では、docker run xxx /bin/bashでコンテナを起動すると、systemctl実行時に下記エラーが表示されます。従いまして、今回は、docker run --privileged xxx /sbin/initで起動することにします。privilegedはセキュリティーの課題があるかもしれないのですが、GlusterFSの検証が目的なので目をつぶります。
・特権モードにする(--privileged)
・コンテナで起動されるコマンドを/sbin/initにする
# systemctl start gluster
Failed to get D-Bus connection: Operation not permitted
また、/sbin/initで起動すると、docker attachコマンドが使用できなくなります。そこで、nsenterを使用します。
$ docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter
(省略)
Status: Downloaded newer image for jpetazzo/nsenter:latest
Installing nsenter to /target
Installing docker-enter to /target
Installing importenv to /target
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos centos7 196e0ce0c9fb 6 days ago 196.6 MB
jpetazzo/nsenter latest c16fe938c1a5 14 months ago 370.9 MB
2. GlusterFS用のマスターイメージの作成と起動
-2.1. マスターイメージの作成
GlusterFS用のマスターイメージを作成すべく、centos7を指定してコンテナを起動します。
$ docker run --privileged -itd --name GlusterMaster centos:centos7 /sbin/init
35740bdcf45f594163f5a9bd9cc0bc38151e4bf2f0c54d54cf7e7e2aa067b93d
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b92d93620ccc centos:centos7 "/sbin/init" 9 seconds ago Up 43 seconds GlusterMaster
Gluster関連パッケージをインストールします。下記を実行すれば、epelを入れる必要がありませんでした。
$ docker-machine ssh default
# docker-enter GlusterMaster
# yum update -y
# yum -y install centos-release-gluster
# yum -y install glusterfs-server
# yum -y install glusterfs
# exit
-2.2. GlusterMasterイメージの作成
Gluster関連パッケージをインストールしたコンテナを、docker commitコマンドにてイメージ化します。
$ docker ps -a
$ docker commit GlusterMaster shimizu/glusterserver
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
shimizu/glusterserver latest b2f06387fe86 7 seconds ago 296MB
centos centos7 196e0ce0c9fb 6 days ago 197MB
jpetazzo/nsenter latest c16fe938c1a5 14 months ago 371MB
-2.3. マスターイメージからコンテナの起動
データボリューム用のコンテナを起動します。
$ docker run -itd -v /data --name gluster1-volume centos:centos7 /sbin/init
$ docker run -itd -v /data --name gluster2-volume centos:centos7 /sbin/init
データボリューム用のコンテナをマウントし、コンテナを起動します。実行するターミナルは、それぞれ別にします。
ターミナルA: gluster-client
$ docker run --privileged -itd --name gluster-client shimizu/glusterserver /sbin/init
ターミナルB: gluster1-server
$ docker run --privileged -itd --volumes-from gluster1-volume --name gluster1-server shimizu/glusterserver /sbin/init
ターミナルC: gluster2-server
$ docker run --privileged -itd --volumes-from gluster2-volume --name gluster2-server shimizu/glusterserver /sbin/init
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3a5e2c99d4f6 shimizu/glusterserver "/sbin/init" Less than a second ago Up 6 seconds gluster2-server
2933fd28433e shimizu/glusterserver "/sbin/init" Less than a second ago Up 14 seconds gluster1-server
1e23056c183c shimizu/glusterserver "/sbin/init" 40 seconds ago Up About a minute gluster-client
92bed989c92d centos:centos7 "/sbin/init" About a minute ago Up About a minute gluster2-volume
5c498f023402 centos:centos7 "/sbin/init" About a minute ago Up About a minute gluster1-volume
b92d93620ccc centos:centos7 "/sbin/init" 22 minutes ago Up 23 minutes GlusterMaster
コンテナに接続し、起動時に指定した/dataがマウントされていることを確認します。
ターミナルB: gluster1-server
$ docker-machine ssh default
$ sudo -s
# docker-enter gluster1-server
# df -k | grep data
/dev/sda1 18745336 461712 17292900 3% /data
ターミナルC: gluster2-server
$ docker-machine ssh default
$ sudo -s
# docker-enter gluster2-server
# df -k | grep data
/dev/sda1 18745336 461724 17292888 3% /data
3. GlusterFSの設定
-3-1. glusterdの起動
最初に、gluster1-serverとgluster2-serverのglusterdを起動します。
ターミナルB: gluster1-server
# docker-enter gluster1-server
# systemctl start glusterd
# systemctl status glusterd
● glusterd.service - GlusterFS, a clustered file-system server
Loaded: loaded (/usr/lib/systemd/system/glusterd.service; disabled; vendor preset: disabled)
Active: active (running) since Thu 2017-09-21 11:50:35 UTC; 5s ago
Process: 116 ExecStart=/usr/sbin/glusterd -p /var/run/glusterd.pid --log-level $LOG_LEVEL $GLUSTERD_OPTIONS (code=exited, status=0/SUCCESS)
Main PID: 117 (glusterd)
CGroup: /system.slice/glusterd.service
└─117 /usr/sbin/glusterd -p /var/run/glusterd.pid --log-level INFO
(省略)
ターミナルC: gluster2-server
# docker-enter gluster2-server
# systemctl start glusterd
# systemctl status glusterd
● glusterd.service - GlusterFS, a clustered file-system server
Loaded: loaded (/usr/lib/systemd/system/glusterd.service; disabled; vendor preset: disabled)
Active: active (running) since Thu 2017-09-21 11:52:28 UTC; 5s ago
Process: 98 ExecStart=/usr/sbin/glusterd -p /var/run/glusterd.pid --log-level $LOG_LEVEL $GLUSTERD_OPTIONS (code=exited, status=0/SUCCESS)
Main PID: 99 (glusterd)
CGroup: /system.slice/glusterd.service
└─99 /usr/sbin/glusterd -p /var/run/glusterd.pid --log-level INFO
(省略)
-3-2. ストレージプールの作成
gluster1-serverから、gluster2-serverをpeerとして登録します。gluster2-serverから、gluster1-serverをpeerとして登録することも可能です。gluster peerを実行することでノード間を認識させ、ストレージプールを作成します。
ターミナルB: gluster1-server
# gluster peer status
Number of Peers: 0
# gluster peer probe 172.17.0.7
peer probe: success.
# gluster peer status
Number of Peers: 1
Hostname: 172.17.0.7
Uuid: 28d83406-c655-4617-955a-96150c409081
State: Peer in Cluster (Connected)
# gluster pool list
UUID Hostname State
28d83406-c655-4617-955a-96150c409081 172.17.0.7 Connected
ca7bb3f6-7d14-4738-a047-2bcbfbaa9b68 localhost Connected
gluster2-serverからも状況を確認します。
ターミナルC: gluster2-server
# gluster peer status
Number of Peers: 1
Hostname: 172.17.0.6
Uuid: ca7bb3f6-7d14-4738-a047-2bcbfbaa9b68
State: Peer in Cluster (Connected)
# gluster pool list
UUID Hostname State
ca7bb3f6-7d14-4738-a047-2bcbfbaa9b68 172.17.0.6 Connected
28d83406-c655-4617-955a-96150c409081 localhost Connected
-3-3. ボリュームの作成
/dataをGlusterFS上のReplicated Volumeとして作成します。最初に、brick用のディレクトリを作成します。
ターミナルB: gluster1-server
# mkdir /data/vol1
ターミナルC: gluster2-server
# mkdir /data/vol1
gluster1-serverからGlusterFSのボリュームを作成します。
ターミナルB: gluster1-server
# gluster volume create test-vol replica 2 172.17.0.6:/data/vol1 172.17.0.7:/data/vol1
volume create: test-vol: success: please start the volume to access data
# gluster volume start test-vol
volume start: test-vol: success
# gluster volume info
Volume Name: test-vol
Type: Replicate
Volume ID: 02a988b9-f365-4028-8e12-72a34c1df544
Status: Started
Snapshot Count: 0
Number of Bricks: 1 x 2 = 2
Transport-type: tcp
Bricks:
Brick1: 172.17.0.6:/data/vol1
Brick2: 172.17.0.7:/data/vol1
Options Reconfigured:
transport.address-family: inet
nfs.disable: on
# gluster volume list
test-vol
# gluster volume status
Status of volume: test-vol
Gluster process TCP Port RDMA Port Online Pid
------------------------------------------------------------------------------
Brick 172.17.0.6:/data/vol1 49152 0 Y 160
Brick 172.17.0.7:/data/vol1 49152 0 Y 126
Self-heal Daemon on localhost N/A N/A Y 146
Self-heal Daemon on 172.17.0.6 N/A N/A Y 180
Task Status of Volume test-vol
------------------------------------------------------------------------------
There are no active volume tasks
4. テスト
-4.1. レプリカの確認
gluster-clientからVolumeをマウントします。マウントコマンド実行時に、下記のWARNINGが出力されましたが、WARNINGなので先に進めました。attr is a command used for extended attributes on XFS filesystem objects とのことで、getfattrを導入すればよいと思ったのですが、導入済みでした。
ターミナルA: gluster-client
# docker-enter gluster-client
# df -k
Filesystem 1K-blocks Used Available Use% Mounted on
none 18745336 867708 16886904 5% /
tmpfs 509824 0 509824 0% /dev
tmpfs 509824 0 509824 0% /sys/fs/cgroup
/dev/sda1 18745336 867708 16886904 5% /etc/hosts
shm 65536 0 65536 0% /dev/shm
tmpfs 509824 6652 503172 2% /run
tmpfs 101968 0 101968 0% /run/user/0
# mkdir /data
# mount -t glusterfs 172.17.0.6:/test-vol /data
WARNING: getfattr not found, certain checks will be skipped..
テストしてみます。すごいです。ファイルを更新しても問題ありません、レプリカされています。
ターミナルA: gluster-client <ファイルを作成
# pwd
/data
# touch shimizu
# ls -la | grep shimizu
-rw-r--r-- 1 root root 0 Sep 21 12:36 shimizu
ターミナルB:gluster1-server </data/vol1を確認
# ls -la /data/vol1 | grep shimizu
-rw-r--r-- 2 root root 0 Sep 21 12:36 shimizu
ターミナルC:gluster2-server </data/vol1を確認
# ls -la /data/vol1 | grep shimizu
-rw-r--r-- 2 root root 0 Sep 21 12:36 shimizu
-4.2. 排他制御の確認
gluster-clientでファイルを操作している時に、gluster2-serverで操作できるのかを確認します。
ターミナルA: gluster-client
# vi /data/shimizu
ターミナルAでviでファイル操作中に、ターミナルBでviを実行してみると、下記になる。想定通りというか、当たり前か... どのノードからファイルを更新しても良いが、1時点では1ノードからしかアクセスできない。
# vi shimizu
E325: ATTENTION
Found a swap file by the name ".shimizu.swp"
owned by: root dated: Fri Sep 22 04:50:04 2017
file name: /data/shimizu
modified: no
user name: root host name: 71d3366cf052
process ID: 208
While opening file "shimizu"
dated: Fri Sep 22 04:50:00 2017
(1) Another program may be editing the same file. If this is the case,
be careful not to end up with two different instances of the same
file when making changes. Quit, or continue with caution.
(2) An edit session for this file crashed.
If this is the case, use ":recover" or "vim -r shimizu"
to recover the changes (see ":help recovery").
If you did this already, delete the swap file ".shimizu.swp"
to avoid this message.
5. 用語の整理
用語 | 意味 |
---|---|
Storage Pool | ストレージクラスタに参加するサーバーの集まり。 |
Brick | 個々のサーバー上のディレクトリになり、GlusterFSにストレージとして提供される。 |
Volume | Brickを論理的に集約した、GlusterFS上の仮想的なストレージ領域。ストレージを使う側は、このVolumeをマウントして利用することになる。 |
Volumeには3つのタイプ(Distributed Volume、Replicated Volume、Striped Volume)があり、Volumeを作成するとき選択できます。タイプ毎にファイルの保存方法が異なります。
まとめ
所感は、OSSなのにすごいです。簡単に作れます。
kubenetesと連携してテストできていないのですが、これからは、GlusterFS等でストレージを仮想化、Kubenetes等でDockerコンテナを仮想化ですね。IBM社はubiquityを提供していますので、何が違うのかについて今後調べたいと思います。
参考
Gluster
DockerでGlusteFS。分散ファイルシステムの実装。
CentOS7でGlusterFSの環境構築