スタートアップのプロダクト成長の舞台裏とコンテナ化までの道のり

こんにちは。スタメンCTOの松谷です。 最近、弊社が提供している 「エンゲージメント経営プラットフォーム TUNAG」「オンラインサロンプラットフォーム FANTS」 のアプリケーション環境をECS上のDockerコンテナへ移行しました。約5年間、EC2で本番運用してきたRailsアプリケーションをコンテナ化することはとても困難でリスクの高い大変な作業でしたが、今後、開発組織としてプロダクトのスケーラビリティに向き合うために必要だと判断し実行しました。

この記事では、スタメンのプロダクトの成長過程において、スケーラビリティにどのように向き合ってきたのか。なぜ今コンテナ化をしたのか。その舞台裏と移行内容を説明します。

経緯

まず、EC2で動かしていたRailsアプリケーションをAmazon ECS上のDockerコンテナへ移行するまでの経緯を説明します。

2017年 〜 2018年 (立ち上げ期)

創業事業である TUNAG は、2017年にサービス提供を開始した今年で5年目のBtoBサービスです。プロダクト立ち上げ時には、アプリケーションの実行環境として ECS という選択肢もありましたが、当時は他社の採用事例が少なく、社内にコンテナや ECS のノウハウが無かったことから、最も慣れている EC2 でRailsを動かすことを選択しました。また、サーバー構成管理ツールとして Chef Solo を導入しました。

サービス提供を開始してから2018年までは、サーバー増設の必要があれば、都度手動でEC2インスタンスを立ち上げ、Chef Solo でサーバーをプロビジョニングしていましたが、導入企業数も少なかったため、増設の頻度は少なく運用コストはほぼありませんでした。

2019年 〜 2021年 (成長期)

ありがたいことに TUNAG の導入企業数が増え、様々な業種のニーズに対応するためにプロダクトの規模が大きくなってきました。また、エンタープライズ企業様の導入が進むにつれて、サーバーの負荷が一気に高まるシーンが増えていました。スケーラビリティの課題が大きくなってきたこの時期に、システムの信頼性向上に取り組むチームとして SREチーム が発足しています。スケーラビリティにおける課題を発見すれば、SREチームがアプリケーションのパフォーマンスチューニングをしたり、手動でサーバーを構築し本番環境に投入していました。ただ、SREチームとはいえインフラ専任ではなく、アプリケーション開発も並行していたため、手動でのインフラ運用コストは無視できなくなってきました。

さらに2020年に新規事業 FANTS のサービス提供が始まりました。TUNAGのスケーラビリティを確保しつつ、一方で FANTSのインフラを支えるということを少人数で実施していました。FANTSのアプリケーションがTUNAGのコードを再利用していたことから、インフラ環境もTUNAGと同じく EC2 を選択しましたが、これまでのインフラ管理方法について以下のような懸念を感じていました。

冪等性を考慮する難しさ

Chef Solo の特性として冪等性というものがありますが、この冪等性を考慮してコードを管理することが難しく、様々な状況を考えないと一発でサーバー設定を完了させることができませんでした。当然、ツール自体の問題ではなく使い方の問題ですが、今後、複数人でサーバーの設定管理していくことの難しさを感じていました。サーバーを増設するたびに、Chef Solo の実行エラーに悩まされたり、他のサーバーと本当に同じ設定になっているかどうかの確認作業によって、少なくない時間を使っていました。

本番稼働中のサーバーを変更する不安

本番サーバーの設定を変更する際には、オンラインで Chef Solo を適用していました。オンラインで適用しても問題ないことを確認しているとはいえ、本番環境で稼働しているサーバーを変更することの安全性に不安を感じていました 。

一部メンバーへの負担の偏り

以下の3点の理由から、サーバー管理スキルの冗長化が遅れ、一部メンバーの負担が高い状況が長いこと続いてしまっていました。

  • 負荷対策は緊急度が高く、他のメンバーに経験してもらう機会を作りにくいこと
  • 作業そのものが危険なため、慣れている人が毎回実施してしまうこと
  • 今後 Chef Solo が更新されないことが分かっており、今から学ぶモチベーションが生まれづらいこと

上記のように、各種インフラ作業の心理的ハードルは高く、プロダクトのスケーラビリティを支える上で、健全な状態ではなかったと言えます。もしコンテナのように、変更の度にアプリケーションを使い捨てにできるのであれば、冪等性の考慮も不要になり、本番で稼働中のサーバーを変更する必要もありません。また、Docker、 ECS、Kubernetesなどコンテナ関連の技術は大きなトレンドにもなっており、エンジニアが学ぶモチベーションにも繋がります。これらのコンテナの特性こそがチームが必要としていたものであったことは理解しており、過去にコンテナ化を検討したことは何度かありましたが、プロダクト開発を優先し見送ってきました。しかし、既存の運用方式は限界に近い状態だったこと、また、ちょうど近い時期に TUNAG と FANTS のRailsメジャーバージョンアップが予定されており、アプリケーション全体の動作確認を実施するのであれば、コンテナ移行のようにアプリケーション全体の動作確認が必要なリリースも一度にまとめてしまおうということで、ついに2021年の春頃にコンテナ移行プロジェクトが始まりました。

移行作業について

コンテナ(ECS)移行における主要な変更点について簡単に共有します。アプリケーションのコンテナ化だけでなく、周辺のシステムアーキテクチャレベルでの変更もいくつかありました。

Chef Solo の内容を Dockerfile へ移行

まずは Chef Solo を読み解くところから始まりました。歴史的経緯などを把握しつつ、コンテナ化する上で必要なミドルウェアや設定を1つ1つ丁寧に確認していきました。そしてこれらの設定をDockerfileへ移植しました。

アプリケーションのコンテナ移行

アプリケーションで稼働していたRailsのプロセスは4種類ありました。Webアプリケーション本体のPuma、非同期処理の Sidekiq と delayed_job、EC2インスタンス上のcronから呼び出されるrakeタスクです。これらプロセスごとに起動するタスク数やスケーリングの設定は異なるため、 プロセスごとに ECS Service を分けて管理しています。各種ECS Serviceにオートスケーリングを設定することで、今後サービスの負荷が増えるにつれてアプリケーションを自動的にスケーリングしてくれる状態を実現することができました。

デプロイ方式の移行

もともとデプロイには Capistrano を利用して、SSHでリモートサーバーにアクセスし、各種プロセスを再起動してアプリケーションを更新していました。このため、sidekiq や delayed_job の更新時にはプロセスが完全に停止し、一時的にキューが詰まるという問題が発生していました。

ECS環境では、デプロイメント方式として「ローリングアップデート」と「BlueGreenデプロイメント」の2つを提供しています。

Sidekiq と delayed_job にはローリングアップデート方式を採用することで、稼働中のプロセスを完全に停止させずに徐々に新しいものに入れ替えていくことができるようになったため、キューが詰まる問題が解消しました。

Pumaについても同じくローリングアップデート方式を採用しようとしましたが、Puma をローリングアップデート方式でデプロイする場合、デプロイ途中に一定時間、新旧のコンテナが混在し、新しいコンテナへのリクエストで表示されたページから、古いコンテナへリクエストが飛ぶケースが存在するため、一度に新旧コンテナへのトラフィックを切り替えるBlueGreen方式を採用することにしました。また、BlueGreenデプロイメント方式は切り戻しが一瞬なので、今後リリース直後の不具合の影響を極小化することができるようになりました。

このようにプロセスのユースケースごとにデプロイメント方式を柔軟に変更できることはECSに移行した大きなメリットでした。

cronサーバーをECS Scheduled Taskへ移行

これまで、定期処理の管理には whenever というgemを利用し、デプロイのタイミングでcrontabを設定していました。crontabの運用では、システムの冗長化が難しく単一障害点となっていました。また、単一のcronサーバーで運用していたため、負荷分散も難しくサーバーのスペックを上げるしか負荷対策の方法がありませんでした。

ECSでは、ECS Scheduled Task という、Amazon EventBridge ルールを使用したECSタスク実行の仕組みを利用しています。このECS Scheduled Task の管理には、elastic_whenever というgemを利用しており、これが whenever の設定ファイルである schedule.rb を読み、ECS Scheduled Taskを登録してくれます。

この移行により、単一障害点であったcronサーバーから、Amazon EventBridge というマネージドサービスに乗り換えることができ、可用性が向上しました。また、ECS Scheduled Task を利用することで各定期処理ごとにコンテナが立ち上がるため、負荷分散が自動で行われるようになり、負荷対策のために定期処理の時間帯をずらすような運用も撤廃できました。

ログ管理を AWS Firelens へ移行

もともとはEC2上で、ログを収集するための kinesisエージェント を起動し、一部アプリケーションのログをKinesis Firehoseへ転送し、S3で保存する仕組みが存在しました。ただ、kinesisエージェントが意図せず停止してしまった場合に、その期間のログが欠損してしまうという問題がありました。また、一部のログ以外のほとんどのシステムログを転送する仕組みが無く、EC2インスタンス上に保存されていました。

今回、コンテナに適したステートレスなアプリケーションにするために、全てのログをAWS Firelens というログルーター経由で外部へ転送する方式に変更しました。AWS Firelens とは、コンテナのサイドカーとして配置し、他のコンテナからはログドライバーとして使用できる仕組みです。また、ECSのタスク定義で、ログルータコンテナとアプリケーションコンテナの依存関係を定義できるので、確実にログルーターコンテナがヘルシーな状態でアプリケーションコンテナを起動することを保証することができるようになり、ログの正確性が向上しました。

勝ち取ったコンテナ環境

コンテナ化に至った背景とその移行内容について共有させていただきました。とても長く大変な作業でした。担当したエンジニアの皆さん本当にお疲れさまでした。多くの課題を乗り越えてようやく勝ち取ったコンテナ環境のおかげで、これまで多くの時間を割いてきたサーバー構成管理やインフラ増強などのSRE業務は圧縮され、プロダクト開発に集中できる状態になってきています。そして、SRE作業の安全性が高まったことから、SRE経験のないメンバーも積極的に巻き込むことができるようになり、徐々に一部メンバーへの負担の偏りも減ってきています。まだまだSREの組織化については課題が沢山ありますが、コンテナ移行をきっかけに大きく前進していきたいと考えています。

そして今後

スタメンは TUNAG と FANTS だけでなく、世の中にいくつもの事業を生み出していきたいと考えています。このように複数事業を運営する組織において、パターン化しやすい領域、つまり事業固有の事情が小さく専門性が高い領域は横断的な価値が活きてきます。今回獲得したコンテナの知識を組織のベストプラクティスとして横展開しインフラ運用効率を上げ、プロダクト開発に集中できるような体制を目指していきたいです。

最後に

少しずつですが、プロダクト開発に集中する上で在るべき姿に近づいてきました。コンテナに移行した後も多くの課題が出てくると思いますが、今後もプロダクトで事業を牽引してくために開発組織一丸となって乗り越えていきたいと思います。

スタメンの開発にはまだまだ課題がたくさんあります。スタメンに興味を持っていただけたら、下記の採用ページからエントリーいただけると幸いです。

また、私のMeetyも公開していますので、この記事について気になることがあれば気軽に聞いてください😄 また、みなさんのチームの舞台裏の奮闘劇をぜひ聞かせてください!