目の前に僕らの道がある

勉強会とか、技術的にはまったことのメモ

#chibapm Chiba.pm#7に参加しました。

参加しました。雑なスライドですみません。

スライド中に出てきてるやつはどれも五反田のお店で出てきます。 五反田企業のガイアックスさんとかモバイルファクトリーさんはPerlの会社なので、美味しいごはんを食べたい人は検討してみてはいかがでしょうか。

そういえば、Chiba.pmの開催回数がKichijoji.pm、Gotanda.pmに抜かされそうです。。

Plack/PSGIなwebアプリケーションの実行環境

この記事は、モバイルファクトリー Advent Calendar 2015 11日目の記事です

※ 投稿内容は私個人の意見であり、所属企業・部門見解ならびに技術戦略を代表するものではありません。

昨日は@rymizukiさんのnpmライブラリの運用と管理についてでした。今日はPerlの話です。

お仕事やプライベートでPerlのwebアプリケーションを書くことが多く、いろいろ知見が溜まってきてるので、ここで少し紹介しようと思います。 今回はPlack/PSGIなwebアプリケーションの実行環境の話です。mod_perlなアプリケーションとはちょっとコンテキストが違います。 少しかっちりコンテキストに近いです。個人で軽くwebアプリケーション立てるならもう少しゆるふわでも問題ないはずです。

OS

UbuntuのLTSを使うことが多いです。Ubuntu前提の内容が後に続きます。

Perl

System Perlは使ってません。OS/ディストリビューションが変わってもなるべくそのまま動くようにしたいためです。 perl-buildで独自ビルドしたPerlを使います。インストール場所としては、 /usr/local/perl/perl-5.${VERSION} に置きます。 Perlを独自ビルドしたものをDebian package化して実行環境にはインストールします。

他の方法としては、ビルド済みのperlをtarで固めて、配布するというのもあります。 どちらでも構わないのですが、ローカルネットワークにaptサーバ立てている関係で、Debian packageの方が運用しやすいのです。 また、perlのマイナーバージョンアップの際もDebian packageを作り直した上で、 apt-get upgrade (or aptitude safe-upgrade)で完結するので、aptの操作に慣れていて楽というのもあります。

モジュール管理

今風にcpanfileでモジュール管理してます。モジュールインストールはCartonを使ってます。

Cartonの後継でCarmelも開発されてます。個人的にはそろそろ触っておきたいところです。

また、cpanfile.snapshotもレポジトリに入れています。 一般的なモジュールは特定の(古い)バージョンに依存せずに動くべきですが、 依存モジュールのバージョン違いによって現在動いているアプリケーションが壊れるのを防ぐために、バージョン固定します。 cpanfile.snapshotがある状態で下記のように carton install してあげると、どの環境でも同じバージョンの モジュールがインストールされます。

carton install --deployment --without develop,test

今やってないですが、別方法としては、モジュールがインストール済みの状態で、 carton bundle すると vendar/ にモジュールのtarが固められるので、それもレポジトリ管理した上で、下記の様にインストールするという手もあります。インストールの際は vendor/bin/carton にfatpackされたcartonコマンドが入るのでそれを使います。 (アプリ実行環境にcartonを敢えて入れる必要は無い)

# 依存モジュールを固める
carton bundle

# インストール
# env.shは後述
./script/env.sh vendor/bin/carton install --cached --deployment --without develop,test

さらに別方法としては、ビルドサーバで依存モジュールをビルドした上で、ディレクトリごと実行環境にrsyncしてあげる方法です。 ビルドサーバを運用しているならば、この方法でも良いでしょう。

参照

独自モジュール

なるべく、独自モジュールは使わない方が良いのですが、個人的な事情などで、CPANに公開出来ないモジュールに関しては、OrePAN2 でDarkpanを作ってそこからローカルに配信するようにしてます。 OrePAN2のサーバを簡単に立ち上げられるOrePAN2::Serverがありますが、一時期は使っていましたが、モジュールのアップロード機能は別にいらないなどの理由で今はwebサーバから静的配信してます。

環境変数

プロジェクトのレポジトリconfig/env.rc という名前で、アプリケーションを動かすために必要な環境変数を定義したファイルを作ります。

PERL5_VERSION="22"
export PROJECT_BASE="/path/to/project"
export PERL_CARTON_MIRROR="http://orepan.local/"
export PERL5LIB="${PROJECT_BASE}/local/lib/perl5:${PROJECT_BASE}/lib"
export PATH="${PROJECT_BASE}/local/bin:/usr/local/perl/perl-5.${PERL5_VERSION}/bin:${PATH}"
export PLACK_PORT=5555

また、 script/env.sh という名前で config/env.rc を読み込んだ上で、プログラムを実行するラッパースクリプトを作ります。 スクリプトなどは基本的にこれを通して実行します。

#!/bin/bash -ue
# 諸々環境変数を設定した上でコマンドを実行する君
#
#       env.sh perl hogehoge.pl
#
source /path/to/project/config/env.rc
exec "$@"

開発環境で、いちいちラッパースクリプト通すのが面倒な場合は、config/env.rc のsymlinkをプロジェクトルートに .envrc として張った上で、direnv使って済ましてしまう場合もあります。

web サーバ起動スクリプト

psgiファイルを plackup するのではなく、こんな感じのスクリプトscript/web みたいな名前で 用意してアプリケーションサーバを起動するようにしてます。

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

use lib "$ENV{PROJECT_BASE}/lib";
use Plack::Loader;
use SomeApplication::Config;
use SomeApplication::Web::Handler;

my $config = SomeApplication::Config->load();
my $app    = SomeApplication::Web->to_app();

Plack::Loader->load(
    $config->{psgi}->{server},
    %{ $config->{psgi}->{config} },
)->run($app);

また、このスクリプトstart_serverを経由して起動することで、(graceful restartによる)ホットデプロイをできるようにしてます。 start_server のプロセスにSIGHUPを送ると子プロセスのアプリケーションサーバを再起動してくれるのですが、 plackup コマンドで起動してると start_server に渡した引数をそのまま使ってplackup を再起動するので、 max_workers の数を変えたいときなど、 start_server 自体のプロセスを再起動しなくてはならないので不便です。 なので、起動スクリプトを作ってます。そのほかにも理由があるのですが、参照リンクに詳しくあります。

サーバ実装としては、StarletGazelleを使ってます。

参照

デーモン管理

現在はUpstartアプリケーションサーバのデーモン管理してます。 以下の理由で、個人的には好きでした(過去形)。最新のUbuntuはSystemdに変わってしまったので、将来的にはSystemdに移行することになるでしょう。

  • Ubuntuに標準で入っていて
  • サーバ起動時の自動起動してくれて
  • デーモン異常終了時に自動再起動してくれて
  • 設定はわりかしわかりやすい

/etc/init/web-some-application.conf みたいな名前でこんな設定ファイルを作ります

description 'some web application'
author 'masasuzu <hogehoge@masasuzu.net>'
start on runlevel [2345]
stop on starting rc RUNLEVEL=[016]

setuid webapp
setgid webapp

# 異常時に再起動する
respawn

script
    . /path/to/project/config/env.rc
    export PLACK_ENV="production"

    exec ${PROJECT_BASE}/local/bin/start_server \
        --interval 10           \
        --port ${PLACK_PORT}    \
        -- ${PROJECT_BASE}/script/service/web
end script

上記のファイルを作ると以下のように操作出来ます。reloadでSIGHUPが送れるので、アプリケーションサーバのstart_server経由のgraceful restartができます。

# 起動
service web-some-application start

# 停止
service web-some-application stop

# (start_serverのプロセスごと)再起動
service web-some-application restart

# Plackサーバを再起動
service web-some-application reload

アプリケーションサーバ以外も、ジョブのワーカーなども、独自に設定ファイルを作って、Upstart経由で起動したりしてます。

Upstart以外の選択肢としては、先に挙げたSystemdの他、以下のものがあるでしょう。 好みと要件に合わせて使えば良いと思います。

参照

おわりに

WAF(Web Application Framework)やログの話など膨らまそうと思えばもっと膨らませられますが、実行環境の話なので、ここまでで抑えておきます。

ざっくりと、Plack/PSGIなアプリケーションの実行環境について説明してきました。 PerlでWebアプリケーションを作る時に何か参考になれば幸いです。 また、もっと良い方法があれば、教えていただけるとありがたいです。

明日は、@nekobato さんです webpackのなにか面白い話があるんじゃないかとわくどきしてます。

Github APIを使おう

この記事は、モバイルファクトリー Advent Calendar 2015 4日目の記事です

今日は、Github APIの話です。

Githubの管理作業は他のWebサービスと同じく基本Webコンソールでできます。 ただ、Organizationとかを管理してる場合、ある程度以上規模が大きくなると、 定型的な管理作業が増えて、Webでぽちぽちやるには煩雑でつらくなってきます。

ここで怠惰エンジニア*1はどうにかこの定型作業を自動化/スクリプト化できないかなと考え始めます。 幸い、GithubにはAPIがあるので、これを利用して要件に合わせて、実装することができます。

ドキュメントは以下の場所にあるので、各APIの使い方などはそちらを参照してください。

apiアクセスを投げる

publicな情報を取得するには普通にcurlでGET発行するだけで、取得出来ます。

curl https://api.github.com/users/masasuzu/repos

が、これだけでは、privateな情報にアクセスできません。ので、Basic認証をしてアクセスをします。

curl -u ${USER}:${PASSWORD} https://api.github.com/orgs/some_privete/repos

ただ、この場合、このアカウントで出来ることが全て実行出来てしまうので、 下記のリンクからアクセストークンを発行して、権限を絞ってAPIにアクセスするのが望ましいです。 アクセストークンは作成時にしか見れないので、ちゃんと書き留めておくようにしましょう。

アクセストークンを使用した場合、下記の3つの方法で認証出来ます。

curl -u :${ACCESS_TOKEN} https://api.github.com/orgs/some_privete/repos
curl -H 'Authorization: token ${ACCESS_TOKEN}' https://api.github.com/orgs/some_privete/repos
curl 'https://api.github.com/orgs/some_private/repos?access_token=${ACCESS_TOKEN}'

ドキュメントに各API発行に必要なscope(権限)が書いてあるので必要なscopeだけ付与してあげると良いです。

perlでの選択肢

今までで、APIアクセスする手段を得ることはできましたが、シェルスクリプトで処理を組み立てるのは、 無謀なので、使い慣れてるプログラミング言語で実装したいところです。 当社ではPerlを使い慣れてるエンジニアが多いので、ここではPerlのクライアントを紹介します。 現在のところ以下の2つの選択肢があります。

私はPithubを使っています。使い始めた時期においてPithubの方が更新されてそうだったからです。 が、今見るとNet::Githubも更新されてるように見えます。

他の言語での選択肢

特にプログラミング言語にこだわりが無いのであれば、githubがメンテナンスしてるoctokitを使うと良いと思います。 RubyとObjective C、.Netに対応してます。たぶん鉄板だと思います。

(しかし、octokitのこのサンライズというかバンダイに怒られそうなデザインは大丈夫なのでしょうか?

まとめ

  • 煩雑で定型的な作業はGithub APIで自動化すると良い
  • Privateな情報の操作はアクセストークンを発行してAPIを発行する
  • PerlにはPithubとNet::Githubのクライアントライブラリがある
  • こだわりがなければ、クライアントはoctokit使うと良い

明日は、 @mihyaeru21 さんです。iOS回りの面白いエントリが見れそうです。

*1:プログラマの3大美徳の1つ

#gotandapm Gotanda.pm Perl Technology Conference #6 でLTしてきました。

gotanda-pm.connpass.com

Gotanda.pmでLTしてきました。

今回のテーマは障碍でした。

半分ネタのトークです。

JSTQB Foundation Level のシラバスに載っているソフトウェアテストの7原則をもじったやつです。

JSTQB認定テスト技術者資格-シラバス(学習事項)・用語集-

言ってみれば、サービスに対して継続的にテストするのが監視なのでテストに対する原則が監視に対しても言えるんじゃないかなーという軽い思いつきから生まれました。 無理矢理な部分もありましたが、わりかし当てはまってる部分もあったのではないかと思いました。

トーク中美味しいにおいがしてきてつらかったです。(このエントリは懇親会の前に書かれてます)

ガイアックスさん会場提供ありがとうございました。

#yapcasia YAPC::Asia 2015でボランティアスタッフしてきた

今年のYAPC::Asiaは終わった。つつがなく終わりました。

f:id:masasuz:20150822175350j:plain

過去のエントリを見直すと2011、2012年は書くのサボっていたみたいでした。 私のYAPC::Asia初参加は2010年で6回目の参加でした。

masasuzu.hatenablog.jp masasuzu.hatenablog.jp masasuzu.hatenablog.jp

今年のYAPCとの関わり方は個人スポンサー+ボランティアスタッフとして参加しました。 個人スポンサーとしては4年目、ボランティアスタッフとしては3年目でした。

今年のYAPCもすごい楽しかったです。 特にここ1,2年でPerl関係の人たちの知り合いがすごい増えたので、いろんな人と話ができてすごい楽しかったです。 トークの方は例年スタッフ業をやっていると聞けないので、(会場にいてもスタッフのお仕事に意識が行くので内容を聞き取れてないことが多い)、動画が上がったら気になっていたトークを追いたいと思います。

さて、だいたい6年前からWebで、Perlでお仕事するようになってからYAPCにはいろいろなものをもらってきました。 だからこそ、ボランティアスタッフをやったり、個人スポンサーになって自分がもらったものを間接的に他の人に与えられたらいいなと思ってやってきました。 自分がもらったものを他の人も受け取ってもらえたらなら良いなと思います。

YAPC::Asiaはいったん終わります。それ自体いろいろ思うところがありますし、残念ではあります。 YAPC::Asiaが無くなっても地域PMなどのPerlのコミュニティ自体が無くなるわけではないので私も細々とコミュニティ活動していきます。 ただ、全国的にPerlな人が集まってくるイベントが今のところ来年無いのは寂しいところです。 もしどこかで動きがあるならお手伝いさせていただければなと思います。

YAPC::Asiaお疲れ様でした。

(初日の懇親会の後の二次会でいろんな人に迷惑かけてしまったようなのでものすごく反省しています。すみません。お酒気を付けます。。。

会期中のつぶやきいくつか