こんにちは、ペイルドの大竹です。
今回は外部サーバーと通信を行っているEC2インスタンスをECS on Fargateに移行した話をしたいと思います。
移行する前は以下のような構成となっていました。
背景
EC2インスタンスの運用にて以下の課題がありました。
- 弊社ではPCI DSS準拠等の理由により、EC2インスタンスへのログインできる人・場所を制限し、ログインには申請が必要となっている
- PCI DSSの要件でユーザーの管理・パスワードを定期更新などが必要
上記課題を解決するため以下の対応をすることにしました。
- ECS on Fargateの採用
- 脆弱性対応はコンテナイメージを修正するだけなので誰でも対応が可能になる
- ログインして手動対応する必要がなくなる
- コンテナのベースイメージにDistroless*1を採用
- Distrolessはシェルを含まないイメージのためユーザー、パスワードの管理が不要になる
また、Distrolessはアプリケーションの実行に必要な最低限のパッケージしかないので、パッケージの脆弱性によるセキュリティリスクを減らすことも期待できました。
移行の課題
1つ目が移行するEC2インスタンスが行っている外部サーバーとの通信は送信元IPアドレスが制限されています。
ECS on FargateはプライベートIPアドレスを固定することができないのですが、2022年11月からNATゲートウェイのプライベートIPアドレスを固定できるようになった*2ので、EC2インスタンスと外部サーバーの間にプライベートNATゲートウェイをかませることでプライベートIPアドレスの固定化を行うことにしました。
2つ目にプライベートIPアドレス1つにつき1コネクションのみという制約がありました。
これに対してはプライベートNATゲートウェイごとにECSサービスを作成し、ECSサービスのタスク数を1つに固定することで解決しました。
また、ECSサービスはデフォルトでminimumHealthyPercent
が100%
、maximumPercent
が200%
となっているのでアプリケーションのデプロイでECSサービスをローリングアップデートする際は以下のような挙動となります。
- 新しいタスクの起動開始
- 新しいタスクの起動完了
- 古いタスクの停止開始
- 古いタスクの停止完了
デフォルトの状態だとデプロイ時に、新しいタスクが外部サーバーとコネクションの確立が行えず正常にタスクが起動できないことが想定されたので、minimumHealthyPercent
を0%
、maximumPercent
を100%
にすることで新しいタスクでコネクションの確立が行えるようにしました。
なお、変更後の挙動はこんな感じになります。
- 古いタスクの停止開始
- 古いタスクの停止完了
- 新しいタスクの起動開始
- 新しいタスクの起動完了
上記の設定を行うと瞬間的にタスク数が0になってしまいます。なので各ECSサービスを同時にデプロイせず順番にデプロイを行うことで外部サーバーとの通信でダウンタイムが発生しないようにしてます。
移行手順
送信元IPアドレスは複数許可されていたので、ダウンタイムを発生させないようにEC2インスタンス1台ずつ撤去してプライベートIPアドレスを開放して、NATゲートウェイに置き換えることにしました。