Amazon Web Services ブログ
詳解: Amazon ECSのタスクネットワーク
この記事はECSのSr. Software Dev EngineerのAnirudh Aithalの寄稿です。
2017年11月14日に、AWSはコンテナにElastic Network InterfaceをアタッチできるようにするAmazon ECSのTask Networkingを発表しました。
この記事では、ECSが管理するインスタンス(コンテナインスタンスと呼ばれます)上でContainer Networking Interfaceプラグインを使って、この新しいコンテナネイティブなawsvpcネットワークモードがどのように実装されているかを詳しくご紹介したいと思います。
こちらはAmazon ECSでタスクネットワークが動作するかにdeep diveしたものです。もし自身のコンテナ化したアプリケーションでどうやってタスクネットワークを使い始めれば良いかについて学びたい時には、Amazon ECSコンテナにCloud Native Networkingが登場をご覧下さい。Cloud Native Computing Foundation (CNCF)がContainer Networking Interface (CNI)プロジェクトをホストしており、Linuxコンテナでネットワークインターフェースを設定するためのプラグインを書くための仕様やライブラリが含まれています。AWSのクラウドネイティブコンピューティングについての詳細は、Adrian CockcroftのCloud Native Computingについての投稿をご覧下さい。
コンテナインスタンスのセットアップ
コンテナインスタンス上でのタスクネットワーク有効化の詳細をご説明する前に、ECSの典型的なインスタンスがどのようになっているかを見てみましょう。
上の図は典型的なコンテナインスタンスを示しています。ECS agentは自身もコンテナとして実行されているのですが、以下のような責任を負っています:
- EC2インスタンスをECSのバックエンドに登録
- コンテナインスタンスに対してECSバックエンドが発生させたタスク状態の変化を、正しく適応
- Dockerデーモンと会話しながら、コンテナの作成、開始、停止、監視
- コンテナの状態とタスクの状態の遷移をECSバックエンドにリレー
ECS agentはその管理下のコンテナのスーパーバイザーの様に動作するので、Dockerデーモン(Dockerのデフォルトネットワークモードで設定されたコンテナ用)、又はCNIプラグイン達(ネットワークモードがawsvpcで設定されたタスク内のコンテナ)のための、ネットワーク設定をする難しさをオフロードしてくれます。
いずれの場合にも、コンテナのネットワークスタックは、ネットワークのnamespaceを通じて設定されます。ip-netns(8)のマニュアルによると「ネットワークnamespaceは論理的なネットワークスタックのコピーで、自身のルーティング、ファイアウォールルール、ネットワークデバイスを持っています。」 とあります。ネットワークnamespaceの構成によって、ホスト上で動いているプロセスやコンテナ間でのネットワークスタックの隔離を可能としてくれます。
ネットワークnamespaceとCNIプラグイン
CNIプラグインとは、CNI仕様を満たしコンテナのネットワーク接続性の設定を行う実行ファイル群です。CNIプロジェクトではプラグインの仕様を定義し、プラグインが利用するライブラリを提供することで、一貫していて信頼でき、かつ簡素なプラグイン用のインタフェースを提供してくれます。
コンテナやネットワークnamespaceを指定してプラグインを呼び出す時に、ADDコマンドでコンテナにネットワークインターフェースを追加したり、DELコマンドでそれを落としたりします。例えばリファレンスのBridgeプラグインは、ホストネットワークnamespaceの中にいるブリッジに対してホスト上の全てのコンテナを追加します。
このプラグインのモデルはECS agentの「コンテナのライフサイクルへの最小限の介入」というモデルと相性が良く、agentはコンテナのネットワーク設定の詳細について考慮する必要がなくなります。また拡張性の高いモデルなので、将来必要になった時には、agentが異なるプラグイン群を利用できるようにスイッチさせることもできます。最後に、これらプラグインは必要な時に呼び出されるだけなので、その死活監視をECS agentがする必要はありません。
ECS agentからCNIプラグインを呼び出す
ECSがElastic Network Interfaceをインスタンスにアタッチし、agentに対しそのElastic Network Interfaceをタスク内のコンテナに対してプロビジョンするようにメッセージを送った時には、(任意のネットワークデバイスを使う) そのElastic Network Interfaceはホストのグローバルデフォルトネットワークnamespaceに現れてきます。ECS agentは複数のCNIプラグインを順番に呼び出すことで、そのElastic Network Interfaceがコンテナのネットワークnamespaceに正しく設定されていることを保証してくれます。これらのプラグインはamazon-ecs-cni-pluginsのGitHubレポジトリで見ることができます。
最初に呼び出されるものはecs-eniプラグインで、Elastic Network Interfaceがコンテナのネットワークnamespaceにアタッチされ、VPCから割り当てられたIPアドレスとサブネットのゲートウェイに対するデフォルトルートが設定されていることを保証します。コンテナは更にIAMロールの認証情報を得るために、(ECS agentが提供している) 認証情報エンドポイントにHTTPリクエストできるようになる必要があります。これはその次に実行されるecs-bridgeとecs-ipamプラグインによって処理されます。CNIのライブラリはこれらのプラグインの実行結果を解釈する仕組みを提供しているので、agent上で効果的にエラーをハンドリングすることができます。以下の図は、このプロセスのそれぞれのステップを図解したものです:
ネットワークスタックの設定とアプリケーションコンテナの中で実行されるコマンドのレースコンディションを避けるために、ECS agentはタスク毎にそのタスク定義内にあるコンテナを開始する前に、pauseコンテナを作成します。その後、前述のCNIプラグイン群を実行することで、pauseコンテナのネットワークnamespaceをセットアップします。それからタスクにある残りのコンテナ達を開始するので、pauseコンテナのネットワークスタックを共有します。これは、タスク内の全てのコンテナはElastic Network InterfaceのIPアドレスによって到達可能であり、かつlocalhostインタフェースを通じて互いに通信することができることを意味しています。
このセットアップ例では、1つのElastic Network Interfaceの後ろに2つのコンテナを持った1つのタスクがあります。以下のコマンドでそれらが同じネットワークスタックを持っていて、localhostインタフェースを通して互いに会話可能であることを見ていきましょう。
ホスト上で実行している最新3つのコンテナをリストする (タスクで起動した2つのコンテナと、ECS agentが追加で起動したネットワークnamespaceの設定用コンテナ):
$ docker ps -n 3 --format "{{.ID}}\t{{.Names}}\t{{.Command}}\t{{.Status}}"
7d7b7fbc30b9 ecs-front-envoy-5-envoy-sds-ecs-ce8bd9eca6dd81a8d101 "/bin/sh -c '/usr/..." Up 3 days
dfdcb2acfc91 ecs-front-envoy-5-front-envoy-faeae686adf9c1d91000 "/bin/sh -c '/usr/..." Up 3 days
f731f6dbb81c ecs-front-envoy-5-internalecspause-a8e6e19e909fa9c9e901 "./pause" Up 3 days
3つのコンテナのインタフェースをリストし、それらが同じであることを確認する:
$ for id in `docker ps -n 3 -q`; do pid=`docker inspect $id -f '{{.State.Pid}}'`; echo container $id; sudo nsenter -t $pid -n ip link show; done
container 7d7b7fbc30b9
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: ecs-eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 0a:58:a9:fe:ac:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
27: eth12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 02:5a:a1:1a:43:42 brd ff:ff:ff:ff:ff:ff
container dfdcb2acfc91
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: ecs-eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 0a:58:a9:fe:ac:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
27: eth12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 02:5a:a1:1a:43:42 brd ff:ff:ff:ff:ff:ff
container f731f6dbb81c
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: ecs-eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 0a:58:a9:fe:ac:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
27: eth12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 02:5a:a1:1a:43:42 brd ff:ff:ff:ff:ff:ff
まとめ
以上の仕組みによって、新しいawsvpcネットワークモードを使うことができ、コンテナに対してネイティブなネットワークサポートによる利便性を享受することができます。awsvpcモードの詳しい使い方は、Amazon ECSコンテナにCloud Native Networkingが登場かECSドキュメントをご覧下さい。
GitHubのECS CNIプラグインかECS Agentのレポジトリで私にフィードバック頂けると幸いです。
原文: Under the Hood: Task Networking for Amazon ECS (翻訳: SA岩永)