クラウドワークス エンジニアブログ

日本最大級のクラウドソーシング「クラウドワークス」の開発の裏側をお届けするエンジニアブログ

Amazon LinuxのEOLに伴いバッチをサーバレス化しFargateに移行した話

はじめまして、2020年3月に中途入社したSREチームの @bayashiok です。

今回は入社後、Fargateでサーバレスバッチ基盤を構築した話を書いていきます。

目次

経緯

日々のSREチームのタスクの中で、EOLとなるソフトウェアの状況を定期的にチェックしているのですが、今回 Amazon Linuxが2020 年 12 月 31 日にEOLを迎えるということで、Amazon Linux上に設置されているシステムを移行する必要がありました。

Amazon Linux2に移行するという案もあるのですが、このままでは負債(後述記載)が残ってしまうためAmazon Linux上に置いてあるバッチの整理と移行バッチのFargate化を行いました。

Fargateを選んだ理由

Fargate化することのメリットは次のようなものがあげられます。

1. リソースの見積もりがCPU/Memoryだけですむ

EC2側で構築する場合はリソースキャパシティを考慮し構築を進めないといけません。 しかしFargateの場合はタスク定義の単位で自由に cpu/memory の変更が可能となります。

※ただしcpuはvCPU 0.25〜4の範囲、memoryは指定したcpuパラメータによって範囲が決まりますが0.5〜30GBの範囲に限られます。詳しくはこちら

2.スケーリングを考えなくて良くなる

既存のサーバの中には多くのバッチを抱えているサーバもあり、 EC2のままAmazon Linux2に移行したとしても全体のキャパシティ状況をモニタリングし 時間と共にスケールさせていかないといけない可能性がありました。

Fargateを利用すればこういった事を考慮せずに、1. で述べたようにバッチ毎にリソースのスケーリング管理が可能になります。

3. セキュリティレベルの向上につながり管理負荷が減る

EC2で運用する場合は、OS やミドルウェアのバージョンアップやセキュリティパッチの適用などの作業が発生し、運用負荷が高くなります。

しかしFargateの管理・運用は AWS で行われ、OS や Docker Engine, ecs-agent 等のバージョンアップやセキュリティパッチの適用もこの中に含まれるため、セキュリティリスクが減ります。

こういった理由からFargateへの移行がチーム内で決定しました。

現行システムで発生している問題点の解消

Fargate(サーバレス)化することによって現行システムで発生している問題点も解決していく必要がありました。

レガシーなバッチのあるあるなんですが、バッチの中には個人ユーザのcrontabで動いたままのバッチや、仕様が正確に把握できなくなってしまったもの、モノリスになりすぎてバッチ間の依存性がわからなくなってしまったものなどの負債が存在していました。

実際移行をした後にサーバの停止を行なったのですが、生きていたバッチがありアラートが発生したものもありました。(バッチ自体は再実行すれば問題ないものだったので影響自体は特にありませんでした)

そのためFargateへの移行を機に依存性などを再整理し、構成図の作成やコンテナ化を行いコード管理ができるようにするなど有るべき姿に整えてきちんと管理できるようにして行きました。

構成

次に、実際に移行した後の構成を解説していきます。

f:id:bayashi_ok:20200717170005j:plain

はい、よくわからないですね。 順番に説明していきます。

FargateのトリガーとしてRundeckを採用

f:id:bayashi_ok:20200717170135j:plain

今回Fargateのタスク実行のトリガーには弊社でジョブスケジューラとして使用しているRundeckを採用しました。 Fargateにはタスクのスケジューリンング機能が実装されておりますが今回Rundeckを使用したのはいくつか理由があります。

理由1: バッチ実行が行われる場所でログを見たかった

Fargateはコンテナのログ設定でawslogsが選択できCloudWatch Logsにログが出力されます。 しかし aws-cliecs-cli ではコマンド実行後ログが標準出力で返ってこないため都度CloudWatch Logsにあるログを見なければならず、バッチが実行されている場所ですぐにログが見れるようにしないとバッチを使う側にとっても負荷になってしまいます。

理由2: ジョブ失敗やSlack通知の仕組み、リトライ方法やジョブ連携などの作り込みを簡単にしたかった

これらの仕組みを実装するには CloudWatch EventsやLambda、Step Functionsなどと連携し処理を行う必要がありそうでした。 しかしこれらを全て実装すると作り込みが必要な上に全体像がわかりづらくなってしまいそうでした。

そういったものを解消するため今回Rundeckをトリガーとすることに決めました。

ただ先ほど書いた以下の部分はRundeckだけでは実現ができませんでした。

コマンド実行後ログが標準出力で返ってこないため都度CloudWatch Logsにあるログを見なければならず、バッチが実行されている場所ですぐにログが見れるようにしないとバッチを使う側にとっても負荷になってしまいます。

そのため今回h3poteto氏が作成したecs-taskを使用させて頂きました。

ecs-taskとの連携について

ecs-taskは解決できなかった問題点を以下のように解決してくれます。

  • CloudWatch Logsに出力されたログを標準出力でみれるため、RundeckのGUI上からエラー内容や実行内容が閲覧可能になる
  • ジョブ終了コードが取得できるので、Rundeckでのエラー判定処理の連携が可能になる

これらの処理によってRundeckと連携しGUI上で簡単に実行結果(Succeesded,Failed)とそのログが見れるようになりました。

f:id:bayashi_ok:20200717170340p:plain

また今回ecs-taskはRundeckのコンテナとは別にwrapperコンテナとして立てたのですがそれには以下の理由があります。

  • Fargateのタスク実行はコマンドが複雑で多くのパラメーターを付与しないといけないのでアプリケーションエンジニアに使いやすいように簡易化した
  • rundeckコンテナにecs-taskを入れてしまうとecs-task周りの処理を変更する時にコンテナの再起動が必要となりバッチ全体に影響が出てしまい運用上好ましくなかった

なお、今回は弊社の都合上 ecs-task を使用しましたが上記こだわりがなければ aws-cliecs-cli を使用すれば同様にタスク実行が可能になります。

デプロイ

次にデプロイ方法について解説してきます。 デプロイについては先ほど紹介したwrapperコンテナのデプロイ、タスク実行させるためのバッチのデプロイの2箇所が存在します。

1. wrapperコンテナのデプロイ

f:id:bayashi_ok:20200717170440j:plain

デプロイの流れは次のようになります。

  1. wrapperコンテナを管理しているGitリポジトリを変更したら、PRを出してレビュー
  2. マージされたらCircleCIがDockerイメージのビルドとプッシュを実施
  3. Rundeckがdocker pullするバッチを定期実行してイメージを最新化

もし修正後、緊急で最新化しないといけない場合などは手動でバッチを叩けば最新化してくれます。

2. バッチのデプロイ

f:id:bayashi_ok:20200717170532j:plain

こちらは3. 以外は先ほどと同じ流れになります。

  1. 対象バッチを管理しているGitリポジトリを変更したらPRを出してレビュー
  2. マージされたらCircleCIがDockerイメージのビルドとプッシュを実施
  3. Fargateがタスク実行する際に最新のものを取得しバッチを実行

また、最近では弊社でもGithub Actionが使われ出したためバッチによってはCircleCIの部分がGithub Actionになっていたりします。(この辺の使用については開発者に任せています。)

Fargateタスク実行について

f:id:bayashi_ok:20200717170551j:plain

こちらの構成はほぼ一般的なものになっていると思います。

ecs-taskで実行されたタスクはECRのコンテナイメージとタスク定義を読み込みコンテナ内で実行されます。 なお、ECRはproduction環境もstaging環境も同じECRを使用しているため環境変数などはSSM Parameter Storeに 、秘匿情報などはKMSで暗号化されたものを使うようにしています。 詳しくはこちらの記事をご参考ください。

移行後の総括

というわけで上記構築後、何個かのバッチをサーバレス化して動かしておりますが、特にこれと言った問題は起きておらずスムーズに移行することができました

よかった点

  • 移行にあたりバッチ単位での権限付与ができた
  • 移行したバッチが全体として何をやっているのか理解ができた、またいらない部分を削除できた
  • 移行前のモノリスサーバを停止することができた

悪かった点

  • バッチの起動時間が伸びてしまった

ここはFargateでのデメリットでもよく挙げられていますが今までは常時起動のEC2上で動いていた為バッチの処理時間のみが実行時間となっていましたがFargateが起動停止する時間を考慮しなければならず実行時間が伸びてしまいました。 具体的には今まで1分ほどで動いていたバッチがFargateでは2,3分かかるようになりました。

  • Fargateがタスク実行を行うまで疎結合

ここは言葉通りで今回これらのリソースをTerraformで作成していたのですが、それらが組み合わされるのはタスク実行を行う際で、クラスターやVPC、SGなどタスク実行するまではこれらを紐づけるような項目がなく疎結合になってしまいます。

AWSコンソール上でもタスク実行を行う際はこれらを選択しないといけないのですが、手動で実行すると絶対これ事故るだろうwと思いました。 なので個人的にはAWSコンソール上でタスク実行するのはあまりやりたくないです。

苦労した点

ここは個人的に苦労した点です。

  • DockerもECSもFargateもきちんと触ったことなかった

前職はオンプレやEC2が中心だったのでDockerやECSは本や勉強会などで知識を身につけていた程度で実際に触る機会があまりありませんでした。 そのためDockerfileの書き方や、local環境とFargate上での実行方法の違い、ECSの運用の仕方、CircleCIでのCI/CDの仕組みなど全てが手探り状態で理解と実装にかなり時間がかかってしまいました。

同じSREチームの人たちにフォローしていただいた部分が大きく改めて感謝を述べさせてください。本当にありがとうございました。

今回SSM Parameter Storeを使用して環境変数の取得を行なったのですが、今ではAWSがいろんなサービスと連携しFargateなどは比較的簡単にパラメーターを取得できるようになっていますが、Dcokerコンテナ内で環境変数を使用するためawscliを使用しsedで設定ファイルに置換するような処理を組み込まないといけないパターンもあり、使うサービスや歴史によって取得方法が異なっていたため初めはかなり混乱しました。

  • IAMの管理が必要最低限の運用になっている

これはとても良いなと思った点でもあるのですが、Terraformで管理していることもありIAMの権限が必要最低限できちんと管理されているため使用するサービスになんの権限が必要なのかきちんと洗い出し付与する必要があり苦労しました。

  • Terraformの構成理解に時間がかかった

Terraformの記述自体はそこまで苦ではありませんでしたがCrowdWorksの既存のTerraformの構造を理解するのに時間がかかりました。

と、いうのもCrowdWorksのTerraformは絶賛リファクタリング中でコードの中には古い書き方と新しい書き方が混在し、そこから今現在のベストプラクティスを導き出さねばならなかったからです。

  • sleepを入れないとうまく動かないバッチがあった

これはどちらかというとDatadogの仕様になると思うのですが、 今回DatadogのDogStatsDを使って定期的にDBのリソース情報を取得しメトリクス を送信するというジョブを移行しました。

しかしバッチ実行後、sleepを入れておかないとデータがうまく送信できないという事象が発生しました。 確かに公式サイトのDogStatsDのドキュメントにも常にsleepが入っていたりしたのですがそこについて触れられている記述はありませんでした。

おそらく処理後すぐに停止してしまうようなサーバレスなものには少し余裕を持たせておく必要があるのかなと感じました。(移行前のバッチはなぜかsleep処理が入っていなかった)

今後の課題

先にブログに書く形になってしまいましたが、 サーバレスバッチ基盤は現在まだ必要な人にしか情報共有ができていない為、社内資料を再度まとめ社内勉強会を開催し、追加・編集が容易になるように周知していく必要があります。

また管理上からやはりSREが手を入れていかないといけない部分も存在するのでコミュニケーションをとりサポートしていけるように進めていきたいと思っています。

最後に

前回のブログが@ysk_118 さんの退職エントリーだったので流れ的には入社エントリーを書こうかなとも思っていたのですが、タイミングも良かったためサーバレスバッチ基盤の構築の話を書きました。

入社後1ヶ月も経たずリモート業務になってしまい何かと苦労する点も多かったですが、CrowdWorksはコロナ前から フルフレックス・フルリモート制 をとっていたため比較的スムーズにリモートワークに移行できていた気がします。

また優秀なエンジニアが多く技術やサービスにおいて一人一人がしっかりと考え発信できる場があるため非常にいい会社だなと思いました。

さらにSREにおいては、日々の改善業務やSLIのチェック、ドキュメントやコードの最新化や管理などきちんとSRE業務を行なっていて本当に見習わないといけない部分が多く転職して良かったなと思う分、自らがCrowdWorksに還元できるように頑張っていきたいという気持ちを強く持ちました。

こういった文化が整っているのも現在Crowdworksで働いているメンバーや@ysk_118 さんはじめ過去にCrowdworksに関わったメンバーの蓄積の賜物だと思っています。

とはいえまだまだ課題も多く残っており、エンジニアやマネージャーの人数も決して多いわけではないので入社してくれるメンバーを随時募集しております。

We Are Hiring!

という事で常套句になりますが、CrowdWorksではエンジニアを積極募集中です。 個人DMなどでも良いので少しでも興味のある方は是非お声掛けください。 気軽に話だけ聞きたいという方も大歓迎です!

www.wantedly.com

www.wantedly.com

© 2016 CrowdWorks, Inc., All rights reserved.