awspecのアカウント系のAPIに悩んでいる

追記 (2017/3/10 無事解決。マージしました)

github.com

awspecでアカウントに紐づくような情報のテストが書けるように「いつかやろう」と思っていたら、とうとうそれ系のPull Requestが来てしまったので いよいよ解決しなければならない感じになっています。

後押しされた感じですね。

何が課題なのか

awspecは、AWSのサービスやリソースをIDやNameタグで一意に特定して、それに対してテストケースを書くようなAPIになっています。

例えば、EC2の場合

describe ec2('i-ec12345a') do
  it { should be_running }
end

のようにインスタンスのIDを渡すことでインスタンスを一意に特定して、そのEC2リソースについてのテストを書きます。一意に特定できなかったらエラーになります。

ところが、「VPCの最大数」や「EIPの最大数」などの上限値のチェックや、最近できたAWS Organizationsのチェックなど、awspecを実行したアカウントに紐づくような情報のテストをするようなAPIは提供されていません。

具体的にaws-sdk-rubyでいうと

  • Aws::EC2::Client#describe_account_attributes
  • Aws::RDS::Client#describe_account_attributes
  • Aws::SES::Client#get_send_quota
  • Aws::Organizations::Client#describe_organization
  • Aws::Organizations::Client#list_accounts

などで取得できるような情報のテストです。

違いとしては、これらは特に一意に特定するようなIDやNameタグがもともと必要ないのです。

微妙な違いですが、そもそも他のリソースタイプと同列に扱って良いのかそうでないのか、決め手がありません。

実装のアイデア

今のところ思いついているアイデアは2つです。

追記: アイデア3をいただきました

イデア1

テストしたい情報を別々のリソースタイプとして定義する

describe ec2_attributes do
  its(:max_elastic_ips) { should eq 5 }
  its(:max_instances) { should eq 20 }
end

describe ses_send_quota do
  its(:max_24_hour_send) { should eq 200.0 }
  its(:max_send_rate) { should eq 1.0 }
  its(:sent_last_24_hours) { should eq 1.0 }
end

describe organization do
  its(:id) { should eq 'o-exampleorgid' }  
  its(:arn) { should eq 'arn:aws:organizations::111111111111:organization/o-exampleorgid' }  
  it { should have_account('222222222222') }
end

イデア2

アカウントとAWS Organizationsの2つにわけて、リソースタイプを定義する

describe account do # or account_attributes
  its('ec2.max_elastic_ips') { should eq 5 }
  its('ec2.max_instances') { should eq 20 }
  its('ses_send_quota.max_24_hour_send') { should eq 200.0 }
  its('ses_send_quota.max_send_rate') { should eq 1.0 }
  its('ses_send_quota.sent_last_24_hours') { should eq 1.0 }
end

describe organization do
  its(:id) { should eq 'o-exampleorgid' }  
  its(:arn) { should eq 'arn:aws:organizations::111111111111:organization/o-exampleorgid' }  
  it { should have_account('222222222222') }
end

イデア3 ( from @inokara )

account_attributeに引数を与えることでネストを防ぐ(おそらくアイデア2と共存可能)

describe account_attribute('ses_send_quota') do
  its(:max_24_hour_send) { should eq 200.0 }
  its(:max_send_rate) { should eq 1.0 }
  its(:sent_last_24_hours) { should eq 1.0 }
end

今のところアイデア2のほうが使う側としては直感的かなーとは思っているのですが、決め手がなく悩んでいるところ。

うーん。

家庭内Slackと家庭内Backlogを連携させたかったので、backslackを作った

もう様々なところでやり尽くした感のあるツールです。

f:id:k1LoW:20170301193718p:plain

github.com

なぜ作ったのか

実は、F社には既に同様のサービスが稼働していて、便利に使わせてもらっています。

ただ、今回連携したかったのが 家庭内 のものだったので、そのまま流用するわけにはいかないかなーと思ったのと、Qiitaのエントリ はあるけどソースが公開されていなかったので、作りました。

使い方

使い方は README にあるとおりなのですが、

  1. backslackをデプロイ (エンドポイントのURLを取得)
  2. SlackのIncoming webhook URLを取得

これだけで初期構築は完了で、あとはBacklogにWebhookを追加するだけでOKです。

https://x0x1x2x3x.execute-api.ap-northeast-1.amazonaws.com/v0/hook?space=myspace&webhook_url=https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX&channel=general

ポイントは、必要な設定をURLのクエリパラメータに入れてしまうことで、あとはbackslackを放置できるところ。

faultlineと同じように POST with config の考え方です。

Backlogのスペースをまたいでも、プロジェクトをまたいでも、Slackチームをまたいでもいくらでも連携できますし、設定いらずなので便利。

というわけで

もし、まだBacklogとSlackを連携していないご家庭がありましたら是非ご利用下さい。

"キーレスエントリ"なスキーマに、テンポラリな外部キーを設定するツール tmpfk を作った

細かすぎて伝わらないツールだ。。。

f:id:k1LoW:20170227204834p:plain

キーレスエントリなスキーマ

SQLアンチパターン に「外部キー嫌い(キーレスエントリ)」というのがあります。

外部キー制約(FOREIGN KEY)の設定をしないデータベース設計です。

(最近の)Ruby on Railsはどうなのかわかりませんが、

例えばCakePHPだと、テーブル名やフィールド名が(Railsと同じ)命名規則に沿っていると外部キーを自動で判定し、bakeしたタイミングで \Cake\ORM\RulesChecker#existsIn() という外部キー制約をサポートするようなコードが生成されます。

そして、そのままキーレスエントリなスキーマで開発が進むことがよくあります。

(ほかにも理由があったりもしますが)

(本エントリでは、キーレスエントリ自身については言及しません)

それでもER図を生成したい

ところで、

Rails/Cakeなエンジニアは、外部キー制約を設定していなくても、命名規則に沿っていればテーブル名やフィールド名を見て外部キーかどうかを判断できます。

しかし、ER図をスキーマからリバースエンジニアリングして生成くれるような世の中の便利ツール がそれらを判定してくれることは少ないです。

rails-erd などでER図を生成できたりはしますが、残念ながら自分の主戦場はRailsではなくCakePHPなのです。( model_info は懐かしい思い出 )

便利なER図生成ツールは使いたい。でも外部キー制約は今ない。

というわけで、

じゃあ、テンポラリに外部キー制約をはっちゃえばいいじゃん。そしてその後外せばいい

というかなり強引なアプローチのためのツールを作りました。

tmpfk

github.com

RailsCakePHP命名規則に沿って外部キーを付けたり外したりするツールです。

必要なもの

インストール

$ gem install tmpfk

使い方

使い方は簡単です。

対象データベースに外部キーを一気につけるコマンド add

$ tmpfk add -c config.yml 

対象データベースからtmpfkでつけた外部キーのみを一気に外すコマンド drop

$ tmpfk drop -c config.yml 

だけです。

簡単だからといって、運用を開始しているデータベースに直接 tmpfk add するのはヤメましょう。 (別途スキーマのみのデータベースを用意するなどしましょう)

ただ、

もし、

「これからも外部キー制約をつけたまま生きていくんだ!」と思ったら --prefix オプションがありますので、ある程度本気度のある外部キー制約名をつけましょう。

$ tmpfk add -c production_config.yml --prefix ore-ha-honki-da_

というわけで

ER図の自動生成をあきらめたキーレスエントリな皆さん。

使ってみて下さい。

$ tmpfk drop -c production_config.yml --prefix ore-ha-honki-da_

やっとDocker for Macで開発用データベースの運用をはじめた

「Docker通り越して次の楽技術こないかなー」と思っていたのですが、やはり当分こなそうなので重い腰を上げてDockerを使いはじめました。

遅すぎですね。

前提

自分は「主にPHPer」ですが、PHPなプロジェクトは大抵がごく普通のLAMPやLAPPなので(環境依存が少ない)、開発時はVagrantでもDockerでもなんでも良いです。

ただ、個人的にPHPはビルトインサーバブームがきているので、「アプリケーション側はホスト上のビルトインサーバ」「データベース側をDocker」にする形で構築することにしました。

「Dockerは永続的データが不得意?」というのは遥か昔の話だったようで、MySQLPostgreSQLもデータ領域は(公式Dockerイメージでは)デフォルトでホスト側にマウント( VOLUME )するようになっていました。これは便利だった。

使い方

Docker for Mac上で、MySQLの公式Dockerイメージを docker pull して docker run するだけ。

$ docker pull mysql:5.6
$ docker run --name mysql56 -e MYSQL_ROOT_PASSWORD=XxxxxXxXx -d -p 13306:3306 mysql:5.6

PostgreSQLも同じような感じで。

$ docker pull postgres:9.6
$ docker run --name postgres96 -e POSTGRES_PASSWORD=XxxxxXxXx -e POSTGRES_INITDB_ARGS="--no-locale --encoding=UTF8" -d -p 15432:5432 postgres:9.6

Data Volumeの再マウント

間違って docker rm をしたときに大変なことにならないようにホスト側に残ったData Volumeの再マウントのテストもしておきます。

まずは、コンテナのマウントの状況を確認

$ docker inspect mysql56 | jq '.[0].Mounts'
[
  {
    "Type": "volume",
    "Name": "f9e1649566faf22d123456789094c12e4af3e04494807f060a2ff561d0f2e",
    "Source": "/var/lib/docker/volumes/"f9e1649566faf22d123456789094c12e4af3e04494807f060a2ff561d0f2e/_data",
    "Destination": "/var/lib/mysql",
    "Driver": "local",
    "Mode": "z",
    "RW": true,
    "Propagation": ""
  }
]

docker volume ls でも同じData Volumeがあることも確認

$ docker volume ls
DRIVER              VOLUME NAME
local               e7248a4a516b4071c286afbfd78deabcdefghijklmn012342881a3c017b1f
local               f9e1649566faf22d123456789094c12e4af3e04494807f060a2ff561d0f2e

MySQLに接続してCREATE DATABASE などしたあとにおもむろに docker rm

$ docker rm mysql56

それでもData Volumeは残っているのを確認

$ docker volume ls
DRIVER              VOLUME NAME
local               e7248a4a516b4071c286afbfd78deabcdefghijklmn012342881a3c017b1f
local               f9e1649566faf22d123456789094c12e4af3e04494807f060a2ff561d0f2e

Data Volumeを指定して docker run

$ docker run --name mysql56-re -v f9e1649566faf22d123456789094c12e4af3e04494807f060a2ff561d0f2e:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=XxxxxXxXx -d -p 33306:3306 mysql:5.6

MySQLに接続して、作成したデータベースが残っていることを確認。

感想

簡単でした。

この程度のライトな使い方だとVagrantでデータベースサーバたてるのとあまり変わらないですが、すぐ手が届くところでDockerを使い続けることで、そのうち興味や理解も深まるはず。

慣れって重要だと思います。

2016年の振り返りと2017年の抱負

明けました。

2016年の振り返り

2016年の後半から、Fusicではテックリードという職位ができました(というか、作りました)。

そして、そのテックリードとして活動できた半期でした。

(プライベートでもいろいろあったのですが割愛。)

(ちなみにテックリードに立候補するために、半期の成果をまとめてPullRequestするのですが、そのおかげで半期ごとの成果をあとで拾いやすくて良いです。)

OSS活動

CakePHP3 PluginからCLIツールまでいろいろ作りました。

(新しく作ったものだけで、メンテナンスしているモノは含んでいません)

2016年の前半は koma 、後半は faultline の開発に夢中だったと思います。

どちらもFusicの業態に沿ったニッチなニーズで、世の中になかったことから作ろうと思ったものだったので、作っているときはとてもワクワクしました。

特にfaultlineのインパクトは今現在個人的にかなり大きく、開発サイクルにおいてとても良い効果を出しています。見える化は大事ですね。

発表/受賞 etc

2016年は今までに増してアウトプットしていた気がします。

これ以上増やすためには、インプットを意識して増やす必要がありそうです。

「そもそも増やす必要があるのか?」という疑問もありますが、世の中にはより高い質でより多くアウトプットしている人がたくさんいるので、まあ良いのではないかと思っています。

2017年の抱負

中学生時代のプログラムのソースコードがでてきました。

中学生時代のプログラムのソースコードが出てきた #n88basic

やっぱりプログラムが好きなんだと実感します。

2017年の目標は「チャレンジ」。

既にアラフォーですが、改めて、現状のままを良しとせず、エンジニアとしてより成長をしたいと強く感じています。

そのためには何かしらリスクを取っていく必要がありそうなので「チャレンジ」としました。(まあ、できればチートでジャンプアップしたいところですが)

Fusicでもミッションシートという制度がはじまったのですが、それに釣られてか、こうやって数年ぶりに目標を立てたので、しっかりと意識して結果をだしていきたいと思います。(具体的な数値目標についてはもう少し考えます)

楽しんでチャレンジしようと思います。


以下は、目標とは別で、2017年の早めにやりたいと思っていることです。

開発環境の見直し

新年といえばコレです。

そろそろコンテナを使っていこうと思います(さすがに作りはしない)。

昨年は「時代がDocker飛び越えてサーバーレスとかにならないかなー」とか思ったのですが、まだ無理そうなので遅れないうちに触っておきます。

あと、衰えたEmacs Listp脳をちょっとだけ活性化したい。もう少しEmacsでいたいです。

サーバーレスアーキテクチャ

とはいえ、今最も興味があるサーバーレスアーキテクチャについては、今後の開発における1つの武器(選択肢)としてキャッチアップしていこうと思っています。

  • JWT
  • Amazon Cognito Your User Pools
  • AWS Step Functions
  • GCP
  • SendGrid

特に、fautlineみたいな「Low PriceでManagelessなアプリケーション」のアイデアは社内でも導入もしやすいので、もっと出して業務効率や品質を上げていきたいです。

あと、個人的にAWSにベンダーロックインされていることについてはあまり気にしていないのですが、いろいろなタイミングでGCPの良さを聞くので、GCPは触っていきたいです。

これに関連して、Goもチョットダケデキルくらいにはなりたいなあ。

継続して勉強をする習慣をつける

これが、一番、難しそうです。。。

仕事とお酒に時間を取られている気がするので、うまく時間とやる気を捻出していきたいところですがなかなか難しそうだなあ。。。

というわけで

今年もどうぞよろしくお願いします。

何か良いアドバイスあれば、ブコメやメンション等で、是非よろしくお願いします。

サーバーレスアーキテクチャなエラートラッキングツール faultline

本エントリーは Serverless Advent Calendar 2016 - QiitaFusic Advent Calendar 2016 - Qiita の7日目の記事です。

今日は AWS re:Invent 2016 Serverless Follow Up がありますね。うらやましい。

サーバーレスアーキテクチャなエラートラッキングツール faultline を作っています。

logo

これは何

AWSのマネージドサービスのみで構築しているサーバーレスアーキテクチャなエラートラッキングツールです。

近いツールとしては、RollbarAirbrakeBugsnagerrbit などがあります。

エラートラッキングのためのAPIバックエンドを提供する faultline と、そのAPIを利用するWeb UIのサンプル実装の faultline-webui があります。

github.com

github.com

Web UI

機能

エラー管理をする上で、最低限の機能を実装しています。

  • エラートラッキング
    • 総数
    • 時間単位総数
    • エラー概要
    • 解決済かどうかのステータス
  • 通知
    • Slackのチャンネルへ通知
    • GitHub Issueへ登録
  • 通知間隔の設定
    • 最初は通知
    • 時間単位総数上限を超えた場合に再通知
    • n回ごとに再通知

なぜ作ったのか

アプリケーションエラーの管理が大変問題

作ったアプリケーションでエラーやExceptionなどがあった場合、 https://github.com/fusic/encounthttps://github.com/k1LoW/Exception を使ってメール通知をしています。

そして、「全てのエラーのメール通知が飛んできてツラい」とか、「どのエラーの解決が終わっているのかの管理ができなくてツラい」とか、よくある問題に遭遇しています(今)。

というわけでなんとかしたいと思っていました。

有償サービスのエラートラッキングツール

多くの有償サービスがあるのですぐにでも使いたいと思っているのですが、いざ会社で導入するとなったとき以下の点でちょっと躊躇しています。

  • どれくらいの費用対効果があるか検証できていない
  • 会社の業務の特性上、1年間だけをみても無数のプロジェクトが立ち上がり、さらにそこから運用フェーズになってアプリケーションとしては残るので、プロジェクト単位の課金だとツラい

正直、健全な方向としては有償サービスを使うべきだとは思っています。(採用するとしたらプロジェクト課金やユーザ課金でない Rollbar かも)

オープンソースのエラートラッキングツール

オープンソースで公開されているerrbitやSentry(OSS)も考えましたが、「サーバーの管理」という別の大きなコストがかかるので、勇気をもって選択できそうになかったです。

サーバーレスアーキテクチャのエラートラッキングツール

欲しい機能としては、

  • 同じエラーをある程度まとめて通知する機能(Slack通知だけでもいい)
  • エラーごとの概要を後から確認できる機能(簡単な時系列のグラフ表示とか)

だけがあればいいかなと思っていて、これにさらに「(ほぼ)管理レス」という無茶要件があったのですが、「もしかしてサーバーレスアーキテクチャで作れるのでは?」と思って試行錯誤してたらできました。

最近v1になったServerless Frameworkを採用することで、AWS Lambdaを中心にS3やDynamoDBも含めて管理できて、少ないコマンドでデプロイできる形に収めることができました。

まずは、サーバーレスなfaultlineの導入をすすめて、もしこれ以上の機能が必要になったら(それは、おそらく効果がでたのだから)、faultlineの拡張をするか、有償サービスを提案しようと思っています。

使い方

faultlineの使い方です。

faultline のデプロイ

まずエラートラッキングをするAPIバックエンドを構築するために falutline をデプロイします。

$ git clone https://github.com/k1LoW/faultline.git
$ cd faultline
$ npm install
$ (Edit ./config.yml)
$ AWS_PROFILE=XXxxXXX npm run deploy

config.yml は config.default.yml をコピーして修正してください。基本的に、S3のバケット名とAPI Keyを設定すればOKです。

npm run deploy まで実行できたらAPIバックエンドのデプロイは完了です。

デプロイ完了時に、StackOutputs に ServiceEndpoint が出力されるのでコピーしておきます。

テストエラー登録

サンプルエラーをcURLで登録してみます。

エラーの登録先URLは POST /projects/{project}/errors になります。ペイロードのサンプルとして sample-errors.json があるのでそれを利用します。

$ curl -X POST -H "x-api-key: [ここにconfig.ymlのclientApiKeyかapiKeyが入ります]" -H "Content-Type: application/json" -d @sample-errors.json [ここにServiceEndpointが入ります]/projects/sample-project/errors

faultline-webui の立ち上げ

次に、Web UIを立ち上げます。Macならローカルで open コマンドで確認可能です。

$ git clone https://github.com/k1LoW/faultline-webui.git
$ cd faultline-webui
$ (Edit ./config.js)
$ open index.html

config.jsはconfig.example.jsをコピーして修正してください。endpoint に faultline の ServiceEndpoint を、apiKey に faultlineのAPI Keyを記載するだけです。

これでWeb UI上でsample-project というプロジェクトにいくつかエラーが登録されていると思います。

通知

faultlineはエラーを保持するだけではなく、通知機能もあります。

Slack 通知

POSTするデータの notifications に Slackの設定を入れて、エラー登録をすればSlack通知ができます。

slack

GitHub Issue 登録

GitHubのIssue登録もUser Token認証限定ですが可能です。

github

費用

ミニマムで$0.1/monthくらいで運用できると思います。AWSの無料枠が残っていたら無料になるくらいのリソース消費量です。

ただ、トラッキングするエラーの流量によってはDynamoDBのキャパシティユニットを増やさないといけないし、保存されているデータも線形で増えていくのでその限りではありません。

Unlimited ProjectsだしUnlimited Users(そもそもUserという概念はない)なので、気にするべきはエラーの流量だけです。

費用がかかってきたら、有償サービスへの移行を検討すると良いと思います。


以下、いろいろと。

faultlineのコンセプト

faultlineを作るにあたって、作っていきたいものを分かりやすくするために、いくつかコンセプトをかかげています。

Simple deploy

構築までに面倒な作業ができるだけないようにしようとしています。

今のところデプロイまでのコマンドは、AWSのクレデンシャルが設定されていれば、config.ymlの作成を含めて5コマンドです。

できれば、これ以上は増やしたくないと思っています。

Manageless

エラー管理を楽にしようとして、結果サーバー管理をするのは本末転倒なので、ここは是非「サーバー管理レス」でいけるようにしたいです。

そのために、サーバーレスアーキテクチャの範囲(AWSマネージドサービスでできる範囲)から超えることなく実装していこうと思っています。

(もし、サーバー管理が必要な機能がでてきたら、その機能は多分あきらめます。)

POST errors with config

“Manageless” にもつながるのですが、1回デプロイすれば、運用時に追加で何か設定する必要がないようにしたいと考えていて、その1つの方法として、"POST errors with config" というアイデアで構築しています。

例えば「Slackのどのチャンネルに通知したいのか」や「どれくらいの頻度で通知したいのか」などの設定は、普通なら管理画面などで設定しそうなものですが、こういう設定をクライアント側からエラー登録と同時に毎回投げてもらう形にしています。

そうすることで、 faultline はエラートラッキング情報は保持しますが、それ以外にはデータを保持する必要がなくなります。

他に faultline が行うのは、エラー情報取得イベント発火時に設定に沿った通知処理などを実行するだけです。

Between “Only mail notify” and “Error tracking services”

あくまで、「エラーメール通知のみの開発の世界」と「有償のエラートラッキングサービスに任せているの開発の世界」の間を狙っています。

本当の「管理レス」は金の弾丸を使った有償サービスなので。

というわけで

最近のプライベートな開発はもっぱら faultline です(そういった意味でもPHPカンファレンス2016で、今までの興味とツールを話し切れたのは良かった)。

実は ServerlessConf Tokyo 2016 のときには、既にコンセプト実装としてある程度動くものができていていたのですが、見せるきっかけも特になく、結局ここまで時間を見つけてはチマチマと作っていました。

実装は、Serverless Frameworkのバージョンアップや、周辺技術の知見の増大や、ふとした思いつきと共に5回くらい作りなおしています。

(最近聞いている boot.fm で k0kubun さんが話していたツールの実装の流れに近い)

今の自分のServerless Framework力、JavaScript力はこれくらいっぽいです。

是非「エラーメール通知のみの開発の世界」から抜けだしましょう。

k1low/xlsx と同じようにPDFを扱えるPHPライブラリ k1low/pdf を作った

前に作って放置していたのを、ちゃんと整備してCakePHPへの依存性を外してPackagistに登録しておきました。

github.com

k1low/xlsxと同じように、テンプレートになるPDFに文字を書き込んで出力するだけのシンプルなライブラリです。

<?php
use Pdf\Pdf;

$pdf = new Pdf();
$pdf->appendTTFfont('/path/to/ipag.ttf');
    ->read('/path/to/template.pdf')
    ->setValue('あいうえお', ['x' => 10, 'y' => 20])
    ->setValue('6ページ目', ['x' => 10, 'y' => 20, 'page' => 5])
    ->setValue('あいうえお', [
        'x' => 120,
        'y' => 45,
        'width' => 100,
        'height' => 230,
        'fontSize' => 24
    ])
    ->write('/path/to/output.pdf');

TTFフォント以外はcomposerでインストールできるので、導入は楽です。「申込書の出力」などの決まりきったフォーマットの帳票出力には使いやすいかと思います。

こちらからは以上です