CentOS Stream 9でRPMパッケージ作成:SSH経由のコピペ作業はもう卒業しよう!

CentOS tutorial - IT technology blog
CentOS tutorial - IT technology blog

デプロイを毎晩の悪夢にしないために

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は毎晩安心して眠るための保険となります。ぜひこのパッケージ化プロセスをマスターしてください!

Share: