コネヒト開発者ブログ

コネヒト開発者ブログ

個人で開発したOSSを会社のプロダクションコードに投入した話

f:id:itosho525:20171114185252p:plain

こんにちは。先日社内LTで乃木坂46の紹介をした@itoshoです。

いつもアイドルの話ばかりしたり、週末はアイドルのライブに行ったりしている僕ですが、実はちょっと前に忙しいヲタ活の合間を縫いながら、OSSをつくりまして、最終的にそれを弊社のサービスに混ぜ込んだ話を今日はしたいと思います。

会社のプロダクションコードに投入するために

せっかくOSSをつくったので、やっぱり実際に使いたい!使われたい!と思うのが自然な流れだと思いますが、いざ実際に動いている会社のプロダクションコードに実績もない個人のOSSを投入するのはつくった本人も怖いですし、周りも(一定以上の信頼関係があるとは言え)大丈夫かな?と心配してしまうと思います。

というわけで、今回個人で開発したOSSを会社のプロダクションコードに投入する際のガイドラインを作成してみました。

以下は、社内で公開したガイドラインの抜粋です。*1

心構え

  • 臆せずどんどんOSSをつくって公開していこう!
  • でも、会社のプロダクションコードに投入するのは責任を持とう!
    • これは別に不具合があった時に怒られるという意味ではなくプロフェッショナルとして誇りを持って投入していこうという意味です。
  • なので、投入する時はちゃんとチームでコンセンサスをとってから投入しましょう。
    • 相談された人も無下にせず、OSSをつくったことを讃え、リスペクトの気持ちを忘れないようにチェックしましょう。

投入するための最低条件

  • MITライセンスであること
  • コミットメッセージやIssueが英語で書かれていること
  • 各言語のパッケージ管理のスタンダードなエコシステムに乗っていること
    • バージョン管理もちゃんとすること
  • テストがきちんと書かれていること
    • CIをPassをしていること
    • カバレッジが高い水準にあること
      • OSSの特性に依ると思うので必ずしも100%である必要はありません
      • ただし、理由はちゃんとチームメンバーに説明しましょう
  • ドキュメントが整備されていること
    • 最低限使い方がREADME読んで理解出来ること
  • メンテし続けていく気概があること

投入までの流れ

  • 上記の条件を満たしてからチームメンバーに導入の相談をする。*2
  • 相談されたメンバーはコード等を確認して、適宜フィードバックを行う。
  • 必要に応じて修正を繰り返して、チームとしてGoサインが出たら、遂に投入です!

ガイドラインを作成してみて

公開してまだ日が浅いので、今後見直しが発生するかもしれませんが、一定の基準や方針が出来たのはよかったかなと思っています。

今回ガイドラインを作成したのは自分自身、基準がなくて困ったということもありますが、個人でつくったOSSが会社のシステムやサービスをよりよくするものであれば、絶対投入したほうがいいし、まして、それが心理的な障壁だけで投入を躊躇しているんだったらもったいないなと思ったので、このような方針を示してみました。

また、これにより少しでも会社のメンバーがOSSをつくるモチベーションが上がればいいなとも思っています!

ちなみに、どんなOSSをつくったの?

ここからはおまけですが、せっかくなので、どんなOSSをつくったか簡単に紹介させていただきます。

一言で言うと、複雑になりがちなDBへのクエリメソッドを簡単に記述出来るCakePHPのBehaviorプラグインです。

名前はそのままでEasy Queryと名付けました。

どれくらいEasyなの?

CakePHPではレコードの一括登録を行いたい時、 通常saveMany()という関数を利用します。

使い方としてはこんな感じです。

<?php

$data = [
    [
        'title' => 'First Article',
        'body' => 'First Article Body',
        'created' => '2012-02-22 00:00:00',
        'modified' => '2012-02-22 00:00:00'
    ],
    [
        'title' => 'Second Article',
        'body' => 'Second Article Body',
        'created' => '2012-02-22 00:00:00',
        'modified' => '2012-02-22 00:00:00'
    ]
];
$articles = TableRegistry::get('Articles');

$entities = $articles->newEntities($data);
$result = $articles->saveMany($entities);

分かりやすいですね。*3

ただ、このsaveMany()とっても便利なのですが、いわゆるBulk Insertではないので、大量のデータを一括登録したい時はパフォーマンスが問題になる場合があります。

どうしても、Cake的な書き方で、Bulk Insertしたい時はこんな書き方をします。

<?php

$data = [
    [
        'title' => 'First Article',
        'body' => 'First Article Body',
        'created' => '2012-02-22 00:00:00',
        'modified' => '2012-02-22 00:00:00'
    ],
    [
        'title' => 'Second Article',
        'body' => 'Second Article Body',
        'created' => '2012-02-22 00:00:00',
        'modified' => '2012-02-22 00:00:00'
    ]
];
$articles = TableRegistry::get('Articles');

$query = $articles->query()->insert([
    'title', 
    'body',
    'created',
    'modified'
]);
$query->clause('values')->values($data);
$result = $query->execute();

コード量はほとんど変わらないですが、やや直感的じゃなくなっちゃいますね。

というわけでBulk Insertのような複雑になっちゃうクエリを抽象化して、簡単に扱えるようにしたのが、今回開発したEasy Queryです。

Bulk Insertの例で言うと、こういう感じで書けます。

<?php

$data = [
    [
        'title' => 'First Article',
        'body' => 'First Article Body',
        'created' => '2012-02-22 00:00:00',
        'modified' => '2012-02-22 00:00:00'
    ],
    [
        'title' => 'Second Article',
        'body' => 'Second Article Body',
        'created' => '2012-02-22 00:00:00',
        'modified' => '2012-02-22 00:00:00'
    ]
];
$articles = TableRegistry::get('Articles');
$articles->addBehavior('Itosho/EasyQuery.Insert');

$entities = $this->Articles->newEntities($data);
$result = $this->Articles->bulkInsert($entities);

saveMany()と同じようなI/Fで書けるので(自分で言うのも何ですが)直感的ですね!

補足

今回はOSSの紹介がメインではないので、インストール方法や細かい利用方法はGithubやPackagistをご覧いただければと思いますが、Bulk Insert以外にもUpsertやBulk Upsertにも対応しておりますので、よかったら使ってみてください。*4

現状MySQLしかサポートしていなかったり、createdmodifiedが自動で更新されなかったりというIssueがありますが、鋭意対応中です!

最後に

僕自身もこれから乃木坂46のようなビックなOSSをつくれるように頑張るぞ!

脚注

*1:一部内容を加筆・修正しております。

*2:もちろん、つくっている途中で相談してもOKですが最終的にはこの条件を満たすようにする。

*3:timestamp behaviorを利用すれば、createdとmodifiedは省略出来ます。

*4:一生懸命つくっていますが、利用に際しては自己責任でお願いいたします。

KotlinConfに行ってきました!

こんにちは!Androidエンジニアの富田です。今回は11/2、11/3に行われたKotlinConfというKotlinの海外カンファレンスに参加してきましたので、簡単にカンファレンス内容からカンファレンスを通じてトライしたことを共有します。

KotlinConfとは

KotlinConfとは、Kotlinに関するプログラミングカンファレンスで今回サンフランシスコで初開催でした。参加者は1200名と初開催ながら大規模なカンファレンスで、なんとAndroidの神Jake Whartonさん、関数型プログラミングのErik Meijerさん、Kotlinのリード設計エンジニアAndrey Breslavさんなど超有名な方々がスピーカーとして登壇されました!日本からもしらじさんが登壇されて国内でも大きな反響がありましたね!

海外カンファレンスに行こうと思ったきっかけ

僕が海外カンファレンスに参加したことがなかったので参加してみたいと思っていました。また、ほとんどの社内の開発メンバーも海外カンファレンスに参加した経験がなかったので、みんなにも少しでも興味をもってもらえたらと思い参加しました。加えて、社内制度として「技術支援制度」ができたので、この制度を活用し活性化させたいと考えていました。

カンファレンスの風景

f:id:tommy_kw:20171113222511j:plain
カンファレンス会場のPIER27

f:id:tommy_kw:20171113222555j:plain
Architectures Using Functional Programming Conceptsセッション

f:id:tommy_kw:20171113222624j:plain
Kotlin水筒

f:id:tommy_kw:20171113222647j:plain
Kotlin可愛い!

f:id:tommy_kw:20171113222708j:plain
「connehito」と記載されたネームプレート!

セッション

まず初めにKotlinの発音は、「コトリン」ではなくて「コットリン」なんですね!うまく伝えられないのでこちらは近日公開されるKotlinConfの動画をご確認ください!それでは特に気になった3つのセッションについて簡単に紹介します。

Opening Keynote

Kotlinの勢いとマルチプラットフォームがメインの内容で、KotlinConfアプリは大変参考になるサンプルでした。日頃Android開発しかしていない僕でもサーバサイドKotlinを触ってみたい!と思う内容でした。

  • Kotlin1.2 RCリリース
  • KotlinConfアプリについて
  • サーバサイド、Android、iOS全てKotlinで記述できる
  • iOSはKotlin/Nativeを用いることで利用できるがまだ初期段階
  • サーバサイドフレームワークはKtorが良さそう
  • コード共通化の手法としてcommonモジュールの登場
  • Android StudioでのKotlin利用率は17%
  • Kotlin Style Guideの登場

Two Stones, One Bird: Implementation Tradeoffs

コレクション操作やスコープ関数などの説明や適切な利用方法について言及した内容で、Map vs Sequenceが興味深く、Mapは中間結果を作成するのに対してSequenceは一時的なリストを生成しない。詳しくはKotlinイン・アクションを読むことをオススメします。

  • Array vs IntArray
  • Map vs Sequence
  • Nullability
  • Inline fun vs Custom getter
  • Delegate.notNull vs lateinit

How to Kontribute

Kotlinのコントリビュート方法についてのお話で、IDEのinspection、intentionについてのコントリビュート方法が細かく説明されていました。これを見るときっとコントリビュートしたい!って気持ちになるのではないでしょうか。

  • IDEのInspection、intentionについて
  • 対応したissueとそれの実装とテストコードの説明
  • 困った時はslackチャンネルの#kontributorsで質問しましょう
  • issueに関しては、youtrackを漁りましょう
  • githubでPR投げたら気長に待ちましょう。なぜならJetbrainsのメンバーは忙しいから
  • 日本のもくもく会についても言及

カンファレンス終了後にトライしたこと

カンファレンスはとても熱量が高く、特に影響を受けた「How to Kontribute」、「Two Stones, One Bird: Implementation Tradeoffs」セッションに関連した以下の2つにトライをしました。

僕もしらじさんのようにInspection、Intentionにコントリビュート!と思い、Kotlin issueを眺めていたのですが、対応できそうなものがなかったため上記のトライをしました。またカンファレンスの中でもKotlinイン・アクションが話題に上がっていたため、気になり読んでみましたが、とてもボリュームがあり高度なサンプルも多く勉強になりました。特にトリプルクオート文字列を用いることによってエスケープ不要となる正規表現とスター投影のMutableList<*>MutableList<Any?>の違いについて言及されて面白かったです。

まとめ

カンファレンス自体は本当に有名人が多く、Dmitry Jemerovさんと一緒に写真を撮ってもらったことが最高の思い出です。カンファレンス動画は近日公開されると思いますので詳細はそちらをご確認ください。いつか日本でもKotlinConfが開催されるといいですね!それでは楽しいKotlinライフを!

CakePHP3.5.5にアップデートしました!

f:id:itosho525:20170430222524j:plain

こんにちは。先日乃木坂46の東京ドーム公演に行ってきた@itoshoです。控えめに言って最高でしたし、こんなにも人を幸せに出来るアイドルって尊いなと思いました。

というわけで、少し時間が空いてしまいましたが、例によって、CakePHPのアップデートを行いましたので、内容を共有させていただきます!

続きを読む

CakePHP3.5.3にアップデートしました!

こんにちは!M-1 2015, 2016, 2016 準決勝を今更見ました!金城 ( @o0h_ )です

https://www.amazon.co.jp/dp/B01NBACQQPwww.amazon.co.jp

ちょっと遅くなりましたが、掲題の通り先日3.5.3へのアップデートを完了しておりますので、
例によって意訳 + 個人的な感想で振り返ってみます〜
CakePHP 3.5.3 Released — Bakery

続きを読む

PHPカンファレンス2017で登壇&企業ブースを出しました!

こんにちは!2017年12月21日発売の『メダロット クラシックス 20th Anniversary Edition』を買おうかガチで悩んでいる高野(@fortkle)です。
第1作目から第5作目までが収録されており、ヒカルから始まってイッキ、コイシマルと懐かしいストーリーをお楽しみ頂けます。あなたはカブトver.?それともクワガタver.?

さて、本題。

PHPカンファレンス2017

先週末に開催された国内最大のPHPのイベント「PHPカンファレンス2017」。 今年もコネヒトから何名か参加させていただいたので、イベント当日の様子をレポートしたいと思います!

企業ブースを出しました!

昨年に引き続き、今年もゴールドスポンサーとして、ブースを出展しました。コネヒトが運営しているママリについて、「知ってます!」「奥さんが使っています!」というお声をちらほら頂けたのが非常に嬉しかったです!

f:id:fortkle:20171010161744j:plain (ブースの準備が完了し気合の入るエンジニア陣)

LTに登壇しました!

ブース出展に加えて昨年に引き続き、今年もLTをさせていただきました!
例年通りLTではネタ枠が豊富な中、「良いテストデータ、悪いテストデータ」という割と真面目系な内容でお送りしました。詳細は発表資料を貼っておくのでそちらをご覧ください!

f:id:fortkle:20171010162748j:plain

気になったセッションなど

PHP7もだんだんと浸透してきたからか、最近のPHPでは「型」を意識した開発をすることが普通になってきました。 新原さんの「型を意識したPHPアプリケーション開発」というセッションではそういった開発への導入部分が丁寧に解説されていて非常にためになりました。

また質疑応答で出ていましたが、「ドメインを表現した型からプリミティブな型への変換」について、コネヒトではデータベースへの出し入れやjsonにシリアライズするケースでCakePHP3の Type という機構を活用して自動的に変換されるようにしています。 詳細については以前公開した下記ブログが参考になると思うので興味がある方はぜひご覧ください。

tech.connehito.com

次に、今回のカンファレンスで特徴的だったのはDocker関係のセッションでしょうか。それぞれ領域は違えど、Docker関係のセッションが3つありました。 最近コネヒトでも開発環境がVagrantからDockerになり、非常に快適に開発することができています。 こちらについても詳細は以前公開した下記ブログが参考になると思うので興味がある方はぜひご覧ください。

tech.connehito.com

おわりに

今年も充実した内容のセッションばかりで、参加メンバー一同楽しかったです。 運営スタッフの皆様本当にお疲れ様でした。また参加者の皆様、たくさんブースにお越しいただきありがとうございました!

以上、高野でした!

コネヒト開発合宿(秋)に行ってきました!

こんにちは!!今期のアニメは何をみるかまだ決めていない結城(@super_manner)です!! コネヒト開発部の面々、先日開発合宿なるものに行って参りました。
本エントリーは合宿の様子、成果物をお届けできればいいなと思い執筆しております 🙆

行き先

開発合宿でおなじみの土善旅館さんにお世話になりました。 平均して都内から2時間程度で到着します。 f:id:supermanner:20171004192311p:plain

1日目

1日目のタイムスケジュール

  • 15:00 チェックイン
  • 15:30 開会の儀@合宿委員
  • 15:40 開発
  • 19:00 晩御飯
  • 21:00 開発
  • 以後好きな時間に好きに就寝

1日目の様子

初日はまず、旅館の方からの説明と、合宿委員による説明がありました。一通り説明をきいたあと、さっそくもくもく開発タイムの始まりです。 今回利用させていただいたのはこちらの大部屋でした。

f:id:supermanner:20171004192349p:plain
開発を行う大部屋

晩御飯までみっちりもくもく開発をおこないました。 さて、19時になったのでそろそろ御飯の時間がやってきます!

f:id:supermanner:20171004192400p:plain
開発に夢中なのでslackで通知

空腹が満たされたところで、引き続き開発を行いに大部屋へ。 まだ1日目ということもあり、みんな比較的リラックスモードで開発・雑談・お酒を楽しみました!

f:id:supermanner:20171004192534p:plain
金曜ロードショーを見ながら開発に勤しむエンジニア伊藤

2日目

2日目のタイムスケジュール

  • 好きな時間に起床して開発
  • 13:00 お昼ごはん
  • 15:30 開発
  • 19:30 晩御飯
  • 20:30 開発
  • 以後好きな時間に好きに就寝

2日目は好きな時間に起床して、それぞれで開発をスタート!

f:id:supermanner:20171004192612p:plain
旅館の猫さん

さて、お腹が減ってきたところで本日のお昼ごはんです。 CTOの鶴の一声で、とんかつに決定しました。秋の気配がぐっと濃くなった昼下がりにてくてくと歩くこと15分。行き先はこちら 💁

f:id:supermanner:20171004192641p:plain
ボリューミーでジューシーなとんかつ!!
とんかつで満腹になったので、徒歩15分はちょうどよい運動になりました。土善旅館がある笹川は自然が多く、 また町の方々も非常に温かい方が多くいらっしゃるのでお散歩中も気持ちがいいです。

腹ごしらえを終えて、またひたすら開発に打ち込みます。 翌日が発表なので最後の追い込みモードな方が多かったですね!

最終日

最終日のスケジュール

  • ~11:00 開発
  • 11:00 成果物発表
  • 14:00 チェックアウト

成果物発表会

前回と同じく、安達が作ったドカベンv2 で順番を決めました。

成果物に対して各人からコメントを頂いたので資料がある方は資料を添えてお伝えしたいと思います。

1. AndroidのタグView作り

今回はAndroidママリアプリの機能改善に繋がるタグViewライブラリを作りました。まだまだ改善する点は多いのですが、なんとか合宿期間内に作りきって一定の成果を収めることができて嬉しいです。今後もアプリ改善に繋がる開発を継続していきたいです。(富田)

2. request-header-switcherの話

@fortkle です!
日頃から開発でUAやRequestHeaderの一部をいじることが多いのですが、公開されているChrome拡張の中で好みのものがなかったので作成しました。
特にURLで影響範囲を限定できる機能が非常に使いやすくて便利です!
アーキテクチャとしては裏側の設定ページで React+Flux Utils を使ってみました。少し整えて Chrome拡張としてストアに公開したいと思います!

3. 初めての蛇語

開発合宿なので普段業務で書いているのとは別の技術要件を使いたいなと思い、Pythonで最近ハマっている某ゲームの便利ツールを作成しました!!
Djangoを始めとするPythonの様々なフレームワークを組み合わせて作成することで、言語による得意分野みたいなものの片鱗を味わえた気がします。
また、Python書きやすいな〜ッと思ったので日々の雑用を快適にするツールを作るのに使っていきたいです(結城)

4. Slack Interactive Message Buttons Oasobi

SlackのInteractive Message Buttonsの機能を社内ツールに投入したいなとかねてより目論んでおり、雑なbotを作ってみた次第です。

  1. 全体の流れを理解する
  2. 以前に触った時に不明だった「状態の引き継ぎ」(差分アップデート)を突破する
  3. "それっぽい"インタラクションを触れるところまで持っていく

というのを目標とし、「みんなでジャンケンをする」というものをアウトプットとしました。 (金城)

↓demo f:id:o0h:20171004225109g:plain

5. AWS環境における秘匿情報を良い感じに管理したい

CTOのtatsushimです。 インフラ業務の中で、AWS環境における秘匿情報(secret key等)の扱いにおいて以下の課題がありました。

  • Secure Stringの手動管理が辛い
    • オペミスコワイ
  • 既存との差分をそのファイルで管理、追加したい
  • でもそれを管理するツールがない

そこで、上記の課題を解決するツールをgolangでつくってみました。 まずは社内で利用して、良さそうであればOSSとして公開したいと思っています!

6. 妊娠〜出産までに準備するものリスト

デザイナーのきよえしです。
私は個人的に「ユーザーさんの課題を解決するwebコンテンツを
自分で作ってみよう」というテーマを持って合宿に挑みました! その中で初めてCakePHPを学習してみたのですが、2〜3日触ると簡単なwebコンテンツだったら作れるんじゃないかという気にさせられました。 調子に乗って今後もがんばってみようと思います🙌

f:id:connehito:20171005101959g:plain:w200

7. jsでwebアプリ作ってみた

kichikuchiです。 普段iosのエンジニアをしているんですが、せっかくの機会だったのでwebアプリを作ってみました。 内容は趣味の大相撲に関するもので、node.js, expressを利用しました。 今回は時間の都合でフロントをiosで作成したのですが、次回はreactに挑戦したいと思っています!

8. 半年前に書いたツールの修正

ry0_adachiです。 前回の開発合宿で作ったCLIツールの設計があまりにも酷すぎたので設計を見直して修正しました。 あとはくじ引きツールのバージョンアップとかSlack OAuthで遊ぼうとして挫折したりしていました 😇

今回の開発合宿の学びは「事前準備は怠らない」でした。

9. golangでツールを作ってみた

インフラエンジニアのshnagaiです。 今回の開発合宿では、golangを学びがてら、ECRリポジトリのdockerイメージを削除するツールを作りました。 ※コードは、やってみたレベルなので機会があれば公開しようと思います。

10. Pon Pon Pain

サーバーサイドエンジニアの itosho です。 最近の楽しみは乃木坂46の東京ドーム公演です。 僕はお腹が弱い(Pon Pon Pain)ので、今回の開発合宿ではTokyo Toiletというサービスをつくりました。(まだ途中)

11. API通信処理のFramework化

エリアA/ヤグラA-/ホコB+の田村です。 今回の合宿ではmacOSアプリを作ろうと思ったのですが作業を始めて1時間で飽きたのでiOSのビルド時間の短縮化に挑戦してみました。 手段としてはプロジェクトのコードの一部をframework化してCarthageで入れられるようにしました。 framework化したコードはClean Architectureで言うところのDataStore/Entity辺りで、変更の多いViewから一番遠いところを対象としました。 また、framework化することによってData層にPresentation Logicが漏れてこないようにすることも目的だったりします。 CocoaPodsは経験があるのですが、Carthageに対応したframeworkを作ったのが初めてだったのでとても良い経験になりました。

さいごに

今回合宿するにあたって調整してくれた合宿委員さん達、ありがとうございました!
普段の生活でここまで開発ばかりをする機会は中々持てない人が多いと思うので、
そういった時間が取れたことや、自分含めメンバーがどういう分野に興味を持っているのかがわかって面白かったことなどなど、 実り多き良き3日間でした。
この機会で得たものを、普段自分たちが作っているプロダクトをよりよくするスパイスにしていけたらいいな、と思います。 本エントリーを読んでくださっている皆さんも、もし機会があれば行ってみてください。
そして面白いものができたら発信してくださいね!

f:id:connehito:20171004221731p:plain

土善旅館さん、本当にお世話になりました!

Amazon ECS ScheduleTaskで実現するスマートなDockerベースのバッチ実行環境

こんにちは。インフラエンジニアの永井(shnagai)です。

コネヒトでは、開発環境に続き、続々と本番サービスにもDockerを導入しています。 今回は、中々運用が大変なcronでスケジュール管理するような定期的なバッチ処理を、Amazon ECSのScheduleTaskを使ってDocker駆動な環境で構築した話です。 他の方法との比較やどのように実現しているのかについて紹介したいと思います。

今回対象とするバッチの種類

今回対象とするバッチ処理は、俗に言うスケジュール系のバッチ処理で、毎日00時00分や10分毎にサイクル起動等、事前に定義した時間に正確に動くことが期待されているものです。 ※ジョブキュー形式のバッチだと、AWS BatchやEBのWorkerもしくは、SQS + Cron on EC2で処理するほうがスマートかと思います。

実行方式の選定

上記要件のバッチを実現する基盤として、下記を検討しました。 基本的には、開発環境はDockerで運用しているのでその資産をうまくいかせるシンプルなアーキテクチャを求めていて、バッチの為だけに新規のインフラ環境を用意するみたいな事はしたくないという前提がありました。 ざっくりですが、pros&consをまとめていたので書いておこうと思います。 ※完全に個人の主観が入っていますので、参考程度に。

Cron on EC2

pros:
  • 運用方法が枯れており、安定感はあるので他の方法が取れなかったらこれ
cons:
  • EC2インスタンスの運用が必要
  • crontabの登録が面倒でジョブスケジューラ系のツール入れるとしても運用が。。
  • 実行環境を作らなければならない (開発環境はdockerなのでそれと同じ実行環境をプロビジョニングツールなどで作らないといけない)

Lambda

pros:
  • スケジュール実行は出来る
  • 手軽に実装出来る
cons:
  • 最大の実行時間が、300秒なので不安がある
  • 利用できる実行環境(言語)が制限される。今回はPHPで書かれたプログラムを使いたかったので大変

AWS Batch

pros:
  • バックエンドがECSなので、ECSの資産を流用出来る
  • コンピューティングリソースは全く管理する必要はない (vCpuとメモリをジョブ定義に指定するだけなのでECSでいうクラスタ管理も不要)
cons:
  • 肝心のスケジュール起動は出来ない(あくまでもジョブキュー系の処理をするためのもの)
  • AWS SAにお聞きしたら、大規模データのバッチ処理みたいな使い方を想定されたサービスで、cron代わりといった用途には向かないとの事。

Amazon ECSのサービス起動しているコンテナ内にcronを定義して実行

pros:
  • ECSの資産をそのまま流用出来る
  • CMD句に指定する起動シェルでcrontabの登録をすればバッチ毎にコンテナを作って実行するアーキテクチャで出来そう
cons:
  • デプロイ処理時に、コンテナを破棄して作り直すのでバッチ実行中にデプロイが走るとバッチが強制終了される
  • バッチ全体のスケジュールを一望出来ないので、バッチ管理台帳みたいなものを用意することになりそう

Amazon ECSのScheduleTask

pros:
  • cron記法でスケジュールを定義する事が出来るのでわかりやすい(裏では、cloud watch eventのルールが作られてい る)
  • コンテナ起動時に、指定したDockerイメージをpullするアーキテクチャなので、デプロイ時に実行中のバッチに影響を与えることがない
  • ECSクラスタとしてホストを固定出来るので、docker pull時にキャッシュが効き起動が早い(LambdaやAWS batchは毎回インスタンスが変わるのでpullにそこそこ時間がかかる)
  • 既存のDockerイメージの資産を使える
  • 標準出力をcloud watch logsに送ることで起動処理の失敗等を、AWSコンソールから気軽に確認出来る(デバッグに役立ちます)
cons:

特に減点になるような要素なし。

  • 「枯れてない」「使ったことない」というところは少し気になりましたが、ECSの知見が溜まっておりイケるという感覚があったので採用に至りました。
  • しいていうなら、ScheduleTaskのAPIがなく、手動で登録しなければいけないところくらい(もしかしたら自分が探せてないだけかもしれませんが)

バッチの組み方

Amazon ECSのScheduleTaskは減点ポイントが特になく、webで運用しているECSの資産と知見も活かせるといった理由で採用が決まりました。 ここでは、Amazon ECSのScheduleTaskで1本のバッチを動かすのに必要なものについて書こうと思います。 このバッチ環境を作るには下記の4つの要素を準備する必要があります。 ECSの用語に慣れていないと複雑に感じるかもしれませんが、一つ一つ見ていけばそんなに難しいものではありません。 ※下記のスライドで、ECSの用語について説明しているので参考にしてもらえるといいかもしれません。

Dockerを本番導入するにあたり得た知見 // Speaker Deck

クラスタ
  • Dockerコンテナを動かすEC2インスタンスの集合体。冗長構成を取るためにmultiAZで2台用意しておくのが無難でしょう。
タスク定義
  • バッチ実行コマンドや環境変数を定義します。(dockerコンテナの起動に必要な情報を定義するイメージ)
  • バッチ一つにつき一つのタスク定義を用意します。
  • CMD句にバッチの実行コマンドを記述して、一つの処理だけを実行するコンテナとして定義します。(終了時にコンテナは破棄される)
  • 弊社では、バッチのタスク定義はterraformで管理していて、開発者がPRを投げるような体制を取っています。
Dockerイメージ(ECR)
  • タスク定義にセットする、バッチが実際に動く実行環境のDockerイメージを用意します。(フレームワークやミドルウェアなどの実行に必要な環境とソースコードがパッケージングされたDockerイメージ)
  • dockerhubでも良く、クラスタ上のホストからpull出来ればどのリポジトリでも構いません。
クラスタ内のScheduleTask
  • タスク定義毎に、1つのスケジュールを用意します。

実際の設定方法は、下記の公式ドキュメントがわかりやすいのでご参照下さい。 docs.aws.amazon.com

アーキテクチャ

デプロイを絡めた全体のアーキテクチャは下記のようなイメージになります。

f:id:nagais:20170913161501p:plain

開発フロー

ステージング環境の例ですが、上の図の青い線の部分を説明するとざっくり下記のような流れになります。

開発環境(Docker)でバッチの開発
↓
GithubでPR後に、masterマージで自動的にDockerビルド&ECRへデプロイ
↓
次回のScheduleTask起動時から新規のDockerイメージ(最新のソースコード)でバッチが動く

ScheduleTaskの画面

個人的には、このScheduleTaskの画面は気に入っていてジョブスケジューラ入れずともこの画面が使えるのは中々のメリットだなと思っています。

  • スケジュールがGUIで一望出来る(コメントも記入可能)
  • Enable,Disableも可能

f:id:nagais:20170913153458p:plain

エラー通知

スケジュールバッチは基本的に、必ずその時間だったり間隔だったりで動くことが期待されているので、エラーがあったら受動的に気づける必要があります。(クリティカルなものであればあるほどリアルタイムの検知は必須になります) アプリケーションのエラーは、弊社だとSentryで取得していますが、Dockerコンテナ起動時のエラー等アプリケーション起動以前のエラーが起きた場合にも、Cloud Watch Logs + SNS + Lambdaを使ってslackにリアルタイムに通知が飛ぶようにしています。 こうすることで、バッチが起動しなかった際は確実に気づける体制を作っています。

Lambdaは初めて触ったのですが、BluePrintという便利なテンプレートが用意されていたので比較的苦労なく実現できました。 コンテナで意図しない標準出力/標準エラー出力があると、下記のようにslackに通知が来ます。

f:id:nagais:20170913161719p:plain

※cloud watch logsにログを送るためには、タスク定義に下記のような設定が必要です。(dockerのログドライバを使う) ※事前にロググループを作成しておかないとコンテナ起動に失敗するので注意が必要です。

f:id:nagais:20170913160617p:plain

これは出来ない

  • ジョブスケジューラにあるようなジョブチェーンの実行やリトライは出来ないです。(出来るようになるとうれしい)
  • リトライに関しては、エラー通知トリガでRunTaskを実行させてあげるのが今のところ一番よさそう。(そこまではやってなくて今のところはリランしたい場合は、手動でのタスク実行を行います)

docs.aws.amazon.com

まとめ

今回は、運用が辛くなりがちなスケジュールバッチ(cron)をDocker環境で動かす事例を紹介しました。 Dockerベースにすることで、各環境差異でバッチがこけるリスクを回避しつつ、ジョブスケジューラを構築せずとも、AWS ECS Task Schedulerの見やすいビューワーでバッチを一覧して管理出来るというのは中々おすすめな構成です。エラーに関しても、cloud watch logsで拾えるので、ほとんど開発や構築なしにAWSマネージドサービスにどっぷり使ってバッチの実行環境を作ることが出来ます。 今後もっといいものが出てくるかもしれませんが、Dockerでバッチジョブ実行環境としてはかなり有力な選択肢になるのではないでしょうか。 スケジュールジョブの環境をどうしようか悩んでいる方がいたら一度気軽にお試ししてもらえるといいかもしれません。