第521回ではLXD 3.0の基本的な使い方を、第535回ではネットワークの設定方法を紹介しました。今回はLXD 2.0から3.0にかけて非常に便利になったストレージ関連の設定について紹介しましょう。
LXDにおけるコンテナストレージ
LXDはシステムコンテナである以上、コンテナのベースイメージや、インスタンスであるルートファイルシステムをどこかに保存しなくてはなりません。LXDにおいてこれは「ストレージプール」と呼ばれています。また、ストレージプールを管理するシステムは「ストレージバックエンド」です。
LXD 2.0ではストレージプール・ストレージバックエンドはシステム上に1つしか設定できませんでした。実際には初期設定時にバックエンドを選択してそれで完了だったのです。
この状況はLXD 2.9で大きく変わることになります。1つのシステム上で複数のストレージプールを設定できるようになったのです。ストレージプールごとに異なるストレージバックエンドを選択可能です。さらに「lxd storage
」コマンドが実装され、ストレージに関する様々な設定を操作できるようになりました。
これにより、たとえばワークロードの大きなインスタンスはSSD上に構築したストレージプールを利用し、サイズが重要なインスタンスはHDD上に構築したストレージプールを利用するといった使い分けが可能になります。
さらにはストレージプールを利用して、コンテナに対して追加のストレージボリュームをかんたんに追加・削除できるようになりました。これはDockerで言うところのVolumeコンテナをイメージすれば良いでしょう。
さて、LXDのインストール直後はストレージプールは何も作られていません。最初のストレージプールは「lxd init
」コマンドで作成します。第521回にも出ている実行例から抜粋すると、次の部分です。
設定を変更しなければ「default」という名前のストレージプールが「btrfsバックエンド」を利用して作成されます。
LXD 3.0でサポートしているバックエンドは次の5つです。
Dirはディレクトリツリーをそのままコンテナとして見せる方式です。古式ゆかしいchrootをLXD再現しているようなものです。どんなシステムでも確実に動くという強みはあるものの、性能的にも容量的にも非常に効率が悪い上に、LXDのコンテナ操作に関するさまざまな便利機能をサポートしていません。よっぽどのことがない限りは、これを選ぶことはないでしょう。
BtrfsとLVM、ZFSはいずれも十分なパフォーマンスを発揮しますので、どれを選んでも良いでしょう。これらのバックエンドを使用するためには、それぞれbtrfs-progs、lvm2、zfsutils-linuxパッケージがインストールされていなくてはなりません。Ubuntuのクラウドイメージだとzfsutils-linuxは初期インストールされていないため、上記の「lxd init
」ではZFSでは表示されていないのです。
Btrfsを選んでおくと、LXDの中でLXDを使う場合に便利です。どれにするか迷ったのなら、UbuntuであればBtrfsを選んでおけば良いでしょう。
分散型計算機向けのオブジェクトストレージシステムであるCephはLXD 2.16からサポートされるようになりました。LXDそのものをクラスタ化する際には、Cephは十分な選択肢となってくるでしょう。
その他、バックエンドごとの機能比較やストレージプールの容量増加方法、注意点などは公式のドキュメントを参照してください。
ちなみに今回の記事も、Ubuntu 18.04 LTS/LXD 3.0を前提としています。
ストレージプールの基本
さて実際にストレージプールを使ってみましょう。まずは「lxd init
」で生成されたdefaultプールを確認してみます。
defaultプールが作られていることがわかります。btfsバックエンドでは、ブロックデバイスを指定しない場合、ファイルイメージ上にbtrfsを構築します。
さらにストレージプールごとの詳細情報を表示してみましょう。
サイズの「5GB」は「lxd init
」時に設定した値です。「used_by
」はこのストレージプールを利用しているコンポーネントのリストです。LXDでは、コンテナ用の設定テンプレートとしてプロファイルが用意されています。このプロファイルもまた、ストレージプールに保存されるのです。
「lxd init
」で作成されるdefaultプロファイルの内容を確認してみましょう。
defaultプロファイルを指定してコンテナを作ったとき、rootディレクトリはdefaultストレージプールを利用することがわかります。
実際にコンテナを作成・立ち上げてみましょう。
コンテナが作られた状態で、defaultプールの状態を確認してみます。
コンテナ本体だけでなく、ダウンロードしたコンテナイメージもまたdefaultプールを使っていることがわかりますね。
新規にストレージプールを作成する
今度は新規にストレージプールを作ってみましょう。
コマンドのフォーマットは「lxc storage create ストレージプール名 バックエンド名 設定
」です。設定を省いた場合は、既定の値が使われます。たとえばbtrfsの場合、ソースファイルはイメージファイルとなります。
defaultプールと異なり、追加で作られたばかりのストレージプールは誰からも使われていません。
ちなみにイメージファイルの場合、シンプロビジョニングになりますので、イメージファイルが存在するデバイスの実サイズ以上のサイズを指定することも可能です。もちろんその場合は、ストレージプールの使用量が100%に達するより前に、ディスクフルになってしまいます。
もうひとつ既定の値以外の設定を使って、ストレージプールを作成してみましょう。設定は「キー=値」の形で指定できます。指定可能なキーは公式ドキュメントの「Storage pool configuration」を参照してください。
たとえばsourceを指定しなかった場合は、上記のようにイメージファイルを使用します。イメージファイルの代わりにブロックデバイスを使いたい場合は、次のように設定します。
新しく作成したストレージプールが/dev/sdb1を専有していることがわかりますね。ストレージプールごとの設定は「lxc storage set プール名 キー 値
」でも変更できます。
作成したストレージプールを指定してコンテナを起動する
新しく作成したストレージプールを指定してコンテナを作成してみましょう。ストレージプールを明示的に指定するには「lxc init
」や「lxc launch
」の「--storage
」オプション(短縮形は「-s
」)を利用します。
新しいコンテナをdefaultプールではなくkofukiプールに作成した結果、kofukiプールのほうにのみ新しいコンテナが現れていることがわかります。
もう一つ注意すべきポイントは、コンテナイメージもkofukiプールに表示されていることです。しかもフィンガープリントはdefaultプールにあるそれと同じです。
LXDではリモートからコンテナイメージを取得した上で、インスタンスを立ち上げます。よって初回のコンテナの立ち上げは、インターネット経由でのイメージの取得の時間が必要になるためどうしても時間がかかってしまうのです。その代わり、同じコンテナイメージを使う限り、2回目以降はすぐに立ち上がります。
しかしながら、今回のように同じコンテナイメージを使うインスタンスであっても、別のストレージプールに作る場合は再度コンテナイメージの取得が必要です。LXDはローカルのイメージを優先的に使用するため、defaultコンテナからkofukiコンテナへのイメージのコピーが発生します。このため、インターネット経由の取得ほどではないにしろ、それなりに時間がかかります。ただし一度kofukiプールにコピーさえしてしまえば、以降は再利用されます。
新規にストレージボリュームを作成する
新しいLXDのストレージ関連のもう一つの新機能が、コンテナにアタッチできる「カスタムストレージボリューム」です[1]。これは要するにDockerのボリュームコンテナみたいなものです。
ストレージプール上に任意の数のボリュームを作成し、そのボリュームを好きなコンテナにアタッチできます。同時に複数のコンテナにもアタッチできるため、コンテナ間の共有ディレクトリのような使い方も可能です。
まずはストレージボリュームを作成してみましょう。
ボリュームの最大容量はプールの容量に依存します。ただし「lxc storage volume set ボリューム名 size 値
」で明示的に制限をかけることも可能です。
特定のコンテナにボリュームをアタッチするには「lxc storage volume attach プール名 ボリューム名 コンテナ名 コンテナ上のパス
」を指定します。少し長いですね。
chieプールはブロックタイプ(/dev/sdb1)のストレージプールなので、そのボリュームであるmiruyaは、そのままbtrfsのサブボリュームがマウントされていることがわかります。アタッチ時は、コンテナ内の必要なパスが適切に作成されます。
ストレージボリュームの利点は、複数のコンテナにマウントできることです。そこで同じmiruyaボリュームをmihonoコンテナにもマウントしましょう。
この時点でボリュームには何もないため、kiyokaコンテナから適当なファイルを表示しようとしても、何も表示されません。
ここで別のmihonoコンテナからファイルを書いてみましょう。
上記のように即座にkiyokコンテナにもその結果が反映されましたね。
ちなみにmihonoコンテナはdefaultプールに、kiyokaンテナはkofukiプールに、miruyaボリュームはchieプールに所属しているものの、これらの違いは特に気にすることなくアタッチ可能なのも便利なポイントのひとつです。
また、不要になれば次のようにデタッチできます。
ボリュームのコピーや移動
ボリュームはプール間のコピーや移動が可能です。
もちろん別名にも変更できますし、複製の伴わない移動も可能です。
上記のように、アタッチ中のボリュームは当然のことながら移動できませんので、適宜デタッチしてください。