Auto ScalingではなくてAuto Cachingという考え方

今年の3月くらいからずっと悶々としていて、なかなか手が出せなかったアイデアがやっと実現できました。

(試行錯誤して書いてみたら、結果たった数行という。。。)

Auto ScalingではなくてAuto Cachingという考え方

AWSではAuto Scalingという、サーバの負荷の変化などによってEC2インスタンスをスケールする便利な機能があります。

が、大抵はクラウド環境でないと容易には実現できません。

例えば、クラウドではなく

  • サーバリソースは増やせない。
  • 普段はキャッシュはしてほしくないコンテンツ。
  • ただ、アクセスが多くなるとかで何かしら負荷が高くなった時には「仕方なく」キャッシュを使っても良い。落ちるよりはマシ。
  • 負荷が戻ったらキャッシュを使わないようにして欲しい。

という状況もあるかもしれません(そしてあります)。

「状況によってWebサーバがいい感じにキャッシュコントロールしてくれないかな」と考えていました。

Auto ScalingならぬAuto Cachingみたいな。

その時のメモがこちら

  • ngx_mruby( + http-dos-detector + mruby-changefinder)とかを駆使して、高負荷を検知したらキャッシュを利用するように変更するとか?
  • mod_mrubyとmod_cacheでもいけるのか?
  • というか、もともとそういう設定できないの?できるんでしょ?

(改めて検索してみたら、はるか以前に同じようなことを実現されていた方が。しかもkazuhoさんという。。)

Fukuoka.rb活動

いろいろ考えてはいたものの、別のOSS活動をしていました。

で、やっと先日のFukuoka.rbで重い腰を上げて試してみました。

なんとかmod_mrubyのインストールまでできたので、そのあとはずっとmod_cacheとmod_mrubyのドキュメントやエントリーを読んで、試行錯誤していました。

Auto Caching

こちらが成果です。

# -*- coding: utf-8 -*-
# LoadModule cache_module modules/mod_cache.so
# LoadModule cache_disk_module modules/mod_cache_disk.so
# LoadModule mruby_module modules/mod_mruby.so
#
# CacheRoot /var/www/cache
# CacheEnable disk /cache-control
# CacheIgnoreCacheControl Off
# CacheIgnoreNoLastMod On
# CacheIgnoreHeaders Set-Cookie
# CacheDefaultExpire 300
# CacheMaxExpire 600
#
# <Location /cache-control>
#   mrubyQuickHandlerFirst /path/to/autocache.rb
# </Location>

r = Apache::Request.new()

r.headers_in['Cache-Control'] = 'no-cache'

wc = Apache::Scoreboard.new()

if wc.loadavg.first > 1
  # cache
  r.headers_in['Cache-Control'] = 'public'
end

Apache.return(Apache::DECLINED)

mod_cache、mod_disk_cacheを併用して使います。

サーバのLoad Averageが1以上になったときにだけ、mod_cacheを利用してコンテンツをキャッシュします。そして、Load Averageが1以下に落ち着いたらキャッシュが解除されます。

若干強引ですが Cache-Control ヘッダをいじってmod_cacheを反応させることで実現しています。

今更ながら mod_mruby / ngx_mruby すごい

たった数行でこんなことができるとは。。。

if wc.loadavg.first > 1 の部分を頑張れば、より柔軟にキャッシュコントロールできそうです。

ギョームではLAMP環境を構築することが多いです。

mod_mrubyというプログラマにやさしいモジュールは、今後インフラを考えるときに選択肢を増やす強力な武器になりそうです。

やさしいツール

AWSもInfrastructure as codeもmod_mruby / ngx_mrubyもプログラマにやさしいです。

やさしさ重要だなーと思う日々です。

今後

Auto Cachingの実戦投入をしてみたい。

JAWS-UG福岡でawspecの中の話をしてきました #jawsug

JAWS-UG福岡:3度目の濃い目にAWSの話をしてみよう - JAWS-UG九州 | Doorkeeper にてawspecの中の話をしてきました。

speakerdeck.com

スライドからもわかるように、AWS成分よりもRuby成分多めになりました。話しているほうはとても楽しかったです。

イムリーに勉強会中にPull Requestがあったので、事前にレビューを済ませた上で、発表中にライブマージ&リリースをするなどしました。

Release v0.41.0 · k1LoW/awspec · GitHub

なんか仕込んでいた感がありましたが、そんなことはありませんよ。

awspecの開発は今どうしているのか?

awspecは基本的に自分が必要になったタイミングで(もしくは周りのメンバーが必要になったタイミングで)機能追加をしています。

リソースタイプについては個人的には困らないレベルにまでなってきたので、最近はもう少し上位のテストをしたいなあという希望があって、悶々としている感じです。

ほんと、待っています。。

JAWS-UG福岡の濃さ

今のJAWS-UG福岡は、完全に技術側に振り切っていて、外から見ていて楽しそうだと思ったし、実際に参加してみたらやっぱり楽しかったです。学ぶことも多かったです。

「最初から乾杯をする」というのも良いですね。昼ビールはヤバいです。呑みながらの発表もヤバいです。

あえて改善点を上げるとしたら、もっと発表内容について語れる時間があるとさらに良いかもと思いました(今回だけ違ったっぽい?)。もっとグダグダでも個人的には良いです。得るものは多かったので良かったです。

運営の皆様、ほろ酔い気分な時間をありがとうございました。

というわけで

awspecへのPull Request待っています!

github.com

CakePHPで開発しているけれどもMigrationsは捨ててRidgepoleを使っているはなし

タイトルは若干釣りです。

CakePHPにはマイグレーションツールとして、CakeDC/Migrations(CakePHP2)や、Phinxベースのcakephp/migrations(CakePHP3)があります。

とても有用ですし、CakePHP Bakerはみんな知っているツールです。自分もずっとお世話になっていました。

ただ、ちょいちょい困ることもあったので、最近はRidgepoleを使い始めています。

Ridgepole

github.com

Ridgepoleはクックパッド社で利用されているというマイグレーションツールです。

techlife.cookpad.com

Ridgepoleは最大の利点が、1つのSchemafileを管理するだけでスキーマのべき等性を担保してくれるということです。

RidgepoleはDSL自体がRailsActiveRecordと同じだということで、Railsだとさらに恩恵をうけられそうですが、この"べき等性"はCakePHPなプロジェクトでもかなりアツいです。

「1ファイルを管理すれば良い」という良さ

特に新規開発スタート時は、スキーマの変更頻度も高いです。

数人で開発するだけでもスキーマ変更のマイグレーションがコンフリクトし、作業をブロック。マイグレーションの順番を検討。チャットで「今からスキーマ触ります」と通知とかし始めて、最後は「もう一度マイグレーションファイルを消して1からやりなおそうか」ということに。。。

それが1つSchemafileをGit(などのバージョン管理システム)で管理するだけで良いというのは、かなりのメリットがあります。

データベース設計書的なファイルとMigrationsのファイル群の2種類を管理する必要がなくなったのも健全です(Schemafileのコメントでフィールドの論理名も管理可能ですし)。

今は深遠なる理由でデータベースコメントも管理したいので、あえて 0.6.3 を利用していますが、現在Rails5への対応を進めているらしい(さらに、Rails5のActiveRecordではデータベースコメントやカラムコメントも管理できるらしいのでもしかしたら。。)ので、楽しみです。

PHPな人も是非試してはいかがでしょうか?

ssh_config形式のファイルからVulsのconfig.tomlを生成するコマンドを作った

今、脆弱性検出ツールでかなりアツいVulsですが、対象のリモートホストへの接続のためにはTOML形式の設定ファイルが必要です。

なんかssh_configに似ているなーと思ったので、作ってみました。

github.com

Usage

まずはインストール。

$ gem install ssh_config_to_vuls_config

インストールすると sc2vc というコマンドが使えるようになるので、あとはSTDINにssh_config形式のファイルをかませるだけです。

$ cat ~/.ssh/config | sc2vc > vuls_config.toml

あれ?なんか koma に使い方が似ていますね。

というわけで

本家のREADMEにも載せてもらえました!嬉しい!

https://github.com/future-architect/vuls#related-projects

エージェントレスでプラットフォームのインベントリ情報を取得するツールkomaを作った

Ansibleにはsetup module、Chefにはohai、Puppetにはfacterというプラットフォームのインベントリ情報を取得するライブラリや機構があります。

ただ、リモートホストのインベントリ情報を取得したいときに、ohaiやfacterはリモートホスト側にインストールが必要だったり、setup moduleは単体で使いにくかったりするので、

「気軽にエージェントレスでプラットフォームのインベントリ情報を取得できるようにしたいなー」

ということでkomaというgemを作りました。

github.com

Installation

$ gem install koma

Usage

まず、公開鍵認証でSSH接続できるリモートホストを用意します。

例えば、

$ ssh k1low@example.com

でログインできるようなホストですね。

で、そのssh コマンドを koma ssh に変えて実行します。

$ koma ssh k1low@example.com

そうすると、インベントリ情報をJSON形式でSTDOUTに出力します。

さらに複数のホストのインベントリ情報を一気に取得したい場合はカンマ区切りで指定できます。

$ koma ssh example.com,k1low@example.jp
{
  "example.com": {
    ...
  },
  "example.jp": {
    ...
  }
}

取得できるインベントリ情報

取得できるインベントリ情報はkoma keysで確認できます(リモートホストディストリビューションによって取得できる情報にはばらつきがあります)。

$ koma keys
memory
ec2 (disabled)
hostname
domain
fqdn
platform
platform_version
filesystem
cpu
virtualization
kernel
block_device
package
user
group
service

インベントリ情報を指定したいときは --key オプションで指定可能です。

$ koma ssh k1low@example.com --key cpu,kernel

(disabled) になっている ec2 などは --enable-ec2 オプションで有効になります。

Pro Tip: ssh_config形式でリモートホストを指定する

komaはssh_config形式のSTDINを入力とすることができます。

$ cat <<EOF > ssh_config_tmp
Host example_com
  User k1low
  Hostname example.com
  PreferredAuthentications publickey
  IdentityFile /path/to/example_rsa

Host example_jp
  User someone
  Hostname example.jp
  PreferredAuthentications publickey
  IdentityFile /path/to/more/example_jp_rsa
EOF

$ cat ssh_config_tmp | koma ssh --key platform,platform_version

ssh_config形式がいけるということは、

$ vagrant ssh-config | koma ssh --key cpu,kernel

みたいに、Vagrantのサーバのインベントリ情報を取得したり、

$ sconb dump example_* | sconb restore | koma ssh --key platform,platform_version

みたいに、sconb~/.ssh/config をフィルタリングしてインベントリ情報を取得できたりします。

というわけで、エージェントレスが好きな皆様におかれましては是非ご利用ください。

以下余談

komaRuby製なのですが、awspecと同様にFukuoka.rbで作りました。

もともと「エージェントレスでohai」みたいなツールはずっと欲しかったのです。

ふとFukuoka.rbのSlackチャンネルでつぶやいたら、うずらさん が反応してくれてやる気になり、ひとりで作ろうとして途方に暮れていたら、やまださん が「Specinfraに Specinfra::HostInventory という求めている機能がある」というところを教えてもらって、一緒にSpecinfraを読んで、プロトタイプまで一気に作ることができました。

というわけでkomaは実はただの Specinfra::HostInventory の薄いラッパーです(一気に信頼度が上がった感。

とはいえ、 Specinfra::HostInventory を拡張しているところがあるので(user group package serviceのインベントリ情報。主にRedHat系しか作っていない)、最終的に拡張部分をSpecinfraに取り込んでもらうところまで頑張ろうと思っています(komaはそのためのユースケースでもある)。

Fukuoka.rb、最近仕事が忙しくて行けてないので、また消え去り認定されないようにまた参加したい。

PHPカンファレンス福岡2016に参加してきました | "ドキュメントを支える技術"

phpcon.fukuoka.jp

PHPカンファレンス福岡2016に運営メンバーとして参加しつつ、発表もしてきました。

あと、Fusicとしてゴールドスポンサーとして協賛させてもらいました!

ドキュメント=紙という話しをしました

ドキュメントというのは印刷が必要な時があって、すぐにOfficeを開くのもいいけれども、そのまえにプログラムで楽ができないか考えてみよう。そして、PHPは意外にも印刷へのアプローチに有効だよ。という話をしたかったのでした。

発表後、Excel系の話題( k1low/xlsxti.mefra.me )に感想が集中したのが予想外でした。皆さんも苦労しているんですね。。。

個人的には実は koma が1番の力作なので、また別エントリで紹介したいと思います。

運営の話し

ここらへんは他の人に譲ります。ちなみに運営も印刷係でした。紙づいています。

スポンサーの話し

いろいろ嬉しいこともあったのですが、会社としては「スポンサーして良かった」ということに決着していることをここに報告しておきます。

というわけで

皆さんお疲れ様でした!!!