みなさんあのね

エクセルいじりがお仕事のインフラ系SEのメモ

RPMを理解する

1. はじめに

yumコマンド(例えばyum install httpd)を実行するとパッケージがインストールされて、サービスコマンドを実行すると(例えばservice httpd start)Webサーバが起動してApacheのデフォルトページが表示される。単純なコマンドでWebサーバが起動しちゃったけど、そこに至るまでの処理ってどうなってるんでしょうか。少し気になって調べてみると、どうやらRPMという仕組みが関係しているようです。「Fedora 22より、デフォルトのパッケージマネージャが変更されるらしい」という話もありますので、ひとつ下のレイヤーの勉強をして、来たる変化に備えておきたいところ。


2. RPMとは

  • RPMとはパッケージ管理の仕組み
  • インストールされたパッケージのデータベースを生成し、そこにそれぞれのバージョン情報が記録される。パッケージのインストール、アンインストール、アップデート、ソースRPMからはアプリケーションを再コンパイルすることも可能
  • 個別のアプリケーションを管理単位とすることにより、アプリケーションのインストールとアンインストールを簡単に行うことができる
  • RPMパッケージとは圧縮されたアーカイブファイルを指し、相互に関係するファイル、ドキュメント、設定情報の集合を含む
  • アプリケーションではなく、設定ファイルを集約したパッケージも存在する(/root/.bashrcを含むrootfilesパッケージ等)。また、パッケージ名にnoarchという文字が含まれていれば、バイナリファイルを含まずスクリプトまたはドキュメントからのみ構成されている環境非依存のパッケージであると判断できる。複数のアプリケーションによって共用できるライブラリのみをまとめたパッケージも存在する
  • Red Hat Package Managerを表していたが、Linuxの他のディストリビューションでも採用され始めたため、RPM Package Mangerという名称に変更された
  • RPMの前身であるRPP(Red Hat Software Packages)では複数アーキテクチャに対応することが難しかったため、RPMが開発された


3. RPMの設計思想

*使いやすいこと

*パッケージに焦点を合わせる

*パッケージをアップグレードできる

手動でアプリケーションをインストールした場合、アップグレード時に設定ファイルが上書きされ、カスタマイズしていた設定情報が失われる場合がある。一方RPMでアップグレードした場合は、カスタマイズ情報は保持される

*パッケージの依存関係をトラッキングする

パッケージ間の依存関係情報をトラッキングし、インストール時やアンインストールに警告を表示させる

*クエリを実行できる

インストールされたすべてのパッケージに関するデータベースがシステム上に作成され、各ファイルがどのパッケージに属するファイルか記録される。RPMは簡単にクエリできるようになっており、データベースに問い合わせてシステムにインストールされているアプリケーションを検索し、各ファイルがどのパッケージに属するか調べることができる

*検証

データベースに記録されたパッケージに関する情報をもとにアプリケーションに属するファイルに問題がないか(すべてのファイルのパーミッションが正しく設定されているか等)チェックし、改ざんされたり壊れたりしているファイルがないか調べることができる

*複数アーキテクチャをサポート

*クリーンなソース

RPM(バイナリパッケージ版)とソースRPM(ソースパッケージ版)の2種類のパッケージを作成する。ソースRPMはオリジナルのソースコードに変更を加えることなく、クリーンなソースコードからパッケージを作成することが可能


4. RPMデータベース

  • RPMデータベースは/var/lib/rpmに格納されている
  • __db.からはじまる名前のファイルはRPMシステムが利用しているロックファイル。その他のファイルはBerkeleyDBフォーマットのデータベースとなっている
  • RPMデータベースは注意深く扱う必要がある。 パッケージをアップグレード、インストール、アンインストールしたあとには、Packagesファイルをバックアップしておくといいかも


5. パッケージのインストール/アンインストール

パッケージのインストールはrpm -Uコマンドかrpm -iコマンドを実行する。rpmコマンドは以下のステップでパッケージをインストールする。

  • インストールすべきパッケージとその中身をチェックする(依存関係、パッケージ間の競合)
  • インストール前のタスクを実行する
  • 圧縮されているファイルを展開して、適切な場所に配置する
  • RPMデータベースを更新する

なお、パッケージを一度に複数インストールする場合はrpmコマンドラインに各ファイルをスペース区切りで列挙すればよい。インストール順序はrpmコマンドが自動判別してくれる。

カスタマイズされた設定ファイルの扱い

パッケージをインストール後、設定ファイルを編集すると、パッケージのアップグレード時に変更を加えた設定ファイルが維持される。(.rpmsaveという新しい拡張子に名前変更されたうえ、バックアップとして保存されることもある。また、.rpmnewという拡張子付きで新しい設定ファイルがインストールされることもある)


5.1. コマンド例(基本)

インストールされているパッケージ一覧を表示する

rpm -qa

パッケージに含まれるファイルの一覧を表示する

# -vオプションを加えるファイルに関する詳細情報が表示される
rpm -qlpi <パッケージ名>.prm
rpm -ql <パッケージ名>

パッケージの設定ファイル一覧を表示する

※設定ファイルを備えていないパッケージも存在する

# -vオプションを加えるファイルに関する詳細情報が表示される
rpm -qc <パッケージ名>

パッケージ内のファイルの状態を表示する

以下、サポートしているファイル状態

  • normal: ファイルがインストールされている
  • not installed: ファイルがパッケージから削除されている
  • replaced: ファイルが別のファイルに置き換えられた
rpm -qs <パッケージ名>
rpm -qsf <ファイル名>
# ファイルを指定してそのファイルを含むパッケージのコンフィグファイルのみの情報を表示
rpm -qcfs <ファイル名>

パッケージ内のスクリプトを表示する

ファイルのインストール/アンインストール時に実行されるスクリプト

rpm -q —scripts <パッケージ名>

パッケージのchangelogを表示する

※対応していないパッケージもある

rpm -q —changelog <パッケージ名>

パッケージの概要情報を表示する

rpm -qi <パッケージ名>

ファイルが属しているパッケージを見つける

rpm -qf <ファイル名>

依存関係を検証する(実際にはインストトールされず依存関係等のチェックのみを行うモード)

# インストールの検証
rpm -Uvh —test <パッケージ名>.rpm
# アンインストールの検証
rpm -e —test <パッケージ名>

インストールディレクトリを変更する

—rootで指定した仮想rootディレクトリにC標準ライブラリを入れておく必要がある

# /tmpを仮想rootディレクトリとして、RPMデータベースは/var/lib/rpmを利用しインストールする
rpm -U --root /tmp —dpath /var/lib/rpm <パッケージ名>.rpm

古いバージョンのパッケージをインストールする

rpm -Uvh —oldpackage <パッケージ名>.rpm

/var/spool/packageにバックアップを残してアンインストールする

rpm -e —repackage <パッケージ名>

最近インストールしたパッケージを表示する

rpm -qa —last | head


5.2. コマンド例(クエリフォーマット)

パッケージ名のみ一覧表示

—qfがクエリフォーマットオプション

# 結果はpfintf形式で表示されるため改行されない。
rpm -qa —qf “%{NAME}"

# 改行したいならこう書く
rpm -qa —qf “%{NAME}¥n"

表示幅の指定

20文字でフォーマットする

rpm -qa —qf “%-20{NAME} %-20{PLATFORM}¥n"

利用できるタグ一覧

  • NAME: パッケージ名
  • VERSION: バージョン情報
  • RELEASE: リリース番号
  • SUMMARY: パッケージの内容を1行に要約
  • DESCRIPTION: パッケージを説明するテキスト
  • BULDTIME: パッケージが構築された時刻
  • SIZE: ペイロード内の通常ファイルのサイズ
  • GROUP: パッケージのグループ(カテゴリ)名
  • OS: パッケージの構築ターゲットとなるOS
  • ARCH: アーキテクチャi386など)
  • PREIN: インストール前のスクリプト
  • POSTIN: インストール後のスクリプト
  • PREUN: アンインストール前のスクリプト
  • POSTUN: アンインストール後のスクリプト
  • PLATFORM: プラットフォーム
# 以下のコマンドでタグ一覧を表示
rpm --querytags

依存情報の表示

$ rpm -qa --qf "[%-10{REQUIRENAME} %{REQUIREFLAGS:depflags} %{REQUIREVERSION}\n]" postfix
/bin/bash
/bin/sh
/sbin/chkconfig
/sbin/service
/usr/sbin/alternatives
/usr/sbin/groupadd
/usr/sbin/useradd
config(postfix) = 2:2.6.6-6.el6_5
cyrus-sasl >= 2.1.10
libc.so.6()(64bit)
libc.so.6(GLIBC_2.11)(64bit)
libc.so.6(GLIBC_2.2.5)(64bit)
libc.so.6(GLIBC_2.3)(64bit)
libc.so.6(GLIBC_2.3.2)(64bit)
libc.so.6(GLIBC_2.3.4)(64bit)
libc.so.6(GLIBC_2.4)(64bit)
libc.so.6(GLIBC_2.7)(64bit)
libcrypto.so.10()(64bit)
libcrypto.so.10(OPENSSL_1.0.1)(64bit)
libcrypto.so.10(OPENSSL_1.0.1_EC)(64bit)
libcrypto.so.10(libcrypto.so.10)(64bit)

ファイル情報一覧の表示

$ rpm -q --qf "[%-15{NAME} %-36{FILENAMES} %{FILEMODES:perms}\n]" postfix
postfix /etc/pam.d/smtp.postfix -rw-r--r--
postfix /etc/postfix drwxr-xr-x
postfix /etc/postfix/access -rw-r--r--
postfix /etc/postfix/canonical -rw-r--r--


6. パッケージの検証

  • S: ファイルサイズが異なる
  • M: ファイルのモードが異なる
  • 5: MD5チェックサムが異なる
  • D: デバイスファイルのバージョンが異なる
  • L: リンクのミスマッチ
  • U: ファイルを所有しているユーザが異なる
  • G: ファイルを所有しているグループが異なる
  • T: ファイルの時刻(mtime)が異なる
$ rpm -V httpd
..5....T. c /etc/httpd/conf/httpd.conf
..?...... /usr/sbin/suexec

# ServerTokens OSをProdに変更
$ vi /etc/httpd/conf/httpd.conf

# 再度検証してみるとSフラグが立っていることがわかる
$ rpm -V httpd
S.5....T. c /etc/httpd/conf/httpd.conf
..?...... /usr/sbin/suexec

# システム全体を検証する時は以下のコマンドを良く使う
$ rpm -Va --nofiles


7. RPMデータベースのメンテナンス

RPMデータベースのバックアップ

# cd /var/lib
# tar cvzf rpmdb.tar.gz ./rpm

RPMデータベース再構築

rpm —rebuilddb

RPMデータベースの再構築

rpm —initdb


8. パッケージの依存関係

依存関係には大きく以下の4つのタイプを定義できる

  • 必要(Requires): パッケージが必要とする機能
  • 提供(Provides):パッケージが他のパッケージに提供する機能
  • 競合(Conflicts):インストールすれば他のパッケージと強豪する機能
  • 廃止(Obsoletes):該当のパッケージによって陳腐化する機能

パッケージが必要とする機能を表示する

インストール済みパッケージに対しても実行可能(-pオプションは省くこと)

$ rpm -qp --requires /tmp/ruby-2.1.5-1.el6.x86_64.rpm
/usr/bin/env
/usr/bin/pkg-config
/usr/bin/ruby
ld-linux-x86-64.so.2()(64bit)
ld-linux-x86-64.so.2(GLIBC_2.2.5)(64bit)
libc.so.6()(64bit)
libc.so.6(GLIBC_2.10)(64bit)
libc.so.6(GLIBC_2.2.5)(64bit)
libc.so.6(GLIBC_2.3)(64bit)
libc.so.6(GLIBC_2.3.4)(64bit)

パッケージが提供している機能を表示する

$ rpm -qp --provides /tmp/ruby-2.1.5-1.el6.x86_64.rpm
big5.so()(64bit)
bigdecimal.so()(64bit)
bubblebabble.so()(64bit)
callback.so()(64bit)
chinese.so()(64bit)
complex.so()(64bit)
console.so()(64bit)
continuation.so()(64bit)

競合しているパッケージを表示する

$ rpm -qp --conflicts /tmp/ruby-2.1.5-1.el6.x86_64.rpm

特定の機能を必要とするパッケージを表示する

[vagrant@localhost ~]$ rpm -q --whatrequires /bin/bash
dkms-2.2.0.3-2.el6.noarch
initscripts-9.03.46-1.el6.centos.1.x86_64
dracut-004-356.el6.noarch
rsyslog-5.8.10-10.el6_6.x86_64
cronie-1.4.4-12.el6.x86_64
lvm2-2.02.111-2.el6_6.1.x86_64

特定の機能を提供するパッケージを調べる

$ rpm -q --whatprovides webserver
httpd-2.2.15-39.el6.centos.x86_64

# 特定ファイルを提供しているパッケージを調べる時は以下を実行する
rpm -qf /etc/httpd/conf/httpd.conf


9. トリガ

パッケージのインストール時、またはアンインストール時に実行されるスクリプトを確認することが可能

$ rpm -q --triggers iptables-ipv6
triggerpostun scriptlet (using /bin/sh) -- iptables-ipv6 < 1.4.7-7
ip6tables=`readlink /etc/alternatives/ip6tables.x86_64`
if [ -z "$ip6tables" -o "$ip6tables" == "/sbin/ip6tables-1.4.7" ]; then
/usr/sbin/alternatives --set ip6tables.x86_64 /sbin/ip6tables-1.4.7
fi


10. 参考

Red Hat RPM Guide (redhat PRESS)

Red Hat RPM Guide (redhat PRESS)