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

第13回LXCの構築・活用 [1] ― テンプレートを紐解く

皆さま初めまして。田向と申します。今回から数回にわたり、加藤さんに代わって、本連載の執筆を担当させていただくことになりました。よろしくお願いいたします。

前回まで、Ubuntuを使ったLXCの基本的な機能を紹介してきましたので、今回からUbuntu以外のディストリビューションでのLXCの構築や活用について紹介していきます。

第8回で、コンテナを作成するコマンドとしてlxc-createを紹介しました。作成したいコンテナに応じて、-tオプションでテンプレートディレクトリ(デフォルトで/usr/share/lxc/templatesにあるテンプレートを選択します。

/usr/share/lxc/templates$ wc *
   387   1220  10789 lxc-alpine
   486   1708  13533 lxc-altlinux
   331   1170  10253 lxc-archlinux
   376   1337   9446 lxc-busybox
   922   3741  28932 lxc-centos
   335   1248  10150 lxc-cirros
   459   1507  12158 lxc-debian
   587   1987  17427 lxc-download
  1424   6455  47200 lxc-fedora
   821   3203  27808 lxc-gentoo
   490   1725  13961 lxc-openmandriva
   433   1528  13705 lxc-opensuse
   839   3850  35445 lxc-oracle
   389   1601  11837 lxc-plamo
   275    921   6851 lxc-sshd
   809   2937  24273 lxc-ubuntu
   406   1584  12401 lxc-ubuntu-cloud
  9769  37722 306169 合計

テンプレートの中身については、第7回のときに簡単に紹介しました。今回は、Plamoテンプレートlxc-plamoを題材に、テンプレートの中で何が行われているのかを、詳細に見ていきたいと思います。

Plamoテンプレートや他のテンプレートの全体は、上記テンプレートディレクトリから参照できます。もし、お手元の環境でlxcがインストールされていなければ、テンプレートの元になる雛型ファイルではありますが、GitHubの生ソースなどを参考にしてください。

Plamoテンプレートの内部紹介

テンプレートは、基本的に標準的な引数を受け取り、指定された場所にコンテナのルートファイルシステムを作成する実行可能なファイルです。テンプレートの形式は、必ずしもシェルスクリプトでなくても良いのですが、今のところPlamoテンプレートを含むすべてのテンプレートが、シェルスクリプト(bash)で書かれています。

テンプレートは、大きく分けて以下の部分で構成されています。

  1. コンテナを作成するためにインストールする資材(パッケージ)をダウンロードする部分
  2. コンテナのルートファイルシステムにパッケージをインストールする部分
  3. 作成したコンテナ内の設定ファイルなどをコンテナ向けに調整する部分
  4. コンテナの設定ファイルconfigを作成する部分

これらを順に説明してきます。

パッケージのダウンロード

まず、Plamo Linuxインストーラのパッケージの分類(カテゴリ)について、簡単に説明します。

Plamo Linuxインストーラには、plamoディレクトリとcontribディレクトリがあり、plamoディレクトリには、現在のところ11種類のカテゴリが用意されています。

00_base
Plamo Linuxの動作に必須のカーネルや基本コマンド、設定ファイルなど。すべての環境でインストールする必要があります。
01_minimum
ALSAやGCC、Perl、Pythonなど、Xなしでも使える重要コマンド集。サーバなどのコンソール環境で使う場合は、ここまででたいてい間に合うはずです。
02_x11
X11とXに必須のパッケージ群。ウィンドウマネージャはtwmのみです。
03_xclassics
GNOMEで使われていたEsounDサウンドサーバや、伝統的なXプロトコルレベルでプロセス間通信を行うソフトウェア、AfterstepやQvwmなどの伝統的なウィンドウマネージャ、CannaやFreeWnn、Kinput2などの伝統的なFEPやIM(インプットメソッド)システム。ここまでインストールすれば、古き良きワークステーション相当の環境になるはずです。
04_xapps
最近のGUI環境の主流になっているGTK環境と主にGTKベースなアプリケーション群。
05_ext
XfceとKDEが共通に利用する、PulseAudioなどの機能拡張用ライブラリを中心としたアプリケーション群。iBusやuim、SCIMなどの最近のインプットメソッドも含みます。
06_xfce
シンプルながら高機能なXfceデスクトップ環境。
07_kde
多機能なKDEデスクトップ環境。
08_tex
TeXの統合パッケージであるTeX Live。
09_kernel
Linuxカーネルのソースコード。
10_lof
Office用統合ツールであるLibreOffice。

これらのカテゴリのうち、00_baseはPlamo Linuxの動作に必須、01_minimumはほぼ必須の環境で、02_x11以降は必要に応じて取捨選択可能です。

一方、contribディレクトリには、以下のようなカテゴリがあります。これらは、サポートレベルが低いパッケージ(カテゴリ)や、ステージングとしての位置づけであるパッケージ(カテゴリ)が含まれています。

カテゴリ含まれる内容
AVtoolオーディオ&ビジュアルツールパッケージ
DBデータベース関連パッケージ
Devel開発向けパッケージ
Education教育用(主に言語系)パッケージ
EmacsEmacs関連パッケージ
Hamradioアマチュア無線関連パッケージ
HaskellHaskell(関数型プログラミング言語)パッケージ
KernelLinuxカーネルパッケージ(予備)
Libraryライブラリ関連パッケージ
MUAMUA(電子メールクライアント)パッケージ
Network ネットワーク関連パッケージ
PythonPython関連パッケージ
Texlive2010Tex Live 2010パッケージ
Texttoolテキスト処理関連パッケージ
Utilitiesユーティリティパッケージ
VLCVLCメディアプレーヤーパッケージ
Virtualization仮想化関連パッケージ
X11X11関連パッケージ

これらのパッケージは、開発中のPlamo Linuxパッケージを格納しているミラーサーバから取得できます。ミラーサーバの内容は、日々更新されているので、ダウンロード時点の最新パッケージ構成で、コンテナを作成することができます。ミラーサーバの情報は、テンプレート内の以下の変数で表現しています。

DLSCHEME
ダウンロードスキーム。httpまたはftpを指定します。デフォルトはhttpです。
MIRRORSRV
ミラーサーバを指定します。デフォルトはwww.ring.or.jpです。
MIRRORPATH
インストーラのパスを指定します。デフォルトは/pub/linux/Plamoです。

仮に、Plamo Linuxインストーラのplamoディレクトリ以下とcontribディレクトリ以下のカテゴリをすべてインストールする場合、インストールDVD1枚分相当のサイズをダウンロードすることになり、またパッケージ展開後のサイズの合計は十数GBに及ぶので、あまり汎用的とは言えません。そこで、Plamoテンプレートでは以下の変数を用意して、ダウンロードするカテゴリ/パッケージを制御できるようにしています。

CATEGORIES
ダウンロードするplamoディレクトリ以下のカテゴリを指定します。デフォルトは00_base01_minimumです。
EXTRACTGRS
ダウンロードするcontribディレクトリ以下のカテゴリを指定します。デフォルトは指定なし、つまりダウンロードしません。
IGNOREPKGS
上記のカテゴリ内のパッケージのうち、ダウンロード対象から除外するパッケージを指定します。デフォルトはgrubkernellilolinux_firmwaremicrocode_ctlcpufreqdcpufrequtilsおよびgpmです。
ADDONPKGS
上記のカテゴリに含まれていないパッケージで、ピンポイントでダウンロードするパッケージを指定します。デフォルトはcontrib/Hamradio/{morse,qrq}です。

これらの変数は、Plamoテンプレート実行時の環境変数で上書きして設定可能です。

パッケージをダウンロードする関数download_plamo()を以下に示します。

download_plamo()関数
download_plamo() {
  # check the mini plamo was not already downloaded
  if ! mkdir -p $ptcache ; then
    echo "Failed to create '$ptcache' directory."
    return 1
  fi
  # download a mini plamo into a cache
  echo "Downloading Plamo-$release minimal..."
  cd $ptcache
  case $DLSCHEME in http) depth=2 ;; ftp) depth=3 ;; esac
  rej=${IGNOREPKGS%% *} ; [ -n "$rej" ] && rej="$rej-*"
  if [ `echo $IGNOREPKGS | wc -w` -gt 1 ] ; then
    for p in ${IGNOREPKGS#* } ; do rej="$rej,$p-*" ; done
  fi
  for i in $CATEGORIES ; do
    wget -nv -e robots=off -r -l $depth -nd -A .tgz,.txz -R "$rej" \
        -I $MIRRORPATH/Plamo-$release/$arch/plamo/$i \
        -X $MIRRORPATH/Plamo-$release/$arch/plamo/$i/old \
        $DLSCHEME://$MIRRORSRV$MIRRORPATH/Plamo-$release/$arch/plamo/$i
    if [ $? -ne 0 ] ; then
      echo "Failed to download the rootfs, aborting."
      return 1
    fi
  done
  for i in $EXTRACTGRS ; do
    wget -nv -e robots=off -r -l $depth -nd -A .tgz,.txz -R "$rej" \
        -I $MIRRORPATH/Plamo-$release/$arch/contrib/$i \
        -X $MIRRORPATH/Plamo-$release/$arch/contrib/$i/old \
        $DLSCHEME://$MIRRORSRV$MIRRORPATH/Plamo-$release/$arch/contrib/$i
    if [ $? -ne 0 ] ; then
      echo "Failed to download the rootfs, aborting."
      return 1
    fi
  done
  for p in $ADDONPKGS ; do
    wget -nv -e robots=off -r -l $depth -nd -A "`basename $p`-*" \
        -I $MIRRORPATH/Plamo-$release/$arch/`dirname $p` \
        -X $MIRRORPATH/Plamo-$release/$arch/`dirname $p`/old \
        $DLSCHEME://$MIRRORSRV$MIRRORPATH/Plamo-$release/$arch/`dirname $p`
    if [ $? -ne 0 ] ; then
      echo "Failed to download the rootfs, aborting."
      return 1
    fi
  done
  mv $ptcache $dlcache
  echo "Download complete."
  return 0
}

Plamo Linuxインストーラ内のカテゴリは、機能単位でまとめられたサブカテゴリを含んでいるので、wgetコマンドを使ってパッケージを再帰的に取得しています。他のテンプレートにおいても、download_<テンプレート名>のような関数名になっているので、興味があればダウンロードの方法を比較してみるのも面白いでしょう。

コンテナのインストール

install_plamo()の関数では、コンテナのルートファイルシステムに対し、パッケージのインストールを行います。他のテンプレートにおいても、install_<テンプレート名>のような関数名になっています。この関数の中核となる部分は以下のコードになります。

      for p in `ls -cr $dlcache/*.t?z` ; do
        installpkg -root $rtcache -priority ADD $p
      done

ここでは、download_plamo()ダウンロードした順にパッケージをインストールしていきます。そのため、インストールされたコンテナのルートファイルシステムは、通常のインストーラでベアメタルのルートファイルシステムにインストールした場合と、ほぼ同じ結果が得られます。

なお、ここに出てくるinstallpkgコマンドは、Slackware由来のものであるため、ディストリビューションによっては用意されていません。そこで、パッケージのインストールに先立ち、installpkgコマンドをLXCキャッシュディレクトリに一時的にインストールしておき、Plamo Linux以外のディストリビューション上でも、Plamoコンテナを作成できるようになっています。

LXCキャッシュディレクトリにインストールしたinstallpkgコマンドは、異なるディストリビューション上で展開したファイル/ディレクトリのUID/GIDを、システム側に合わせることなく、オリジナルのUID/GIDを維持します。以前、いくつかのテンプレートで、この考慮が抜けているケースがあったのですが、筆者がテンプレートに対する修正パッチを投稿したので、現在lxc-1.0.5以降)は任意のディストリビューション上で、どのテンプレートを使ってコンテナを作成しても、コンテナのルートファイルシステム上のファイル/ディレクトリは、正しいUID/GIDで展開されるようになっています。

コンテナ内の設定ファイルの調整

Plamoテンプレートを使って作成したコンテナを起動するとき、コンテナ内ではinitを最初に起動して、通常のOSが起動するのと同じような環境を作成します。このような環境を、システムコンテナと呼ばれるということを、以前説明しましたね。

configure_plamo()の関数では、作成したコンテナ内の設定ファイルをコンテナ向けに調整したり、コンテナ内で起動するrcスクリプトの不要な処理の削除などを行います。他のテンプレートにおいても、configure_<テンプレート名>のような関数名になっています。

デバイスファイルの初期化
Plamoコンテナでは、起動時のudevを無効にしているので、コンテナの起動に必要なデバイスファイルを作成したり、権限を調整します。また、udevのログレベル出力を無効にします。
/etc/fstabの初期化
ファイルシステム情報ファイルをコンテナ向けに作成します。
/etc/inittabの修正
lxc-startコマンドを実行したとき、コンソールにログインプロンプトを表示するための設定を追加し、ログインプロンプトを表示する仮想コンソールを4つに制限します。また、lxc-stopコマンドを実行すると、デフォルトではSIGPWRinitに送ります。このとき、Plamo Linuxのデフォルト設定だと、ランレベル1(シングルユーザモード)に移行し、lxc-stopによってコンテナを強制停止する60秒後に、コンテナ上のすべてのタスクがkill -9されるまで、システムが停止しません。そこで、SIGPWRinitに送られたらシステムが停止するように、/etc/inittabを修正します。
ホスト名の設定
lxc-createコマンドの-nオプションで指定した名前を、コンテナのホスト名として設定します。
ネットワークの設定
DHCPを使うように、コンテナのネットワークを設定します。
タイムゾーンの設定
コンテナのタイムゾーンを+0900(JST)に設定します。
/etc/pam.d/loginファイルの編集(libvirt対策)
libvirtのLXCドライバ経由でゲストにログイン可能にするため、/etc/pam.d/loginファイル内のpam_loginuid.soの行をコメントアウトします。
/etc/ld.so.confファイルの生成
コンテナ上でldconfigを実行して、/etc/ld.so.confファイルを生成します。
パスワードの設定
rootのパスワードを暫定的に"root"に設定します。
/etc/rc.d/rc.[SM]ファイルの編集
コンテナ内で起動するrcスクリプトの不要な処理の削除などを行います。
/etc/rc.d/rc.inet1.tradnetファイルの生成および編集
カスタマイズしたnetconfigコマンドのコピーを実行して、/etc/rc.d/rc.inet1.tradnetファイルを生成します。また、ホストOSで無線LANを使用するために、カーネルの起動時パラメータにwlanを指定した環境でコンテナを起動すると、起動スクリプトでもホストOSの/proc/cmdlineを参照して、コンテナ上でも無線LANを使用しようとします。そのため、無線LANの設定を抑止する処理を追加します。

コンテナの設定ファイルconfigの作成

copy_configuration()の関数では、コンテナの設定ファイルconfigを完成させます。他のテンプレート間で、処理内容にあまり顕著な違いが見られないこともあり、テンプレートに依らない共通の関数名になっているようです。また、中身が空のfstabファイルも併せて作成します。

lxc-createコマンドを実行すると、コンテナの設定ファイルのヘッダ部が作られ、第8回で説明したように、コンテナのデフォルト設定ファイルの設定値がコピーされます。その後、copy_configuration()によって、lxc.utsnamelxc.mountlxc.archの設定および共通で使用する設定ファイルを読み込む設定lxc.includeが追記されます。これらの設定項目については、第11回を参照してください。

まとめ

今回は、Plamoテンプレートlxc-plamoを題材に、テンプレートの中身を詳しく紹介しました。テンプレートを機能ごとに分けて見ていくと、意外とすっきりした構成であることが、おわかりいただけたのではないかと思います。他のテンプレートについても、基本的にやっていることは同じですので、ぜひ中身を紐解いてみてください。

次回は、lxc-createコマンドを使ってコンテナを作成するときの、root権限と一般ユーザ権限での動作の違いを紹介し、その後でPlamo Linuxを使ったLXCの構築や活用について紹介する予定です。

おすすめ記事

記事・ニュース一覧