LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術

第26回LXCの構築・活用[12] ─ APIと言語バインディング

第8回以降、LXCをインストールした際にインストールされる"lxc-"で始まる付属のコマンド群を使って、LXCの機能を紹介してきました。今回は、独自のプログラムをLXCを使って開発する際に使うAPIと言語バインディングについて簡単に紹介しましょう。

Ubuntuでは、"lxc-"で始まるコマンド群は"lxc"パッケージに含まれています。"lxc"パッケージをインストールする際、依存関係により"liblxc1"というパッケージがインストールされます。この"liblxc1"パッケージに含まれるliblxcは、文字通りLXCを使ってコンテナを扱うためのライブラリです。いわば、これがLXCのコアとなる部分で、C言語のAPIを提供するライブラリです。

"lxc-"で始まるコマンド群は、このliblxcが提供するAPIを使い実装されています。liblxcを使って何かプログラムを書く場合は、これらのコマンド群自身がliblxcが提供するAPIを使う際の良い例となるでしょう。

"lxc-"で始まるコマンド群は、コンテナに関する一般的な操作を行うコマンドしかありません。自身のコンテナを利用するアプリケーションやシステムを実装する際、独自の操作を実装するとともに、その中でAPIを使用してコンテナを操作するような独自のコマンドを実装できます。

しかし、実際にはC言語でプログラムを書く場合だけでなく、C言語以外のスクリプト言語を使う場合も多いはずです。そのような場合に備えて、LXCでは各種言語のバインディングが用意されています。

LXCのソースには言語バインディングとして、

  • Python3
  • Lua

が同梱されています。

"lxc-"で始まるコマンド群の中にもこれらの言語バインディングを使って書かれているコマンドがあります。たとえば前回紹介したlxc-start-ephemeralコマンドや、コンテナのリストを表示するlxc-lsコマンドはPython3で書かれています。また、Ubuntuではインストールされていませんが、コンテナの一覧をtopコマンドのように表示するlxc-topというコマンドがLuaを使って書かれています。

また、ソースツリーと別に以下の言語バインディングが存在します。

Haskell以外はLXCの公式リポジトリ以下に存在しています。Go言語のバインディングは、LXC関連のプロダクトで開発が非常に活発なLXDに使われていますので、今一番活発に利用されている言語バインディングかもしれません。

C

C言語からliblxcを使う場合は、linuxcontainer.hを参照してください。ここに挙がっているものだけが公開のAPIとなります。

開発のmasterブランチから生成したAPIドキュメントもあります。このドキュメントはソースから生成できます。

APIを使ってコンテナを作成し、起動してみましょう。

  • コンテナ名は"gihyo"
  • downloadテンプレートを使用
  • 使用するイメージはUbuntu Trustyのamd64版イメージ
  • ストレージバックエンドは"dir"を使用
 1: #include <stdio.h>
 2: #include <lxc/lxccontainer.h>
 3:
 4: int main() {
 5:     struct lxc_container *c;
 6:     int ret = 1;
 7:
 8:     /* 新しいコンテナの作成、名前は"gihyo" */
 9:     c = lxc_container_new("gihyo", NULL);
10:     if (!c)
11:         goto out;
12:
13:     /* コンテナの作成 */
14:     if (!c->createl(c, "download", "dir", NULL, LXC_CREATE_QUIET,
15:                     "-d", "ubuntu", "-r", "trusty", "-a", "amd64", NULL)) {
16:         fprintf(stderr, "Failed to create container\n");
17:         goto out;
18:     }
19:
20:     /* コンテナの起動 */
21:     if (!c->start(c, 0, NULL)) {
22:         fprintf(stderr, "Failed to start container\n");
23:         goto out;
24:     }
25:
26:     /* コンテナ名、コンテナの状態を表示 */
27:     printf("Container %s is %s\n", c->name, c->state(c));
28:
29:     ret = 0;
30:
31: out:
32:
33:     /* 後始末 */
34:     lxc_container_put(c);
35:     return ret;
36: }

簡単に処理を追って説明します。

  • 9行目でlxc_container_newを使い、LXCでコンテナを表すlxc_container構造体を作成します。このlxc_container構造体に、コンテナの持つ属性やコンテナを操作する関数が全て入っています。あとはこの構造体内の関数を呼び出してコンテナの操作を行います。
  • 13行目でlxc_container構造体に定義されたcreatelを使い、コンテナの作成を行っています。これはちょうど以下のコマンドの実行と同じです。
lxc-create -t download -n gihyo -- -d ubuntu -r trusty -a amd64
  • 21行目でstartを使いコンテナを起動しています。これはlxc-startコマンドに相当します。
  • 27行目でコンテナが起動したことを確認するためにコンテナ名とコンテナの状態をstateを使って表示しています。
  • 34行目は後始末です。確保したlxc_container構造体を開放しています。

このプログラムをgihyo.cという名前で保存し、以下のようにコンパイルして起動してみます。

$ gcc -o gihyo gihyo.c -llxc
$ sudo ./gihyo
Container gihyo is RUNNING

実行すると以上のようにコンテナが実行中であることが表示されます。stateを使うと第10回で紹介したコンテナの状態が取得でき、ここでは実行中である"RUNNING"が表示されています。

このように起動したコンテナはlxc-startで起動したコンテナと同じように実行されていますので、lxc-で始まる付属コマンドで操作できます。

$ sudo lxc-ls -f
NAME   STATE    IPV4        IPV6  AUTOSTART  
-------------------------------------------
gihyo  RUNNING  10.0.3.166  -     NO         

lxc-lsコマンドで状態の表示ができました。lxc-stopコマンドで停止させてみましょう。

$ sudo lxc-stop -n gihyo
$ sudo lxc-ls -f
NAME   STATE    IPV4  IPV6  AUTOSTART  
-------------------------------------
gihyo  STOPPED  -     -     NO         

以上のように停止しましたね。

liblxc1が提供しているAPIは比較的シンプルですので、linuxcontainer.hを見たり、付属のコマンドを見たりして試してみてはいかがでしょうか。

Python

自身が開発するアプリケーションやシステム内でAPIを使ってLXCコンテナを操作する場合、C言語を使って開発するよりは、各種のスクリプト言語を用いるケースが多いでしょう。

ここではスクリプト言語からコンテナを操作する例として、ソースに同梱されているPythonバインディングを使った例を紹介しましょう。

C言語で示した例と同様にコンテナを作成し起動した後、コンテナ内で処理を行ってみます。

 1: #!/usr/bin/python3
 2: import lxc
 3: import sys
 4: import socket
 5:
 6: # ホスト名を表示する
 7: def print_hostname():
 8:     print("Hostname: {}".format(socket.gethostname()))
 9:     return 0
10:
11: # 新しいコンテナの生成、名前は"gihyo"
12: c = lxc.Container("gihyo")
13: if c.defined:
14:     print("Container already exists", file=sys.stderr)
15:     sys.exit(1)
16:
17: # コンテナの作成
18: if not c.create("download", lxc.LXC_CREATE_QUIET, {"d": "ubuntu",
19:                                                    "r": "trusty",
20:                                                    "a": "amd64"}):
21:     print("Failed to create container", file=sys.stderr)
22:     sys.exit(1)
23:
24: # コンテナの起動
25: if not c.start():
26:     print("Failed to start container", file=sys.stderr)
27:     sys.exit(1)
28:
29: # コンテナ名、コンテナの状態を表示
30: print("Container {} is {}".format(c.name, c.state))
31:
32: # コンテナ内でprint_hostnameを実行
33: c.attach_wait(print_hostname)
34:
35: sys.exit(0)

29行目でコンテナの状態を表示しているところまではC言語の例と同じです。その後attach_waitという関数を使って5〜8行目で定義したprint_hostnameという関数を実行しています。

print_hostnameはホスト名を表示するだけの簡単な関数です。attach_waitlxc-attachと同様に指定したコンテナの名前空間内で指定した処理をするための関数ですので、print_hostnameはコンテナ内で実行されます。

このスクリプトを実行すると、以下のように作成したコンテナで設定されているgihyoというホスト名が表示されます。

$ sudo python3 gihyo.py
Container gihyo is RUNNING
Hostname: gihyo

このようにスクリプト言語を使用すると、簡単にコンテナの名前空間内でスクリプト言語の関数を実行できますので、スクリプト内でコンテナ内のセットアップまで行えます。多数のコンテナを同時にセットアップしつつ、コンテナ内のカスタマイズする処理を自動化したいといった用途に使えますね。

これ以外にも、LXCがサポートするさまざまな処理をバインディング経由で行えますので、クローンを行った後にコンテナに必要な変更を行ったり、存在するコンテナ全てに同じ処理を行ったりといった処理が容易に行えます。

まとめ

今回はCとPythonの簡単なプログラムを使って、LXCが提供するC言語のAPIと言語バインディングについて簡単に説明しました。

APIやバインディングを用いて、比較的容易にLXCコンテナが扱えることがおわかりいただけたのではないかと思います。Pythonバインディングの例では、Pythonの関数をコンテナの名前空間内で実行できることを説明しました。この機能により、コンテナ内のセットアップやカスタマイズが行えます。

バインディングについては、紹介したPython以外のバインディングについても同様に記述できるはずですので、それぞれの言語に堪能な方はぜひ試していただきたいと思います。

また、今回のプログラムを書くにあたって参考にしたサイトを最後に挙げておきます。

連載のお礼と今後

元々この連載は、私がLXCのmanページの翻訳を始めたり、Plamo LinuxでLXCを使えるようにしていたところ、コンテナ技術が徐々に注目を集めだしたので、Linuxのコンテナ技術の概要とLXCの使い方を6〜7回程度で簡単に紹介しようという企画から始まりました。まだDockerが今のように爆発的な注目を集める前の話でした。

それが、いざ書き始めてみると意外に説明する機能や技術が多く、書いている間に量が増えていき、Linuxカーネルの機能を説明しただけで当初考えていた回数に到達し、LXCの説明を始めるとあっという間に予定の回数を超え、気づいてみると前回の25回でもう連載を開始してから1年を超えていました。

これまで連載を続けてきて、たくさんの方々にネット上でブックマークやツイートなどで反応をいただいたり、勉強会で記事をきっかけに声をかけていただいたりと、うれしいことがたくさんありました。ありがとうございました。

また、この連載をきっかけに気づいたマニュアルの不備やバグの修正をパッチとして提出しました。このようにLXCを紹介しながら、LXCの完成度の向上に少し貢献できたこともうれしいことの一つです。

全ての機能を紹介したわけではありませんが、今回で連載の目的であったLXC 1.0が持つ機能の紹介については一通り説明が終わりました。

そこで一旦、今回でこの連載はひと区切りとさせていただきたいと思います。とは言っても連載を終わるわけではありません。

連載を続けているうちに、LXCは1.1がリリースされて機能が追加されています。コンテナを取り巻く状況は変わり、LXDなどのプロジェクトがスタートしたりと、LXC周辺でもいろいろと動きがありました。

これまでは隔週で連載を続けてきましたが、今後は連載を続けているうちに変化したことや新しく追加された機能などを、今までより少しゆっくりとしたペースで紹介していければと思っています。当面はLXC 1.1の新機能を調べながら紹介していこうかと思っています。

これまで私のつたない説明に目を通していただきありがとうございました。そして今後もよろしくお願いいたします。

第7回 コンテナ型仮想化の情報交換会@大阪

6/20(土)に大阪でコンテナを扱う勉強会の開催を予定しています。ご興味のある方は、ご都合が合えばぜひご参加ください。

おすすめ記事

記事・ニュース一覧