Published on

AWS Fargate、Task中のContainer間の通信はlocalhost:PORTで行う理由

Authors
  • avatar
    Name
    グレッグ
    Twitter

Overview

一般的に Container 間の通信は該当 Container の Service 名を指定すると Host として Networking 可能ですが、Fargate の場合通信出来ません。

結論から言うとHost Networkingだと認識して、相手の Container にはlocalhost:[PORT]より通信を行います。

Fargate はなぜ Host Networking になるのかみていきます。

原理的な話なため図が不足している部分はご了承下さい。

前提条件

  • Docker を理解している
    • 開発者目線で一般的には Docker 利用が多いこと、Podman とも交換性が高い意味で Docker 基準でお話します
  • AWS ECS を経験したことがある
    • または EC2
  • 基礎的な Network 知識があること
    • IP Address
    • Port
    • Binding

Fargate の awsvpc どこで宣言されている?

{
    "family": "",
    "runtimePlatform": {
        "operatingSystemFamily": ""
    },
    "taskRoleArn": "",
    "executionRoleArn": "",
    "networkMode": "awsvpc",
    "platformFamily": "",
    "containerDefinitions": [],
    "requiresCompatibilities": ["FARGATE"],
    "cpu": "",
    "memory": "",
    ...
}

Fargate で Task Definition を作成する際に requiresCompatibilitiesと共にnetworkModeawsvpcと記載します。

Host Networking とは?

AWS の理解の以前に Docker を基準とし Container の Network 環境について少し確認してみましょう。

Host は Client と通信するために Server になる Computer そのもの自体を意味し、Container ではNetworking Typeとして

  • bridge
  • host
  • overlay
  • ipvlan
  • maclan

があります。

※参考、AWS ECS Task Networking

Docker 社では次のように定義しています。

host: For standalone containers, remove network isolation between the container and the Docker host, and use the host’s networking directly. See use the host network.

要は Host の Network を直接利用することです。

物理的には Computer に付いている LAN/Wireless LAN 等を直接利用するということです。

Host 意外はVIF(Virtual Network Interface)概念を利用するし、Container が Host であっても Computer の設定によっては VIF を利用することも可能ではあります。

具体的にどう違うのかは Bridge をみながら確認してみましょう

Host vs Bridge network

基本的な Network Type は Bridge が Default であることが多いと思います。

根本的に違うのは

  • Network Address が Host とは独立される
  • Container 間の Network が独立する

ことです

Network Address が Host Machine とは独立される

Docker が指定する Host はの Mac の場合 Docker Desktop の Dashboard で次の Panel より確認出来ます。

docker-daemon-network-setting

※Linux の場合/etc/docker/daemon.jsonから確認出来ます。

OS の Network 環境に影響を受けないため、Container の IP が共に更新されるなり Docker Application そのもの自体の動きが予測出来ます。

Container も仮想化した Resource ではあるので Network Layer が Host から抽象化されるのも自然ですね。

普段あんまり無いことかも知れませんが、Network 監視 Tool で Traffic を限定させたり、Anti-Virus Application から監視対象から外したり細かい開発障害物から Filtering することが安易にできます。

あと、別途に Port Publishing(--port Option)を宣言しない限り Host の外からはアクセス出来ない状態になるので Security 面でも良いです。

Container 間の Network が独立する

docker-compose で Container を実行した時、別の docker-compose Project から実行された Container には通信出来無く、docker-compose を統合(Override)して使ったことがあると思います。

その時に通信経路(Routing)を Docker Daemon(具体的には Iptables)が制御しているから独立した Container Network が構成されます。

通信がただは出来ませんが、docker-compose Project 間 Service 名が被る問題が回避出来たりするので実は気づかない利点も多いです。

Host を使うと?

Bride が提供してくれた Network Address が Host Machine と同様になるため、外部から常にアクセス出来る状態になります。

Application の設定 Network Binding が 0.0.0.0:PORT になるようなことです。

なので、独立した docker-compose 同士でも Host Networking であればお互いに通信が出来るし、Port が被ると起動に Binding Conflict が発生します。

複数の Application を同時に開発する時はこの Binding Conflict で苦労することが度々あるので基本的に Host Networking は使わない方が便利だと思います。

この時に Container 間の通信はどうなるでしょう?

Docker-compose Project では Service 名してでしたが、Docker-compose の境界線からも独立しているので Service 名自体が意味を喪失し Host の Network Address を従うことになります。

Container を使わずに Application を起動したことと同じ状況になるため、Container は自然と Host の Loopback に当たるlocalhostが Container の Hostname になります。

AWS Fargate は訳があってこの Host Networking が採用されています。

よって、AWS Fargate の中に宣言されている Service 同士は localhost:[PORT] でアクセス出来る訳です。

AWS Fargate が Host Networking を採用している訳は NIC が[awsvpc]であるため

AWS Fargate 登場前の ECS 環境

Fargate の登場前には Kubernetes の Node みたいに ECS は EC2(AWS EC2 Instance Host)にECS Container Agentが起動してContainer Orchestration(Container の起動)を行いました。

そうすると、EC2 自体を立てて管理する必要がありました。簡単に Container だけを考えて Deployment 出来る環境では無かったです。

Docker Swarm とかもそのような概念だったので最初は可笑しい概念では無いですが Application だけをみている開発者観点では大変不便です。

AWS Fargate の登場

AWS Fargate はこの EC2 の Deployment が AWS 側で Managed Service として起動され AWS User の視野からは消えて起動することになりました。

Container そのもの自体として扱えるようになりましたが、裏では EC2 が起動しているみたいな状態です。 ※そなため新しい EC2 の起動や AWS Resource 調整のため EC2 を Container の Provider として使っていた従来よりは Container 起動スピードは落ちますが遅いです

ここで発生する問題はどうやってManaged ServiceをAWS AccountのVPCにつなげるか?が残ります。

その対策がawsvpc Network Modeとなります。

NIC さえ VPC の中に Resource として存在(AWS Resource 的には ENI)していれば Managed Service と AWS Account の世界が繋がる訳です。

ここからは Infrastructure の原理を元に私からの推測の記述になります。 AWS Engineer では無いので具現化したものが異なるかも知れませんが原理的には同じ流動だと思います。 ※もし、AWS Engineer 方がこの記事を見たのであれば Feedback お願いします。

この方式は ENI を一つ Fargate 対象の Host に Assign するし、他の AWS User の Fargate Service が同じ EC2 に実行されていることを考えると Resource の独立のために NIC 自体の Isolation も当然必要になります。

よって、NIC として ENI をまるごと Fargate Service に当てて、それを Host Networking Mode として提供することで VPC の Network Address との Mapping や同じ EC2 の中で他の AWS User の Fargate Service と独立性を保証出来たと思います。

そもそも Cloud Computing なので基本的に他の AWS User と Resource Sharing が行われるのが当然ではあるのでこのような方式になったのでは無いかと思います。

Dedicated Machine が Support されれば話は変わりますが、Task/Service の定義でそのような宣言が Option として存在しないため個人的には今の推測が正しいのでは無いかと思います。

Reference