はじめに

この記事は Perl Advent Calendar 2022 の 1日目の記事です。


ある Perl 屋の副業の物語

この物語は実際のお仕事を元につくられたフィクションです。

あなたは時々、副業で Perl 関連の仕事を請けている。 最近は Perl を自ら進んで書く人は減ってしまったが、競争も少ない分買い叩かれることもなく、 悪くない仕事だと思っている。

今回の仕事の内容は、顧客に依頼されたメールサーバーに Perl で書かれたプログラムを導入して設定することだ。導入したいプログラムは authentication_milter、初めて知ったプログラムだ。これは CPAN にも Mail::Milter::Authentication として登録されている。対象となるメールサーバーの OS は CentOS Stream 8 だが、このモジュールの rpm はどこにも無いようだ。さて、どうやってインストールするのが良いだろう…?

制約条件

  • 対象プログラム(authentication_milter)はメールサーバーソフト(postfix)から呼び出され、OS の標準サービスの一部として働く予定だ。

    • そのため、OS添付の /usr/bin/perl (いわゆるシステムPerl)を活用したい
      (plenv/ perlbrew/ perl-build などで独自の Perl バイナリーをインストールすることは、運用を他人に引き継いだ後の混乱の元になるという理由で、今回は避けるとする)
      幸い、CentOS Stream 8 の現在の Perl は v5.26.3。新しくはないが、使えないほど古いものでもない。
  • このサーバーには既に SpamAssassin (これも Perl で書かれている)が OS のパッケージ管理システム dnf を通じて導入されている。この挙動は壊したくない。

  • テストサーバー上で authentication_milter を導入し、問題が発覚した時は撤退することで顧客の同意を得ている。ただし、撤退時は完全なアンインストールが必須だ。

普通に cpanm する方法の問題点

公式サイトでは普通に cpanm でインストールする方法が紹介されている。運が良ければこれで動くだろう。

cpanm Mail::Milter::Authentication

けど、運が悪かったら? undo してやり直したくなったら? (cpanm には --uninstall オプションがあるが、自分で使ったことはない。どの程度信用できるだろうか?)。また、実験サーバーで動いたとして、本番サーバーでも cpanm を実行した時に同じバージョンのモジュールが入るとは限らない。第一、たまたま通信エラーが起きたらどうする?そのためだけにローカルに CPAN サーバーを用意するのは…負担が大きい…

OrePAN を使って、予め CPAN のローカルミラーを作って git 管理する方法があるそうだが… もっと直接的に、 インストール結果ディレクトリ自体を git 管理 する方法が、あるのではないか?

着眼

CPAN モジュールのインストール結果ディレクトリ自体を git 管理すれば、 branch を使って undo も redo も自由自在だ。 git submodule で github から CPAN モジュールを取り込む事も出来るだろう。 sha1 のお陰で改ざん防止にもなるし、システム変更の履歴も残せる。 良いことばかりじゃないか?

提案:git 管理された /usr/local/perl5

標準的な Linux ディストリビューションの /usr/bin/perl で cpanm や cpm を使ってグローバルにインストールした CPAN モジュール群は、 Perl Configinstallsitearch installsitelib の指すディレクトリにインストールされる。(※)

% perl -MConfig -le 'print "$_=$Config{q(installsite).$_}" 
  for qw(arch lib)'

# CentOS Stream 8 の場合(Perl 5.26)
arch=/usr/local/lib64/perl5
lib=/usr/local/share/perl5

# Fedora 36 の場合
arch=/usr/local/lib64/perl5/5.34
lib=/usr/local/share/perl5/5.34

そこで、これらのディレクトリを symlink にし、 実体は /usr/local/perl5 に置いて、そこを git の管理下に置くのはどうだろうか…?

% cd /usr/local

% ls -ld lib64/perl5 share/perl5
lrwxrwxrwx. 1 root root  20  8月 23 14:09 lib64/perl5 -> ../perl5/lib64/perl5
lrwxrwxrwx. 1 root root  20  8月 23 14:09 share/perl5 -> ../perl5/share/perl5

% tree -L 2 perl5
perl5
├── cpanfile
├── lib64
│   └── perl5
├── make-symlink.zsh
├── run-cpm.zsh
└── share
    └── perl5

※ sitearchexp, sitelibexp を参照した方が良いかもしれません

実装の例

私が業務で 2016年頃から用いてきたスクリプト群を手直しし、テンプレート化したものを github に置きました。(fedora:latest コンテナ内で動作確認済みです)

github.com/hkoba/usr-local-perl5-template

  • 一部のスクリプト※が Fedora, CentOS Stream などの RedHat 系を前提にしています。
    Debian, Ubuntu 系で用いたい場合は、代わりのものを実装して下さい。

  • *.zsh とあるスクリプトは実行に zsh が必要です


※ dnf-install.zsh

使い方

  • clone して cpanfile に欲しいモジュールを追記し、run-cpm.zsh を 実行して下さい。

    dnf install zsh perl git
    
    cd /usr/local
    
    git clone https://github.com/hkoba/usr-local-perl5-template.git perl5
    
    cd $_
    
    # EDIT cpanfile and dnf-install-perlmodules.lst
    
    # Then
    
    ./run-cpm.zsh
    
  • 例えばシステムの openssl に依存するもののように、OS のパッケージ管理でインストールしたほうが簡単な CPAN モジュールも有るでしょう。そういうものは 下記のファイルにモジュール名を列挙して下さい。

    dnf-install-perlmodules.lst
    
  • 別マシンでインストール結果を再現したい場合は、git clone 後に以下のコマンドで symlink を作成して下さい

    ./dnf-install.zsh
    ./make-symlink.zsh
    

おしまい

最後まで読んで下さり、ありがとうございました!