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

第32回 コンテナのチェックポイント・リストア

この記事を読むのに必要な時間:およそ 6 分

前回を書いてからいつの間にか4ヵ月も経ってしまいました。この間にLXCを含むlinuxcontainers.orgの各プロジェクトからは,いずれもバージョンを合わせた,新しいstableリリースとなる2.0が4月にリリースされています。

これまではLXCというソフトウェアだけが正式にリリースされていましたが,このタイミングでLXCLXDLXCFSというソフトウェアが同時にリリースされました。以前紹介したことがあるCGManagerに関しては,新しいカーネルのリリースに含まれた機能とLXCFSのリリースにより不要となったので,今後はメンテナンスのみが行われます。

これらのstableリリースとなる2.0は,いずれもUbuntuの新しい長期サポート版である16.04に含まれています。

LXC 2.0や,その他のソフトウェアについては,今後機会があればこの連載でも取り上げたいと思います。


LXC 1.1で導入された大きな新機能は,コンテナ内で起動するinitとしてsystemdがサポートされたこと,CRIUを使ったチェックポイント・リストア機能がサポートされたことでした。

第31回で紹介したのは設定項目に関する変更点でした。このうちのいくつかはsystemdをサポートするために内部の実装が変更されたことに伴う変更でした。

そして,まだ紹介していないLXC 1.1の新機能がCRIUを使ったチェックポイント・リストア機能です。今回はこの機能について紹介しましょう。

なお,今回は新たにリリースされたUbuntu 16.04 LTS上でLXC 2.0を使っていますが,LXC 1.1でも同じように実行できるはずです。

チェックポイント・リストアとCRIU

チェックポイント機能は,実行中のプロセスの状態をファイルに保存します。リストア機能は,そのファイルに保存された情報を使ってプロセスを再開させ,保存した時点の状態に戻します。

チェックポイント・リストア処理に必要な機能はLinuxカーネルに実装されています。そしてこの機能を実際に使ってチェックポイント・リストア処理を行うために,OpenVZの開発チームによって開発されているツールが,"Checkpoint/Restore In Userspace"の頭文字を取って命名されているCRIUというツールです。

チェックポイントの際,CRIUは主に/proc以下からプロセスに関する情報を収集し,それをファイルに保存します。リストア処理の際は,ファイルから各種リソースの情報を取得してリストアし,プロセスを生成します。

CRIUはOpenVZ関連のプロジェクトですが,OpenVZに特化しているわけではありません。LXCやDockerというコンテナだけでなく,Linux上で動作しているプロセス一般に使えます。

CRIUが動作する環境

CRIUはカーネル3.11以上で動作します。

動作条件を満たすディストリビューションでは,パッケージが準備されているかもしれません。その場合はパッケージからインストールすれば簡単に使用する環境が整います。CRIUのページにパッケージ情報のページがありますのでチェックしてみてください。

パッケージがなくても,比較的簡単にソースからビルドできます。こちらも公式ページに手順が説明されています。この場合,CRIUのインストールが済んだあとに,カーネルがCRIUに必要な機能をサポートしているかをチェックできます。

$ sudo criu check
Looks good.

CRIUの用途

CRIUの用途として考えられることは,CRIUのページにも"Usage scenarios"として様々なシナリオが挙げられているようにいろいろあります。

ここに挙がっているシナリオのうち,LXCがチェックポイント・リストア処理をサポートする目的は主に,

  • ライブマイグレーション
  • 起動が遅いサービスのスピードアップ

の2つでしょう。

ライブマイグレーションについては,大規模な仮想マシン環境ですでに使われている場合は多いでしょうから,みなさんもイメージしやすいと思います。あるコンテナホスト上で起動しているコンテナを,チェックポイント機能を使って実行イメージを保存し,保存したイメージを別ホストにコピーしてそのイメージから起動することにより,起動したままホスト間を移動させます。

後者の「起動が遅いサービスのスピードアップ」は,たとえばJavaサーブレットを使う環境などで,アプリの起動に非常に時間がかかるケースがあります。このような場合,起動をスピードアップするために,アプリが起動した状態でCRIUを使ってチェックポイント機能を実行し,実行イメージを保存しておき,起動時にそのイメージから起動できます。

CRIUコマンド

CRIUコマンドを試す前に,CRIUコマンドの実行方法を確認しておきましょう。

criuでは,criuのあとに行いたい処理をコマンドとして指定し,そのあとにオプションを指定する形で実行します。チェックポイント処理の場合はcriu dumpリストア処理の場合はcriu restoreとなります。

criuコマンドはいろいろな機能を持っており,バージョンによっても機能が変わりますので,ここでは今回使用するコマンド,オプションのみを紹介します。

表1 criuのコマンド(主なもの)

コマンド 機能
dump チェックポイント処理を実行
restore リストア処理を実行
check カーネルがCRIUに必要な機能をサポートするかどうかチェック

コマンドのあとに指定するオプションのうち,dumprestoreで共通に使うものは以下のようなオプションです。

表2 共通オプション(主なもの)

オプション 意味
-D / --images-dir チェックポイントデータの保存ディレクトリ
-o / --log-file ログファイル名
-v ログレベル。vの数でレベルを指定でき,最大4まで
-j / --shell-job シェルから実行したプロセスを対象とする場合に指定

dumpコマンドでは以下のようなオプションを使用します。チェックポイント対象のプロセスを指定する必要がありますので,-tは必ず指定します。

表3 dumpコマンドで使う主なオプション

オプション 意味
-t / --tree チェックポイント対象のプロセスの指定

restoreコマンドは,-dオプションを指定せずにcriu restoreを実行すると,リストアしたプロセスはcriuコマンドの子プロセスになりますので,通常は-dを指定すると良いでしょう。

表4 restoreコマンドで使う主なオプション

オプション 意味
-d / --restore-detached リストア後プロセスをcriuから切り離す

CRIUを使ったプロセスのチェックポイントとリストア

それでは実際にCRIUを使っていきましょう。

今回の実行例はUbuntu 16.04 LTSを使用しています。CRIUはパッケージからインストールしており,バージョンは2.0です。

$ lsb_release -d
Description:    Ubuntu 16.04 LTS
$ uname -r
4.4.0-21-generic
$ criu --version
Version: 2.0

criuはパッケージインストールしていますので,動作して当然なのですが,一応環境がCRIUをサポートしているかチェックしてみましょう。

$ sudo criu check
Warn  (libnetlink.c:65): ERROR -2 reported by netlink
Warn  (libnetlink.c:65): ERROR -2 reported by netlink
Warn  (sockets.c:702): The current kernel doesn't support packet_diag
Warn  (libnetlink.c:65): ERROR -2 reported by netlink
Warn  (sockets.c:712): The current kernel doesn't support netlink_diag
Looks good.

警告は出るものの"Looks good"と出ているようにCRIUが動作する環境であることがわかります。

ではプロセスの状態をファイルに保存し,保存したファイルからリストアしてみましょう。チェックポイント・リストア処理の対象として,以下のようなシェルスクリプトを準備しました。1秒おきにファイルにインクリメントした数字を追加していくだけの簡単なスクリプトです。

#!/bin/sh
n=0
while :
do
  sleep 1
  n=`expr $n + 1`
  echo $n >> testfile
done

このスクリプトを実行し,ファイルへ数字が書き込まれていく様子を確認します。pstreeコマンドでプロセスの様子も確認しておきます。

$ sh test.sh &
[1] 16246
$ tail -f testfile 
1
2
3
4
5
6
^C
$ pstree -p 15599
bash(15599)─┬─pstree(16265)
            └─sh(16246)───sleep(16264)

さてそれではチェックポイント機能でプロセスの状態をファイルに保存します。ファイルを保存するディレクトリを作成したあと,criuコマンドでチェックポイント処理を実行します。

$ mkdir criu
$ sudo criu dump -t 16246 -vvvv -D criu/ -o dump.log -j
[1]+  Killed                  sh test.sh
$ pstree -p 15599
bash(15599)───pstree(16308)    (プロセスは存在しない)
$ sudo tail -n 1 criu/dump.log 
(00.021306) Dumping finished successfully    (ログに処理が成功したことが記録されている)

以上のようにチェックポイント処理を実行すると,デフォルトではチェックポイント対象のプロセスは停止します。tail -f testfileを実行すると,インクリメントされた数字の出力が止まっていることが確認できます。

ファイルが保存されているディレクトリを確認してみましょう。

$ ls -F criu/
core-16246.img  ids-16246.img      pages-1.img        stats-dump
core-16297.img  ids-16297.img      pages-2.img        stats-restore
dump.log        inventory.img      pstree.img         tty.img
fdinfo-2.img    mm-16246.img       reg-files.img      tty-info.img
fdinfo-3.img    mm-16297.img       restore.log
fs-16246.img    pagemap-16246.img  sigacts-16246.img
fs-16297.img    pagemap-16297.img  sigacts-16297.img

プロセスの状態を保存したファイルが確認できます。今回の例ではシンプルなシェルスクリプトの実行状態を保存しただけですので,ファイルの数は少ないですが,システムコンテナや子プロセスが多数存在するようなプロセスを保存した場合はもっと多数のファイルが保存されます。

では,チェックポイント処理は成功したようなので,この生成されたファイルからリストア処理を実行してみましょう。

$ sudo criu restore -vvvv -D criu/ -o restore.log -j -d 
$ ps axjf
  : (略)
    1 16246 16313 15599 pts/0    20037 S     1001   0:00 sh test.sh
16246 20036 16313 15599 pts/0    20037 S     1001   0:00  \_ sleep 1

psコマンドを実行すると,dumpコマンド実行後存在しなかったプロセスが復活していることが確認できます。-dでcriuコマンドから切り離したあと,criuコマンドは終了していますので,親プロセスのPIDは1となっています。

数字を出力していたファイルを確認すると,またインクリメントされた数字の出力が始まっていることが確認できました。

$ tail -f testfile 
58
59
60
^C

著者プロフィール

加藤泰文(かとうやすふみ)

2009年頃にLinuxカーネルのcgroup機能に興味を持って以来,Linuxのコンテナ関連の最新情報を追っかけたり,コンテナの勉強会を開いたりして勉強しています。英語力のない自分用にLXCのmanページを日本語訳していたところ,あっさり本家にマージされてしまい,それ以来日本語訳のパッチを送り続けています。

Plamo Linuxメンテナ。ファーストサーバ株式会社所属。

Twitter:@ten_forward
技術系のブログ:http://tenforward.hatenablog.com/

コメント

コメントの記入