2014年6月アーカイブ

タイトルがそのままですが、GrowthForecastのDocker imageを作りました。

https://registry.hub.docker.com/u/kazeburo/growthforecast/

使い方は単純に起動するだけなら次のようになります。

$ docker run -p 5125:5125 kazeburo/growthforecast

これだと、データが永続化されないので、適当なボリュームをマウントします。

$ docker run -p 5125:5125 -v /host/data:/var/lib/growthforecast kazeburo/growthforecast

起動オプションを変更したい場合は、コマンドを渡すか、Dockerfileを書いてビルドすると良いでしょう。

$ docker run -p 5125:5125 -v /host/data:/var/lib/growthforecast kazeburo/growthforecast \
    growthforecast.pl --time-zone UTC --data-dir /var/lib/growthforecast

ヘルプの表示

$ docker run -i kazeburo/growthforecast growthforecast.pl -h

Dockerfileの例

FROM kazeburo/growthforecast CMD growthforecast.pl —time-zone Asia/Tokyo —data-dir /var/lib/growthforecast —front-proxy 0.0.0.0/0 ..

GitHubとDocker Hubを組み合わせてDocker imageの作成を自動化

このDocker imageはGitHubとDocker HubのAutomated Build Repositoryの機能を組み合わせて、GitHub上でタグが作れたのをフックして自動的に作られています。

Automated Build Repositoryを使うには、まずDocker Hub側で、ビルドを開始するためのTrigger URLを有効にします。

gf_gh_trigger.png

そして、このURLをGitHubに入力します。新規のwebhookを追加し、Payloadに先ほどのURLをいれます。Secretは使わないので適当に入れました。今回はタグが作成された際にDocker Imageを作りたいので、Webhookを起動するイベントの「individual events」のラジオボタンを押し、出てきた中から、「Create」だけにチェックボックスをいれました。

gf_hook_gh.png

あと、Dockerfileで最新のタグを指定してソースコードを取得し、インストールを行うようにしています。

RUN git clone -b $(curl -s https://api.github.com/repos/kazeburo/GrowthForecast/tags|jq -r '.[0].name') https://github.com/kazeburo/GrowthForecast.git /tmp/GrowthForecast
RUN cpanm -n --no-man-pages -v --no-interactive /tmp/GrowthForecast

GrowthForecast(や他のCPANモジュール)は、MinillaShipItというツールで、タグの追加とCPANへのリリースを同時に行っていますが、上の例でGrowthForecastのインストールをCPANから行わずにgithubから取得しているのは、DockerのAutomated Buildがgit pushした瞬間から開始されて、CPANのインデックスの更新が追いつかずdocker build中に最新版が取得できない可能性があるからです。

どうぞご利用くださいませ。

最近、Vagrantのprovisionerを使ってパッケージの作成などをいくつか行っているのですが、その際にVMを落とし忘れ、ホストしてるマシンの余計なリソースを使ってしまっていることがあります。

なので、provisionerでサーバをdestroy/haltするやつを書いてみました。

rubygems: https://rubygems.org/gems/vagrant-destroy-provisioner
github: https://github.com/kazeburo/vagrant-destroy-provisioner

勝手にshutdownしてイメージを破棄するデモ動画です。

インストールはvagrant pluginコマンドから行います。

$ vagrant plugin install vagrant-destroy-provisioner

使い方はこんな感じ

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "CentOS-6.4-x86_64-v20131103"
  config.vm.box_url = "http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.4-x86_64-v20131103.box"
  config.vm.provision "shell", inline: "echo 'Hello Provisioner'"
  config.vm.provision "destroy"
end

VMのshutdownだけをするモードも一応サポートしていて

config.vm.provision "destroy", destroy: false

とすると、vagrant halt相当のみ実行されます。destroyオプションのデフォルトはtrueです。

Docker Provisionerを使う場合は、destroy: falserun: "always" を使うと多分便利。先日のPerl-Buildのfatpackの例だと

 config.vm.provision "docker", run: "always" do |d|
    d.build_image "/perl-build/author",
        args: "-t perl-build"
end
config.vm.provision "shell", run: "always",
    inline: "docker run -v /perl-build:/perl-build perl-build"
config.vm.provision "destroy", destroy: false, run: "always"

となります。毎度 vagrant up に —provision オプションを付けなくても良いので楽。

vagrant-destroy-provisionerを使うと、VMの使い捨てが自動化されて非常に便利。どうぞご利用ください。

以下のgems、サイトを参考にしました。

https://rubygems.org/gems/vagrant-reload

vagrantのprovisionerを自作する - Qiita

plenvやxbuildで使っているperl-buildなのですが、ひろむ氏からコミット権限頂いてアップデートをしました。

変更点としてはいつでも使えるように search.cpan.org への依存度を減らしたことと、だれでも同じように作業ができるよう依存モジュールを1つのスクリプトにまとめるfatpackにDockerを導入して自動化した点です。

search.cpan.org への依存度の削減

perl-buildはperlのバージョンを引数に渡してインストールを行います。

$ perl-build 5.20.0 /opt/perl-5.20

この際に、渡されたperlのバージョンからアーカイブのパスを調べる必要があります。アーカイブのパスとは以下のようなものです

R/RJ/RJBS/perl-5.21.0.tar.gz
R/RJ/RJBS/perl-5.20.0.tar.gz
R/RJ/RJBS/perl-5.20.0-RC1.tar.gz
S/SH/SHAY/perl-5.19.11.tar.gz
A/AR/ARC/perl-5.19.10.tar.bz2
T/TO/TONYC/perl-5.19.9.tar.bz2

アーカイブはリリースを行ったCPAN Authorのディレクトリ以下に配置されます。perlのソースコードをダウンロードするにはそのバージョンのperlをリリースしたAuthorのPAUSE IDやパスをなにかしらの方法で調べる必要があります。

この一つの方法が CPAN::Perl::Releases モジュールです。CPAN::Perl::Releasesを使うとこんな感じでパスが取れます。

use CPAN::Perl::Releases qw/perl_tarballs/;
perl_tarballs( '5.14.0' );

Returns a hashref like:

{
  "tar.bz2" => "J/JE/JESSE/perl-5.14.0.tar.bz2",
  "tar.gz" => "J/JE/JESSE/perl-5.14.0.tar.gz"
}

CPAN::Perl::Releasesのソースコード中にベタにバージョンとPAUSE IDの対照表が書かれています。

perl-buildのスクリプトにはCPAN::Perl::Releasesが組み込まれており、最初にCPAN::Perl::Releasesを使ってパスを得ようとします。しかし、組み込まれているCPAN::Perl::Releasesはperl-buildスクリプトをアップデートしない限り、どんどん古くなって行くので、新しいバージョンがリリースされたときに追従出来ず、パスを探せなくなります。

そこでperl-buildは次に http://search.cpan.org/dist/perl-$version をスクレイピングし、パスを調べます。ところが最近、しばしばsearch.cpan.orgがダウンし、またそのダウンタイムも長くなっている(感覚値)ことから、perlをインストールしたい時にエラーでインストールができないということも起きています。

そこで、search.cpan.orgへの依存を減らすべく、こんなページを作りました。curlでアクセスするとこんな感じ。

$ curl -s http://perl-releases.s3-website-us-east-1.amazonaws.com/|head
5.21.0  R/RJ/RJBS/perl-5.21.0.tar.gz
5.20.0  R/RJ/RJBS/perl-5.20.0.tar.gz
5.20.0-RC1      R/RJ/RJBS/perl-5.20.0-RC1.tar.gz
5.19.11 S/SH/SHAY/perl-5.19.11.tar.gz
5.19.10 A/AR/ARC/perl-5.19.10.tar.bz2
5.19.9  T/TO/TONYC/perl-5.19.9.tar.bz2
5.19.8  R/RJ/RJBS/perl-5.19.8.tar.bz2

中身はtsvファイルで、バージョンとパスの組み合わせが得られるだけのページです。静的ファイルなのでs3でホストしています。tsvファイルを作るスクリプトは

https://github.com/kazeburo/perl-releases-list

にあげてあります。このスクリプトをcronで定期的に動かし、s3にアップロードしています。

新しいperl-buildはsearch.cpan.orgにアクセスする前に、このページをダウンロードしてパスを解決します。このページでも解決できない場合はsearch.cpan.orgへアクセスします。

さらに、perlのアーカイブをダウンロードする際のデフォルトのミラーがsearch.cpan.orgだったので、www.cpan.orgへ変更し、search.cpan.orgへの依存をぐっと減らしました。これでもし、search.cpan.orgが落ちていたとしてもperl-buildが使えるようになりました。

ちなみにミラーは環境変数で変更が可能です。

$ PERL_BUILD_CPAN_MIRROR=http://ftp.jaist.ac.jp/pub/CPAN/ perl-build 5.18.1 /opt/perl-5.18

国内ミラーの方がダウンロード速度は速くなるんじゃないかなぁと思います。

Dockerを使ったfatpack

githubに上がっているperl-buildは依存モジュール等を1つにまとめたスクリプトとなっています。これはApp::Fatpackerを使って生成したファイルとなっています。

fatpackしたスクリプトが古いperl 5.8でも動くようにするために、fatpackを行うperlも5.8を使います。以前はtokuhirom氏のローカル環境でやっていた思うのですが、だれでも簡単に再現できるようにした方がいいよねということで、Docker(+Vagrant)で自動化してみました。

Vagrantは1.63が必要です。実行は

$ cd author
$ vagrant up --provision
$ vagrant halt

Docker provisionerを使ってimageを作って実行します。Vagrantfileはこんな感じ

Vagrant.configure("2") do |config|
  config.vm.box = "hashicorp/precise64"
  config.vm.synced_folder "../", "/perl-build"
  config.vm.provision "docker" do |d|
    d.build_image "/perl-build/author",
      args: "-t perl-build"
  end
  config.vm.provision "shell",
    inline: "docker run -v /perl-build:/perl-build perl-build"
end

最後、shell provisionerを使ってdocker runしていますが、これはDocker provisionerにサポートされているrun機能を使うとrunが終了するまえにvagrant upコマンドが終了してしまう(runはバックグラウンドで実行されている)からです。shellで実行するとfatpackが完了するまでvagrant upが待ってくれるので分かりやすくなります。

Dockerfileはこんなの

FROM jmmills/plenv-base:latest
RUN plenv install 5.8.5
RUN plenv global 5.8.5
ENV PLENV_VERSION 5.8.5
RUN curl -L http://cpanmin.us/ | plenv exec perl - -n ExtUtils::MakeMaker@6.56
RUN curl -L http://cpanmin.us/ | plenv exec perl - -n App::cpanminus
RUN curl -L http://cpanmin.us/ | plenv exec perl - -n Perl::Strip App::FatPacker
RUN plenv rehash
CMD bash -l -c 'cd /perl-build; cpanm -n --installdeps . ; bash author/fatpack.sh'

あとは、作ったスクリプトのテストもDocker使ってできるといいなぁと思ってます。

どうぞご利用ください。

あるモジュールがPerlのコアモジュールに含まれているか、どのバージョンが含まれているかをたまに確認したくなりますが、その時に使うのが Modure::CoreList です。Modure::CoreListにはコマンドラインツールも用意されているのですが、tokuhiormが Web Interface版を作っていてとても便利でした。が、こちらは今404になってしまっているので、tokuhiromに確認の上、新しくサイトを動かしました。

http://corelist.rpee.be/

画面はこんな感じ

corelistweb.png

あるバージョンのperlにどのモジュールのどのバージョンが含まれているのかと、モジュールがどのPerlに含まれているのかのリストがでます。

corelistweb2.png

もとのソースコードを参考にしつつ、Kossyとboostrap3で移植しました。移植するついでに、Proclet、Server::Starter、cpanmを使い、無停止でModule::CoreListが自動でアップデートされるようにしてみました。コードはこんな感じ

my $proclet = Proclet->new;

$proclet->service(
    every => '3 * * * *',
    tag => 'cron',
    code => sub {
        open(my $fh, "<", "server.pid") or die "$@";
        my $pid = <$fh>;
        chomp $pid;
        my ($result,$exit_code) = capture(['cpanm','-lCoreList-lib','Module::CoreList']);
        if ( $exit_code == 0 && $result =~ m!Successfully installed Module-CoreList! ) {
            warn "KILLHUP server-starter ($pid)\n";
            kill 'HUP', $pid;
        }
    }
);

$proclet->service(
    code => sub {
        exec(qw!start_server --port!,$port,qw!--pid-file server.pid  --!,
             qw!plackup -Mlib=CoreList-lib/lib/perl5 -E production!,
             qw!-s Starlet --max-workers 10 -a  app.psgi!);
    },
    tag => 'web',
);

$proclet->run;

ニッチですがご利用ください