Linux
rpm
rpmbuild

こわくない、rpmbuild

こんな人向けです。

  • rpmパッケージを作れと急に言われたけどよう分からん
  • 既存rpmパッケージを引き継いだが make rpm とかで勝手にrpmファイルできることしか分からん
  • 「ただし未伸張」にトラウマがある

この番組はお馴染みCentOS7環境でお送りしています(2018年08月当時のものです)。

$ uname -r
3.10.0-862.11.6.el7.x86_64
$ rpmbuild --version
RPM バージョン 4.11.3

なぜrpmにするのか

RPM Package Managerというくらいなので、 "パッケージを管理する" ためです。管理すると具体的にどうなるのかは「おしえて、rpmコマンド」をご覧いただけるとよいと思います。パッケージに含まれるファイル群の調査、追加、削除などが簡単に行えるようになります(たぶん)。

まずはミニマムでやってみよう

とりあえずrpm-buildをインストールしましょう。

$ yum install rpm-build

そして、minimum_rpm.sh とでも名付けて以下をコピペしてください。

minimum_rpm.sh
#!/bin/bash -x

# ビルドディレクトリの作成
BUILDDIR=$(pwd)/minbuild
mkdir -p $BUILDDIR/SOURCES

# コマンドの作成
CMD=minimum
cat <<EOF > $BUILDDIR/SOURCES/$CMD
#!/bin/bash
echo "Minimum!"
EOF

# SPECファイル作成
SPEC=minimum.spec
cat <<EOF > ./$SPEC
Name:    minimum
Version: 1
Release: 1%{?dist}
Summary: minimum test command

License: No License No Life
Source0: minimum

%description
minimum test command!!

%install
mkdir -p %{buildroot}/%{_bindir}
install -p -m 755 %{SOURCE0} %{buildroot}/%{_bindir}

%files
%{_bindir}/minimum
EOF

# ビルド
rpmbuild --define "_topdir ${BUILDDIR}" -bb ./$SPEC

実行してみます。

$ bash minimum_rpm.sh
  : ()
+ exit 0

成功したっぽいので、カレントのminbuildを確認してみます。

$ find minbuild/ -type f
minbuild/SOURCES/minimum
minbuild/RPMS/x86_64/minimum-1-1.el7.centos.x86_64.rpm

rpmができてるのでインストールしてみます。

$ sudo rpm -ivh minbuild/RPMS/x86_64/minimum-1-1.el7.centos.x86_64.rpm
準備しています...              ################################# [100%]
更新中 / インストール中...
   1:minimum-1-1.el7.centos           ################################# [100%]

Minimumを叫ぶコマンドが以下にインストールされました。

$ /usr/bin/minimum
Minimum!

以上です、ありがとうございました。次回作にご期待下さい。

っておい

これで終わったら泣く泣く打ち切られた漫画家さんたちに申し訳ない(おい)。

最小構成のrpmをとりあえず作ってみましたので、一つずつ振り返ってみます。お手元のファイルを参照しながらご確認ください。

specファイル

まず、minimum.specファイルを作りました。spec = specification = 仕様 です。要は、どんなパッケージをつくるかの仕様書になります。前半にパッケージの情報、後半にパッケージ処理が書いてあります。細かい内容については、後述の参考サイトなどをご確認ください(丸投げ)。多少後述します。

minimum.spec
Name:    minimum
Version: 1
Release: 1%{?dist}
Summary: minimum test command
License: No License No Life
Source0: minimum

%description
minimum test command!!

%install
mkdir -p %{buildroot}/%{_bindir}
install -p -m 755 %{SOURCE0} %{buildroot}/%{_bindir}

%files
%{_bindir}/minimum

インストールしたrpmパッケージ情報を確認すると、specファイルに記載した情報が表示されることがわかります。

# rpm -qi は "minimum" というパッケージの情報を表示する
$ rpm -qi minimum
Name        : minimum
Version     : 1
Release     : 1.el7.centos
Architecture: x86_64
Install Date: 2018年08月27日 21時08分23秒
Group       : Unspecified
Size        : 28
License     : No License No Life
Signature   : (none)
Source RPM  : minimum-1-1.el7.centos.src.rpm
Build Date  : 2018年08月27日 21時06分20秒
Build Host  : mypcname
Relocations : (not relocatable)
Summary     : minimum test command
Description :
minimum test command!!

ソースファイル

今回rpmに含めたファイルは minimum コマンド一つです。これを minbuild/SOURCES/minimum に配置しています。rpmに含めるファイルはSOURCESディレクトリに放り込む必要があります。

これをどうパッケージングするかも、先程のspecファイルに書いてあります。

minimum.spec
# Source0 として"minimum"という名前のファイルを定義
Source0: minimum  

%install
# buildroot, bindir は事前に定義されているマクロ。
# minbuild/BUILDROOT/usr/bin を作って、そこにSOURCE0 をインストールする
mkdir -p %{buildroot}/%{_bindir}
install -p -m 755 %{SOURCE0} %{buildroot}/%{_bindir}

%files
# rpmに含めるファイルは全てここで指定する必要がある
%{_bindir}/minimum

rpmbuild コマンド

作成したspecファイルの情報をもとに、rpmパッケージをつくるのがrpmbuildです。

$ rpmbuild --define "_topdir $(pwd)/minbuild" -bb ./minimum.spec

今回は、コマンド実行時に「ここでビルドしてね」という意味のマクロ定義 "_topdir {ディレクトリ}" で指示しています。これを指定しない場合は、\$HOME/rpmbuild がデフォルトのビルド場所になるため、$HOME/rpmbuild/SOURCESを作ってそちらにminimumファイルをコピーする必要があります。

"-bb" はビルドオプションです。このオプション指定により、何をどの段階までビルドするかなどを変更できます。man rpmbuild見てね。

以上が、ミニマムの解説です。


めんどくさー、こんなことせんでもコマンドをコピーすればええやんけ!という声もあるかと思います。確かに、コマンド一個ならばrpmを作る必要はほぼ無いでしょう。

では少し発展したケースを考えてみましょう。

設定ファイルを伴うパッケージ例

"Minimum!"と出すだけでは面白味がないので、品川庄司の庄司さんばりに"Minimuuuuuum!"と叫ばすコマンドを用意して、叫び方を設定ファイルで指定できるようにしてみます。せっかくなのでC言語の練習でもしながらやるかあ。

…とかやってたら、無駄に長い超クソコードになってしまいました… まあ、とりあえずrpm作りたいだけなのでこれを使ってビルドします。

shoutbuild.sh
#!/bin/bash

# サンプル持ってきてとりあえずビルド
[ -d shout ] || git clone https://github.com/hijili/shout
(cd shout; make)

# 以下のディレクトリでrpmbuildする
BUILDDIR=$(pwd)/shoutbuild
rm -rf $BUILDDIR

# サンプルコードをSOURCESディレクトリにコピー
mkdir -p $BUILDDIR/SOURCES
cp -f shout/shout $BUILDDIR/SOURCES/
cp -f shout/shout.conf $BUILDDIR/SOURCES/

# specファイルの記述
mkdir -p $BUILDDIR/SPECS
SPEC=./shout.spec
cat <<EOF > $SPEC
Name:    shout
Version: 1
Release: 1%{?dist}
Summary: Shout word

License: MIT License
Source0: shout
Source1: shout.conf

%description
Shout word.

%install
mkdir -p %{buildroot}/%{_bindir}
mkdir -p %{buildroot}/%{_sysconfdir}/shout
install -p -m 0755 %{SOURCE0} %{buildroot}/%{_bindir}
install -p -m 0644 %{SOURCE1} %{buildroot}/%{_sysconfdir}/shout

%files
%{_bindir}/shout
%config(noreplace) %{_sysconfdir}/shout/shout.conf
EOF

rpmbuild --define "_topdir ${BUILDDIR}" -bb $SPEC

スクリプトを実行してrpmを作ってみましょう。

$ bash shoutbuild.sh
   : ()

$ find shoutbuild/ -type f
shoutbuild/SPECS/shout.spec
shoutbuild/SOURCES/shout
shoutbuild/SOURCES/shout.conf
shoutbuild/RPMS/x86_64/shout-1-1.el7.centos.x86_64.rpm

無事できたようなのでインストールしてみます。

$ sudo rpm -ivh shoutbuild/RPMS/x86_64/shout-1-1.el7.centos.x86_64.rpm
  : 
$ /usr/bin/shout 
shouuuuuuuuuut!!!!!!!!!!
$ /usr/bin/shout hoge
hogeeeeeeeeee!!!!!!!!!!

動きました。ここまでは先程と同じです。

設定ファイルの変更

では設定ファイルを変更してみます。例えば、このサーバは本気で叫べそうなので(意味不明)、叫びの設定値を10から100に変更したとします。

$ sudo vi /etc/shout/shout.conf
# comment
EXCLAMATION=100
CYCLES=100
$ /usr/bin/shout hoge
hogeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

うるさいですね。さて、ここで、shoutにバグが見つかりアップデートしたとします(しないけど)。せっかくなので、specファイルを編集してrpmのバージョンを上げてビルドしなおしてみます。

$ vi shoutbuild.sh
  : ()
Name:    shout
Version: 2  # ここを2に変更
$ ./shoutbuild.sh
  :

ビルドできたら、version2をインストールしてみます。

$ sudo rpm -Uvh shoutbuild/RPMS/x86_64/shout-2-1.el7.x86_64.rpm 
準備しています...              ################################# [100%]
更新中 / インストール中...
   1:shout-2-1.el7                    ################################# [ 50%]
整理中 / 削除中...
   2:shout-1-1.el7                    ################################# [100%]

これで、shoutコマンドは、新たにパッケージングしたversion2(といっても何も変えてませんが…)に更新されました。しかし、shout.confは先程編集した内容が維持されています。

$ cat /etc/shout/shout.conf 
# comment
EXCLAMATION=100
CYCLES=100

これは、shout.specに以下のように記述したためです。

shout.spec
%files
%{_bindir}/shout
%config(noreplace) %{_sysconfdir}/shout/shout.conf

shout.confは設定ファイルだから更新しないでね、という旨を記述しています。

このように、rpmパッケージの中身がどういう位置づけのものか指定することで、更新や削除が楽になります。※configに新しい項目を追加するなどは対応が必要ですが...

管理漏れダメゼッタイ

specファイルにconfigと書いたら設定ファイルになりましたが、何も書かなかったらどうなるでしょう。shoutbuld.shのspec記述部分で、configをコメントアウトしてみます。

shoutbuild.sh
%files
%{_bindir}/shout
# コメントアウト %config(noreplace) %{_sysconfdir}/shout/shout.conf
$ ./shoutbuild.sh
   : ()
パッケージに含まれないファイルの検査中: /usr/lib/rpm/check-files /home/hoshino/TestDir/dont_afraid_rpmbuild/new/shoutbuild/BUILDROOT/shout-2-1.el7.x86_64
エラー: インストール済み(ただしパッケージに含まれない)ファイルが見つかりました:
   /etc/shout/shout.conf


RPM ビルドのエラー:
    インストール済み(ただしパッケージに含まれない)ファイルが見つかりました:
   /etc/shout/shout.conf

このように怒られます。rpmさんは管理漏れに厳しいのです。1ファイルも見逃してくれません。

余談

上記のように管理漏れしたときのエラーが、昔のバージョンでは以下のように表示されていました。

伸張ファイルの検査中: xxx
エラー: インストール済み(ただし未伸張)ファイルが見つかりました:

「ただし未伸張」ってなんだよ、なんかこえーよ!と、rpmbuildが嫌いになった苦い思い出です…(遠い目)

削除する

不要になったrpmパッケージは簡単に削除できます。

$ sudo rpm -e shout
警告: /etc/shout/shout.conf は /etc/shout/shout.conf.rpmsave として保存されました。
[hoshino@localhost new]$ ll /etc/shout/shout.conf.rpmsave

今回の場合、configファイルに独自の修正がされているため、rpmさんが気を利かせて xxx.rpmsaveという形でバックアップを残してくれました。特に何も更新されていない場合はこのバックアップは残りません。

このように、rpmさんはすべてのファイルに目を配っているわけです。例えば、どんなファイルが含まれていて、変更されているかなども一目瞭然の管理っぷりです。このあたりは「おしえて、rpmコマンド」の方をご参照ください(くどい)。

まとめ

rpmbuildの初歩を書いてみました。こわくなくなったでしょうか。最初に複雑なrpmを引き継いだりすると、「なんでこんなややこしいことを…」と思うかもしれませんが、一度rpmにしておくと、その後のメンテナンスが楽になったり、サーバ管理やトラブルシュートの助けになると思います。ケースバイケースなところもありますが…
多くのファイルを複数箇所に配置したい場合などはrpmは有用です。

誤り指摘や質問などありましたらお気軽にどうぞ。

参考サイト