ちょっと過去の話ですが、会社の技術ブログで書いてました。
障碍対応と私
この記事は、モバイルファクトリー Advent Calendar 2015 18日目の記事です
昨日は @yashims85さんのAndroid drawableは画像を入れておくだけじゃないでした。今日は障碍の話です。
普段障碍対応しているときにやってること考えてることをざっくりと時系列を追って書いていきたいと思います。 コンテキストとしてはLinuxサーバでwebサービスをやっていると思っていただければと思います。
障碍の検知
webサービスを運営していれば、何かしらの監視システムからSlackなりIRCなりメールなり電話なりでアラートの通知が来ると思います。
対応報告
障碍対応をしている旨をメールなり、何かの連絡手段で伝えます。同じく見ている人がいれば調査作業の分担もできます。
状況把握
どこで障碍?
アラートの通知内容にどのサーバで何が起きた的なことが書いてあるはずなので、それを確認します。 だいたいの組織に於いてはサーバ管理表的なものがwebなりExcelなり設定ファイルなりにあるはずなので、そこと照らし合わせてどのプロジェクトのどのロールなのかを把握します。
直前に何をした? いつもと違うことは何?
webアプリケーションであれば直前に入れた変更が原因かもしれません。また、ちょっと前に入れていた変更だが、cronで時限発火したというケースも考えられるかも知れません。 イベント開始で急にトラフィックが上がったと言うことも考えられるかも知れません。普段と変わったことは何かということが把握出来れば対処の幅が広がります。
影響範囲は?
サービス全体なのか、サービスの1機能の障碍なのか、ミドルウェア障碍なのか、影響がどの範囲に及んでいるのかを見ます。 ミドルウェア障碍であれば、最近であれば、冗長化されてるのが普通なので、サービスから切り離して、監視から外せば終わりというパターンも多いです。 サービス全体が落ちている場合は、ひとまず重要な関係者に状況の1次連絡すぐにした方が良いでしょう。
接続出来る?
そもそも、該当サーバに接続出来ない場合は、できることはほぼないので、該当サーバをサービスから外した上で、監視対象から外します。(単体のサーバ障碍の場合)
# pingは通る? ping ${IP} # sshできる? ssh ${IP}
ログの確認
該当サーバ上で動いているミドルウェアやアプリケーションサーバのエラーログを主に見ます。だいたいこの辺に重要な情報が出力されている可能性があります。
システムのログも確認した方が良いです。主にsyslogやkernelログを見ると良いでしょう。
# syslogを見る less /var/log/syslog # kernelログを見る less /var/log/kern.log # kernelログを見る2 dmesg
サーバ状態の確認
負荷の関係で障碍が起きているのであれば、現在のサーバの状態を確認しましょう。 以下のようなコマンドが現状把握に役立つでしょう。
# loadaverageおよびログイン中のユーザを見る w # 変なプロセス無いか見る ps -ef # or ps auxwwww # 開いているポートを確認する netstat -tlnp # ネットワークコネクションを確認する netstat -taopen # なにかCPU使いまくってないか見る top # 現在の負荷の経過を見る dstat -tamsl 5 # 過去の負荷情報を見る ## CPU sar ## memory sar -r ## la sar -q
対処
直前のコミットにバグを入れ込んでしまったのであればリバートすれば解決するでしょうし、特定のサーバ落ちたのであれば、サービスから外してあげるだけで良いかも知れません。 障碍の内容によって対処方法は様々です。ここで気を付けたいのは二次災害を起こさないことです。 可能であれば、コマンドなり対処スクリプトのレビューをしてもらったり、現状認識に間違いがないかを周りの人にしてもらうと良いでしょう。 (往々にして一人で障碍対応せざるを得ない場合もありますが。。)
事後報告
障碍対応が終わったら、記憶が新鮮なうちに下記の内容をまとめてしかるべき場所に投稿します。 この辺の報告のフォーマットはだいたいの組織において決まっていることが多いでしょう。
- 障碍内容
- 影響範囲
- 経過
- 対処方法
- 将来の対策
面倒くさがらずに事実をなるべく詳細に書いておくと未来の自分や自組織のためになると思います。 私の組織でも過去の障碍報告がだいぶ良い感じにデータベースになっており、たまに読み返すと気付きが得られます。
また、この障碍報告を元に、同種の障碍をなるべく起こさない仕組み作りをしていくことが肝要だと思います。
終わりに
自分が障碍対応しているときにやってること、考えてることをざっくり書いてきました。 誰にやり方を教わったわけでもないので、そこは違うとかこうした方がいいとかあれば、いただけると幸いです。
明日は、@lycoris102さんのGameJam部 活動年間活動報告です。きっと面白い話なのではないでしょうか。
#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 自体のプロセスを再起動しなくてはならないので不便です。
なので、起動スクリプトを作ってます。そのほかにも理由があるのですが、参照リンクに詳しくあります。
サーバ実装としては、StarletやGazelleを使ってます。
参照
デーモン管理
現在はUpstartでアプリケーションサーバのデーモン管理してます。 以下の理由で、個人的には好きでした(過去形)。最新のUbuntuはSystemdに変わってしまったので、将来的にはSystemdに移行することになるでしょう。
/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の他、以下のものがあるでしょう。 好みと要件に合わせて使えば良いと思います。
参照
- Server::Starterから学ぶhot deployの仕組み
- Server::Starter の --interval オプションは大切
- Upstart を使ってお手軽 daemon 化
- Upstart Intro, Cookbook and Best Practises
おわりに
WAF(Web Application Framework)やログの話など膨らまそうと思えばもっと膨らませられますが、実行環境の話なので、ここまでで抑えておきます。
ざっくりと、Plack/PSGIなアプリケーションの実行環境について説明してきました。 PerlでWebアプリケーションを作る時に何か参考になれば幸いです。 また、もっと良い方法があれば、教えていただけるとありがたいです。
明日は、@nekobato さんです webpackのなにか面白い話があるんじゃないかとわくどきしてます。
Github APIを使おう
この記事は、モバイルファクトリー Advent Calendar 2015 4日目の記事です
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回りの面白いエントリが見れそうです。