15
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

この記事は 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がこんな感じで依存が多くあったとします。

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サーバです。

h2o.conf
"/":
  fastcgi.spawn: 'exec /var/www/apps/hogeapi/p5env plackup -s FCGI --nproc 16 -a /var/www/apps/hogeapi/app.psgi'

こんな感じに h2oから、FastCGIプロセスを起動して管理してもらいます。

p5env
#!/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と一緒に暮らしていく」 です!

15
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?