目次


Perlモジュールの展開を自動化する

CPANを超えるスクリプトでネットワーク経由インストールが容易に

Comments

Perlモジュールのインストール

皆さんはPerlをインストールした途端に、いかに多くのモジュールがPerlの「ベース」インストールを構成しているかに気がつくでしょう。そして時間が経つにつれ、Perlインストールの機能を追加、改善するために、さらに多くのモジュールをインストールする必要が出てきます。モジュールのインストール自体は難しくありません。大部分のモジュールは、単純な、圧縮されたtarballとしてパッケージされています。このtarballには、必要があればサードパーティーのライブラリーと統合するためのC/C++ソースコードを含めて、必要なファイルが含まれています。

ほとんどのPerlモジュールはMakeMakerシステムを使っています。MakeMakerもPerlのベース・インストールと共にインストールされるPerlモジュールの一つですが、Perlインストールに関する情報だけではなく、コンポーネントのビルド機構や、適切な場所にインストールするための情報を提供しています。MakeMakerは単純なコンフィギュレーション・ファイルを、(おなじみのmake コマンドで使われる)標準のmakefileに変換します。

CPANを使う

まだCPAN(Comprehensive Perl Archive Network)を知らないなら、各インストールと共に配布されるドキュメントの、メイン・ページを参照して下さい。CPANの使い方としては、対話型シェルを通して使う方法と、広範なPerlスクリプト・ベースのソリューションの一部として使われるファンクション・シリーズを通して使う使い方です。最も単純な使い方はモジュールのインストールに使うもので、その場合はperl -MCPAN -e "install modulename" とタイプします(ここでmodulename は、インストール対象のパッケージ名やバンドル名、あるいは完全なPerlモジュールの名前です)。そうすると、あとはCPANが処理してくれるのです。

CPANを自動化する

ほとんどの人は、Perlモジュールをビルド、インストールするための対話型シェルとしてCPANを知っています。ところが、こうした機能を提供するCPANモジュールは、実際には内部API(application program interface)を取り巻くラッパーに過ぎないことを、多くの人は知りません。例えば、CPANに用意されている使えるバージョンと比べて古くなっているインストール・モジュールのリストを生成するためには、単純にCPAN::Shell->rを呼べばよいのです。リスト1はこのコマンドと、その出力の例です。

リスト1. 古くなっているモジュールのリストを生成するコード
$ perl -MCPAN -e 'CPAN::Shell->r'
CPAN: Storable loaded ok
Going to read /export/build/solaris/cpan/Metadata
  Database was generated on Sun, 25 Jul 2004 02:10:00 GMT
Package namespace         installed    latest  in CPAN file
B::Assembler                   0.06      0.07  N/NW/NWCLARK/perl-5.8.5.tar.gz
Cwd                            2.19      2.20  K/KW/KWILLIAMS/Cwd-2.20.tar.gz
DBD::mysql                   2.9003    2.9004  R/RU/RUDY/DBD-mysql-2.9004.tar.gz
DateTime                     0.2101      0.22  D/DR/DROLSKY/DateTime-0.22.tar.gz
DateTime::TimeZone             0.27      0.28  D/DR/DROLSKY/DateTime-TimeZone-0.28.tar.gz
File::Scan                     1.23      1.25  H/HD/HDIAS/File-Scan-1.25.tar.gz
File::Spec                     0.87      0.88  K/KW/KWILLIAMS/File-Spec-0.88.tar.gz
Image::Magick                 5.5.7       6.0  J/JC/JCRISTY/PerlMagick-6.02.tar.gz
Mail::ClamAV                   0.08      0.11  S/SA/SABECK/Mail-ClamAV-0.11.tar.gz
Module::CoreList               1.94      1.95  R/RC/RCLAMP/Module-CoreList-1.95.tar.gz
POE                          0.2802      0.29  R/RC/RCAPUTO/POE-0.29.tar.gz
XML::RSS::Parser               2.11      2.15  T/TI/TIMA/XML-RSS-Parser-2.15.tar.gz
htmlop                       v0.2.6      0.26  J/JA/JANL/w3mir-1.0.10.tar.gz
5 installed modules have a version number of 0
890 installed modules have no parseable version number

最新を保つために、こうしたモジュールを自動的にインストールするためには、次のように、CPAN::Shell->r へのコールをCPAN::Shell->install ファンクションに埋め込みます。

$ /usr/local/bin/perl -MCPAN -e 'CPAN::Shell->install(CPAN::Shell->r)'

このコードでリスト1の情報がダンプされ、次に、最新版に更新するために各モジュールがインストールされます。

ネットワークにまたがってCPANを自動化する

CPANは素晴らしいツールですが、このシステムには制限があります。一つ大きな欠点として、単一システム用のソリューションだという点です。それでも、1台のコンピューター上でPerlインストールを管理しようとする場合には問題ありません。ところがWebのサーバー群にまたがって、あるいは研究室内で様々なプラットフォームにまたがってPerlモジュール・セットがある場合には、全コンピューターで最新を保つためには、上記の自動化手法を使ったとしても、非常に大きな時間が必要となります。

CPANにはまた、CPANを使う各コンピューター上でインターネット帯域幅も大量に消費します。つまりCPANは、中央のCPANリポジトリーの一つからファイルのコピーをダウンロードすることを想定しているのです。またCPANは、各マシン用に微調整されたコンフィギュレーションに依存します。プラットフォームを全く同一に設定できる場合でないと、/perlinstalldirectory/CPAN/Config.pmにあるコンフィギュレーション・ファイルをコピーできません。

CPANを使うときには、まず確実にautobundle ファンクションを使います。このファンクションはPerlインストールでインストールされたモジュールのリストを生成し、次にそのリストの中から選択したものを、(最新のPerlバージョンに更新後)同じコンピューターに、あるいは別のコンピューターに再インストールできるフォーマットでダンプします。リスト2のコードは、新しいバンドルの作り方を示しています。

リスト2. CPAN autobundleを作るためのコード
$ perl -MCPAN -e autobundle
...
Package namespace         installed    latest  in CPAN file
AnyDBM_File                    1.00      1.00  N/NW/NWCLARK/perl-5.8.5.tar.gz
Apache::ASP                    2.57      2.57  C/CH/CHAMAS/Apache-ASP-2.57.tar.gz
Apache::ASP::ApacheCommon     undef     undef  C/CH/CHAMAS/Apache-ASP-2.57.tar.gz
Apache::ASP::Application      undef     undef  C/CH/CHAMAS/Apache-ASP-2.57.tar.gz
Apache::ASP::CGI              undef     undef  C/CH/CHAMAS/Apache-ASP-2.57.tar.gz
Apache::ASP::CGI::Table       undef     undef  C/CH/CHAMAS/Apache-ASP-2.57.tar.gz
Apache::ASP::CGI::Test        undef     undef  C/CH/CHAMAS/Apache-ASP-2.57.tar.gz
Apache::ASP::Collection       undef     undef  C/CH/CHAMAS/Apache-ASP-2.57.tar.gz
Apache::ASP::CollectionItem     undef     undef  C/CH/CHAMAS/Apache-ASP-2.57.tar.gz
Apache::ASP::Date             undef     undef  C/CH/CHAMAS/Apache-ASP-2.57.tar.gz
...

Wrote bundle file
	/export/build/solaris/cpan/Bundle/Snapshot_2004_08_08_00.pm

生成されるファイルは、CPANインストール・ディレクトリー内に作られます。そのファイルをその場所からコピーするか、あるいは、新しいバージョンのPerlに更新するのであれば、次のように単純にbundle モジュールを実行して、すべてを再インストールします。

$ perl -MCPAN -e 'install Bundle::Snapshot_2004_08_08_00'

bundle ファンクションを使っても構わないのですが、実は私は幾つかの理由から、ネットワーク・ソリューションとしてのバンドル・システムをあまり好きではありません。第1の理由として、バンドルは各コンピューターが同じ構成であることを前提にしています。全てが同じであれば、これでも構いません。しかし、異なるプラットフォームや環境がある場合には、すぐに問題に突き当たります。第2に、autobundle機能では、インストールされている全モジュールをリストアップするため、複数のパッケージをリストアップしてしまいます(個々のパッケージは複数のモジュールを含む可能性があります)。しかしバンドルでは、(一部のモジュール更新のソースとして)後のバージョンのPerlへの参照もリストアップするのです。

最後の問題として、バンドルでは一台のコンピューターが全モジュールの最新バージョンを持っていることを前提にしています。バンドルを使って、標準パッケージを最新バージョン(それが何であれ)に更新することはできません。そのため、ネットワーク環境では使いにくいシステムになります。

カスタムのソリューションをビルドするためには2つの方法があります。中央CPANインストール・ディレクトリーを使う方法と、中央CPANソース・ディレクトリーを使う方法です。

中央CPANインストール・ディレクトリーを使う

ネットワークにまたがってCPANを構成するために比較的単純な方法、そして全コンピューターが同じである場合に使える方法として、NFS(Network File System)経由で共有される単一のCPANディレクトリーを作り、各コンピューターにCPAN/Config.pmファイルをコピーし、次に上記のCPAN::Shell 手法を使って各コンピューターにモジュールをインストールします。メインのコンピューター(通常はNFS経由でCPANディレクトリーを共有しています)には「ベース」モジュール・セットをインストールします。他の各コンピューターではソースのtarballが既に存在しているため、必要な各モジュールのビルド、インストールのプロセスは迅速に行うことができます。従って再度tarballをダウンロードする必要はなく、貴重なインターネット帯域幅を節約でき、時間も大幅に短縮できるのです。

この手法の主な問題は、他の点では全て同じ、というコンピューターにとっては、プロセッサー時間の浪費になることです。既にコンパイルは一度行ってあるので、再度コンパイルするのは無駄です。また、同じビルド・ディレクトリーが複数のコンピューターで使われる、という危険な状況に陥ることにもなります。これは、別々のコンピューターが同時にソースをコンパイルする可能性があるため、様々なタイミング・エラーが発生したり、クロス・プラットフォームの環境ではリンク時に不正なオブジェクト・ファイルが生成されたりすることになりかねません。

CPANソース・ディレクトリーを使う

上記ソリューションの変形として、同じソース・ディレクトリーと基本CPANコンフィギュレーションを使いながら、手動でコンフィギュレーション・ファイルを変更する方法があります。つまり、各ホストの設定情報の大部分が、ホスト固有となるようにするのです。こうすることによって、ビルド・ディレクトリーの問題を回避しながら、ローカル(つまりネットワーク上)にキャッシュされたtarballを使えるようになります。リスト3は、そうしたコンフィギュレーション・ファイルを示しています。

リスト3. CPAN::Configファイルの例
# This is CPAN.pm's systemwide configuration file. This file provides
# defaults for users, and the values can be changed in a per-user
# configuration file. The user-config file is being looked for as
# ~/.cpan/CPAN/MyConfig.pm.
$CPAN::Config = {
  'build_cache' => q[200],
  'build_dir' => q[/export/build/solaris/cpan/build],
  'cache_metadata' => q[1],
  'cpan_home' => q[/export/build/solaris/cpan],
  'dontload_hash' => {  },
  'ftp' => q[/usr/bin/ftp],
  'ftp_proxy' => q[proxy.mcslp.pri:8080],
  'getcwd' => q[cwd],
  'gpg' => q[],
  'gzip' => q[/usr/bin/gzip],
  'histfile' => q[/export/build/solaris/cpan/histfile],
  'histsize' => q[100],
  'http_proxy' => q[proxy.mcslp.pri:8080],
  'inactivity_timeout' => q[0],
  'index_expire' => q[1],
  'inhibit_startup_message' => q[0],
  'keep_source_where' => q[/export/build/solaris/cpan/sources],
  'lynx' => q[],
  'make' => q[/usr/local/bin/make],
  'make_arg' => q[-j3],
  'make_install_arg' => q[UNINST=1],
  'makepl_arg' => q[],
  'ncftp' => q[],
  'ncftpget' => q[],
  'no_proxy' => q[],
  'pager' => q[/usr/bin/less],
  'prerequisites_policy' => q[follow],
  'scan_cache' => q[atstart],
  'shell' => q[/usr/local/bin/bash],
  'tar' => q[/usr/local/bin/tar],
  'term_is_latin' => q[1],
  'unzip' => q[/usr/bin/unzip],
  'urllist' => [q[ftp://cpan.etla.org/pub/CPAN], q[ftp://cpan.teleglobe.net/pub/CPAN],
    q[ftp://ftp.demon.co.uk/pub/CPAN/], q[ftp://ftp.flirble.org/pub/languages/perl/CPAN/],
    q[ftp://ftp.mirror.ac.uk/sites/ftp.funet.fi/pub/languages/perl/CPAN/],
    q[ftp://ftp.mirror.anlx.net/CPAN/], q[ftp://ftp.plig.org/pub/CPAN/],
    q[ftp://usit.shef.ac.uk/pub/packages/CPAN/], q[http://cpan.hambule.co.uk/]],
  'wget' => q[],
};
1;
			__END__

コンフィギュレーション・ディレクトリーのパラメーターはすべて、各コンピューターでローカルなものに変更する必要があります。例えば、ライン'build_dir' => q[/export/build/solaris/cpan/build] を、ローカル・マシン上のディレクトリーを指すように変更します。その一方、メインのコンピューターでCPANソース・ディレクトリーを共有してから、NFSマウントされたディレクトリーをkeep_source_where パラメーターが指すように変更するのです。

残念ながら、この方法でも幾つかの問題が残ります。まず、各コンピューターにどのモジュールをインストールしたいのかを手軽に記録する方法がありません。また、ソース・ディレクトリー(と、その他のCPANディレクトリー)の中の情報を正しく最新に保つ、という問題にも突き当たります(これを、新しいバージョンのtarballに更新したり新しいバージョンのtarballをダウンロードしたりせず、そして他のコンピューターの現状に影響を与えずに行う必要があります)。そうすると、各システムにインストールされたモジュールの各バージョンが、違いはわずかでも決定的に異なる、ということが起こり得ます。これは私達が解決しようとしている課題にとって致命的です。

CPANを使って厳密なインストールを作る

上記2つのソリューションはどちらも、CPANを使い、そして何らかのコンフィギュレーション・ファイル操作によってCPANを動作させるという問題があります。上の細工を使ったとしても、CPANはLAN(local area network)上では理想的な解ではありません。従って、こうしたシステム的な制限を回避することが必要なのです。では次に、そのための方法として、マスター・ディストリビューションを設定する方法、各プラットフォーム用のインストール・セットの作り方、そしてそのインストールを各コンピューターで実行する方法を説明しましょう。

マスター・ディストリビューションを設定する

最初のステップとして、既に説明した要素を幾つか使います。まず、通常通りCPANを使うように1台のコンピューターを設定し、デフォルトのモジュール・セットを設定します。次にNFSを使って、ネットワーク上の他のコンピューターに対して必要なファイルを配布するための共有ディレクトリーを設定します。今度はリスト4にある$destdir 変数を編集してから、リスト4のスクリプトを実行します。このスクリプトは下記の3つを行います。

  • モジュールを特定する
  • ソース・ファイルをダウンロードする
  • ソース・ファイルを配布ディレクトリーにコピーする

最初のステージでは、perllocal.podファイルの内容を調べることによって、インストールされているモジュールを特定します。このファイルは、MakeMakerシステムを使ってモジュールがインストールされる度に更新されます。CPANに組み込みのモジュールの代わりにこのファイルを使うことによって、ベースのPerlインストールにインストールされているサードパーティー・モジュールのリストが得られます。2番目のステージでは、最終的にtarballまたは .zipファイルをコピーする前に、CPANを使って、CPAN自体の中に設定されている任意の方法によってソースtarballをダウンロードします。そのプロセスの一部として、コピーされたモジュールのリストも作ります(このモジュールは、他のコンピューターにこのファイルをインストールするときに使います)。

リスト4. ベース・ディストリビューションを作るコード
use CPAN;
use Config;
use File::Copy;
use File::Spec::Functions;
# Set up the directories to store the module packages
my $basedestdir = catfile('export','cpaninst');
mkdir($basedestdir);
my $destdir = catfile($basedestdir,'srcs');
mkdir($destdir);
# Extract a list of the third party modules installed on this machine
my $files = {};
my $podfile = catfile($Config{'archlibexp'},'perllocal.pod');
open(DATA,$podfile) or die "Can't open module list ($podfile): $!";
while(<DATA>)
{
    if (m/.*C<Module> L<(.*)>/)
    {
        my ($module) = split /\|/,$1,0;
        my $mod = expand('Module',$module);
        next unless $mod;
        $mod->get(); #Make sure to download the version again, in case we no
                        #longer have it locally
        $files->{$mod->{RO}->{CPAN_FILE}} = 1; #Save the location of the file
    }
}
close(DATA);
# Now copy each source installer to the source destination directory
# We save a copy of the module file, for reference, as part of the process
my $modulelist = catfile($basedestdir,'modules.lst');
open(DATA,">$modulelist") or die "Can't open the module list file ($modulelist): $!";
foreach my $file (keys %{$files})
{
    my $src = catfile($CPAN::Config->{'keep_source_where'},$file);
    my ($vol,$path,$filename) = splitpath($file);
    my $dest = catfile($destdir,$filename);
    copy($src,$dest) or warn "Copy of $src failed: $!\n";
    print DATA "$filename\n";
}
close(DATA);

これで全てのソース・インストール・パッケージを含むディレクトリーができたことになります。これを使って、Perlモジュールの配布対象となる各プラットフォーム用に、コンパイル済みディストリビューション・パッケージをビルドするのです。ここから先をどうするかは、皆さんの環境に依存します。同質的な環境の場合には、ネットワーク全体に対して、下記に示すステージを1度だけ実行します。様々なプラットフォームを含む異機種構成ネットワークの場合には、下記に示すステップを、それぞれの環境に対して実行する必要があります。

各プラットフォーム用にインストール・セットを作る

各プラットフォームに対して、ソース・ファイルを抽出し、MakeMakerを実行し、そしてインストーラーを実行する必要があります。これを自動的に行うためには、リスト5のスクリプトを使います。残念ながら、MakeMakerのすべてが完全に自動なわけではありません。ですから、例えばディレクトリー位置やデフォルト・オプションを設定する場合などは、ディストリビューションをビルドする度に、対話型で行う必要があります。

リスト5. 各プラットフォーム用のモジュールをビルドするためのコード
srcdir="/export/cpan"
srcfile="$srcdir/module.lst"
platformdir="/export/cpan/solaris-x86"
for file in `cat $srcfile`
  do
    cd $platformdir
    tar zxf $srcdir/$file
    dir=`echo $file|sed -e "s/\.tar\.gz//g"`
    cd $dir
    perl Makefile.PL
    make
done

各コンピューターでインストールを実行する

リスト5のスクリプトを実行すると、対象のプラットフォームに対する「インストール準備完了」モジュールを全て含んだ、一つのディレクトリーができます。こうしたモジュールを、同じプラットフォームを持つ任意のコンピューターにインストールするには、単純にそれぞれのディレクトリーにてmake installを実行します。ここでも、リスト6に示すようなスクリプトを使って、このプロセスを処理することができます。

リスト6. 各ホストにファイルをインストールするためのコード
srcdir="/export/cpan"
srcfile="$srcdir/module.lst"
platformdir="/export/cpan/solaris-x86"
for file in `cat $srcfile`
  do
    cd $platformdir
    tar zxf $srcdir/$file
    dir=`echo $file|sed -e "s/\.tar\.gz//g"`
    cd $dir
    make install
done

まとめ

PerlやCPAN、MakeMakerシステムで提供されている機能を使ったとしても、Perlモジュールのインストールと配布を完全に自動化することはできません。しかし、様々なコンピューターにまたがるプロセスを単純にすることはできます。それぞれのモジュールには独自の設定があり、それぞれのプラットフォームには独自の微妙な要素が絡むため、事態は必要以上に複雑なものになります。この記事で説明したスクリプトを使うことによって、そうしたプロセスにつきものの複雑さが単純化され、また時間も大幅に節約できるようになります。

このソリューションで全てが解決できるわけではありません。例えば、サードパーティー・モジュールでは、ここで説明した方法でインストールしたものではないサードパーティー・ライブラリーを利用している場合がよくあります。そうした場合については、私がdeveloperWorksで書いている他の記事を参考にしてください。


ダウンロード可能なリソース


関連トピック

  • Perlコードからもっとパフォーマンスを搾り出したいと思っているなら、「Perlを最適化する」(developerWorks, 2004年10月)を読んでみてください。
  • Perlは長年、Linux開発者にとって重要なスクリプト・ツールでした。developerWorksには、Perlに関する豊富な記事 が用意されています。
  • Comprehensive Perl Archive Network はCPANネットワーク・システムの本拠地です。
  • developerWorksのLinuxゾーンには、Linux開発者向けの資料が豊富に取り揃えられています。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux, Open source
ArticleID=228113
ArticleTitle=Perlモジュールの展開を自動化する
publish-date=03082004