アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

ZookeeperをAWS ECSで稼働させてみた

こんにちは!!こんにちは!!
インフラエンジニアのyamamotoです。

いこーよのインフラをKubernetesに切り替え、古いサーバーを整理していたのですが、厄介だったのが「Zookeeper」でした。
ZookeeperはSolrのステータスを管理するために利用しているのですが、できれば3台全てが常時稼働していることが望ましいため、Kubernetes環境のように、podやノードの入れ替えなどがあって頻繁に止まってしまうのは問題がありました。
ただ、ダウンした時に自動復旧するようにして管理コストを抑えたいという要望もあり、いろいろ検討した結果、AWS ECSでの運用を試してみることにしました。

ECSにしたときの問題

さっそくZookeeperの公式イメージを使って、ECSの構築をはじめました。
しかし、ZookeeperをECS、つまりコンテナ環境にするには、いくつか重大な問題がありました。

  1. Zookeeperクラスタ内の各Zookeeperノードに固有のIDを振る必要がある
  2. 各Zookeeperノードを個別に認識する必要がある(固定IP・ホスト名)

1.については、環境変数 ZOO_MY_ID にIDを設定すれば、コンテナの起動スクリプトが設定してくれるのですが、設定できる環境変数はタスク定義ごとに1種類だけ。
1つのタスク定義・1つのサービス内ではクラスタ構成は実現できません。

2.についても、ZOO_SERVERS 環境変数で他のノードを指定しますが、1つのサービス内でタスクを展開するとIPアドレスが自動的に割り振られてしまうため、個々のノードを指定することができません。

解決法

そこで、1ノードにつき1タスク定義・1サービス・1タスクという体制にすることにしました。
また、「サービスディスカバリ」という機能を使って、サービス単位で固定のノード名(DNS Aレコード)を取得するようにしました。

f:id:yamamoto-kazuyasu:20200720151315p:plain

このようにすることで、ECSにおいてもZookeeperで必要な個別IDや固定ホスト名の割当が可能になりました。

しかしさらに問題が

しかし実際に試してみるとうまく起動できませんでした。
様子を観察していると、どうもタスクが立ち上がってからZookeeperが立ち上がるまでの間に、AWS側のサービスディスカバリの自動設定が間に合わず、Zookeeperクラスタの他のメンバーを見つけられずに落ちてしまうようでした。
ウェイトを入れればなんとかなりそうだったので、Dockerの起動コマンド設定に無理やりsleepを入れてZookeeperの起動を遅らせるようにしました。

それでもまだうまく起動できないことがありました。原因は、ZOO_MY_ID の不整合でした。
環境変数 ZOO_MY_ID にIDを設定すると、Dockerの起動コマンドdocker-entrypoint.shがIDをファイルに書き出し優先的に使用します。これが残ってしまうと、インスタンスが入れ替わったときに本来指定したいIDとズレることがあります。
この対策として、Dockerの起動コマンド設定にファイルを削除する処理を追加しました。

このようにあれこれ調整して、ようやくECS環境で動作するようになりました。

さいごに

当社ではこの構成をAWS CDKで構築することで、複雑な構成でも何度でも作り直しができるようにしました。
開発環境でもスクラップ&ビルドが簡単にできて検証がとても楽でした。

ECSでZookeeperを立ち上げるというのは初めての経験でしたが、稼働してみると、トラブルが発生しても手を入れること無く自動復旧するのでたいへん助かっています。
現在では、同じくECSでSolrの環境も構築して、障害に強い構成になっています。