デプロイを毎晩の悪夢にしないために
30台あるサーバーのうちの1台で、設定ファイルのコピー漏れという「つまらない」ミスのために、深夜2時まで復旧作業をしたことはありませんか?駆け出しの頃の私は、SSHでログインしてはGitからコードをプルし、各ノードで一つずつchmodを実行するという、指が疲れるような作業を繰り返していました。システムが5台から50台へとスケールしたとき、この手動の手法はまさに時限爆弾となります。小さなステップを一つ忘れるだけで、クラスター全体が停止してしまうのです。
プロのDevOpsエンジニアは、この問題を解決するためにアプリケーションをRPM (Red Hat Package Manager)ファイルとしてパッケージ化します。バラバラのファイル群を送る代わりに、単一の.rpmファイルを転送するだけで済みます。システムは自動的に依存関係をチェックし、ファイルを正しい場所に配置します。最も素晴らしいのは、トラブルが発生した際にdnf removeコマンドでクリーンにロールバックできる点です。
CentOS Stream 9上の銀行システムでこのプロセスを6ヶ月間運用した経験から、最短の学習ルートをまとめました。Red Hatの難解なドキュメントをすべて読み込む必要はありません。この記事でrpmbuildをマスターしましょう。
実践:初めてのRPMパッケージを作成する
始める前に、クリーンなビルド環境を用意しましょう。非常に重要な注意点として、絶対にrootユーザーを使用しないでください。ビルドスクリプト内の小さなミスが、一瞬にしてシステム上のデータを一掃してしまう可能性があるからです。
# 標準ツールセットのインストール
sudo dnf install -y rpm-build rpmdevtools gcc
# ビルドディレクトリ構造の初期化
rpmdev-setuptree
上記のコマンドにより、~/rpmbuildディレクトリが作成されます。その中で特に重要なのは、SOURCES(元のソースコードを格納)とSPECS(ビルド設定ファイルを格納)です。まずは、動作の流れを理解するために、hello-itfromzero.shというシンプルなスクリプトをパッケージ化してみましょう。
# サンプルソースファイルの作成
echo 'echo "itfromzero.comへようこそ!"' > ~/rpmbuild/SOURCES/hello-itfromzero.sh
次に、パッケージの設計図となるSPECファイルを作成します。
nano ~/rpmbuild/SPECS/hello.spec
以下の内容を貼り付けてください:
Name: hello-itfromzero
Version: 1.0
Release: 1%{?dist}
Summary: itfromzeroからのウェルカムスクリプト
License: GPL
Source0: hello-itfromzero.sh
BuildArch: noarch
%description
CentOS Stream 9でのRPMビルド方法をデモするためのシンプルなスクリプト。
%install
mkdir -p %{buildroot}/usr/bin/
cp %{_sourcedir}/hello-itfromzero.sh %{buildroot}/usr/bin/hello-itfromzero
chmod +x %{buildroot}/usr/bin/hello-itfromzero
%files
/usr/bin/hello-itfromzero
最後に、ビルドコマンドを実行します:
rpmbuild -ba ~/rpmbuild/SPECS/hello.spec
わずか3〜5秒で、RPMファイルが~/rpmbuild/RPMS/noarch/ディレクトリに生成されます。これで、このファイルを他のCentOS 9マシンに持っていき、dnf installコマンド一つでインストールできるようになります。
SPECファイルの解剖:覚えておくべき重要要素
実際の運用では、SPECファイルは上記の例よりもはるかに複雑になります。JavaやGoのアプリケーションをパッケージ化する際によく遭遇する3つの重要ポイントを紹介します。
1. Requiresによる依存関係管理
ここでは、必要条件を定義します。例えば、Requires: python3, nginx >= 1.20のように記述します。ユーザーがパッケージをインストールする際、dnfが自動的に不足しているライブラリを計算してダウンロードします。これにより、「ライブラリが存在しない」というエラーを効果的に防ぐことができます。
2. %install – サンドボックス
初心者がよく誤解するのは、%installがクライアントマシンにRPMをインストールする時に実行されるコマンドだと思ってしまうことです。実際には、これはビルド中に実行されるコマンドです。ソースディレクトリからBuildRootと呼ばれる一時ディレクトリにファイルをコピーします。BuildRootを仮想のOSと考えてください。そこにファイルを配置した通りに、RPMインストール時に実マシンの同じパスへファイルが配置されます。
3. %post と %pre:インストール後の自動化
これらはターゲットマシン上で直接実行されるスクリプトです。%preを使用してインストール前にシステムユーザーを作成したり、%postを使用してインストール直後にサービスを起動したりできます。
応用:Systemdで動作するアプリケーションのパッケージ化
企業環境では、ほぼすべてのアプリがサービスとして動作する必要があります。CentOS Stream 9では、安定性を確保するためにsystemdのマクロを活用すべきです。手動でsystemctl reloadを叩くのではなく、RPMに任せましょう。
# %install セクション内
install -D -m 644 %{SOURCE1} %{buildroot}%{_unitdir}/my-app.service
# インストール後にサービスを自動登録
%post
%systemd_post my-app.service
# 削除時にサービスをクリーンアップ
%preun
%systemd_preun my-app.service
%systemd_postのようなマクロを使用することで、システムは安全にデーモンをリロードできます。これは、バラバラのBashスクリプトを書くよりもはるかにプロフェッショナルな手法です。
実践的な経験:私が遭遇した「罠」
システムをCentOS 7からCentOS Stream 9へ移行した際、少なくないトラブルに遭遇しました。皆さんが同じ轍を踏まないための教訓をいくつか共有します。
- 「Installed but unpackaged」エラー:ファイルを
BuildRootにコピーしても、%filesセクションに記載し忘れると、ビルドは即座に失敗します。すべてのファイルは「点呼」を受ける必要があります。 - 設定ファイルの競合:システムファイルに直接上書きしてはいけません。他のパッケージとの競合を避けるため、
/etc/my-company/app.confのような独自のディレクトリを作成しましょう。 - Mockを使用してビルドする:どのマシンでも確実に動作させる(「自分の環境では動く」を防ぐ)ために、
mockの使用をお勧めします。このツールは100%クリーンなchroot環境を作成してビルドするため、依存関係の欠如を初期段階で発見できます。
RPMのパッケージ化は、最初は単純なBashスクリプトよりも手間がかかるように感じるかもしれません。しかし、数百台のサーバーのバージョン管理が必要になったとき、RPMは毎晩安心して眠るための保険となります。ぜひこのパッケージ化プロセスをマスターしてください!

