maehachi08 Anything Blog

2012年06月24日
LXC(Linux Containers)のRPMビルド

LXC(Linux Containers)のソース入手

ソースのtarボールは 以下サイトより入手しました。

$ wget http://downloads.sourceforge.net/project/lxc/lxc/lxc-0.8.0/lxc-0.8.0-rc1.tar.gz?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Flxc%2F&ts=1340287785&use_mirror=jaist
downloads.sourceforge.net をDNSに問いあわせています... 216.34.181.59
downloads.sourceforge.net|216.34.181.59|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 302 Found
場所: http://jaist.dl.sourceforge.net/project/lxc/lxc/lxc-0.8.0/lxc-0.8.0-rc1.tar.gz [続く]
--2012-06-23 03:09:14--  http://jaist.dl.sourceforge.net/project/lxc/lxc/lxc-0.8.0/lxc-0.8.0-rc1.tar.gz
jaist.dl.sourceforge.net をDNSに問いあわせています... 150.65.7.130
jaist.dl.sourceforge.net|150.65.7.130|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 301029 (294K) [application/x-gzip]
`lxc-0.8.0-rc1.tar.gz' に保存中

100%[=========================================================================================>] 301,029     1.28M/s 時間 0.2s

2012-06-23 03:09:14 (1.28 MB/s) - `lxc-0.8.0-rc1.tar.gz' へ保存完了 [301029/301029]

LXCのSPECファイルの入手

LXCのSPECファイルはtarボール内にあったので、それを流用しました。

$ tar xzvf lxc-0.8.0-rc1.tar.gz
$ ls -l lxc-0.8.0-rc1/lxc.spec
-rw-rw-r-- 1 rpmbuilder rpmbuilder 3990  3月  2 08:04 2012 lxc-0.8.0-rc1/lxc.spec
$ cp -p lxc-0.8.0-rc1/lxc.spec rpmbuild/SPECS/lxc.spec

LXCのRPMビルド作業の備忘録

LXCのソースからRPMパッケージをビルドする時に色々エラーになったので、纏めます。

      マクロ変数の%{Version}に不正な記号であるハイフン(-)が含まれている
      展開ディレクトリ名がデフォルトでBUILD/%{name}-%{version}である
      %{ksrc}に値が代入されていないので、"Linux dir not found"エラーが出る
      lxc-initの指定パスが実際と違う

1つ目は、完全に文法エラーです。
2つ目は、1つ目のエラー対処に%{Release}を使ったのが裏目に出ました。
3つ目は、環境依存なので、各自で入れろってことでしょうか。
4つ目は、SPECファイルに記載されたパスが%{_libdir}だったのですが、実際は、%{_libexecdir}だったというものです。

では、1つ1つの問題をどう解決したのかを以下で説明します。

マクロ変数の%{Version}に不正な記号であるハイフン(-)が含まれている

ドキュメント等から記載を見つけることは出来ませんでしたが、マクロ変数の%{Version}にハイフン(-)を含めると"Illegal char"としてエラーとなってしまうようです。lxc.specでは%{Version}に"0.8.0-rc1"というような感じでハイフンが利用されていましたので、エラーになったと考えられます。
対応方法としては、"rc1"のみ別途%{Release}マクロ変数に代入し、%{version}-%{Release}と表現することで解決しました。

rpmbuildコマンド実行時のエラー

$ rpmbuild -ba rpmbuild/SPECS/lxc.spec
エラー: line 24: Illegal char '-' in: Version: 0.8.0-rc1

lxc.specのマクロ%{version}と%{release}の既定値

$ egrep "Version:|Release:" rpmbuild/SPECS/lxc.spec
Version: 0.8.0-rc1
Release: 1

lxc.specのマクロ%{version}と%{release}の変更後の値

$ egrep "Version:|Release:" rpmbuild/SPECS/lxc.spec
Version: 0.8.0
Release: rc1

%{version}と%{release}の変更にともなって、マクロ%{source}と%{buildroot}の値も変更しました。

lxc.specのマクロ%{source}と%{buildroot}の既定値

$ egrep "Source:|BuildRoot:" rpmbuild/SPECS/lxc.spec
Source: http://dl.sourceforge.net/sourceforge/%{name}/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-build

lxc.specのマクロ%{source}と%{buildroot}の変更後の値

$ egrep "Source:|BuildRoot:" rpmbuild/SPECS/lxc.spec
Source: http://dl.sourceforge.net/sourceforge/%{name}/%{name}-%{version}-%{release}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-build

展開ディレクトリ名がデフォルトでBUILD/%{name}-%{version}である

先ほど、%{buildroot}の値を変更したのですが、%{buildroot}はあくまでビルド作業ディレクトリの定義です。%{buildroot}のディレクトリ名とtarボールの解凍後の展開ディレクトリ名が一致する必要があるのですが、%{buildroot}を変更したことで食い違ってしまいました。
tarボールの展開先ディレクトリ名はデフォルトでは%{name}-%{version}です。そして、ビルド処理用一時スクリプトでは、展開先ディレクトリ(%{name}-%{version})にcdコマンドでディレクトリ移動します。今回、このcdコマンドでコケていました。
つまり、%{buildroot}定義とtarボールの展開先ディレクトリを合わせる必要があります。
ここを参考にさせて頂いたのですが、tarボールの解凍処理に関する記述はSPECファイルでは%setup行になります。そして、%setup行に-n と記述することでtarボールの展開先を"hogehoge"というディレクトリ名にしてくれます。
今回は、%{buildroot}と同じにするために、"-n %{name}-%{version}-%{release}"を加えることで解決しました。

rpmbuildコマンド実行時のエラー

+ '[' 0 -ne 0 ']'
+ cd lxc-0.8.0
/var/tmp/rpm-tmp.a15m9d: line 38: cd: lxc-0.8.0: No such file or directory
エラー: /var/tmp/rpm-tmp.a15m9d の不正な終了ステータス (%prep)


RPM ビルドエラー:
    /var/tmp/rpm-tmp.a15m9d の不正な終了ステータス (%prep)

%setupにtarボールの展開先ディレクトリ名を指定

%setup -q -n %{name}-%{version}-%{release}

%{ksrc}に値が代入されていないので、"Linux dir not found"エラーが出る

%{ksrc}というマクロ変数に何も入っていなかったので、処理途中でエラーになっていました。
そもそも、この%{ksrc}というマクロ変数は何を示すものなのでしょうか。lxc.specにtestコマンドから始まる以下のような行がありました。

test "%{ksrc}" != "none" && args="--with-linuxdir=%{ksrc}"

まず、testコマンドで%{ksrc}の値が"none"かどうか判定しています。"none"でない場合は、&&以降のコマンドを実行します。
つまり、configureスクリプトの--with-linuxdirオプションの値に%{ksrc}を代入しています。
./configure --helpを確認することで、--with-linuxdirオプションにはLinuxカーネルソースディレクトリパスが代入されるべきだと分かりました。

$ rpmbuild/BUILD/lxc-0.8.0-rc1/configure --help
  --with-linuxdir=DIR     specify path to Linux source directory

私の環境(CentOS6.2-x86_64)では、/usr/src/kernels/2.6.32-220.el6.x86_64ディレクトリです。なので、testコマンドの1行上にマクロ変数%{ksrc}の値を定義する行を追記します。
今回は、lxc.specに%define ksrc /usr/src/kernels/2.6.32-220.el6.x86_64というマクロ変数定義行を追記し、解決しました。

rpmbuildコマンド実行時のエラー

checking for Linux in %{ksrc}... configure: error: Linux dir not found
エラー: /var/tmp/rpm-tmp.fFbK73 の不正な終了ステータス (%build)


RPM ビルドエラー:
    /var/tmp/rpm-tmp.fFbK73 の不正な終了ステータス (%build)

%{ksrc}マクロ変数の定義

%prep
%setup -q -n %{name}-%{version}-%{release}
%build
%define ksrc = /usr/src/kernels/2.6.32-220.el6.x86_64
test "%{ksrc}" != "none" && args="--with-linuxdir=%{ksrc}"
PATH=$PATH:/usr/sbin:/sbin %configure $args --disable-rpath
make %{?_smp_mflags}

lxc-initの指定パスが実際と違う

lxc-initとはLXCをアプリケーションコンテナとして使用する場合に、デーモンプロセスを起動させる重要な役割を持っているのですが、そいつが/home/rpmbuilder/rpmbuild/BUILDROOT/lxc-0.8.0-rc1.x86_64/usr/lib64/lxc/lxc-initとして見つからないというエラーです。ちなみに、上記パスは、%{rpm_build_root}/%{_libdir}/%{name}/lxc-initが解釈されたパスです。
しかし、実際は、/home/rpmbuilder/rpmbuild/BUILDROOT/lxc-0.8.0-rc1.x86_64/usr/libexec/lxc/lxc-initでした。
/usr/libexec/は環境変数では%{_libexecdir}で定義されています。RPMビルド時の環境変数はrpm --showrcコマンドで確認できます。

lxc-initファイルをfindコマンドで確認

$ find ./ -name "lxc-init"
./rpmbuild/BUILDROOT/lxc-0.8.0-rc1.x86_64/usr/libexec/lxc/lxc-init
./rpmbuild/BUILD/lxc-0.8.0-rc1/src/lxc/lxc-init

/usr/libexecを表す環境変数の確認

$ rpm --showrc | grep "/libexec"
-14: _libexecdir        %{_exec_prefix}/libexec

今回は%{libdir}を%{_libexecdir}に変更することで解決しました。
"ファイルが2回表記されています"というメッセージはrpmbuildコマンドに--define="
_check_files %{nil}"オプションを付けると解消できます。

rpmbuildコマンド実行時のエラー

Processing files: lxc-0.8.0-rc1.x86_64
警告: ファイルが2回表記されています: /usr/bin/lxc-attach
警告: ファイルが2回表記されています: /usr/bin/lxc-checkpoint
警告: ファイルが2回表記されています: /usr/bin/lxc-clone
警告: ファイルが2回表記されています: /usr/bin/lxc-create
警告: ファイルが2回表記されています: /usr/bin/lxc-execute
警告: ファイルが2回表記されています: /usr/bin/lxc-netstat
警告: ファイルが2回表記されています: /usr/bin/lxc-restart
警告: ファイルが2回表記されています: /usr/bin/lxc-start
警告: ファイルが2回表記されています: /usr/bin/lxc-unshare
Requires(interp): /bin/sh
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires(post): /bin/sh
Requires: /bin/bash /usr/bin/perl libc.so.6()(64bit) libc.so.6(GLIBC_2.2.5)(64bit) libc.so.6(GLIBC_2.3)(64bit) libc.so.6(GLIBC_2.3.4)(64bit) libc.so.6(GLIBC_2.4)(64bit) libc.so.6(GLIBC_2.8)(64bit) libcap.so.2()(64bit) liblxc.so.0()(64bit) perl(Getopt::Long) perl(strict) rtld(GNU_HASH)
Processing files: lxc-libs-0.8.0-rc1.x86_64
エラー: ファイルが見つかりません: /home/rpmbuilder/rpmbuild/BUILDROOT/lxc-0.8.0-rc1.x86_64/usr/lib64/lxc/lxc-init


RPM ビルドエラー:
    ファイルが2回表記されています: /usr/bin/lxc-attach
    ファイルが2回表記されています: /usr/bin/lxc-checkpoint
    ファイルが2回表記されています: /usr/bin/lxc-clone
    ファイルが2回表記されています: /usr/bin/lxc-create
    ファイルが2回表記されています: /usr/bin/lxc-execute
    ファイルが2回表記されています: /usr/bin/lxc-netstat
    ファイルが2回表記されています: /usr/bin/lxc-restart
    ファイルが2回表記されています: /usr/bin/lxc-start
    ファイルが2回表記されています: /usr/bin/lxc-unshare
    ファイルが見つかりません: /home/rpmbuilder/rpmbuild/BUILDROOT/lxc-0.8.0-rc1.x86_64/usr/lib64/lxc/lxc-init

lxc-initのパス変更

$ grep "lxc-init" rpmbuild/SPECS/lxc.spec
%attr(4555,root,root) %{_libexecdir}/%{name}/lxc-init

いよいよRPMビルド

SPECファイルさえ固まってしまえば、rpmbuildコマンド一発です。

$ rpmbuild -ba --define="__check_files %{nil}" rpmbuild/SPECS/lxc.spec

$ ls -l rpmbuild/RPMS/x86_64/lxc-*
-rw-rw-r-- 1 rpmbuilder rpmbuilder  72472  6月 22 11:09 2012 rpmbuild/RPMS/x86_64/lxc-0.8.0-rc1.x86_64.rpm
-rw-rw-r-- 1 rpmbuilder rpmbuilder 242556  6月 22 11:09 2012 rpmbuild/RPMS/x86_64/lxc-debuginfo-0.8.0-rc1.x86_64.rpm
-rw-rw-r-- 1 rpmbuilder rpmbuilder  12548  6月 22 11:09 2012 rpmbuild/RPMS/x86_64/lxc-devel-0.8.0-rc1.x86_64.rpm
-rw-rw-r-- 1 rpmbuilder rpmbuilder  84464  6月 22 11:09 2012 rpmbuild/RPMS/x86_64/lxc-libs-0.8.0-rc1.x86_64.rpm

LXCインストール

さて、インストールはrpmコマンド一発です。

$ ls rpmbuild/RPMS/x86_64/lxc-* | xargs sudo rpm -ivh
[sudo] password for rpmbuilder:
準備中...                ########################################### [100%]
   1:lxc-libs               ########################################### [ 25%]
   2:lxc                    ########################################### [ 50%]
   3:lxc-devel              ########################################### [ 75%]
   4:lxc-debuginfo          ########################################### [100%]

$ sudo rpm -qa | grep "lxc"
[sudo] password for rpmbuilder:
lxc-devel-0.8.0-rc1.x86_64
lxc-libs-0.8.0-rc1.x86_64
lxc-0.8.0-rc1.x86_64
lxc-debuginfo-0.8.0-rc1.x86_64