RHEL 8/Fedora 28で導入されたModularity

Red Hatでソリューションアーキテクトをしている小島です。

本記事は赤帽エンジニアAdvent Calendar 2018の14日目です。

RHEL 8/Fedora 28ではModularityという概念が導入され、アプリケーションのライフサイクルを設定するための新しい仕組みが追加されました。本記事ではModularityの概要や利用方法について紹介していきます。

Modularityとは

Modularityは、RHELやFedoraといったOSからアプリケーションのライフサイクルをある程度独立させるための仕組みです。Modularityを利用しているイメージは下図のようになります。

f:id:h-kojima:20181212180958p:plain
Fedoraドキュメントから引用

この図では「Fedora AppStream」という名前のリポジトリが、nodejs, calc unstable, djangoと名付けられたModuleを提供しています。Moduleは小さなRPMリポジトリであり、それぞれの名前に関連したRPMパッケージ郡から構成されています。また、nodejs-{6,8,10}unstableといったバージョンに関する情報によってModuleを分けることができます。これをStreamと定義していて、StreamごとにFedora 28やFedora 29といった異なるリリースのOSで利用できるようなAPI/ABIの互換性を担保するようにModuleが作られます(作られるべきとしています)。

一方、「Base」という名前のリポジトリは、OSのリリースに紐付いたRPMパッケージを提供します。「Base」リポジトリの利用は従来と変わる所はありません。こうした仕組みにより、アプリケーションをある程度OSと独立して利用できるようになります。例えば、Fedoraのように半年ごとにリリースされるOS上では、リリース間隔より長いサポート期間を持つ古めのアプリケーションを利用し、RHELのように長期間のサポートを提供するOSの上では、独自に定義されたサポート期間のもとに新しめのアプリケーションを利用できるようになります。

f:id:h-kojima:20181213004206p:plain

RHEL 8のリポジトリ

Fedora 28をベースとして開発されたRHEL 8もModularityという概念を取り入れています。RHEL 8の主なリポジトリは、「BaseOS」と「AppStream」の2つです。「BaseOS」がRHEL7までのベースリポジトリに該当します。「AppStream」ではいくつかのアプリケーションをModuleとして提供している他に、従来のRHELのSoftware CollectionsExtrasリポジトリで提供していたアプリケーションもいくつか提供しています。これらのリポジトリが提供するModuleやパッケージ名の一覧は、下記を参照してください。

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8-beta/html/8.0_beta_release_notes/modules-in-appstream

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8-beta/html/8.0_beta_release_notes/packages-in-baseos

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8-beta/html/8.0_beta_release_notes/packages-in-appstream

Software Collectionsとの違い

Software Collectionsも同様に、利用者はOS標準のアプリケーションとは異なるバージョンのアプリケーションを利用できます。ただし、Software Collectionsのアプリケーションは、OS標準のアプリケーションとは別に、専用のPATHにインストールするようになっています。そのため、異なるバージョンのアプリケーションを1つのシステムにインストールできます。

Modularityの場合はSoftware Collectionsと異なり、基本的には複数のバージョンのアプリケーションをインストールできないようになっています。アプリケーションの並列な導入という点ではSoftware Collectionsが上ですが、Software Collectionsの特徴に起因した特別な変更*1をしなくていいといった利点も産まれます。Modularityを利用していて、1つのシステムに複数のバージョンのアプリケーションを導入したい場合はコンテナ環境の利用を推奨します。

なお、現時点では、Fedora ProjectによるSoftware Collectionsのサポートは提供されていません。そのため、Red Hat系のLinuxディストリビューションを今後利用していく場合、Software CollectionsだけでなくModularityにも慣れていくことを推奨します。

Moduleの利用方法

RHEL 8を例にします。最初にRed Hat Developer Programを利用してRHEL 8のインストールイメージを取得し、RHEL 8をローカルマシンにインストールします。インストール後は、RHEL 8上で次のコマンドを実行してRed Hatのカスタマーポータルへにシステムを登録し、必要なリポジトリの利用を有効化します。

# subscription-manager register --username <username> --password <password> --auto-attach
# subscription-manager repos --disable="*"
# subscription-manager repos --enable=rhel-8-for-x86_64-baseos-beta-rpms --enable=rhel-8-for-x86_64-appstream-beta-rpms

これでModuleの利用準備が整いました。どのModuleが利用できるかはdnf module list [module_name]*2で確認できます。

# dnf module list postgresql
Red Hat Enterprise Linux 8 for x86_64 - AppStream Beta (RPMs)
Name                                   Stream                                Profiles                                           Summary                                     
postgresql                             10 [d]                                client, default [d]                                postgresql module                           
postgresql                             9.6                                   client, default [d]                                postgresql module

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled

この例では「AppStream」リポジトリで提供しているPostgreSQLのModule一覧を表示しています。ProfileはPostgreSQLのModuleに関するRPMパッケージ郡に付けられた名前であり、clientdefaultの2つがあることを意味しています。clientdefaultがどのRPMパッケージを含んでいるかについては、DNFリポジトリのメタデータ(repodataディレクトリにあるxxx-modules.yaml.gz)で、次のように記載されています。

  profiles:
    client:
      rpms:
      - postgresql
    default:
      rpms:
      - postgresql-server

また、[d]efault, [e]nabled, [x]disabled, [i]nstalledとの表示がありますが、それぞれ次の意味を持ちます。

[d]efault:
Moduleをインストールする時に利用されるStreamとProfileのデフォルト値。これらはDNFリポジトリのメタデータで定義しています。
[e]nabled:
ModuleのStreamにあるRPMパッケージ郡が、dnfでインストールできる(RPMパッケージの依存関係を確認できる)ようになっている状態です。
[x]disabled:
ModuleのStreamにあるRPMパッケージ郡が、dnfでインストールできない(RPMパッケージの依存関係を確認できない)ようになっている状態です。
[i]nstalled:
Moduleがインストールされた場合に表示されます。例えばclientProfileをインストールすると、Profileの箇所にclient [i]と表示されるようになります。

Streamのenableddisabledは、Fedoraのメジャーリリースのアップグレード(28 -> 29など)などの需要に基づいて産まれたものです。アップグレードの際に、今まで使えていたStreamが廃止されて新しいStreamを利用しなくてはいけない場合、またはその逆で、RPMパッケージの競合状態を防ぐために特定のStreamにあるRPMパッケージ郡を利用しないようにする場合に使われます。なお、enableddisabledはあくまでもDNFリポジトリでの依存関係の確認の可否に関わるものであり、システムの既存のRPMパッケージに影響を及ぼすものではありません。

では、PostgreSQLのModuleをインストールしてみましょう。dnf module install <module_spec>でModuleをインストールできます。<module_spec>では、module:stream/profileを指定しますが、StreamとProfileは省略できます。その場合は[d]efaultで指定されている値が利用されます。この時Streamがdisabled状態であれば、自動的にenabled状態に変更されます。

# dnf -y module install postgresql:10/client
Dependencies resolved.
============================================================================================================================================================================
 Package                         Arch                        Version                                       Repository                                                  Size
============================================================================================================================================================================
Installing group/module packages:
 postgresql                      x86_64                      10.5-1.el8+1546+27ad5f8e                      rhel-8-for-x86_64-appstream-beta-rpms                      1.5 M
Installing dependencies:
 libpq                           x86_64                      10.5-1.el8                                    rhel-8-for-x86_64-appstream-beta-rpms                      188 k
Enabling module streams:
 postgresql                                                  10                                                                                                            

Transaction Summary
============================================================================================================================================================================
Install  2 Packages

Total download size: 1.7 M
Installed size: 6.2 M
Downloading Packages:
(1/2): libpq-10.5-1.el8.x86_64.rpm                                                                                                          154 kB/s | 188 kB     00:01    
(2/2): postgresql-10.5-1.el8+1546+27ad5f8e.x86_64.rpm                                                                                       1.1 MB/s | 1.5 MB     00:01    
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                                       1.3 MB/s | 1.7 MB     00:01     
...<snip>...
Installed:
  postgresql-10.5-1.el8+1546+27ad5f8e.x86_64                                                     libpq-10.5-1.el8.x86_64                                                    

Complete!

この後、インストールされたPostgreSQL Moduleの状態を確認してみます。

# dnf module list postgresql
Red Hat Enterprise Linux 8 for x86_64 - AppStream Beta (RPMs)
Name                                   Stream                                Profiles                                           Summary                                     
postgresql                             10 [d][e]                             client [i], default [d]                            postgresql module                           
postgresql                             9.6                                   client, default [d]                                postgresql module

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled

PostgreSQL Moduleの10Streamがenabled状態になっていて、clientProfileがインストールされた状態になっていることを確認できます。ちなみに、この状態でPostgreSQL Moduleの9.6Streamをインストールする場合、9.6Streamへのダウングレードと切り替えを自動的に実行してくれます。

# dnf -y module install postgresql:9.6/client
Dependencies resolved.
============================================================================================================================================================================
 Package                        Arch                       Version                                          Repository                                                 Size
============================================================================================================================================================================
Downgrading:
 postgresql                     x86_64                     9.6.10-1.el8+1547+210b7007                       rhel-8-for-x86_64-appstream-beta-rpms                     1.4 M
Switching module streams:
 postgresql                                                10 -> 9.6                                                                                                       

Transaction Summary
============================================================================================================================================================================
Downgrade  1 Package

Total download size: 1.4 M
Downloading Packages:
postgresql-9.6.10-1.el8+1547+210b7007.x86_64.rpm                                                                                            433 kB/s | 1.4 MB     00:03    
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                                       432 kB/s | 1.4 MB     00:03     
...<snip>...
Downgraded:
  postgresql-9.6.10-1.el8+1547+210b7007.x86_64                                                                                                                              

Complete!

不要になったModuleを削除する場合は、dnf module remove <module_spec>を実行します。Moduleを削除するときも、DNFリポジトリのメタデータを参照して削除対象のModuleを決定します。なお、Module削除の場合は、自動的にStreamがdisabled状態に変更されることはありません。

# dnf -y module remove postgresql:9.6/client
Dependencies resolved.
============================================================================================================================================================================
 Package                        Arch                       Version                                         Repository                                                  Size
============================================================================================================================================================================
Removing:
 postgresql                     x86_64                     9.6.10-1.el8+1547+210b7007                      @rhel-8-for-x86_64-appstream-beta-rpms                     5.1 M
Removing unused dependencies:
 libpq                          x86_64                     10.5-1.el8                                      @rhel-8-for-x86_64-appstream-beta-rpms                     702 k
Removing module profiles:
 postgresql/client                                                                                                                                                         

Transaction Summary
============================================================================================================================================================================
Remove  2 Packages

Freed space: 5.8 M
...<snip>...
Removed:
  postgresql-9.6.10-1.el8+1547+210b7007.x86_64                                                    libpq-10.5-1.el8.x86_64                                                   

Complete!
# dnf module list postgresql
Red Hat Enterprise Linux 8 for x86_64 - AppStream Beta (RPMs)
Name                                    Stream                               Profiles                                         Summary                                       
postgresql                              10 [d]                               client, default [d]                              postgresql module                             
postgresql                              9.6 [e]                              client, default [d]                              postgresql module 

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled

Moduleの配信方法

RHEL 8のデフォルトに目当てのModuleが無い場合、既存のRPMパッケージを指定してModule用のリポジトリを作ることができます。その際は、指定したRPMパッケージをModuleとして配信するためのメタデータを、RPMリポジトリ内に作成・追加する必要があります。この手順をzshRPMパッケージを例にして見ていきましょう。

最初にzshパッケージを適当なディレクトリに保存します。zshパッケージはRHEL 8のインストールイメージから取得してもいいですし、次の例のようにdnf downloadでRed Hatのカスタマーポータルのリポジトリからダウンロードすることもできます。

# mkdir /tmp/moduledir; cd /tmp/moduledir/
# dnf download zsh

次にzshModule用のメタデータをYAML形式のファイルで作成します。これはmodulemdファイルと定義されています。簡単なメタデータのサンプルが下記になります。最初のdocument: modulemdversion: 2の2行で、modulemdファイルであることを宣言します。そしてModule名、Stream名、アーキテクチャ名、実行時の要件(下記の例ではRHEL 8を指定)、Profileの名前(最低限defaultという名前のProfileが1つ必要)、defaultProfileに紐付けるRPMパッケージの名前zshを記載して保存します。

# cat <<EOF  > /tmp/moduledir/zsh-modules.yaml
---
document: modulemd
version: 2
data:
  name: zsh                        # <- Module name
  stream: latest                   # <- Stream name
  arch: x86_64
  summary: zsh package

  dependencies:
    - requires:
        platform: [el8]            # <- Run on RHEL 8

  profiles:
    default:                       # <- Profile default name
      description: zsh package
      rpms:
        - zsh                      # <- Binary RPM package name
EOF

こうして作成したzsh-modules.yamlをRPMリポジトリのメタデータに追加します。まずはローカルにRPMリポジトリを作るためにcreaterepo_c <path_of_repository>を実行し、zshRPMパッケージを保存したディレクトリ内にメタデータ一式(repodataディレクトリ)を作成します。続いて、/tmp/moduledir/repodata/内にあるメタデータに先程作成したzsh-modules.yamlを追加するために、modifyrepo_c --mdtype=modules <modulemd_file> <repodata_path_of_directory>を実行します。これによってrepodataディレクトリ内に、xxx-zsh-modules.yaml.gzという名前のgzファイルが自動的に作成されます。最後に作成したローカルリポジトリを利用するための設定ファイルを作成します。リポジトリを利用するための設定ファイルの保存場所はYUMと同様に、/etc/yum.repos.d/となります。

# dnf -y install createrepo_c
# createrepo_c /tmp/moduledir
# modifyrepo_c --mdtype=modules zsh-modules.yaml /tmp/moduledir/repodata/
# ls /tmp/moduledir/repodata/
xxx-zsh-modules.yaml.gz
...<snip>...
# cat <<EOF  > /etc/yum.repos.d/local.repo
[local]
name=local-repo
baseurl=file:///tmp/moduledir/
gpgcheck=0
enabled=1
EOF

これでローカルリポジトリにあるModuleを利用するための準備が完了しました。あとは先程紹介したのと同様の手順で、Moduleの一覧出力やインストールなどができるようになります。

# dnf module list zsh
local-repo
Name                                    Stream                                    Profiles                                    Summary                                       
zsh                                     latest                                    default                                     zsh package                                   

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled
# dnf -y module install zsh:latest/default
Dependencies resolved.
============================================================================================================================================================================
 Package                               Arch                                     Version                                       Repository                               Size
============================================================================================================================================================================
Installing group/module packages:
 zsh                                   x86_64                                   5.5.1-4.el8                                   local                                   2.9 M
Installing module profiles:
 zsh/default                                                                                                                                                               
Enabling module streams:
 zsh                                                                            latest                                                                                     

Transaction Summary
============================================================================================================================================================================
Install  1 Package

Total size: 2.9 M
...<snip>...
Installed:
  zsh-5.5.1-4.el8.x86_64                                                                                                                                                    

Complete!
# dnf module list zsh
local-repo
Name                                   Stream                                      Profiles                                     Summary                                     
zsh                                    latest [e]                                  default [i]                                  zsh package
...<snip>...

ちなみに、Streamのデフォルト値を指定したい場合、先程作成したzsh-modules.yamlに下記の行を追加して、DNFリポジトリのメタデータを修正します。document: modulemd-defaultsを追加してzshModuleのlatestStreamを指定することで、latestStreamがデフォルト値として使われるようになります。メタデータ修正後、modifyrepo_cでModuleに関する既存のメタデータの削除と、新規メタデータの追加を行います。

# cat <<EOF  >> /tmp/moduledir/zsh-modules.yaml
...
---
document: modulemd-defaults
version: 1
data:
  module: zsh
  stream: latest
  profiles:
    latest: [default]
EOF
# modifyrepo_c --remove=modules /tmp/moduledir/repodata/
# modifyrepo_c --mdtype=modules zsh-modules /tmp/moduledir/repodata/

そして、DNFリポジトリのキャッシュを削除してzshModuleの情報を見てみると、デフォルト値が指定されていることが分かります。これでModuleの利用者が特にStream/Profileの値を指定しなくても、zshModuleのデフォルトのStream/Profileをインストール・削除できるようになります。

# dnf clean all
# dnf module list zsh
local-repo
Name                                   Stream                                      Profiles                                     Summary                                     
zsh                                    latest [d]                                  default [d]                                  zsh package
...<snip>...

ここで取り上げた例以外にも、modulemdファイルには様々な設定項目があります。これらの詳細を知りたい場合は、次のドキュメントも参考にしてください。

github.com

References

Introduction :: Fedora Docs Site

DNF Command Reference — dnf latest documentation

*1:専用のPATHを考慮したカスタムスクリプトの作成・保守など。そもそも、FHS(Filesystem Hierarchy Standard)に違反するから非推奨にすべきという意見もあります。

*2:RHEL 8からYUMの後継としてDNFが導入されました。従来どおりyumコマンドも使えますが、yumはdnfのシンボリックリンクなので、dnfコマンドの利用例を載せています。

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。