🔦「お気持ち会」で暗闇を払う

こんにちは、@mugi_uno です。気付いたら弥生社員になってました!!

プロジェクトの立ち上げはむずかしい

Misocaチームで何かしらの課題に取り組む場合、基本的にはプロジェクト化して進めていきます。

その際、まずはインセプションデッキを作成して「目的やゴールは何か」「何をして、何をしないか」といったことを明文化し、メンバーで認識を揃える作業をします。

ですが、現実的にはそれ自体が難しいケースが存在します。

何から手を付ければいいのかわかりません!

たとえば

  • 多種多様な立場の人が参加するプロジェクトを始めるが、メンバー個々人が何を重要視しているかを互いに知らない
  • ○○について効率化したいけど、具体的に何が課題で次に何をすべきかが誰もハッキリとは見えていない
  • 膨大なタスクが存在していて、どういった判断軸で優先順位をつけていけばいいのかがわからない

みたいな経験はないでしょうか。

このような状態だと、いきなり関係者でインセプションデッキを書こうにも、「一体何から話せばいいのか」「そもそもゴールとは?」となってしまい、議論が発散して収集がつきません。

何かミーティングをすれば解決する?

インセプションデッキ作成も、言ってしまえばミーティングの一種です。

困ったことがあると、つい「とりあえず集まってミーティングだ!」となりがちですが、内容が曖昧なミーティングをして、結局何も決まらずに空振りするという話も良く聞きます。(自戒)

対して、次のようなプラクティスが存在します。

  • アジェンダをきちんと用意する
  • ミーティングのゴールを定める
  • 次のアクションを出す

これらはMisocaチームでも積極的に実践されており、日常的にミーティングを効率的に終わらせるよう工夫していますが、先に挙げたような状態では、そもそもアジェンダを作る時点から「アジェンダ...?」となります。

整理された議論に意識が引っ張られる

ある程度キッチリとしたミーティングでは、何か意見を言うときも「ある程度自分のなかで整理された意見を言おう」「議論が前に進むような発言をしよう」という方向に意識が向きます。

それ自体はとても良いことですが、テーマが漠然としている場合には、一人の頭のなかで考えるには重たすぎたり、整理された意見というより「気持ち」に近い部分の意見は発言するタイミングが難しかったりもします。

こういう場合は、人が集まったわりには沈黙が多かったりします。

「お気持ち会」という文化

先に挙げた状態の場合、Misocaチームでは 「お気持ち会」 という30分-1時間程度の会が開催されることがあります。

お気持ち会の特徴

  • 30分〜1時間程度
  • ハッキリしたアジェンダやゴールは無い
  • 朝会などで全体に告知されて、プロジェクト外のメンバーからも参加を募ることが多い
  • 明確なゴールがあらかじめ設定されることは少なく、わりとゆるく開催される

だいたいは次のような流れで行われます。

  1. お気持ち会のテーマに関して各自が「思っていること」「考えていること」を Trelloに自由に吐き出す
  2. 掘り下げて話したいものにラベルをつけて議論する

お気持ち会の具体例「脱jQueryプロジェクト」

Misocaのコードベースにはフロントエンド部分でツラい箇所がまだまだ残っており、それをなんとかしよう!と「脱jQueryプロジェクト」をフロントエンドチームで始めることにしました。

が、いきなりスタートしようにも

  • え、対象多すぎでは..?
  • そもそも何のためにこれやるんだっけ
  • どこから手をつければいいの

といった心境になります。そこで、「脱jQueryお気持ち会」をチームで開催しました。

実際に出てきたカード

f:id:mugi1:20200703105057p:plain:w200

ざっくりと会話をしたことで「どうやらjQuery自体が問題というわけではないかもしれない」「修正対象がどの程度の規模感なのか誰も知らないよね」といったことが見えてきました。

最終的には、お気持ち会で出た議論をもとに、次のような方向性が定まり、実際に動き始めました。

  • プロダクトのロードマップなどを確認して、何を優先すべきか検討しよう
  • 対象のコードや影響範囲がどの程度のものなのか整理して把握しよう

お気持ち会のメリット

お気持ち会は、その名の通り「お気持ち」を表明するだけでも歓迎されます。お気持ちですので、ふわっとした意見でも問題ありません。

「正直よくわからんけど、難しそうだなって思いました!!」

とかでもオッケーです。具体的な方針や対策を書く必要もありません。

f:id:mugi1:20200706151726p:plain:w300
ふわっとしたカードの例

そのぐらいハードルを下げることで、多くの人からバラエティ豊かな意見やアイデアを集めることができます。

また、参加する側としても「この意見はこの場では言うべきではないかもしれない」というような不安を払拭でき、より心理的に安全な形で参加することができます。

お気持ち会によって得られるもの

お気持ち会を開催することで

  • 不安な箇所がわかる
  • 「知らないこと」が何かわかる
  • メンバーがどういった方向を向いているかを相互に確認できる

といったことを得られます。

輪郭がハッキリしないテーマで何かを始めるのは、暗闇の中にいる状態からスタートするようなものかと思います。

まずはどこに向けて進むか決める必要がありますが、お気持ち会という場で情報を集めることで、暗闇を払って最初の1歩を進むための手がかりになっているのかな〜と感じています。

考察 / お気持ち会の正体

お気持ち会という名前で会が開催されてはいますが、結局のところコレはブレインストーミングをMisocaチームなりに形にしたものかな、と思います。

ブレインストーミング - Wikipedia

とはいえ「お気持ち会」という名前にしていることで、ブレインストーミングの原則である「判断・結論を出さない」「粗野な考えを歓迎する」などと言った部分が説明せずとも理解されているのかもしれませんね。

まとめ

というわけで今回はMisocaで実施されている「お気持ち会」のご紹介でした。それほど準備コストもかけずに気軽にはじめられるので、興味があれば試してみてはいかがでしょうか。

Misoca開発者ブログは「弥生開発者ブログ by Misocaチーム」に生まれ変わります

こんにちは、Misoca開発チームの黒曜(@kokuyouwind)です。

最近ウィングスパンを買ったので、ボドゲ会を開きたい今日このごろです。

🏢 弥生との合併を受けて

株式会社Misocaは2020年7月1日付けで弥生と合併し、Misocaのメンバーは弥生の社員になりました。

とはいえ業務上は大きく変わらないのですが、ひとつ問題が。

このブログ、「Misoca開発者ブログ」という名前なんですよね。

実は弥生にも元々弥生開発者ブログがあるのですが、結構な数ある過去記事のお引越しは大変そうだし、デザインが違うので崩れも怖い… 突貫作業ではやりたくない…

というわけで、このブログは「弥生開発者ブログ by Misocaチーム」として生まれ変わります!

具体的には、ブログタイトルとロゴの2点が生まれ変わりました!

ヘッダーにも出てますが、こんな感じです。

f:id:kokuyouwind:20200702170424p:plain

当面は今まで通り、Misocaのメンバーが様々な記事を投稿する予定です。

Misoca開発者ブログあらため、弥生開発者ブログ by Misocaチームを今後ともよろしくお願いします!

📢 宣伝

Misocaチームでは弥生と一緒にプロダクトを作りたいエンジニアを募集しています!

SectionReport フォーマットを実装した拡張版 Thinreports の公開

こんにちは、Misoca の日高(@hidakatsuya)です。

Fit Boxing は何度始めても3日坊主になります。

拡張版 Thinreports の公開

Thinreports は、オープンソース のPDF 生成ツールです。Thinreports では、Editor と呼ばれる帳票デザインツールで作成したテンプレートファイルを、RubyGems である Generator を使って読み込み、値の埋め込みなどを行って PDF を作成することができます。

Misoca でも以前から一部の PDF 生成機能で利用していましたが、昨年より、本格的に利用を進めるにあたって、不足した機能の拡張という形で SectionReport フォーマットの実装を進めてきました。

Editor 及び Generator それぞれの実装は下記リポジトリの section-report ブランチで公開し、現在も少しづつ開発を進めています。

github.com

github.com

SectionReport フォーマット

SectionReport フォーマットとは、コミュニティで提案されている Thinreports の新しいレイアウトフォーマット です。公開した拡張版 Thinreports は、この提案に基づいて実装した形です。

このレイアウトフォーマットは、

レイアウト定義時点でページの制約をなくし、出力した結果によってページを決めるレイアウトフォーマット

と、提案の中でも説明されているように、従来のフォーマットのような、ページ単位の固定なレイアウトではなく、レイアウトを「セクション」と呼ばれる単位で分割して定義し、PDF生成処理の中で、それらのセクションを組み合わせたり、カスタマイズすることによって、柔軟なレイアウトを可能にします。

f:id:hidakatsuya:20200629164435p:plain
Example: Basic Usage のレイアウト定義

主な特徴を紹介します。

セクションの高さの自動伸縮

描画した結果、テキストの内容がセクションの高さに収まらないとき、それに応じてセクション自体の高さを自動的に拡張させることができます。また、後述する StackView による自動縮小もサポートしています。詳細は Example: Section Auto Stretch を参照してください。

StackView ツール

図形やテキストを配置できる複数の領域(row)をもつ、Misoca 独自の新しいツールです。

StackView は他の図形同様、セクション内に配置することができます。その row は、動的に非表示にすることができ、その下に続く row は上に詰めて描画されます。また、row はセクション同様、自動伸縮をサポートします。StackView を使うことによって、セクション内のレイアウトを動的かつ柔軟なものにすることができます。詳細は、Example: StackView を参照してください。

その他の機能や実装状況

その他の機能や実装状況など、詳細は下記 README に記載しています。また、StackView ツールなどの Misoca 独自機能についても説明しています。

使い方

それぞれの README を参照してください。

また、いくつかの example も用意しています。各 example には、テンプレートファイルと Ruby のコード、その出力結果PDFが含まれています。こちらも参考にしてください。

なお、Editor は現時点では SectionReport フォーマット専用です。従来のフォーマットを編集することはできません。

今後について

いずれの実装もまだまだ発展途上です。Misoca としても開発を継続しつつ、近く Thinreports コミュニティに pull request を送る形で提案していきます。 そして、活発な議論のもと、より良い形での機能の提案ができればと思っています。その際は、ぜひレビューやコメントをしていただけると嬉しいです。

最後に

拡張版 Thinreports の概要と公開のお知らせを中心にご紹介しました。 今後も、この拡張版 Thinreports について、詳しい使い方や Misoca での具体的な利用例などを引き続きご紹介していきたいと思います。

宣伝

Misocaでは OSS に貢献したいエンジニアを募集しています。

www.wantedly.com

急なレスポンスタイム悪化から、オープンソースプロジェクトにPull Requestを送るまで

こんにちは、Misoca開発チームの黒曜(@kokuyouwind)です。

最近はシャニマスのイベントシナリオ感想記事をnoteにまとめたりしています。

😨 急に本番のレスポンスタイムが悪化した話

Webエンジニアにとって、「本番障害」という4文字ほど見たくないものはないでしょう。

本番障害ほどではないにしても、「急なレスポンスタイム悪化」もあまり見たくない文字列ですね。まぁ、見たくなくても向こうからやってくるんですが…

というわけで、今回は本番レスポンスが急に悪化したときの話です。いろいろ調べた結果、利用しているオープンソースプロジェクトが原因だったことがわかりPull Requestを送ったので、その流れをまとめてみたいと思います。

❗️ レスポンスタイム悪化の検知

Misocaでは監視ツールとしてMackerelを、APMツールとしてSkylightを利用しています。

本番レスポンスタイムはMackerelでアラートを設定しており、平常値から大きく悪化した場合はSlackに通知されるようになっています。

その日はリリース作業を行った直後、レスポンスタイム悪化のアラートが飛んできました。気になってSkylightを確認したところ、驚きの事態が。*1

f:id:kokuyouwind:20200609181504p:plain

リリース以降、95パーセンタイルがめちゃくちゃ悪化しとるやん!*2*3

🩹 応急処置

幸いアプリケーションが使えなくなるほどの悪化ではなかったため、落ち着いて応急処置に臨みます。

Skylightで表示する期間をリリース前とリリース後で切り替えて比べた結果、どうやらPDF生成処理にかかる時間が伸びているらしいとわかりました。

リリース内容を精査したところ、ちょうどそのタイミングでPDF生成処理に関係しそうなTTFunk gemの更新が入っていることが判明。*4

おそらくこれだろうとアタリをつけ、該当コミットを巻き戻してリリース。結果、見事にレスポンスタイムが回復しました。

f:id:kokuyouwind:20200609182842p:plain

🕵️‍♀️ 原因調査

ひとまず本番の問題は落ち着いたため、なにが原因だったのかを調査していきます。

まずはローカル環境での再現確認。以下のようなコードでベンチマークを取り、gem更新前と更新後とでPDF生成にかかる時間が増えるかを確認します。

10回繰り返しているのはActiveRecordアクセスなどPDF生成以外の要因を相対的に小さくするためです。

require 'benchmark'

Benchmark.bmbm do |x|
  x.report('generate') {
    10.times { Misoca::PDF.generate(Invoice.first) }
  }
end

結果、ttfunk 1.5.1のときと比べて、ttfunk 1.6.2.1では概ね4倍ほど遅くなることが確認できました。

本番でしか起きない問題だと調査が難しいのですが、ローカルでも再現することがわかったため調査がしやすくなりましたね。

続けてStackprofを使ってプロファイルを取り、どのような処理に時間がかかっているかを調べていきます。

require 'stackprof'

StackProf.run(mode: :cpu, out: 'tmp/stackprof-cpu-myapp.dump', raw: true) do
  10.times { Misoca::PDF.generate(Invoice.first) }
end

stackprof tmp/stackprof-cpu-myapp.dump で確認した結果、以下のようにActiveSupport::CompareWithRange#cover?が50%以上の時間を使っていることがわかりました。

==================================
  Mode: cpu(1000)
  Samples: 13617 (0.71% miss rate)
  GC: 1461 (10.73%)
==================================
     TOTAL    (pct)     SAMPLES    (pct)     FRAME
      7765  (57.0%)        7765  (57.0%)     ActiveSupport::CompareWithRange#cover?
      1138   (8.4%)        1138   (8.4%)     (marking)
      8609  (63.2%)         844   (6.2%)     TTFunk::Table::OS2.group_original_code_points_by_bit
       322   (2.4%)         322   (2.4%)     String#unpack
       322   (2.4%)         322   (2.4%)     (sweeping)
...

TTFunk::Table::OS2.group_original_code_points_by_bitもTOTALでは多くの時間を使っており、SAMPLESは少なくなっています。 このことから、TTFunk::Table::OS2.group_original_code_points_by_bitからActiveSupport::CompareWithRange#cover?を呼び出している箇所が重いのだろうと推測することができました。

実際にTTFunk::Table::OS2.group_original_code_points_by_bitのコードを確認すると、以下のようにr.cover?を繰り返し呼び出しています。

os2.file.cmap.unicode.first.code_map.each_key do |code_point|
  # find corresponding bit
  range = UNICODE_RANGES.find { |r| r.cover?(code_point) }

この処理は1.6.0で追加されたものでした。ここにパフォーマンス上の問題があるようですね。

📝 Issueを立てる

問題が把握できたため既存のIssueやPull Requestを確認しましたが、どうやらまだ報告されていないようでした。

新しいIssueを立てたいところですが、このためには最小限の再現コードを作り、ttfunk自体の問題である確証を得ておきたいところです。

PDF生成の内部処理からどのようにttfunkが呼び出されているかわからなかったため、stackprof --graphviz tmp/stackprof-cpu-myapp.dump > tmp/stackprof.dotでdotファイルを作成し、dot -T pdf -o tmp/stackprof.pdf tmp/stackprof.dotでPDF化して呼び出しグラフを見てみました。*5

f:id:kokuyouwind:20200610134938p:plain:h300

どうやら、TTFunk::Subset::Base#encodeが外部とのインターフェイスのようです。

specファイルを参考にしつつ、この処理を呼び出す再現コードを書いてみます。

require 'ttfunk'
require 'benchmark'

# English Font
file = TTFunk::File.open("DejaVuSans.ttf")
# Japanese Font
# file = TTFunk::File.open("GenShinGothic-Normal.ttf")

subset = TTFunk::Subset.for(file, :unicode)
Benchmark.bmbm { |x| x.report('encode') { 10.times { subset.encode } } }

日本語などのマルチバイト文字でしか再現しない問題かもしれないので、フォントを英字フォントと日本語フォントの2種類で確認できるようにしています。

このコードを用いて1.5.1と1.6.2.1でベンチマークを取ったところ、英字フォント・日本語フォントを問わず実に30倍程度遅くなっていることがわかりました。やはり日本語フォントのほうが長時間かかるため、英字フォントを扱う海外ではパフォーマンスの問題に気づかなかったのかもしれません。

無事ttfunkのみで再現コードを作り計測もできたため、Issueとして報告することができました。

🛠 修正Pull requestを送る

あまりに難しそうな問題であれば手出しできませんが、今回は比較的読めそうなコードだったため、自分で直せないか検討してみることにします。

問題の箇所ではos2.file.cmap.unicode.first.code_mapの各キーについてeachを呼び出し、UNICODE_RANGESの中からr.cover?(code_point)を満たすものを探し出しています。

それぞれの要素数をN,M とすると、この処理は Ο(N * M)の計算量になります。Mは200弱の固定値ですが、それでも効率の悪い計算に見えますね。

素直に思いつくのはUNICODE_RANGESを探索木にすることです。ただしUNICODE_RANGESRangeの配列のため通常の探索木ではなく区間木を使うことになります。Ruby標準でサポートされないデータ構造のため依存gemを増やすか自力で実装するかになりますが、いずれも少々大きな変更になります。オープンソースプロジェクトへのPull Requestとしては、できれば避けたいところです。

ここで発想を変えて、「UNICODE_RANGESごとに、その範囲に含まれるcode_mapキーをまとめて見つけ出す」としたらどうでしょうか。code_mapが整列していた場合、同じUNICODE_RANGESに含まれるキーは必ず固まって並ぶため、効率良く処理できそうです。またUNICODE_RANGESは互いに重複しない範囲であるため、他のUNICODE_RANGESに含まれていたものを以降の判定から除外することができます。

この方針で実装してみたところうまく動いたため、Pull Requestを出すことにしました。計算量はΟ(max(N, M))まで改善しており、ベンチマークも8倍ほど早くなっています。

💬 感想

今回は本番でパフォーマンス悪化に気づいてから原因を調査し、オープンソースプロジェクトにIssueを立ててPull Requestを送るまでの流れをまとめてみました。

定番ですがStackprofを用いたプロファイル分析は大切ですね。またみんなのコンピュータサイエンス読書会で読んだばかりの計算量やアルゴリズムの話がさっそく活かせたのも良かったです。

tech.misoca.jp

今後も利用しているオープンソースプロジェクトの問題を見つけたときは、Issueで報告して直せるものはPull Requestを出していきたいと思います。

📢 宣伝

Misocaではパフォーマンスの問題を改善したいエンジニアを募集しています。

*1:話を簡単にするために省略しましたが、実は月初の負荷にまぎれてしまい、当日はアクセス量の問題だと思っていました。翌日も数値が回復しなかったため怪しんで調査し、コード起因の問題であったことがわかりました。

*2:95パーセンタイルは、レスポンスタイムすべてを短い順に並べて95%目の値を取り出したものです。SkylightのTypical responseは中央値(50パーセンタイル)を、Problem Responseは95パーセンタイルを表示しています。

*3:グラフの縦軸は具体的なパフォーマンスの情報になってしまうため、意図的に伏せています。

*4:話を簡単にするために省略しましたが、実際には別のgemの更新に伴い、依存していたttfunkも更新されていました。原因調査の際はここの切り分けでかなり苦労しました。

*5:flamegraphでも同じようなコールスタックが見えますが、スクリーンショットで貼ったときに細かすぎて見づらいため、今回はgraphvizを使っています。

みんなのコンピュータサイエンス読書会

こんにちは、Misoca開発チームの黒曜(@kokuyouwind)です。

最近はVTuberのシャニマス実況を見て無限に時間を溶かしています。だいたい委員長のせいです。

📕 みんなのコンピュータサイエンス読書会

Misocaでは有志で集まりみんなのコンピュータサイエンスの読書会を開催しています。

みんなのコンピュータサイエンス

みんなのコンピュータサイエンス

読書会を始めたのは「単に自分が読みたかったから」という理由が大きいのですが、コンピュータサイエンス(以下CS)の知識のベースラインを揃える取り組みをしたかったという面もあります。

チームメンバーの来歴はCSの専門課程を経た人から独学でプログラミングを学んだ人まで様々です。

例えば「MySQLのクエリはインデックスが効かないと遅くなる」という知識ひとつをとっても、CSの知識があれば「インデックスが探索木になっているから、Ο(log N) と Ο(N) の差があるんだな」とイメージを持てるのに対して、計算量や探索木の知識がない場合は「とにかくインデックスが効かないとだめなのかな」という理解になってしまいかねません。このように理解の齟齬がある状況では、「どの程度のサイズのテーブルで、どのカラムにインデックスを足すべきか」といった議論がまともに成り立たなくなってしまうでしょう。

こういった問題を防ぐために、CSの基礎知識をチームで揃えるのは重要だと個人的に考えています。その点で、CSの基礎を広く平易に扱ったこの本はちょうどよい題材になったと思います。*1

🏃‍♂️ 進め方

読書会では、節ごとに誰かが音読してから掘り下げて議論する流れを取っています。これは読む速度で取り残される人が出ないようにするとともに、内容をしっかり掘り下げられるようにするためです。

掘り下げ議論では、詳細を追って参加者全員の理解を確認することに加えて、現実での応用例や自社サービスで使える箇所がないかなどもよく話しています。例えば貪欲法の節では並列テストのグループ振り分けに利用している話や、探索木の節ではMySQL InnoDBのインデックスがB+木である話などをしていました。

掘り下げの際にMiroを使ってグラフや図を描くこともあります。以下は動的計画法のボトムアップについて、グラフを描いて確認したものです。

f:id:kokuyouwind:20200526173251p:plain:w480

ツールをろくに使わずフリーハンドで描いているため汚いですが、こういった図を描きながら話すことでより理解しやすくなりました。もう少し使いこなせるようになりたいですね。

📈 進捗

年初から始めて、現在5.3節までを読み終わったところです。本全体の半分ちょっとくらいでしょうか。

かなりゆっくりしたペースですが、これはかなり掘り下げて理解を確認しながら進めていることと、参加者の都合が合わず中止になる日も多いためです。

特に基礎となる論理・確率や計算量などは理解しないまま進めてしまうと後で困りそうだったので、1章で大きく時間を割いていました。

残りもこのペースでじっくり読み進められればと思います。

📢 宣伝

MisocaではCSの基礎を固めて業務に活かしたいエンジニアを募集しています!

*1:ベースラインを揃える目的で、基本情報技術者試験などの取得を推奨する企業も多いと思います。そちらも有効な手段だと思いますがやや堅苦しくなってしまうため、個人的には読書会くらいのライトさが好みです。

IaC を意識しつつ、Redash を ECS に移行する

先日、弊社内で利用する Redash のインフラ構成を docker-compose on EC2 な環境から ECS, RDS, ElastiCache に移行し、さらに Redash を v7 から v8 にバージョンアップしました。今回はどのように移行を進めたのか、どのようにバージョンアップ作業を行ったのかを紹介します。

これまでのRedash

Redash サーバは開発合宿の成果物として社内に導入されました。当時は動作することを優先させるために、公式が提供するEC2 AMI から docker-compose を使ってコンテナ群を立ち上げるようにしていました。DBやインメモリストアといったミドルウェアも docker-compose でコンテナとして起動している状態でした。

tech.misoca.jp

その後、社内の KGI/KPI や Misoca の SLO の可視化など、利用シーンが広がり社内の重要度が高まってきていました。

tech.misoca.jp

tech.misoca.jp

そうなると、不安となるのがシステムのレガシー化です。1台の EC2 インスタンス上で全部動かしていたのでコンピューティングリソースの不足が気になりますし、Redash のバージョンアップの際も懸念材料となっていました。

というわけで、レガシーになってしまう前に Redash サーバのインフラを見直し、強く柔軟な構成に移行することにしました。

Redash の新インフラ構成

最初に触れたように、新しいインフラ構成は ECS, RDS, ElastiCache を使ったマネージドサービス中心の構成にしています。

f:id:mizukmb:20200518103208p:plain
Redash 新インフラ構成

Server サービスには Redash の画面を提供する Docker コンテナを起動するタスク定義を指定いており、このサービスにのみ ALB を経由した外部アクセスができるようにしています。Workers サービスにはクエリを実行等を行う複数のDocker コンテナを集約させたタスク定義を指定しています。

Workers サービスが起動する Docker コンテナの種類は公式のdocker-compose.ymlと同じにしています。こういう構成にしようというこだわりが無かったので公式に合わせました。後々変えていくことはありうると思います。

インフラ構成のコード化

インフラ構成のコード化 (IaC) は、今では当たり前のようになってきましたが、ここで今一度 Redash のインフラ構成のコード化によって得られる恩恵は何であるかを列挙します。

  • コードがドキュメント代わりになる
  • コードレビュー、CI/CDといったソフトウェア開発で用いられる手法がインフラでも使える

その他にも様々な恩恵・利点は確かにありますが、今回は上記2点に絞りコード化の作業を進めました。

インフラ管理には Terraform を利用しました。社内でも既に AWS リソース管理に使われており、ほぼこれ一択という感じで決定しました。もっと様々な観点から他のツールも検討するべきとは思いますが、社内向けのアプリケーションであることと、自分以外の作業者でも問題無くコードが読めること (ドキュメント代わりになる) を重視した結果、社内で広く使われているツールを採用することにしました。

Terraform のファイル構成は以下の通りです。AWS のリソース毎にファイルを切り、 provider や Terraform 自身の設定は main.tf に集約させています。

.
├── README.md
├── ecs.tf
├── elasticache.tf
├── lb.tf
├── main.tf
├── rds.tf
├── task-definitions
│   ├── redash-server.yaml.tpl
│   └── redash-workers.yaml.tpl
└── vpc.tf

ちなみに、 task-definitions の yaml ファイル群はこちらの Issue コメントを参考にして、一度 yamldecode したオブジェクトを jsonencode して読み込むといった一手間を加えています。

GitHub Actions を使ったテスト、apply の自動化

プルリクエスト時の terraform plan や master ブランチ更新時の terraform apply といった事を自動で行うために GitHub Actions を使ってこれらを実現します。HashiCorp 社の公式テンプレートがあるので、今回はこちらを利用しました。

github.com

プルリクエスト単位では fmt -> init -> validate -> plan の順番で実行し、 plan を除いた全て成功すればグリーンとしています。また、 plan の結果についてはプルリクエストのコメントに残すようにもしています。この辺の設定も tf_actions_comment: true とするだけで良いのでとっても簡単です。 master ブランチ更新時 (= PR マージ時) には上記サイクルに加えて最後に apply を実行して、実際に Terraform の定義と AWS リソースの状態を合わせるようにしています。こうすることで、 master ブランチ == AWS リソースの状態となり、常に最新の状態を確認できるドキュメントとしても十分に機能してくれます。

……と、ここまで hashicorp/terraform-github-actions の使い方等を紹介しましたが、どうやら記事執筆時点ではこのリポジトリはアーカイブ状態になっていて、今後は積極的な開発やメンテナンスが行われないようです。今後は hashicorp/setup-terraform の使用が推奨されますので、皆様もこちらを使う方が良いかと思われます。私自身使ったことは無いので紹介だけ。

github.com

作業時点では hashicorp/terraform-github-actions リポジトリもアーカイブになっていなかったので、コミット履歴等を見るに最近決まったみたいですね。設定したばかりなのにまた書き直さないといけないのか (とほほ)。

Redash v7 → v8 へのバージョンアップ

Terraform による IaC と、GitHub Actions による CI/CD のセットアップが完了し、残すは Redash アプリケーションのバージョンアップ作業のみとなりました。ここまでくれば、バージョンアップ作業は Terraform のコードをいじって PR をマージするだけで作業は完了してしまいます。

f:id:mizukmb:20200519104255p:plain
GitHub のプルリクエストを使って Redash のバージョンを上げている様子

resource aws_ecs_task_definition が持つ container_definitions で設定する image の値を変更します。 Redash の公式 Docker イメージは Docker Hub で管理されているので、そこから v8 系のタグを探して Terraform 側で設定してあげましょう。

hub.docker.com

バージョンアップのPRをマージすることで GitHub Actions から terraform apply が実行され、 AWS ECS のタスク定義とサービスを更新します。サービスは自らのタスクを入れ替えてデプロイが完了します。

NOTE: Terraform を使った AWS ECS リソースの更新について

今回、AWS ECS 周りのコード化〜自動デプロイまで全て Terraform で行いましたが、実際にやってみるといくつか気になる点が出てきました。

まずは、タスク定義のリビジョンが更新されず、最新のリビジョン番号の内容を上書きしてしまう点です。例えば前回のデプロイ内容をリビジョン番号から辿れなくなってしまう問題があります。リビジョン番号が更新されないのは resouce aws_ecs_task_definition の仕様であり、私も事前に知ってはいましたが、コード自体は Git でバージョン管理できているしロールバックするのも git revert 等やり方は色々思い付くので大丈夫だろうと思っていました。しかし、やはり AWS 上でもリビジョンは更新されてほしいという気持ちもあります。

次に、 ECS へのデプロイ戦略についてです。社内向けアプリケーションということもあり、デプロイは ECS タスク総入れ替えという結構豪快なやり方を取っていますが、ダウンタイムやロールバック方法についてよりシビアに考えるのであれば、ローリングアップデートや blue-green デプロイといった方法でデプロイができるのが好ましいでしょう。 terraform apply ではこの辺りの融通が効かず、難しい印象を受けました。 Terraform で工夫するよりも、コード管理は Terraform, デプロイは他のツールを使うといった併用の形を取っても良いと思います。

今回はデプロイについても Terraform で行うようにしましたが、こちらについては他のデプロイツールの使用も検討して良いかもしれないという個人的な学びがありました。

まとめ

弊社内で利用している Redash のインフラを ECS やその他マネージドサービスへの移行と IaC 化、そして自動デプロイを使った v8 へのバージョンアップについて紹介しました。

まだまだ詰めきれていない部分も多いですが、こちらについては少しずつ磨いていければと考えています。ひとまずは移行が完了してホッとしています。

採用

今回の作業は SRE 業務の一環として行われたものです。 SRE 職種では IaC でいい感じにやっていくことが好きな方々を募集しています。

recruit.misoca.jp

開発メンバー id:mizukmb でした。

突撃!! 隣のリモート飯 🥄

こんにちは。@kawamataRyoです。
いつもは技術に関する話題を投稿している本開発ブログですが、今回は番外編としてMisocaのリモートワーカーのお昼事情の紹介します!

Misocaのリモートワークベテラン勢はどんなリモート飯を取っているのか?
急にリモートワークが始まり毎日のお昼ご飯に悩んでる皆さんの参考になれば嬉しいです。

@torimizuno

角煮ラーメン

f:id:ba068082:20200422083526p:plain

こだわりポイント

  • 夜に炭水化物を抜くので、お昼は炭水化物メイン
  • フルリモートになり、炊飯器でつくる角煮と味玉を仕込んだので、ラーメンにトッピング
  • 有名ラーメン店の器で食べるとそれだけで美味さマシマシです (器はお土産に友人から貰いました)

@k0matatsu

焼肉(円盤状無煙カセットコンロ)

f:id:ba068082:20200422083548j:plain

こだわりポイント

イワ◯ニを信じて肉を捧げろ

@rktm

パン(完全栄養食)

f:id:ba068082:20200422083616j:plain

こだわりポイント

  • 手で半分に割ってスライスチーズとハムを盛ってレンジで1分半というスピード調理
  • なんと、洗う食器はお皿一枚!
  • 糖質少なめながら一食に必要な栄養を賄える
  • 作り始めから食べ終えて食器を洗うまで15分で終わるので昼休憩の残り時間を有意義に使える

id: eitoball

サプリメント or プロテイン

走ったら、サプリメント

f:id:ba068082:20200422083643p:plain

走っていない時は、ソイプロテイン

f:id:ba068082:20200422083711p:plain

こだわりポイント

  • 走ったら、回復が早くなる(らしい)サプリメント を飲むようにしています。ちょっと癖のある味だけど、慣れるとやみつきになります。

id: sunflat

カレーライス(自炊)

f:id:ba068082:20200422083731j:plain

こだわりポイント

  • 圧力鍋で野菜と肉を煮込んで柔らかくしている
  • 食物繊維が不足しがちなので、胚芽押麦を混ぜた麦ごはんを使っている
  • 野菜が不足しがちなので、野菜を多めにしている
  • 隠し味に、カットトマト缶とレーズンととんかつソースを入れている
  • 多めに作って冷凍したいので、じゃがいもは入れてない

@mizukmb

ホットサンド

(ホットサンドの写真が無かったので先日作ったダルゴナコーヒーの写真を代わりに載せておきます。)

f:id:ba068082:20200422083752p:plain

こだわりポイント

  • 春に行われる有名なパンの祭りでシールを集めるために買った食パンを消費するため
  • 具材は適当ですが、スライスチーズは万能選手なのでたくさんあると良いです

@kanizmb

宅配すし 🍣

f:id:ba068082:20200422084757j:plain

こだわりポイント

  • 普段は冷凍食品・コンビニ・残り物で適当にすませるのですが、元気がない時やリリース終わりのめでたい時などには宅配すしを利用します
  • 午後の眠気対策に、お昼を食べずに1時間昼寝することもわりとあります

id:ryotaway

低糖質

f:id:ba068082:20200422084821p:plain

こだわりポイント

  • 1日1食、お昼だけとってます
  • 基本的に卵・肉・チーズしか食べないのですが、たまに味噌汁が飲みたくなるのでその時は味噌汁を作ります
  • これだけだとタンパク質が足りてないので、お昼以外の時間帯にプロテインを飲みます
  • 写真はないですが、チーズをおやつとしてちょこちょこ食べます
  • 食後はコーヒーで締めます

id:yoshoku

納豆

f:id:ba068082:20200422084909j:plain

こだわりポイント

  • カラシを足してます。

@Tooka_91

冷凍パスタ + 白米 + プロテイン(牛乳割り)

f:id:ba068082:20200422084940j:plain

こだわりポイント

  • 痩せやすい体質なので、とにかく何でもいいから食べる。
  • 冷凍パスタは200円でコスパ◎。(オフィスの近くで食べたら、1000円はする。)
  • タバスコが好きなので、いっぱいかける。
  • プロテインを飲めば、野菜を摂取しなくても健康になれるらしい。

@mugi_uno

\\\ 冷 凍 食 品 ///

f:id:ba068082:20200422085001j:plain

こだわりポイント

  • 昼なんて空腹を満たせればなんでも良いんですよ!!

@nezurika

炒めもの+味付け卵+サラダ

f:id:ba068082:20200422085019j:plain

こだわりポイント

  • 下味冷凍していた鶏肉(これはマヨしょうゆにんにく)と冷凍していた切ったねぎと冷凍していたしめじを炒めたものです
  • 味付け卵は週末のリモート飲み会用に作って余ったものです
  • 基本的に、何かしらの炒めものがおかずにあれば良い
  • ご飯はいつもは解凍してラップのままお茶碗に乗せています
  • 映えなんてなく日常なんてこんなもんですよ

id: mallowlabs

スパイスカレー (自炊)

f:id:ba068082:20200422085037j:plain

こだわりポイント

  • 調理時間があまりかからない料理を作っています
  • スパイスカレーは最近ハマっていて、煮込まずに作れるのと、スパイスがあれば作れるので気に入っています
  • しかも結構おいしく作れます
  • 難点があるとすれば、常に部屋がインドの香りになることくらいです

@kosappi_

近所の肉屋のお弁当

これは日替弁当が唐揚げだったときの唐揚げです。

f:id:ba068082:20200422085112j:plain

こだわりポイント

  • お昼は基本的に完成したものを調達するスタイルです
  • 昼休みになると、妻と娘の3人でお弁当屋まで散歩します
  • 密にならないように気をつけています
  • お弁当は日替わりですが事前に電話すれば好きなメニューを作っておいてくれます(すごい!)
  • 金曜日はかならずカレーです

@kawamataRyo

プロテイン(波動拳風味) + 完全栄養食 + EAA

f:id:ba068082:20200422083209p:plain

こだわりポイント

  • 美味しい粉です。
  • 昼休みは、懸垂・腕立て・ランニング・仮眠と色々やりたいので効率よくエネルギーが取れることに注力してます
  • 元袋のジップはちゃちいので、粉を移し変えておくと毎回の開け締めのUXが向上するのでオススメ。

終わりに

いかがでしたでしょうか?お昼ごはんの参考になりましたか?
「インスタ映えの連発だわい」と思って集めたお昼ごはん画像ですが、思いの外クセが強かったです。
美味しいお昼ごはんでパワーアップして午後の業務に備えましょう!!!

採用

Misocaでは、お昼ごはんにも開発にもこだわりを持つエンジニアを募集しています。