いままでのECSの起動モード(EC2起動モード)のネットワーク設定(bridge ネットワークモード)とFargate起動モードを利用した場合のネットワーク設定関連で嬉しいことについて
2017年11月14日にAWSがAmazon ECSのTask Networkingを発表*1し、その恩恵を受ける Fargate 起動タイプが2018年7月4日に東京リージョンでサービス開始となりました*2。
自分の職場でも一部サービスでFargate(with awsvpcモード)の採用が始まったのをレビューで見たのはいいものの、いままでのECSのネットワークモードとの違いがよくわからず、最初のPRについては「俺を信じるお前を信じろ」になってしまったため、ドキュメント見て少し調べたメモです。
目次
- いままでのECSの起動モード(
EC2
)のネットワーク設定(bridge ネットワークモード)について- ECSが利用しているEC2のネットワーク設定
- Dockerのデフォルトの
bridge
ネットワークモードをECSで利用する場合にタスクのネットワークに関して起きること - ECSでEC2起動モードで利用するDockerのデフォルトの
bridge
ネットワークモードを利用することで起きる制限
- Fargate起動モードで利用する
awsvpc
ネットワークモードについてawsvpc
ネットワークモードでは、ecs-agent
が利用するCNIプラグインを利用してタスクにENIをアタッチするawsvpc
ネットワークモードの利用で嬉しいこと- ECSで
awsvpc
ネットワークモードを利用する場合の制限の話
- 参考
いままでのECSの起動モード( EC2
)のネットワーク設定(bridge ネットワークモード)について
実は、 Fargate
起動モードや awsvpc
ネットワークモード以前に、既存の EC2
起動モードや EC2
起動モードの際に前提とされてる気がするDockerのデフォルトの bridge
ネットワークモードについてよく知らなかったのでそこから確認しました。
ECSが利用しているEC2のネットワーク設定
ECSのコンテナインスタンスはかなり大雑把にいうと ecs-agent
が動作し、ECSに登録されたEC2インスタンス*3のことを指しますが、ECSのネットワークに関係する設定はEC2のネットワーク設定の方法に依存しています。
なので、最初にEC2のネットワーク周りのことをおさらいしました。
EC2を起動するには、AWS ドキュメント » Amazon Elastic File System (EFS) » ユーザーガイド » Amazon Elastic File System の開始方法 » ステップ 1: EC2 リソースを作成し EC2 インスタンスを起動するに記載されている通りVPCの利用が前提となっています。
そのVPC内のEC2インスタンスは自分たちでsshした後にコマンドを叩かなくても、VPCのルーティングテーブルに設定が登録されており、VPC内の他のインスタンス + 外部エンドポイントにアクセス可能なわけですが、これを実現しているのがENI(Elastic Network Interface)と呼ばれるVPC内の仮想的なネットワーク・インタフェースとなっています。
ENIはすべてのEC2インスタンスに1つ以上アサインされ、EC2インスタンスの起動時に自動的にアサインされる1つのENIを プライマリネットワークインタフェース
と呼びます。
EC2インスタンスのネットワーク設定にあたる各種属性( IPアドレスやセキュリティグループなど
)は、実際はEC2インスタンスにアサインされているENIに設定される属性です。
Dockerのデフォルトの bridge
ネットワークモードをECSで利用する場合にタスクのネットワークに関して起きること
ECSではいままでDocker側で用意されている3種類のネットワークモード*4が利用できました。
https://aws.amazon.com/jp/blogs/news/introducing-cloud-native-networking-for-ecs-containers/ では、そのうち、bridgeモードについて説明されていたので、この記事でもそれに沿って考えることにします。
ECSでは、同じタスク定義のコンテナ一式は同じコンテナインスタンスの中で動作し、さらに1つのコンテナインスタンスの中で複数のタスクが動くことがあります*5。
このとき、ECSのコンテナとして動くコンテナの間で利用するネットワークインタフェースは共通( docker0
のブリッジが接続されているインタフェース)なので、コンテナたちはすべて同じネットワークインタフェースを経由して通信を行い*6、ENIとそれに伴うネットワーク設定も共有します。
また、コンテナ同士で外部からアクセスされる際に経由するネットワークインタフェースを共有するので、外部から来た通信をそれぞれのコンテナに接続する際に同じ定義のタスクでも違うポート番号を割り振らなければいけないことに関するややこしさがありました。
ECSでEC2起動モードで利用するDockerのデフォルトの bridge
ネットワークモードを利用することで起きる制限
前節で述べたことをもとに考えると、これまでのECSのネットワーク設定では
同じコンテナインスタンス上のコンテナはすべて同じENI(の裏のネットワークインタフェース)を経由する前提なので
- 比較的ネットワークリソースの干渉が起きやすく、複数のコンテナが1つのホストに配置された場合、ネットワークが詰まってパフォーマンスが出ない場合もありそう
- また、同じ定義のタスクが同じコンテナインスタンスで動く際のネットワーク設定がややこしかった
同じホスト上のコンテナはすべて同じENI(に紐づいたネットワーク設定)を利用する前提なので
- セキュリティに気を使うコンテナとそうでないコンテナの設定が一緒くたになってしまう
といった問題が発生していたみたいです。
Fargate起動モードで利用する awsvpc
ネットワークモードについて
EC2起動モードの際に利用するネットワークモードについて確認したところで新しい awsvpc
ネットワークモードについて確認します。
awsvpc
ネットワークモードでは、 ecs-agent
が利用するCNIプラグインを利用してタスクにENIをアタッチする
ネットワークの名前空間には名前空間ごとにルーティングテーブルが用意できるだけでなく、ネットワークデバイスを追加することも可能*9ですが、 awsvpc
ネットワークモードでは、タスクごとにネットワークの名前空間を作成し、ECSのコンテナインスタンス上にある、ホストマシンのプライマリネットワークインタフェース以外のENIをそのタスク用の名前空間に追加します*10。
つまり、 awsvpc
ネットワークモードではタスクごとに専用のネットワークインタフェース(ENI)が用意されます。
一方、bridge
ネットワークモードの時は、ECSのコンテナインスタンス上にあるホストマシンのプライマリネットワークインタフェースにあたるネットワークデバイスしか利用してなかった*11、つまり、同じホストで動くコンテナ全体で1つのENI*12しか用意されていませんでした。
awsvpc
ネットワークモードの利用で嬉しいこと
タスクごとに専用のENIを用意すると何が嬉しいのでしょうか。
ENIにネットワーク設定がアサインされているので、タスクごとにネットワーク設定ができるようになり、1つのコンテナインスタンスで複数同じタスクが動く場合の設定のややこしさも解消されました。
さらに、同じホストで動くタスクの間でネットワークリソースの干渉が減少し、ネットワークで詰まっていたアプリケーションがあったとしたら、ネットワークモードの変更だけでパフォーマンスが改善する可能性があります。
また、ENI(いままでのEC2のネットワーク関係の設定や追跡機能が紐づいているもの)とタスクが1対1で対応しているので、タスクごとの通信内容がVPCフローログなどで既存のEC2のネットワーキング機能を利用して確認できるようになります。
ECSで awsvpc
ネットワークモードを利用する場合の制限の話
今までのネットワークモードより便利そうな点が多い awsvpc
ネットワークモードですが、タスクごとにENIを割り当てることに関連していると思しき制限もあります。
この記事では、その中の印象的だったもの*13をメモして〆たいと思います。
- いままで利用していた
link
設定が利用できない - タスクごとにネットワークインタフェースをアタッチしているので、クラスタで利用しているEC2インスタンスのインスタンスタイプで設定されている
ENIの数 - 1
以上にタスクをコンテナインスタンスに配置できない タスクごとにネットワークの名前空間を作成し、ECSのコンテナインスタンス上にある、ホストマシンのプライマリネットワークインタフェース以外のENIをそのタスク用の名前空間に追加する
の部分をecs-agent
のawsvpc
モード用に用意されたCNIプラグイン達を通して行う*16からか、手動でawsvpc
ネットワークモードのタスクが動くコンテナインスタンスに対して ENIのアタッチをしていて、他に余っているENIがなければ、awsvpc
ネットワークモードのタスクはPROVISIONING
=>DEPROVISIONING
=>STOPPED
に移行して動かない
制限やEC2起動モードとの違いの詳細には、 https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task-networking.html を確認してください。
参考
この記事を書き始める前に重点的に読んだもの。他の参考記事は注釈部に。
- Amazon ECSコンテナにCloud Native Networkingが登場
- 詳解: Amazon ECSのタスクネットワーク
- AWS ドキュメント » Amazon EC2 Container Service » 開発者ガイド » Amazon ECS タスク定義 » タスクネットワーキングと awsvpc ネットワークモード
- AWS ドキュメント » Amazon EC2 » Linux インスタンス用ユーザーガイド » ネットワークとセキュリティ » Elastic Network Interface
VPCとALBについてもう少し詳しくなりたいけど、業務的に火急なのはElasticCacheで自分は何をやっているんだ...、現場からは以上です。
*1:https://aws.amazon.com/jp/blogs/news/introducing-cloud-native-networking-for-ecs-containers/
*2:https://aws.amazon.com/jp/blogs/news/aws-fargate-tokyo/
*3:https://aws.amazon.com/jp/blogs/news/under-the-hood-task-networking-for-amazon-ecs/ の図など
*4:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/create-task-definition.html と https://docs.docker.com/engine/reference/run/#network-settings より
*5:http://www.slideshare.net/AmazonWebServicesJapan/aws-blackbelt-2015-ecs の20ページとかみたいに
*6:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html より今まで使えた設定でもhost ネットワークモードを使えば話は違うみたいですが、たぶん設定がややこしかったのでは
*7:https://aws.amazon.com/jp/blogs/news/introducing-cloud-native-networking-for-ecs-containers/
*8:http://www.slideshare.net/AmazonWebServicesJapan/aws-blackbelt-2015-ecs 69~70ページあたりで2015年時点のその辺の様子を確認できます。ポート番号が被らないように発展編の設定を使ったり、同一Taskは一つのコンテナインスタンスに一つまで、と制限したり
*9:https://docs.openstack.org/liberty/ja/networking-guide/intro-network-namespaces.html
*10:https://aws.amazon.com/jp/blogs/news/under-the-hood-task-networking-for-amazon-ecs/
*11:https://aws.amazon.com/jp/blogs/news/introducing-cloud-native-networking-for-ecs-containers/ の 「コンテナはこのブリッジを利用し、それが実行されているインスタンスのプライマリネットワークインタフェースを使う」 から
*12:ENIは仮想的なインタフェースで論理的に分割されている可能性もあるんでしょうが、インスタンスタイプによってENIの数変わるし、物理的にもある程度そのような気はする...
*13:主にレビューの時に「へぇ」といったり、個人的にトラブルシューティングで使いそうな目処がついたもの
*14:https://qiita.com/taishin/items/84122ad85bedf8b8a682
*15:上の記事とは関係ないんですが、もともとlinkはポート番号が使えないから利用したい機能でポート番号がアプリケーションに対応した番号で固定で使えるならいらないでしょ + アプリケーションが設定しているポートを見て設定するようになるとELBやセキュリティグループの設定で混乱がなくなる、みたいな考えでもあるのか?
*16:https://aws.amazon.com/jp/blogs/news/under-the-hood-task-networking-for-amazon-ecs/