1. Introduction
포스팅 작성 시점 기준으로 저는 ECS에서는 awsvpc, EKS에서는 VPC CNI 이외의 컨테이너간 네트워크에 대한 사용 경험이 없습니다.
즉 AWS VPC에 종속된 네트워크 환경만 경험했기 때문에, 서비스 별 Network 환경에 대한 이해가 필요했고, Network Mode 별로 작동 방식이나 설정 가능한 옵션 등이 다르기 때문에 해당 내용에 대해 공부하는 시간을 가졌습니다.
2. Network Mode
내용이 Linux의 Network Mode 위주로 구성되어있습니다.
ECS는 AWS의 완전관리형 Container Ochestration 서비스이기 때문에, 여러 Network Mode를 공식적으로 지원합니다.
2.1 OS별 지원되는 Network Mode
다음 표는 EC2 Instance 유형으로 ECS Container Instance를 구성했을 때 유효합니다.
Fargate 유형은 awsvpc 모드만 사용할 수 있습니다.
Network mode | Linux containers on EC2 | Windows containers on EC2 |
awsvpc | O | O |
bridge | O | X |
host | O | X |
none | O | X |
default | X | O |
2.2 Network Mode 종류
awsvpc mode
Task에 고유한 ENI와 Primary private IPv4 주소가 할당됩니다. 이렇게 하면 태스크에 Amazon EC2 인스턴스와 동일한 네트워킹 속성이 적용됩니다.
Task별로 ENI가 할당되기 때문에, AWS의 다른 서비스와의 결합이 쉽고 Network / ENI 관리 또한 AWS가 관리합니다.
ECS용 Instance의 type에 따른 ENI 할당량이 존재하여 하나의 인스턴스에 할당할 수 있는 ECS Task 개수가 제한되지만, ENI Trunking Mode (후술) 를 사용하여 ENI 한계를 확장할 수 있습니다.
다음은 awsvpc 모드의 특징 중 제 기준에 중요해보이는 내용을 정리했습니다.
•
Task 가 자동으로 생성하는 ENI는 public ip 주소가 제공되지 않음 (자연스럽게 private subnet + NAT 가 요구됨)
•
Task와 연결된 ENI가 실수로 삭제되는 것을 방지하기 위해서 ENI는 수동으로 분리하거나 수정할 수 없습니다. (Task의 ENI를 해제하려면 Task를 중지해야함)
•
모든 Task에 ENI가 연결되기 때문에 Task 별 보안 그룹 액세스 제어 가능
•
ALB/NLB의 대상으로 항상 IP를 지정해야함 (EC2 Instance로 설정하면 기본적으로 Primary ENI가 할당될 것임)
•
IP 주소와 탄력적 네트워크 인터페이스의 DNS 이름으로 주소 지정 가능
•
애플리케이션 로드밸런서 및 네트워크 로드밸런서에 'IP' 타깃으로 연결 가능
•
VPC Flowlog를 통한 네트워크 흐름 관찰 가능
•
포트 충돌 걱정 없이 동일한 인스턴스에서 동일한 작업 정의의 여러 복사본을 실행 가능
•
docker0 가상 브릿지 인터페이스를 사용하지 않기 때문에, 네트워크 성능 저하 없음
다음 사진은 awsvpc 모드에 대한 다이어그램입니다.
host mode
이 task는 컨테이너 포트를 EC2 인스턴스 ENI에 직접 매핑하여 Docker의 기본 제공 가상 네트워크를 우회하는 호스트의 네트워크를 사용합니다.
이 네트워크 모드에서는 동적 포트 매핑을 사용할 수 없습니다. 이 모드에서 컨테이너는 특정 호스트 포트 번호를 지정해야 합니다. 호스트의 포트 번호는 여러 작업에서 동일하게 사용할 수 없습니다. 따라서 단일 Amazon EC2 인스턴스에서 동일한 포트로 여러 Task를 실행할 수 없습니다.
다음 사진과 같이 Container에서 Port 3000으로 서비스를 시작하는 경우, 호스트 인스턴스도 3000번 포트를 사용하게 됩니다.
bridge mode
이 Task는 각 Amazon EC2 인스턴스 내부에서 실행되는 Linux의 기본 제공 가상 네트워크인 Docker를 사용합니다. Linux의 기본 제공 가상 네트워크는 브리지 Docker 네트워크 드라이버를 사용합니다. 작업 정의에 네트워크 모드가 지정되지 않은 경우 이 모드가 Linux의 기본 네트워크 모드입니다.
정적 포트 매핑
•
host 모드와 동일하게 각 호스트 인스턴스에서 동일한 포트를 동시에 하나만 실행할 수 있습니다.
동적 포트 매핑
•
하나의 EC2 Instance에서 여러개의 동일한 Container Port 혹은 Task를 실행할 수 있지만, 서비스간 네트워크 제어가 쉽지 않다.
다음은 bridge 모드의 특징입니다.
•
docker0 가상 브릿지 인터페이스 사용으로 인한 추가 네트워크 홉 및 성능 저하
•
호스트 포트 매핑에는 추가적인 운영 노력과 고려 사항이 필요함
•
단일 EC2 ENI가 여러 컨테이너에 의해 공유됨
•
단일 컨테이너에 대한 Security Group 적용이 불가능함
•
AWS network obsevability와 통합되지 않음
default mode
작업 정의에 네트워크 모드가 지정되지 않은 경우 default 모드가 Windows의 기본 모드입니다.
이 Task는 각 EC2 인스턴스 내부에서 실행되는 Windows의 Docker 기본 제공 가상 네트워크를 사용합니다. Windows의 기본 제공 가상 네트워크는 nat Docker 네트워크 드라이버를 사용합니다.
none mode
외부 네트워크 연결이 없습니다.
3. 관련 개념 정리
3.1 ENI Trunking Mode
awsvpc네트워크 모드를 사용하는 각 Amazon ECS Task는 자체 ENI를 가지며, 해당 Task를 호스팅하는 컨테이너 인스턴스에 연결됩니다. 그렇기 때문에 인스턴스 타입별 최대 할당 가능한 ENI 개수에 영향을 받습니다.
기본적으로 awsvpc 모드는 각 task에 ENI를 할당합니다. 그리고 기본적으로 Host Instance에서 Primary ENI로 1개의 ENI를 할당합니다. 그래서 인스턴스 유형에 따라 빠르게 할당 가능한 ENI가 고갈될 수 있습니다.
•
예를 들어 c5.large 는 3개의 ENI Limit을 가지기 때문에, Host ENI (Primary ENI)를 제외하면 2개의 Task만 실행할 수 있습니다.
이 한계를 해소하기 위해 나온 개념이 ENI Trunking Mode입니다.
ENI Trunking은 ECS가 EC2 인스턴스당 시작할 수 있는 컨테이너 작업의 수를 크게 늘립니다. ENI 트렁킹 모드에서는 EC2 호스트당 2개의 ENI만 사용됩니다. 하나의 ENI는 EC2 호스트에서 사용되며, 다른 하나의 트렁크 ENI는 호스트의 모든 컨테이너가 공유합니다.
•
•
정확한 문서를 찾지는 못했지만, 위 그림을 보며 이해할 때 ECS Task는 기본적으로 ENI 자체를 할당하지만 Trunking Mode에서의 Task는 Trunking ENI를 공유하면서 secondary ip를 할당하여 사용하는것으로 보여집니다.
다음 사진과 같이 VPC에 사용하지 않는 대역을 추가하여 Trunk ENI가 ECS를 호스팅하는 EC2 Instance와 다른 대역에서 생성되도록 할 수 있습니다. (IP 주소 고갈 방지)
3.2 Linux Namespace
동일한 시스템에서 별개의 독립된 공간을 격리된 환경에서 운영하는 가상화 기술.
하이퍼바이저와 다음과 같은차이가 있습니다.
•
하이퍼바이저는 하드웨어를 가상화합니다. 그래서 물리적으로 분리된 Guest OS 및 Kernel이 존재합니다.
•
네임스페이스는 하드웨어를 분리하지 않습니다. 동일한 OS 및 Kernel 위에서 동작합니다.
Linux 에는 다음과 같은 Namespace가 있습니다.
1.
UTS namespace
•
hostname을 네임스페이스 별로 분할 격리 시켜줍니다.
2.
IPC namespace (Interprocess Communication)
•
IPC는 프로세스간 데이터를 주고받는 경로를 의미합니다. IPC 네임스페이스는 IPC 리소스를 분할 격리 시켜줍니다. 즉, 프로세스간 통신을 격리시킵니다.
3.
PID namespace
•
PID(process ID)를 분할 관리합니다. PID 네임스페이스를 이용하면 하나의 시스템에서 동일한 PID가 2개인것처럼보이게 프로세스를 만들 수 있습니다.
4.
Mount namespace
•
파일 시스템의 마운트(mount)지점을 분할하여 격리합니다.
5.
NET namespace
•
네트워크 인터페이스, iptables 등 네트워크 리소스와 관련된 정보를 분할합니다.
6.
USER namespace
•
user와 group ID를 분할하고 격리합니다.
7.
Time namespace
•
시간 정보를 격리합니다.
8.
cgroup namespace
•
cgroup 격리를 통해서 프로세스는 /proc/self/cgroup에 가상화된 새로운 cgroup 마운트를 가집니다.
3.3 Pause Container
ECS의 네트워크를 awsvpc mode로 사용할 때
ECS가 인스턴스에 탄력적 네트워크 인터페이스를 연결하고 에이전트에 메시지를 전송하여 작업의 컨테이너에 대한 탄력적 네트워크 인터페이스를 프로비저닝하면, ENI가 호스트의 Global Default 네트워크 네임스페이스에 표시됩니다. ECS 에이전트는 CNI plug-in 체인을 호출하여 컨테이너의 네트워크 네임스페이스에서 ENI가 적절하게 구성되었는지 확인합니다.
또한 컨테이너는 IAM 역할 자격 증명을 수임 받기 위해서 ECS 에이전트가 호스팅하는 자격 증명 엔드포인트에 HTTP 요청을 해야 합니다. 이 작업은 ecs-bridge 및 ecs-ipam 플러그인에 의해 처리됩니다.
다음 다이어그램은 위에 설명된 프로세스를 보여줍니다.
네트워크 스택 구성과 애플리케이션 컨테이너에서 호출되는 명령 사이의 경합 조건(Race Condition)을 피하기 위해 ECS 에이전트는 작업 정의에서 컨테이너를 시작하기 전에 각 작업에 대해 추가로 pause container를 생성합니다.
다음 앞서 언급한 CNI 플러그인을 실행하여 일시 중지 컨테이너의 네트워크 네임스페이스를 설정합니다. 또한 작업의 나머지 컨테이너도 시작하여 일시 중지 컨테이너의 네트워크 스택을 공유하도록 합니다. 즉, 작업의 모든 컨테이너는 ENI IP 주소로 지정할 수 있으며, localhost 인터페이스를 통해 서로 통신할 수 있습니다.
awsvpc mode는 pause container가 network namespace를 관리하기 때문에, ECS Cluster에서는 확인할 수 없더라도 EC2 Instance에 접속한 후 docker ps 명령어를 입력하면 pause container가 동작중임을 확인하실 수 있습니다.