この記事は Perl Advent Calendar 2017 の7日目です。
6日は songmuさんによる、 えるしっているか、Lは便利 でした。
今日は、新しいCPANのモジュールマネージャー周りのお話をしたいと思います。
Perlでプロジェクト/ツールの開発をしよう! という時に、モジュールマネージャー Carton を使われる場合が多いのではないでしょうか。
しかし、Perlでプログラムを書いていくと、依存するCPANモジュールが数百個...というのはよくある事で、プロジェクト作成毎に、数百のモジュールインストールを待つには人生は短すぎる、、、そう思われている方も多い事でしょう。
そんな時は、もう一つのモジュールマネージャー Carmel の出番です!
Carmelとは
Cartonと同じ作者である、Tatsuhiko Miyagawaさんが開発されている新しいモジュールマネージャーです。
Carmel - CPAN Artifact Repository Manager
Carmelの特徴は、一度インストールしたバージョンのモジュールは、ローカル内の中央のリポジトリ(~/.carmel)に保存されます。
同じモジュールの違うバージョンも、別々に保存され切り替える事などが可能です。
その為、違うプロジェクトを開始する時でも、一度モジュールをcarmel経由でインストールしていれば、中央のリポジトリから使い回されるので、「モジュールをダウンロードしてインストール」という工程を省く事ができ、とても素早くプロジェクトを作成できます。
まずは、cpanmなどからインストールします。バージョンが表示されればインストールされています。
$ cpanm Carmel --notest
$ carmel version
例えば、プロジェクトのcpanfileがこんな感じで依存が多くあったとします。
# catalyst application runtime
requires 'Catalyst::Runtime' => '== 5.90115';
requires 'Catalyst::View::JSON' => '== 0.36';
requires 'Catalyst::View::TT' => '== 0.44';
requires 'Catalyst::Helper::View::JSON';
requires 'Catalyst::Helper::View::TT';
requires 'Catalyst::ControllerRole::CatchErrors';
requires 'Catalyst::Plugin::File::RotateLogs' => '== 0.06';
requires 'Catalyst::Plugin::ConfigLoader';
requires 'Catalyst::Action::RenderView';
requires 'Catalyst::ActionRole::JSV';
# json schema validator
requires 'JSV' => '== 0.08';
# databases
requires 'DBI';
requires 'DBD::mysql';
requires 'SQL::Format';
requires 'DBIx::TransactionManager';
requires 'Scope::Container';
requires 'Plack::Middleware::Scope::Container';
# datetime
requires 'Time::Moment';
# error handler
requires 'Try::Tiny';
# access token generator
requires "Crypt::JWT" => "== 0.018";
# FastCGI on H2O
requires "FCGI::ProcManager";
on 'develop' => sub {
requires 'Catalyst::Devel' => '== 1.39';
requires 'Term::Size::Any';
requires 'Devel::REPL';
requires 'Text::API::Blueprint';
};
on 'test' => sub {
requires "Plack::Test";
requires "Plack::Util";
requires "Path::Tiny";
requires "Test::More";
requires "Test::JSON";
}
おもむろに、インストールコマンドを打ちます。
$ carmel install
初回はまだどのモジュールもインストールされていないので、ダウンロードandインストールする時間は、Carton同様にかかります。が、これらのいずれかのモジュールを使うcpanfileを、違うプロジェクトなどで用意し、carmel installを実行してみると、かつてダウンロードしたモジュールはスキップされるので、インストールが高速化される事がわかると思います。一旦reinstallしたい、などの場合も効果的です。
インストールが完了すると、Carton互換の cpanfile.snapshot が出来ているのが確認できます。
同時に、 .carmel/MySetup.pm も作成されます。
これは、carmelが管理している、実行時にモジュールを参照するパスを繋げる為のモジュールです。(Carmelが管理しているファイルなのでいじりません。
実行する時は cartonとほぼ同じ使い方なので、スムーズに覚える事ができます。
$ carmel exec -- perl hoge.pl
$ carmel exec -- plackup -a myapp.psgi
などなど。以上で、モジュールを中央リポジトリからロードして使う事は、このままで可能なのですが、 cartonの様に、local/にモジュールを集めてパスを通して使う方が、本番環境などの場合など利便性があるでしょう。
$ carmel rollout
すると、中央リポジトリから参照している依存モジュール全てを、local/ にインストール(コピー)します。cartonと同じ状態ですね。
一旦 rolloutすると、中央リポジトリではなく、local/からのみモジュールをロードするように挙動が変わります。
そのため、一旦rollout後、新しく依存モジュールをcpanfileに記載して、carmel installだけでは local/にはまだ保存されていないため、度に rolloutが必要になります。
補足ですが、起動方法のついては別の起動方法もあり、carmelコマンドを使用せず、下記のように、perlコマンドから依存性を解決した状態で起動する事も可能です。
$ perl -MCarmel::Setup test.pl
Carmel::Setupモジュールは、.carmel/MySetup.pmを読もうとしますので、パスを繋げるなどの必要はあります。
これで、サクサクPerlプロジェクトを作成できるようになりましたね!
App::cpm
cpmは、Shoichi Kajiさんが開発されている、並列CPANモジュールインストーラーです。
App::cpm - a fast CPAN module installer
本番環境でも、cartonやcarmelを使って、cpanfile.snapshot から deployment install... というのが定番かと思いますが、やはり本番環境でもインストールを高速化したいところです。
cpmは、cpanfile.snapshotから並列にモジュールをインストールできるばかりか、数々の豊富なオプションが揃っております。
使い方もhelpで表示されますが、ここではオプションを中心に見てみましょう。
$ cpm --help
.....
....
...
Options:
-w, --workers=N
number of workers, default: 5
-L, --local-lib-contained=DIR
directory to install modules into, default: local/
-g, --global
install modules into current @INC instead of local/
-v, --verbose
verbose mode; you can see what is going on
--prebuilt, --no-prebuilt
save builds for CPAN distributions; and later, install the prebuilts if available
you can also set $ENV{PERL_CPM_PREBUILT} true to enable this option
--target-perl=VERSION (EXPERIMENTAL)
install modules as if verison is your perl is VERSION
--mirror=URL
base url for the CPAN mirror to use, you can use --mirror multiple times
default: https://cpan.metacpan.org
-r, --resolver=class,args (EXPERIMENTAL, will be removed or renamed)
specify resolvers, you can use --resolver multiple times
available classes: metadb/metacpan/02packages/snapshot
--reinstall
reinstall the distribution even if you already have the latest version installed
--dev (EXPERIMENTAL)
resolve TRIAL distributions too
--color, --no-color
turn on/off color output, default: on
--test, --no-test
run test cases, default: no
--man-pages
generate man pages
--retry, --no-retry
retry configure/build/test/install if fails, default: retry
--configure-timeout=sec, --build-timeout=sec, --test-timeout=sec
specify configure/build/test timeout second, default: 60sec, 3600sec, 1800sec
--show-progress, --no-show-progress
show progress, default: on
-V, --version
show version
-h, --help
show this help
--with-requires, --without-requires (default: with)
--with-recommends, --without-recommends (default: without)
--with-suggests, --without-suggests (default: without)
--with-configure, --without-configure (default: without)
--with-build, --without-build (default: with)
--with-test, --without-test (default: with)
--with-runtime, --without-runtime (default: with)
--with-develop, --without-develop (default: without)
specify types/phases of dependencies in cpanfile to be installed
素晴らしいオプションの数々!!
本番環境では、cpanfile.snapshotから developとtestの依存モジュールを抜いたruntimeのモジュールだけ、並列コア数を適切に増やして並列インストールするのが良い感じです。
$ cpm install --without-develop --without-test --workers=8
これで、本番環境へのデプロイも速くなりましたね!
運用するサーバについて余談
Nginx+PSGIサーバや、Apache+mod_perlなど用途に合わせた多種多様の起動方法がありますが、僕は最近、カジュアルにPerlアプリを動かすために、H2O を使っています。
H2O - the optimized HTTP/1, HTTP/2 server
PSGIサーバStarletなど数々のPerlモジュールを開発している Oku Kazuhoさんが開発されている高速なWebサーバです。
"/":
fastcgi.spawn: 'exec /var/www/apps/hogeapi/p5env plackup -s FCGI --nproc 16 -a /var/www/apps/hogeapi/app.psgi'
こんな感じに h2oから、FastCGIプロセスを起動して管理してもらいます。
#!/bin/sh
set -e
export CATALYST_HOME="/var/www/apps/hogeapi"
export PLACK_ENV="production"
export PERL5LIB="/var/www/apps/hogeapi/local/lib/perl5:/var/www/apps/hogeapi/lib"
exec "$@"
上記は cpm でinstallしたモジュールにパスを繋げる程度のファイルです。
PSGIサーバを前段のWebサーバからリバースプロキシさせる方法と違って、h2oプロセスだけ死活監視、スタートアップさせればいいというカジュアルな運用が出来ます。
それでは今日の話は以上です。
明日は mackee_wさんで 「Test2と一緒に暮らしていく」 です!