CoreOS+DockerコンテナでCephブロックデバイス(RBD)を試してみた

###更新履歴

2014/10/11 cephx auth無効化しないでmap imageできたので、修正しました

----------------

Docker環境ではDBファイル等を保存する永続データストアは、各ホストのローカルストレージに置いてしまうとコンテナがホストを移動できなくなってしまうので、外部共有ストレージを使う必要があります。AWS/GCP等のパブリッククラウドでは、目的に応じてストレージサービスを選べばいい訳ですが、ローカル環境では耐障害性を考慮した外部共有ストレージを用意する必要があります。

高価なNAS/SANストレージにかわる共有ストレージとして注目されている、[Ceph](http://ceph.com)を[CoreOS](http://coreos.com)上のDockerコンテナからマウントできるか試してみました。

Cephを使用する方法として、オブジェクトストレージ（AWS S3/Openstack SWIFT互換 REST API)、POSIXファイルシステム、ブロックデバイスの３通りの方法が可能です。

一番簡単なのは、Ceph-FUSEを使ってPOSIXファイルシステムとして直接マウントする方法ですが、CoreOSでは423.0.0からCephブロックデバイスカーネルモジュールが追加されたので、実際にコンテナからマウントできるか試してみました。

##構築環境

CoreOSは、現在stableチャネルは410.2.0のため、betaチャネルを使用します。

````
$ cat /etc/os-release
NAME=CoreOS
ID=coreos
VERSION=444.3.0
VERSION_ID=444.3.0
BUILD_ID=
PRETTY_NAME="CoreOS 444.3.0"
ANSI_COLOR="1;32"
HOME_URL="https://coreos.com/"
BUG_REPORT_URL="https://github.com/coreos/bugs/issues"
````

念のためceph-rbdのカーネルモジュールがあるか確認します。

````
$ find /lib/ -type f | egrep 'ceph|rbd'
/lib/modules/3.16.2+/kernel/net/ceph/libceph.ko
/lib/modules/3.16.2+/kernel/drivers/block/rbd.ko
````

Cephは、CoreOSクラスタとは別に構築したCephクラスタ(Firefly)を使用します。

````
# ceph -v
ceph version 0.80.5
````

##クライアント環境の作成

まずCoreOS上に/etc/cephディレクトリを作成し、Cephに接続するための構成ファイルとキーファイルをCephクラスタからコピーします。

````
$ sudo mkdir /etc/ceph
$ sudo scp root@<cephノードアドレス>:/etc/ceph/ceph.conf root@<cephノードアドレス>:/etc/ceph/ceph.client.<cephユーザ>.keyring /etc/ceph/
$ sudo mkdir /mnt/ceph
````

Cephマウント用として/mnt/cephデイレクトリも作成しておき、コンテナ実行時に/etc/cephと/mnt/cephを-vオプションでコンテナにマウントします。

CoreOS自身にはなにもインストールできないので、Cephのクライアント（ceph-common）はコンテナにインストールする必要があります。コンテナはCephを標準でサポートしているUbuntu14.04で作成します。
注：ここでは予め作成しておいたsshサーバがインストールされて、rootログインできるコンテナを使っています。いきなり下記コマンドでコンテナ作成してもsshログインできません。
コンテナは、--privilegedモードで実行しないとエラーになります。

````
$ docker run --privileged -v /etc/ceph:/etc/ceph -v /mnt/ceph:/mnt/ceph -d -p 1022:22 ossl/ubuntu /usr/sbin/sshd -D
````

コンテナが起動されたことを確認して、sshログインします。

````
$ docker ps
CONTAINER ID        IMAGE               COMMAND               CREATED             STATUS              PORTS                   NAMES
974c0461a790        ossl/ubuntu1:0.1    "/usr/sbin/sshd -D"   15 hours ago        Up 15 hours         0.0.0.0:1022->22/tcp    distracted_brown
$ ssh -p 1022 root@<coreosホストアドレス>
````
Cephのクライアント（ceph-common）をインストールし、Cephへの接続確認をします。

````
root@974c0461a790:~# apt-get install ceph-common
root@974c0461a790:~# ceph -s
    cluster d3270e97-4b31-4c7b-9ca7-08d0672889c9
     health HEALTH_OK
     monmap e2: 3 mons at {EXFS1=192.168.0.1:6789/0,EXFS2=192.168.0.2:6789/0,EXFS3=192.168.0.3:6789/0}, election epoch 66, quorum 0,1,2 EXFS1,EXFS2,EXFS3
     mdsmap e120: 1/1/1 up {0=EXFS2=up:active}, 2 up:standby
     osdmap e244: 3 osds: 3 up, 3 in
      pgmap v11119: 296 pgs, 16 pools, 10332 kB data, 108 objects
            41007 MB used, 610 GB / 685 GB avail
                 296 active+clean
````

上記のようにCephクラスタの状態が表示されればOKですので、あとはコンテナからCephのRBDコマンドを使ってプールとイメージを作成します。

````
# pool作成
root@974c0461a790:~# rados mkpool test-pool
root@974c0461a790:~# rados lspools
 
# image作成
#	- sizeの単位はMB
root@974c0461a790:~# rbd --pool test-pool create --size 1024 test-image
root@974c0461a790:~# rbd --pool test-pool ls -l
````

次にローカルデバイスにmapすれば良いのですが、残念ながら現行バージョンでは *rbd map* コマンドに[バグ](http://tracker.ceph.com/issues/9355)があり使えません。
~~上記バグを回避するには、Cephクラスタの認証を無効にします。クライアントとクラスタ全ノードのceph.confファイルの[global]セクションを下記のように変更し、再起動します。
※[Ceph公式ドキュメント](http://ceph.com/docs/giant/rados/configuration/auth-config-ref/)にあるように、本番環境で認証を無効化することはお勧めできません。~~

次にCoreOS上で[kernel object operation](http://ceph.com/docs/argonaut/rbd/rbd-ko/)を実行します。

````
$ sudo modprobe rbd
$ echo "{mon-ip-address}  name={user-name},secret={keyringファイル内のkey = 以降の文字列} {pool-name} {image-name}" | sudo tee /sys/bus/rbd/add
````
例
`echo "192.168.100.1,192.168.100.2,192.168.100.3 name=admin,secret=XQDPptNTKBAOBRAA2+OX4mz1Bw+YeEhBdd4xOg== test-pool test-image"|sudo tee /sys/bus/rbd/add`

再度コンテナを起動しsshログイン後、mapを確認します。

````
root@974c0461a790:~# rbd showmapped
id pool      image      snap device
0  test-pool test-image -    /dev/rbd0
````

確認後、フォーマットしマウントします。

````
root@974c0461a790:~# mkfs.btrfs /dev/rbd0
root@974c0461a790:~# mount /dev/rbd0 /mnt/ceph
root@974c0461a790:~# df -Th
Filesystem     Type   Size  Used Avail Use% Mounted on
/dev/vda9      btrfs  7.4G  1.8G  5.4G  25% /
tmpfs          tmpfs  500M     0  500M   0% /dev
shm            tmpfs   64M     0   64M   0% /dev/shm
/dev/vda9      btrfs  7.4G  1.8G  5.4G  25% /etc/ceph
/dev/rbd0      btrfs  1.0G  256K  894M   1% /mnt/ceph
````

これで書き込める状態になりました。
とりあえず、きょうはここまで。