RPM を使ってソフトウェアをパッケージ化する: 第 2 回 ソフトウェアのアップグレードとアンインストール

この記事では、RPM Package Manager に関する 3 回連載の記事の第 2 回として、RPM を使って Linux システムのソフトウェアをアップグレードする方法、そしてアンインストールする方法について説明します。(この連載記事は Dan Poirier が以前 RPM に関して書いた連載記事を置き換えるものです。)

専門知識をお持ちの方へ:  RPM に関してどんなテクニックをよく使いますか?記事の終わりにあるコメント欄にコメントをお寄せください。

Martin Streicher, Software Developer, Pixel, Byte, and Comma

author photo - martin streicherMartin Streicher はフリーランスの Ruby on Rails 開発者であり、以前は Linux Magazine の編集責任者でした。彼は Purdue University でコンピューター・サイエンスの修士号を取得しており、1986年以来 UNIX ライクなシステムのプログラミングをしてきました。彼は美術品やおもちゃを収集しています。


developerWorks 貢献著者レベル

2010年 1月 12日

通信業界での「ラスト・ワン・マイル」とは、家庭や会社で通信を利用する膨大な数のユーザーにサービスを提供する上で必要な、インフラ、建築物、コスト、その他諸々の要素を指します。通信事業者にとって、衛星回線を使って国の端と端を結ぶことは簡単なことですが、さまざまな権利を取得して地面を掘り返し、すべての家庭と会社までのケーブルを敷設するとなると、衛星の場合とはまったく異なる非常に骨の折れる作業になることが見込まれます。ラスト・ワン・マイルは概念を表す言葉で、必ずしも実際の距離を意味するわけではありませんが、考え方によっては、実は 10 億マイルにも匹敵すると言えるかもしれません。

他の業界も、通信事業者のラスト・ワン・マイルと同じような問題に直面しています。何店もの食料雑貨店がオンライン・ビジネスで何度も失敗していますが、その大きな理由はラスト・ワン・マイルに非常にコストがかかるためです。United States Postal Service (米国郵政公社) は、(まさに文字どおり) ラスト・ワン・マイルに手紙を配達するために、大きな損失を出し続けています。ソフトウェア開発者もラスト・ワン・マイルの問題に直面しています。ソフトウェアが完成しても、それがデプロイされるまでは、そのソフトウェアは大量の 1 と 0 の集まりにすぎません。概念としては、インストールは簡単です。しかしケーブルの敷設やバナナや封筒の配達と同様、困難は個々の環境に対応するための詳細な部分にあります。

この連載の第 1 回の記事では、よく使われるソフトウェア配布システムである RPM を紹介しました。RPM は多くの Linux ディストリビューションで使われており、そのため、商用ソフトウェアやオープンソース・ソフトウェア (例えば Red Hat Linux や Fedora Core Linux のバリエーションなど) のデプロイメントに広く使われています。また第 1 回の記事では、何もない状態のシステムに対してソースからアプリケーションをビルドしてパッケージ化し、インストールする方法についても説明しました。

今回の記事では、RPM とその多様な使い方についての説明の続きとして、既存のソフトウェアのアップグレードとアンインストールを取り上げます。最終回の第 3 回では、少し変わったシナリオとして、ソース・コードにパッチを当てる方法やソース・コードを配布する方法について説明します。

アップグレードの実情

ソフトウェアを初めてインストールする作業は、最も単純なデプロイメントの例です。ターゲット・システムには、そのソフトウェア・パッケージのデーモンやバイナリー・ファイル、構成ファイル、データ・ファイルなどがありません。そのため、初めてインストールする際には、進行中の作業を停止したり、ファイルをバックアップ、リストア、そしておそらくマージしたりする必要もありません。

しかし、そのソフトウェアの以前のバージョンや現在のバージョンがターゲット・システムにある場合や、そのソフトウェアが他のコードやサービスと互いに関係している場合には、RPM は動作可能な構成を維持するために特別な注意を払わなければなりません。プロセスの停止、ファイルの交換や保存、そして新しいコードがシステムにコピーされた後のアプリケーションの再起動が必要となるかもしれません。当然ですが、後方互換性を維持することが常に可能とは限りません。そうした場合には、RPM は変更を最小限にとどめ、引き続きセキュアに機能するシステムを維持する必要があります。場合によると、そのためには古い設定を解釈して新しい設定に変換する、緻密なスクリプトを作成する必要があるかもしれません。

RPM には、インストールとアンインストールのシーケンスにコマンドを注入するためのフックが 4 つ用意されており、2 つはインストール用、2 つはアンインストール用です。すべてのフックはターゲット・システム上で実行され、通常は大部分の一般的な作業には十分です。この 4 つのフックを以下に挙げます。

  • %pre フックの中に指定されたすべてのコマンドは、そのパッケージがインストールされる前に実行されます。
  • %post フックの中に指定されたコマンドは、そのパッケージがインストールされた後に実行されます。
  • %preun フックは、そのパッケージがシステムから削除される前に実行されます。
  • %postun の中に指定されたコマンドは、そのパッケージがシステムから削除された後に実行されます。

従って、アップグレードの際のオペレーションの順序は以下のとおりです。

  1. インストールされる RPM の %pre セクションを実行します。
  2. RPM が提供するファイルをインストールします。
  3. RPM の %post セクションを実行します。
  4. 古いパッケージの %preun を実行します。
  5. 新しいバージョンによって上書きされなかった古いファイルをすべて削除します。(このステップによって、新しいパッケージに不要のファイルが削除されます。)
  6. 古いパッケージの %postun フックを実行します。

ステップ 4 と 6 は少し疑わしく見えるかもしれませんが、それはもっともなことです。あるパッケージのアップグレードをしている場合、古いバージョンのアンインストール・フックを実行すると、ステップ 1 から 3 で行われた処理の一部またはすべてが取り消されてしまうかもしれません。実際、古いバージョンのアンインストール・フックによって、無条件に新しいバージョンが使えなくなってしまう場合があります。意図していないにもかかわらず、パッケージが使えなくなってしまうことがないように、RPM は各フックに 1 つのフラグを引数として渡します。以下のように、フラグの値はどのオペレーションが実行されるのかを示します。

  • %pre の最初の引数の値が 1 の場合には、RPM のオペレーションは初めてのインストールであり、2 の場合には、オペレーションは既存のバージョンから新しいバージョンへのアップグレードです。
  • 同様に、%post の引数が 12 の場合には、オペレーションは新しいインストールとアップグレードです。(この場合も、%pre%post はアンインストール中には実行されません。)
  • %preun%postun の最初の引数が 1 の場合、そのアクションはアップグレードです。
  • %preun%postun の最初の引数が 0 の場合、そのアクションはアンインストールです。

各フックをロジックでラップして引数の値をテストし、適切なコードを実行します。別のスクリプト・インタープリター (Perl など) を指定しない限り、各フックはデフォルトで Bourne シェル (通常は /bin/sh) スクリプトと解釈されます。以下に示すのは Bourne シェル用に作成され、条件分岐を行う %pre フックの例です。

%pre 
if [ "$1" = "1" ]; then
  # Perform tasks to prepare for the initial installation
elif [ "$1" = "2" ]; then
  # Perform whatever maintenance must occur before the upgrade begins
fi

同じフックを Perl で作成したものを以下に示します。フック・スクリプト用に別のインタープリターを使用する場合には、-p オプションを指定し、そのインタープリターへの完全修飾パスを指定します。

%pre -p /usr/bin/perl
if ( $ARGV[0] == 1 ) {
  print "Preparing for initial install...\n"
} 
elsif ( $ARGV[0] == 2 ) {
  print "Preparing to upgrade software...\n"
}

ターゲット・マシンに存在しないインタープリターを指定すると、RPM ユーティリティーは以下のようなエラーを生成します。

$ sudo rpm -i RPMS/i386/wget-1.12-1.i386.rpm
error: Failed dependencies:
	/usr/bin/perl is needed by wget-1.12-1.i386

こうしたメッセージが表示された場合、ターゲット・システムのシステム管理者は、依存関係のための RPM をインストールしてから、再度インストールを行う必要があります。


トリガーを設定する

RPM は一般的に、他のパッケージのファイルなどをほとんど必要としない、単独のパッケージをインストールします。通常、RPM には前提となるファイル群や同時に必要なファイル群がありますが、それらを除けば RPM は他から独立しています。とは言え、他に影響するパッケージもあります。

例えば、拡張可能なテキスト・エディターに Ruby 用の補完パッケージを追加すると、このプログラミング言語の構文が強調表示されるようになる場合があります。そうしたエディターが先にインストールされている場合、後から補完機能を追加すればその新しい機能は期待どおりに動作します。しかし、その補完機能が (何種類かのエディターに有効であるという理由で) 既にインストールされており、その後でエディターがインストールされたとしたらどうでしょう。理想的には、そうした場合にも、まったく同じように補完機能が追加されなければなりません。これが RPM のトリガーの概念です。

RPM は、パッケージをインストールした後で別のパッケージがインストールまたはアンインストールされると、それによって 1 つ以上のタスクが実行されるように、最初にインストールしたパッケージのなかにトリガーを追加しておくことができます。各トリガーは、%pre%post 用に作成したスクリプトと同じように、単なるスクリプトです。さらに、別のインタープリターを指定することさえできます。

  • %triggerin スクリプトは、指定されたパッケージがインストールされた時に実行されます。
  • %triggerun は、指定されたパッケージがアンインストールされた時に実行されます。
  • %triggerpostun スクリプトは、指定されたパッケージがアンインストールされた後に実行されます。

例えば、パッケージがシステムにインストールされた後で Ruby がインストールされた場合にスクリプトを実行するには、以下のスクリプトを作成します。

%triggerin -p /usr/bin/perl -- ruby
# React to the addition of Ruby

-p オプションの指定は任意です。-- (2 つのハイフン) を入力した後、動作を監視する対象となるパッケージを指定します。

コピーとフック、そしてトリガーを頭に入れた上で、N という新しいパッケージをインストールする際には以下の順序でアクションを実行する必要があります。(このパッケージの前のバージョンの名前は n です。)

  1. N の %pre スクリプトを実行します。
  2. N の新しいファイルをファイルシステムにコピーします。
  3. N の %post スクリプトを実行します。
  4. N をインストールすると開始される、すべてのインストール・トリガー (他のパッケージで %triggerin とマーキングされているもの) を実行します。
  5. N のインストール・トリガーをすべて実行します。
  6. n のアンインストール・トリガー (%triggerun トリガー) をすべて実行します。
  7. n をアンインストールすると開始される、すべてのアンインストール・トリガー (他のパッケージにあるアンインストール・トリガー) を実行します。
  8. n の %preun フックを実行します。
  9. N をインストールしても上書きされなかった、すべてのファイルを削除します。
  10. n の中にある、すべてのアンインストール・トリガー (%triggerpostun トリガー) を実行します。

ソフトウェアのインストールは複雑ですが、フックとトリガーによって、ほとんどすべてのシナリオに対応することができます。ただし 1 つ注意すべきことがあります。このプロセスのどのステップにおいても、ユーザーとやり取りしようとしてはいけません。RPM はバッチでのインストールを想定して設計されており、インストール時にユーザーがその場にいる必要はありません。もし、RPM パッケージがインストール中に一時停止して質問を表示するようだと、誰もその質問を見ている人がいない場合には、そのインストールはハングアップしたように見えてしまいます。


RPM の変数

RPM ファイルは長くて複雑なものになる場合があります。アプリケーションでの簡潔な表現のために変数を使うのと同じように、RPM の spec ファイルのプレースホルダーとして変数を使うことができます。

例えば、spec ファイルの先頭付近で変数を定義し、%{変数名} を使ってその変数を spec ファイル全体で参照することができ、さらには以下のように %pre 用のスクリプトの中でも参照することができます。

%define foo_dir /usr/lib/foo

%install
cp install.time.message $RPM_BUILD_ROOT/%{foo_dir}

%files
%{foo_dir}/install.time.message

%post
/bin/cat %{foo_dir}/install.time.message

まとめ

UNIX® マシンや Linux マシン用にソフトウェアを開発する場合、インストーラーの作成は面倒な作業になる可能性があります。幸いなことに、インストール技術をゼロから作成する必要はありません。RPM はソフトウェアの配布用フォーマットとして高機能であり、広くサポートされています。RPM によって、「ラスト・ワン・マイル」は公園の散歩のように簡単なものになります。

参考文献

学ぶために

製品や技術を入手するために

  • rpmlint について学び、また rpmlint をダウンロードしてください。
  • Easy RPM Builder について学び、また Easy RPM Builder をダウンロードしてください。
  • developerWorks から直接ダウンロードできる IBM ソフトウェアの試用版を使用して、皆さんの次期 Linux プロジェクトを革新してください。

議論するために

  • My developerWorks コミュニティーに参加してください。開発者向けのブログ、フォーラム、グループ、ウィキなどを利用しながら、他の developerWorks ユーザーとつながりを持ってください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux
ArticleID=230490
ArticleTitle=RPM を使ってソフトウェアをパッケージ化する: 第 2 回 ソフトウェアのアップグレードとアンインストール
publish-date=01122010