こんにちは!株式会社フィードフォース新卒エンジニアの@kielzeです。最近は会社から支給されたMacBookProのTouchBarにsushiを流したりしています。
フィードフォースには新しい技術に積極的に挑戦できるような環境があります。そして、挑戦した結果がよいものであれば、本番環境でもガンガン使われます。
若手も新卒も関係無く、全てのエンジニアがその挑戦権を持っています。
今回は、先輩エンジニアである@tsubさんが、当時新卒1年目で社内で使われているバッチサーバーのDocker化に挑戦した話をしようと思います。
ちなみにtsubさんはとても知識が豊富で何を聞いても答えてくれるので、とても頼もしい先輩です!
Dockerを導入した経緯
フィードフォースでは、データフィードマネージメントサービス「DF PLUS」を提供しています。
このサービスの裏側では、お客様から頂いた商品データなどを用いてデータフィード(広告に必要なデータを媒体ごとにフォーマットしたもの)を作成するアプリケーションが動いています。
そのアプリケーションの特性上、ある時刻になったらあるお客様のマスターデータを取得し広告を配信したい媒体のサーバーに取り込ませる、ということをする必要があるのですが、その処理をバッチ処理として行っています。
以前はバッチ処理の登録をcrontab + wheneverを用いて行っていました。しかし、それだと1つのサーバーが落ちた際にそのサーバーのcrontabに登録されているバッチ処理が全て動かなくなってしまうという問題があり、そこが単一障害点となってしまっていました。
そのため、あるサーバーが落ちても他のサーバーがcronを実行でき、かつ1つのサーバーに依存せずどのサーバーでもバッチ処理を動かせるようにすることが課題でした。
その課題を解決するために用いたのがDockerです。
Dockerとバッチ処理は相性が良い
Dockerを用いることで、バッチ処理をする時にコンテナを立ち上げ、処理が終わったら消すということが出来ます。それにより、バッチ処理の実行後に残ってしまう不要なデータをコンテナごと削除することが出来ます。
また、バッチ処理を行っていない時にはコンテナは存在しないので、コンテナが立っているかを監視するだけでバッチ処理が動いている状況を知ることが出来ます。
EC2 Container Service(ECS)
ECSはDockerコンテナを簡単に実行、停止、管理できる非常にスケーラブルで高速なコンテナ管理サービスです。ECSにはいくつか独自の概念があります。
Cluster
クラスターはタスクが実行されるEC2インスタンスの集合体
Service
常駐化させたいタスクのこと
Task
タスクはインスタンス上で実行されている実際のコンテナ
Task Definitionでタスクで使うコンテナ及び周辺設定の定義をしている
Scheduler
クラスターの状態を見てタスクを配置する
Manager
クラスターのリソースとタスクの状態を管理する
単一障害点を取り除く
ECSのSchedulerを用いることで、落ちたサーバーのバッチ処理を他のサーバーに割り振ることが出来ます。そのため、あるサーバーが落ちてしまっても他のサーバーで補うことが出来ます。
実際にDockerでどう動かしているのか
構成の全体像と、ECSの内部は以下の図のようになっています。
バッチ実行システム構成図
ECS内部の詳細
ECSの内部にjob-kickerクラスタを設置(hakoの利用)
hakoはクックパッド社eagletmtさん謹製のDockerコンテナのデプロイツールです。ymlで設定ファイルを書くことで、hako deploy hako.yml
みたいな感じでDockerのデプロイをすることが出来ます。
これにより、aws-sdkだと使いづらい操作を開発者のCLI上から簡単に行うことが出来ます。
このhakoをわざわざECSで複数起動しているのは、オートスケールアウトをするためです。
hakoにはタスクを立てることが出来るoneshot
という機能があるのですが、このoneshotを使うことでタスクを立てる際にhakoが色々とよしなに面倒を見てくれます。
例えば、バッチサーバーなので大容量のファイルをメモリに展開した時など、瞬間的に使用するリソースが増える場合があります。この際、オートスケールアウトのために通常AWSがサポートしているCloudWatchのアラームを使うと、スケールアウトが間に合わずバッチが動かせない、もしくはバッチ処理が遅くなる可能性があります。
そこの部分をhakoに任せることで、バッチを動かす際に適切にスケールアウトしてもらうことが出来ます。
cronの代替として、CloudWatchEvents + Lambdaを使用
cronの代替としては、CloudWatchEvents + Lambdaが最高だったそうです。
CloudWatchEventsにはスケジューラーがあります。それを簡単に利用するために管理画面を作成し、スケジュールと何の処理をするのかを登録することが出来るようにしています。
流れを説明すると、まずCloudWatchEventsがスケジュールされた時刻にLambdaをキックし、ECSにhakoタスクを立てます。立ち上がったhakoタスクはバッチ処理を実行するアプリケーションのタスクを立てます。
そして、バッチ処理が実行され、処理が終わるとhakoタスクとバッチ処理を実行するアプリケーションのタスクは消滅します。
これにより、毎回新しい環境でバッチを動かすことが出来ます。
Dockerを導入してみた結果
ECSのSchedulerを用いることで単一障害点を取り除くこと成功し、サーバーの稼働率が上がりエンジニアの対応を減らす事ができました。
また、以前はchefを用いてプロビジョニングしていたのですが、recipeの管理やプロビジョニングに時間がかかるなどの辛さを回避することも出来たようです。
Dockerfileにまとめて書けるのはやはり楽なようで、サーバーの構成を作るのも簡単になりました。
また、自分たちの作った構成がイケてて、カッコイイと思えるのもモチベーションに繋がっているようです!
新人でも新しいものにチャレンジできる環境
このプロジェクトは3人のチームで進めていったということでした。お話を伺ったtsubさんによれば、開発を進めていく中で新卒だからどうこうということは一切なく、お互いに意見を出し合って開発を進めていったそうです。
また、開発当初は全員がアプリケーションエンジニアで、インフラの知識がそこまであるわけではなかったそうです。しかし、自分たちで調べたり社内のインフラエンジニアに協力したりしてもらいながら、みんなで進めていった結果がこれだということでした。
フィードフォースのエンジニアはフレンドリーな方が多く、何でも気軽に相談できるのが良いところです。
この、新しいことに挑戦する人を応援するという文化はエンジニアにとって非常に貴重なものだと思います。
私も挑戦していきます!
フィードフォースで新しいことにチャレンジしたい方は是非!
株式会社フィードフォースでは一緒に働く仲間を募集しています
株式会社フィードフォースでは一緒に働く仲間を募集しています