TT Lab
はじめる
学ぶ 学習パス コース

RHEL系の管理

モジュラリティとmodule_hotfixes

TT Labで続きを見る

一言でいうと

モジュラーRPMは、通常のRPM依存関係の上に重なった追加の階層を持ちます。その階層の情報がないと、パッケージがファイルとしてはあるのに、照会されません。

なぜ必要なのか

エアギャップ環境で、次のような報告が来ます。

ls /srv/repo/appstream/ | grep nodejs
# nodejs-18.20.4-1.module+el9.4.0+21212+d9e3c1f2.x86_64.rpm

dnf list available nodejs
# No matching Packages to list

ファイルはそこにあります。ところがdnfは、ないと言います。エラーも出ません。

どう動くのか

なぜこうなるのか

因果は5段階です。

  1. dnf reposyncでAppStreamを取得したのに、--download-metadataを付けていません
  2. パッケージファイルはすべて届きましたが、モジュールメタデータは届きません
  3. createrepo_cは、rpmファイルから通常のメタデータだけを作ります。モジュールデータはrpmの中にないので、作れません
  4. 内側のdnfはモジュラーRPMを見ても、どのストリームに属するのかわかりません
  5. フィルタリングの結果、そのパッケージが照会されません

RHEL 9のドキュメントは、モジュールの依存関係を「通常のRPM依存関係の上にある追加の階層」と表現し、「リポジトリ間の仮想的な依存関係のように動作する」と説明しています。

バージョンごとの違い

項目 RHEL 8 RHEL 9 RHEL 10
モジュールの提供 AppStreamの中核的な方式 9.1からライフサイクルの短い追加バージョンとして提供 公式ドキュメントにモジュールの章がない
デフォルトストリーム あり あらかじめ定義されたデフォルトストリームなし 該当なし
ストリームを指定せずにインストール デフォルトストリームが自動で有効化 ストリームを指定する必要がある 該当なし
ストリームの切り替え distro-sync → module reset → module enable → distro-sync dnf module switch-toの1行 該当なし

RHEL 8からRHEL 9へ移る過程でモジュールの比重が大きく減り、RHEL 10では事実上なくなりました。しかし、RHEL 8/9のシステムは、これからも長く残ります。

コマンド

dnf module list
dnf module list nodejs
dnf module info nodejs:20
dnf module enable nodejs:20
dnf module install nodejs:20/common
dnf module reset nodejs
dnf module switch-to nodejs:20      # RHEL 9
dnf module list --installed > state-modules.txt

resetは有効化の状態を初期化します。ストリームを切り替えるには、通常はresetが先です。

解決策の3つの方向

方法1: 取得するときに一緒に取得する(定石)

dnf reposync --repoid=...appstream-rpms --download-path=/srv/sync \
  --download-metadata --gpgcheck --arch=x86_64 --arch=noarch

この場合、持ち込み後にcreaterepo_cを再び実行してはいけません。実行すると、かえってモジュールデータを失います。

方法2: dnf modulesync

モジュールに属するパッケージを取得しながら、モジュールデータが含まれたリポジトリを作ってくれます。

dnf --destdir=/srv/bundle/nodejs modulesync nodejs:20/minimal --resolve

方法3: module_hotfixes=1(最後の手段)

[airgap-appstream]
name=RHEL 9 AppStream (airgap, no modular metadata)
baseurl=file:///srv/repo/appstream
enabled=1
gpgcheck=1
module_hotfixes=1
metadata_expire=-1

ドキュメント上の定義: 「モジュールRPMのフィルタリングを無効にして、リポジトリのすべてのRPMを利用可能にします。デフォルトはFalse。」

代償があります。異なるストリームのパッケージが混ざってインストールされることがあり、その組み合わせは、Red Hatが検証した組み合わせではありません。そのため「最後の手段」です。

installrootを使うとき

空のルートを基準に計算するときは、モジュールのプラットフォームIDを一緒に指定する必要があります。

dnf download --installroot=/var/tmp/airgap-root --releasever=9.4 \
  --setopt=module_platform_id=platform:el9 \
  --resolve --alldeps --destdir=/srv/bundle nodejs

指定しないと、その値が空のルートの/etc/os-releaseから来ますが、生成時点ではそのファイルがないので値が空になり、モジュールコンテンツがエラーなしでまるごと抜け落ちます。静かに抜け落ちるため、最も発見しにくい種類の事故です。

grep PLATFORM_ID /etc/os-release
# PLATFORM_ID="platform:el9"

現場での姿

状態記録の4種類。持ち込みの前後に、この4つを残しておくと、調査がずっと楽になります。

dnf module list --installed > state-modules.txt
rpm -qa --qf '%{NAME}\t%|EPOCH?{%{EPOCH}}:{0}|\t%{VERSION}\t%{RELEASE}\t%{ARCH}\n' | sort > state-packages.tsv
dnf history userinstalled > state-userinstalled.txt
dnf history list > state-history.txt

3つ目が特に役に立ちます。ユーザーが明示的にインストールしたものだけが出力されるので、その一覧だけを別のサーバーにインストールすれば、依存関係は自動でついてきます。パッケージ一覧全体をそのまま流し込むより、ずっと安全です。

次の確認で見ること

このモジュールは、概念を判断するクイズで締めくくります。モジュールメタデータが抜けたときに現れる症状と、module_hotfixesの危険範囲を区別したうえで、次のモジュールのrh-createrepoとrh-airgapのラボで、リポジトリの複製方式を選択します。