CheckInstall による Slurm の deb パッケージ化
こんにちは.NTT の新井です.
「Git LFSについて調べてみた」などで触れているように,露崎や私のチームでは GPU クラスタ (参考) の構築と運用を行っており,その中で内製の deb パッケージを使用しています.この記事ではそのパッケージの作成方法をご紹介します.
はじめに
現在主要なソフトウェアは概ねパッケージとして配布されていますが,最新版を利用するためには依然としてソースコードの tarball から自分でビルドしなければならないことがあります.最新版の利用は新機能の活用のみならず,OSS コミュニティに関与していくためにも重要です.例えば我々はジョブスケジューラの Slurm を使用しており,可能な限りその最新版を配備するようにしています.しかしながら,ソースコードからのインストールは依存関係の管理やソフトウェアの削除を煩雑にしがちです.
そこで我々は tarball からパッケージを作成することにしました.形式は Ubuntu など Debian 系ディストリビューションで使用される deb です.
本格的な deb パッケージの作成には debuild などのツールが使われますが,ここではより簡単な CheckInstall を使用します.なんと make install の代わりにcheckinstall
を実行するだけというお手軽さです.とはいえそれだけでは使いやすいパッケージを作成できないことも多いため,以降では Ubuntu 18.04 上の Slurm 20.02.2 を題材にパッケージ作成の具体的な手順を説明します.
ちなみに,NTT は国内の Slurm ユーザ向けイベント Slurm User Group Meetup Tokyo #1 の会場提供などを行いました.第2回以降も開催される見込みですので,ご興味のある方はぜひ Slurm User Group Japan のメンバーになってください.
通常の Slurm インストール手順
初めに,パッケージ化せず Slurm をインストールする手順をシェルスクリプトinstall_slurm.sh
で示します.実際に Slurm を使おうとされている方以外は,./configure && make && make install
の他にもやることが沢山あるんだなァという程度の気持ちで眺めていただけば十分です.
これを root 権限で実行すると Slurm をインストールできます.ただし Slurm を動作させるためには設定ファイル/etc/slurm/slurm.conf
の変更が必要です.面倒ですが,実用的な設定をデフォルトで提供することは困難なのでやむを得ません.最低限の動作確認のため,ここでは localhost のみから成るクラスタを構成するように設定します.その後デーモンを起動すると Slurm が動作します.
$ sudo bash install-slurm.sh
[...]
$ sudo sed -i \
-e 's/^ClusterName=.*$/ClusterName=cluster/' \
-e 's/^ControlMachine=.*$/ControlMachine=localhost/' \
-e 's/^NodeName=.*$/NodeName=localhost Procs=1 State=UNKNOWN/' \
/etc/slurm/slurm.conf
$ sudo systemctl start slurmdbd
$ sudo systemctl start slurmd
$ sudo systemctl start slurmctld
$ sinfo
PARTITION AVAIL TIMELIMIT NODES STATE NODELIST
debug* up infinite 1 idle localhost
$ sinfo --version
slurm 20.02.2
$ srun echo 'hello, world'
hello, world
以降ではinstall-slurm.sh
に相当するインストール手順をパッケージ化します.
パッケージ作成手順
詳細に入る前に,これからどのようなパッケージを作成しようとしているかを説明します.
パッケージ化のためにはいくつかのファイルが必要になるので,その内容のサンプルをまとめて gist に置きました.以下のようにbuild.sh
を実行することでパッケージファイルslurm_20.02.2-1_amd64.deb
を生成できます.ただしパッケージを作成した環境には依存パッケージと共に Slurm がインストールされてしまうことに注意してください.
$ wget https://gist.github.com/araij/7fe6e14c31d08f69e5873e8cd7fa4fd0/archive/a9d02a25159c2d219f2e252294bf276c0e84c3ec.zip
$ unzip -jd slurm-packaging/ a9d02a25159c2d219f2e252294bf276c0e84c3ec.zip
[...]
$ cd slurm-packaging
$ sudo bash build.sh
[...]
$ ls *.deb
slurm_20.02.2–1_amd64.deb
生成したパッケージは (恐らくは 64 bit の Ubuntu 18.04 であれば) 他のマシンでも利用できます.Slurm を動作させるための手順はパッケージ化前と同じです.
$ sudo apt update
$ sudo apt install -y ./slurm_20.02.2-1_amd64.deb
$ sudo sed -i \
-e 's/^ControlMachine=.*$/ControlMachine=localhost/' \
-e 's/^NodeName=.*$/NodeName=localhost Procs=1 State=UNKNOWN/' \
/etc/slurm/slurm.conf
$ sudo systemctl start slurmdbd
$ sudo systemctl start slurmd
$ sudo systemctl start slurmctld
$ sinfo
PARTITION AVAIL TIMELIMIT NODES STATE NODELIST
debug* up infinite 1 idle localhost
$ sinfo --version
slurm 20.02.2
$ srun echo 'hello, world'
hello, world
さて,それではパッケージを作成するスクリプトbuild.sh
はどのような内容になっているのでしょうか.
先に示したinstall-slurm.sh
とbuild.sh
の違いは “Copy CheckInstall files” と “Make and install the package” のステップにあります.以降でこれらについて詳しく説明します.
Copy CheckInstall files
Deb パッケージではインストール (ファイル配置) の前後およびアンインストール (ファイル削除) の前後の合わせて4つのタイミングにスクリプトを実行できます.CheckInstall においてそれらはpreinstall-pak
,postinstall-pak
,preremove-pak
,postremove-pak
というファイルにそれぞれ対応します.*-pak
ファイルは shebang (例えば#!/bin/bash
) で始まり,終了コードは成功時にゼロ,失敗時に非ゼロでなければなりません (参考).今回の場合make install
より後がインストール後の処理に相当するので,基本的にはこれを丸ごとpostinstall-pak
に記述することになります.さらに再インストールとアンインストールに備えて,preinstall-pak
とpreremove-pak
では Slurm 関連デーモンの停止と自動起動の無効化 (systemctl disable
) を実施するとよいでしょう.
さらに,CheckInstall はパッケージ管理システム上で表示する説明文としてdescription-pak
というファイルの内容を使用します.このファイルには例えば Ubuntu のパッケージと同じようにSimple Linux Utility for Resource Management
等と書いておきます.
これらの*-pak
ファイルはmake install
するディレクトリに置いておく必要があるので,”Copy CheckInstall files” のステップでコピーしています.
Make and install the package
設定ファイルの同梱
インストール手順から察せられるように,Slurm のmake install
は設定ファイルを配置しません.CheckInstall はmake install
によるファイル操作を再現するようなパッケージを作成するので,このままでは設定ファイルがパッケージから除外されてしまいます.
そこでcheckinstall
コマンドのオプション--include
を使用します.同梱したいファイルのリストをファイルに書き--include
で渡すと,それらのファイルもインストールされるようになります.ただしファイルのリストを書く際のパスには注意が必要です.パッケージ作成時にはcheckinstall
コマンド実行時のカレントディレクトリからの相対パスとして解釈されますが,インストール時には/
からの相対パスとして解釈されます.そのため,パッケージ作成時に/
からのディレクトリ構造をカレントディレクトリ内に構築し,そこへ一度設定ファイルをコピーしてからパッケージ化します.例えば systemd ユニットファイル./etc/slurmd.service
はcheckinstall
コマンドの前に./lib/systemd/system/slurmd.service
へコピーしています.(build.sh
の43行目)
※ --include
で指定するファイルのパスについて誤った記述があったため,本文とパッケージ作成スクリプトを 5/20 に修正しました.スクリプトの差分は Gist で確認できます.記事をご覧になった方にはご迷惑をおかけいたしました.
依存パッケージの指定
パッケージ管理システムを使う大きな利点の一つが依存パッケージの自動インストールです.パッケージ作成時にオプション--requires
でカンマ区切りのパッケージリストを渡すと依存先として指定できます.例えば--require=munge,libmunge2,libmysqlclient20
のようにします.
ところで依存先パッケージはどこで分かるのかというと,自動的に抽出する方法は私も知りません.Ubuntu のパッケージ情報を参考にする,あるいはバイナリの依存先共有ライブラリ (.so) からパッケージを逆引きする,などが有効そうではあります.しかし依存関係は不正確ならば定義されていないほうがむしろ良いだろうと思います.不足があればその時インストールすることにして,ここでは明らかに必要なパッケージのみ記述しました.
おわりに
この記事では Slurm 20.02.2 を題材に CheckInstall を用いて deb パッケージを作成する手順について解説しました.普通にmake && make install
する場合と比べてさほど大きくない手間でパッケージ化できることをご理解いただけたと思います.
しかしながら前述したように,パッケージを作成するマシンには依存パッケージ等がインストールされてしまいます.普段の作業環境ではあまりやりたくありませんよね.そこで後日になりますが,GitHub Actions を用いて GitHub 上でパッケージ化とリリースを行う方法もご紹介したいと思っています.ご興味のある方はご確認ください.(5/13 に公開しました)
私たち NTT は OSS を活用した研究開発を共に行う仲間を募集しています.ぜひ弊社ソフトウェアイノベーションセンタ紹介ページや,採用情報ページをご覧ください.