パブリックサブネットで起動したECS(EC2 + awsvpc)でコンテナがインターネット接続出来ない点について

2020.03.06

こんばんわ、札幌のヨシエです。

先日mackerelでコンテナ監視を行う時に注意するポイントを社内で説明する時に挙動確認で躓いた部分を共有します。

躓いた点

  • mackerel-container-agentの起動に失敗する

mackerel-container-agentのログより、タスク定義のホスト登録に失敗(作成が出来ない)旨のメッセージが表示されました。

2020/03/05 11:47:34 INFO <agent> retry to find host: failed to create a new host: Post https://api.mackerelio.com/api/v0/hosts: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

結果

諸々の確認結果はEC2 + awsvpcの環境ではパブリックIPアドレスが付与されているENIが使用できませんでした。

パブリックIPアドレスが振られないことでインターネット接続が出来ず、NATGatewayへのルーティングを持っているサブネットに移すことで正常にホスト登録が出来ました。

今回の構成について

以前に検証で使用していたVPCを流用しました。

万が一のトラブルシュートに向けてEC2へSSHを行いたいという気持ちから、IntenetGatewayへのルーティング設定が入っているパブリックサブネットにコンテナホストを起動しました。

ここで重要な点としてパブリックサブネットには「パブリックIPv4アドレスの自動割当」を有効にしてました。

図に起こすと以下のような構成になります。

調査内容

調査①:状況の確認

mackerel-container-agentのタスク定義を確認

  • 最初に疑ったのはmackerel-container-agentへ渡す環境変数の設定誤りと考えました

  • 渡している環境変数としては以下の3つで問題がないことを確認しました

環境変数名 備考
MACKEREL_APIKEY APIキー オーガニゼーション用APIキー
MACKEREL_CONTAINER_PLATFORM ecs ECSで動かすためにecsを指定
MACKEREL_ROLES ecs:ecs 検証なのでecsサービス/ecsロールに紐付け

ECSクラスターへデータプレーンが参加している

  • データプレーンをECSクラスターへ追加する時は「インターネット経由でECSと疎通が取れる」か「VPCエンドポイントを設定」する必要があります。
  • VPCエンドポイントは使用しておらず、インターネット経由でアクセスをしていることを想定しましたのでインターネット接続は問題ないものと考えておりました

コンテナをチェック

mackerel-container-agent自体の起動は問題なかったので、EC2へSSH接続 → docker execにてbashを起動し、ping、netcat、digコマンドが入っていないことを認識していたのでapt-getを実施したところタイムアウトしました。

この時点でNW部分が怪しい気持ちが増しました。

調査②:ネットワークモードを変更

ネットワークモードを変更(awsvpc → bridge)

確認観点としてネットワークモードが要因であればbridgeモードへ変更することでEC2にアタッチされているENIを利用する仕組みからインターネット接続が出来るものと考えたためです。

bridgeモードに変更することでmackerelへホスト登録が出来ました。

この点からawsvpcの設定不備の要因が大きいと考えました。

調査③:データプレーンを変更(EC2 → Fargate)

タスク定義はEC2/Fargateどちらでも使用できるタスク定義を目的としました。

NWモードをawsvpcとして理由がこの部分でしたので、データプレーンをEC2→Fargateに変更することでmackerelへホスト登録が出来ました。

以上の状況より、awsvpcモードとしては問題がなくEC2との組み合わせ時に発生するものと考え、ドキュメントを確認すると理由が判明しました。

awsvpc ネットワークモードは、EC2 起動タイプを使用するタスクには、パブリック IP アドレスを使用する ENI を提供しません。EC2 起動タイプを使用するタスクでインターネットにアクセスするには、NAT ゲートウェイを使用するよう設定されたプライベートサブネットでタスクを起動する必要があります。

引用:タスクネットワーキングと awsvpc ネットワークモード - Amazon Elastic Container Service

本事象との関連

今回はパブリックサブネットで「パブリックIPv4アドレスの自動割当」を有効にしていたことでコンテナホストと同様にawsvpcとして設定されたタスクに紐づくENIに対してもIPv4アドレスが割り当てられるものと思い込んでおりました。

以下は実際にアタッチされているENIの設定状況となります。

説明に記載があるようにPrimary network interfaceにはIPv4アドレスが割り当てられますが、awsvpcとして起動したタスクに紐づくENIに対してはIPv4アドレスが割り当てられませんでした。

試しにEIPを一つ確保して上記のタスクに紐づくENIへ割り当てを試みましたが失敗しました。

※そもそもスケーリングを想定しているタスクへ一つ一つEIPを付与するのは現実的ではありません。

以上の内容より記事冒頭で記載したようにEC2をコンテナホストとした際にインターネット接続を行うためにはIPv4を利用することが可能なNATGatewayを経由する必要があるということでがわかりました。

最後に

今回のようなネットワーク構成を取ることはほぼないと思われますが、awsvpcの使い方が少し分かった課題でした。 ECSを使う方の参考になると嬉しいです。