エンジニアチーム内LTを始めることになりました
私はGMOペパボのムームードメインというサービスのエンジニアをしています。2ヶ月ごとにロリポップ!、ヘテムル、ムームードメインと、サービスを横断するインフラチーム合同でTechMTGが開かれています。(1回目の模様はこちら)
昨日2回目が開催されたのですが、とても良い内容が多く参考になるものばかりでとても良かったです。ペパボのテックブログにそのうちレポートが書かれると思います。
ムームードメインのエンジニアも1人TechMTGに登壇したのですが、あまり登壇経験がなく準備もすごく大変そうで、チーム内レビューもあるのですがレビュアーも登壇経験が少ないためレビューも大変でした。
チーム内LTを始めてみようと提案
ムームードメインのエンジニアは現在4人なのですが、皆登壇経験があまりなく少し苦手意識を持っているようでした。そこでチームにLTをやってみませんかともちかけたところすぐにみんなOKしてくれました。(フォロワーシップ!)
すぐにいいねと言ってくれるメンバーたちにも感謝。
LTのルール
◯ 内容
サービスの仕様の話、技術的な話、エモい話、とにかく何でもあり。
◯ 時間
5分程度でまとまるくらい小さなものでOK。大きすぎると逆に負担になるからライトな感じで。
◯ 資料
スライドなりテキストなり何かしら資料としては残す。口頭だけではとにかく忘れてしまうから。
ということで早速始まった
初回、まずは自分がやるぞ!ということで、何にしようかと迷いましたが、エモい話をすることにしました。
その時のスライドがこれです。 speakerdeck.com
内容としては
- 個人の強みを活かそう
- その上でチームとして根幹の指針(共通認識みたいなもの)を皆で考えたい
例えば「困ったらコードで解決する」というチームの指針があったとします。何か問題が起こったときや改善したいときなどに「コードで解決するにはどうしたら良いだろう」という考えがまず自然と浮かんで浮かんできて、解決方法に悩んだり迷ったりする時間が減らせるのではないかという感じです。
資料としては全然洗練されてなくて、ただの提案LTですが気持ちは伝わったようでこうするとよさそうだ!とか話が広がってすごくよかったです。
思ったこと
最近、何事も小さく始めてみるというのが良いと思っています。大きくやろうとすると、それについて考えることが多すぎて時間がかかってそのうち熱が冷めてしまって結局なにもできなかったということになることが多いと感じます。
その1つとして小さくチーム内でLTを始められたことは良かったです。事業部全体で!会社全体で!ってなると途端にハードルが上がってしまって手を挙げづらいところがあるので、まずはこの感じで続けていきたいと思います。
Railsアプリを簡単にメンテナンス表示するにはturnout(+capistrano+whenever)が便利かもです
Railsアプリをメンテナンス表示にしたい時、みなさんどうされているのでしょうか。大規模サービスであればリバースプロキシでメンテ状態にするのが今風かもしれませんが、もっとお手軽にメンテナンスにしたいときはアプリケーション側でやってもいいかもしれません。
メンテナンス表示にする
turnoutというgemを使うと簡単そうです。
Gemfile
gem 'turnout'
tmp/maintenance.yml
というファイルがあればメンテナンス表示されます。
コメントとか許可するIPとかを書けるようです。
tmp/maintenance.yml
reason: 終了予定時間は 8/1 5:00 を予定しております。 allowed_ips: - 1.2.3.4
これだけでまずは全ページメンテナンスに出来ました。reasonに書いた文字列が表示されています。
メンテナンス中の表示をカスタマイズしたい場合は、public/maintenance.html
を置いておけばそのHTMLが表示されます。{{ reason }}
と書いておくとyamlファイルで設定したreasonが展開されます。
public/maintenance.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <style type="text/css"> <!-- h1 { color: red; } --> </style> </head> <body> <h1>現在メンテナンス中です。</h1> <p>{{ reason }}</p> </body> </html>
簡単。
capistranoのタスクでメンテナンスの開始/終了を切り替える
まずは先程のyamlファイルをconfig/
にでも置いておきましょう。
config/maintenance.yml
reason: 終了予定時間は 8/1 5:00 を予定しております。 allowed_ips: - 1.2.3.4
capistranoのタスクを書きます。
lib/capistrano/tasks/maintenance.rake
namespace :maintenance do desc 'メンテナンス開始' task :start do on roles(:web), in: :sequence do within current_path do # tmp/maintenance.ymlがなければ config/ から tmp/ にコピーする unless test(:test, "-f tmp/maintenance.yml") execute :cp, 'config/maintenance.yml tmp/maintenance.yml' end end end end desc 'メンテナンス終了' task :finish do on roles(:web), in: :sequence do within current_path do # tmp/maintenance.ymlがあれば削除する if test(:test, "-f tmp/maintenance.yml") execute :rm, 'tmp/maintenance.yml' end end end end end
上のように定義しておくと
bundle exec cap production maintenance:start # メンテナンス開始 bundle exec cap production maintenance:finish # メンテナンス終了
のコマンド一発で開始/終了を切り替えられます!やった!
メンテナンスタイマーを仕込みたい
whenever gemでcronを仕込みましょう。やり方は同じです。指定した時刻にtmp/maintenance.yml
を置いたり消したりするだけです。
Gemfile
gem 'whenever', require: false
config/schedule.rb
set :output, "#{Whenever.path}/log/cron.log" set :environment, :production set :path, '/path/to/app/current' # メンテナンス開始 (8/1 0:00) every '00 00 1 8 *' do # config/maintenance.yml (copy ->) tmp/maintenance.yml command "cp #{Whenever.path}/config/maintenance.yml #{Whenever.path}/tmp/maintenance.yml" end # メンテナンス終了 (8/1 3:00) every '00 03 1 8 *' do # remove tmp/maintenance.yml command "rm #{Whenever.path}/tmp/maintenance.yml" end
あとはcapistranoでデプロイするときにwheneverを実行させましょう。
Capfile
require 'whenever/capistrano'
config/deploy.rb
set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:stage)}" } set :whenever_roles, ->{ :cron }
config/deploy/production.rb
role :cron, %w(sshuser@app.server.com)
これでcapistranoでデプロイしたときにデプロイユーザにcrontabがつくので指定した時刻に実行されます!よい!
終わりに
unicornとかミドルウェアによっては再起動が必要と思うので、都度再起動をするような命令を入れておけば良さそうです。
アプリケーションまでアクセスすらきてほしくない時はこの方法ではダメなのでもっと手前のレイヤーでメンテナンス状態にしてください。
まぁでもcronって定期的に何かを実行させたりするやつなんでこういう1回きりのタイマーに使っていいのかというのもあるので、なんかいい案があれば教えてください!
Capistranoでデプロイした時にGithubのどのPullRequestをリリースしたかをSlackに通知する
上のような感じで、Capistranoでデプロイした時にどのPullRequestがリリースされたかをSlackに通知するGemを作りました。
Capistrano v3 のみ対応です。masterブランチにマージされた最新のPullRequestを取得して通知しますので、デプロイするときは一旦masterブランチに切り替えてgit pullしてからデプロイすると間違いないです。
@linyows さんが作ったcapistrano-github-releasesとcapistrano-slack_notificationに完全に依存しています。ありがとうございます!
セットアップ
Gemfile
gem 'capistrano-releases-notification'
Capfile
require 'capistrano/github/releases' # 依存 require 'capistrano/slack_notification' # 依存 require 'capistrano/releases/notification'
config/deploy.rb
# slack webhook set :slack_endpoint, 'https://hooks.slack.com' set :slack_path, '/services/xxxxxxxxx/yyyyyyyyy/zzzzzzzzzzzzzzzzzzzzzzz' # slack通知設定 set :release_notify_channel, ['#general'] # 通知チャンネル名(複数指定可) set :release_notify_mention, ['@kimromi'] # メンション(複数指定可) # Github Enterpriseの場合 Octokit.configure do |c| c.api_endpoint = 'http://your.enterprise.domain/api/v3' c.web_endpoint = 'http://your.enterprise.domain/' end
config/deploy/production.rb
# デプロイ終了後に通知する設定 after 'deploy:finishing', 'release:notify'
必要なstageで追加してください。
使いみち
メッセージやタイトルも編集できますので、我がムームードメインではカスタマーサービスチームにメンションを飛ばして何がリリースされたかを通知して共有するようにしています。下の例ではPullRequestの内容まで取得しています。
set :release_notify_mention, ['@cs'] set :release_notify_title, 'ムームードメイン' set :release_notify_message, -> { "リリースしました。 #{fetch(:release_notify_mention).join(' ')}" } set :release_notify_attachment, -> { pull_request = Octokit.pull(fetch(:github_repo), fetch(:pull_request_id)) [ pull_request.title, pull_request.html_url, '------------', pull_request.body[0, 200] ].join("\n") }
お試しあれ〜