Masteries

技術的なことや仕事に関することを書いていきます.

Dockerコンテナの中でいい感じにCartonしたい

Dockerで建てたコンテナの上でPerlのWebサービスを開発している場合, 例えばテストを実行するとき等はコンテナ上で実行する必要があります. そういった時, 皆さんはどうしていますか?

例えばdocker-composeでコンテナ群を立ち上げていて, PerlのWebサービスがappというコンテナで動いている時, 次のような選択肢があると思います:

  • docker-compose exec app carton ...する
  • docker-compose exec app /bin/shでコンテナの中に入り, carton ...する

...これでも全然良いのですけれど, とはいえ個人的には面倒という気持ちがあります. やはり, 無意識にこれまで通りcartonでコマンドを実行をすると, 自動的にDockerコンテナの中で実行されて欲しい!!!

...と考えた結果, このようなスクリプトが生まれました.

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;

my $cmd;
my $argv = join ' ', @ARGV;

if ($ENV{'DISABLE_DOCKER'}) {
    $cmd = sprintf(q{$(plenv which carton) %s}, $argv);
} else {
    my $plack_env = $ENV{'PLACK_ENV'} || 'local';
    my $env       = join ' ', map { sprintf('%s=%s', $_, $ENV{$_}) } grep { $_ =~ /^PLACK_ENV$/ } keys %ENV;

    my @commands = 'carton';

    unshift @commands, $env if $env;
    push @commands, $argv if $argv;

    $cmd = sprintf(q{PLACK_ENV=%s docker-compose exec app /bin/sh -c '%s'}, $plack_env, join(' ', @commands));
    print "exec: $cmd\n";
}

exec $cmd;

あとはこのスクリプトをcartonとして呼び出せるようにしてあげればOKで, 例えばcarton exec prove tとすると,

PLACK_ENV=local docker-compose exec app /bin/sh -c 'PLACK_ENV=local carton exec prove t'

というコマンドが実行されます. もしDockerコンテナの中で実行したくないならば, DISABLE_DOCKER=1を付けて実行すればOK.

...ね, 簡単でしょう?


ちなみに, Dockerを使っている時だけこのcartonのラッパースクリプトを使いたい, という時はdirenvを使うと便利です. 例えば, このスクリプトが /path/to/script に設置されていて, /path/to/script/carton で使えるようになっているなら,

export PATH=/path/to/script:$PATH

という感じで.envrcを設置しれあげれば, そのディレクトリ下でのみ, cartonのラッパースクリプトが使われるようになります.

papix.hatenablog.com