Skip to content

네트워크 구성

< 이전: 사전 요구 사항 | 목차 | 다음: 에어갭 환경 구성 >

지원 버전: EKS 1.31+, nodeadm 0.1+ 마지막 업데이트: 2026년 2월 23일

이 문서에서는 EKS Hybrid Nodes 환경에서 필요한 CIDR 요구 사항, 방화벽 포트, AWS 엔드포인트 접근, 보안 그룹 구성, DNS 구성을 다룹니다.

네트워크 아키텍처 개요

다음 다이어그램은 VPC 구성, Transit Gateway 라우팅, 원격 CIDR, 방화벽 규칙을 포함한 EKS Hybrid Nodes의 전체 네트워크 토폴로지를 보여줍니다.

EKS Hybrid Nodes 네트워크 사전 요구 사항

VPC 네트워크 허브 개념

EKS Hybrid Nodes 환경에서 VPC는 하이브리드 노드와 컨트롤 플레인 간의 네트워크 허브 역할을 합니다.

  • ENI 배치: EKS 컨트롤 플레인은 VPC 서브넷에 ENI(Elastic Network Interface)를 배치합니다. 이 ENI들이 컨트롤 플레인과 하이브리드 노드 간의 통신 엔드포인트입니다.
  • 트래픽 경로: 컨트롤 플레인과 하이브리드 노드 간의 모든 트래픽은 이 ENI를 통해 흐릅니다. API 서버 요청, kubelet 통신, 웹훅 호출 등 모든 제어 평면 트래픽이 VPC ENI를 경유합니다.
  • ENI IP 변경 가능성: 클러스터 업데이트(버전 업그레이드 등) 시 ENI가 삭제되고 재생성될 수 있으며, 이때 ENI IP 주소가 변경될 수 있습니다. 방화벽 규칙에서 개별 IP 대신 서브넷 CIDR 범위를 사용하면 이러한 변경에 유연하게 대응할 수 있습니다.
┌─────────────────────────────────────────────────────────────────┐
│                         AWS Cloud                                │
│  ┌──────────────────┐    ┌──────────────────────────────────┐   │
│  │  EKS Control     │    │              VPC                  │   │
│  │     Plane        │◄──►│  ┌────────┐  ┌────────┐          │   │
│  │                  │    │  │  ENI   │  │  ENI   │          │   │
│  └──────────────────┘    │  │10.0.1.x│  │10.0.2.x│          │   │
│                          │  └────┬───┘  └────┬───┘          │   │
│                          └───────┼───────────┼──────────────┘   │
└──────────────────────────────────┼───────────┼──────────────────┘
                                   │           │
                           VPN / Direct Connect
                                   │           │
┌──────────────────────────────────┼───────────┼──────────────────┐
│                          On-Premises                             │
│                    ┌─────────────┴───────────┴─────────────┐    │
│                    │         Hybrid Nodes                   │    │
│                    │   ┌─────────┐    ┌─────────┐          │    │
│                    │   │  Node   │    │  Node   │          │    │
│                    │   │ kubelet │    │ kubelet │          │    │
│                    │   └─────────┘    └─────────┘          │    │
│                    └───────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

CIDR 범위 요구 사항

온프레미스 노드 및 파드 CIDR은 다음 조건을 충족해야 합니다:

  • RFC-1918 범위 내에 있어야 합니다: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
  • 다음과 겹치지 않아야 합니다:
    • 서로 다른 CIDR 간 (노드 CIDR ↔ 파드 CIDR)
    • EKS 클러스터의 VPC CIDR
    • Kubernetes 서비스 IPv4 CIDR

EKS 클러스터 생성 시 RemoteNodeNetworkRemotePodNetwork 필드에 온프레미스 CIDR을 지정합니다.

라우팅 가능 vs 라우팅 불가능 파드 네트워크

구성라우팅 가능 (권장)라우팅 불가능
설정BGP(권장), 정적 라우트 또는 커스텀 라우팅CNI egress masquerade/NAT 사용
웹훅Hybrid 노드에서 실행 가능클라우드 노드에서만 실행 가능
Pod↔Pod 통신클라우드↔온프레미스 직접 통신 가능직접 통신 불가
AWS 서비스 연동ALB, Prometheus 등이 Hybrid 워크로드와 통신 가능통신 불가

권장 사항: Cilium BGP Control Plane을 사용하여 파드 CIDR을 라우팅 가능하게 구성하세요.


필수 방화벽 포트

클러스터 통신 포트

온프레미스와 AWS 간 통신을 위해 다음 포트를 열어야 합니다:

포트프로토콜방향용도
443TCPOn-Prem → AWSKubelet에서 Kubernetes API 서버로 통신
443TCPOn-Prem → AWS파드에서 Kubernetes API 서버로 통신
10250TCPAWS → On-PremAPI 서버에서 Kubelet으로 통신
웹훅 포트TCPAWS → On-PremAPI 서버에서 웹훅으로 통신 (라우팅 가능 파드 네트워크만)
53TCP/UDP양방향CoreDNS (파드 CIDR ↔ 파드 CIDR, 클라우드 CoreDNS 시 VPC CIDR 포함)
앱 포트사용자 정의양방향Pod-to-Pod 애플리케이션 통신

VPN 포트 (Site-to-Site VPN 사용 시)

포트프로토콜방향용도
500UDP양방향IKE (Internet Key Exchange)
4500UDP양방향IPSec NAT-T

Cilium CNI 포트

Cilium을 CNI로 사용할 때 추가로 필요한 포트:

포트프로토콜방향용도
8472UDP양방향VXLAN 오버레이 (기본 터널 모드)
4240TCP양방향헬스 체크

참고: Cilium 및 Calico의 상세 방화벽 요구 사항은 각 프로젝트의 공식 문서를 참조하세요.

iptables 규칙 예시

bash
# Kubernetes API 서버 통신 허용
sudo iptables -A INPUT -p tcp --dport 443 -s 10.0.0.0/8 -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 443 -d 10.0.0.0/8 -j ACCEPT

# Kubelet API 허용
sudo iptables -A INPUT -p tcp --dport 10250 -s 10.0.0.0/8 -j ACCEPT

# Cilium VXLAN 허용
sudo iptables -A INPUT -p udp --dport 8472 -j ACCEPT
sudo iptables -A OUTPUT -p udp --dport 8472 -j ACCEPT

# Cilium 헬스 체크 허용
sudo iptables -A INPUT -p tcp --dport 4240 -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 4240 -j ACCEPT

# DNS 허용
sudo iptables -A INPUT -p tcp --dport 53 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
sudo iptables -A OUTPUT -p udp --dport 53 -j ACCEPT

# 규칙 저장
sudo iptables-save | sudo tee /etc/iptables/rules.v4

온프레미스 아웃바운드 접근 요구 사항

설치 및 업그레이드 시 필요한 엔드포인트

nodeadm 설치 및 업그레이드를 위해 온프레미스 노드에서 다음 AWS 엔드포인트에 HTTPS(443) 접근이 필요합니다:

컴포넌트URL비고
EKS 노드 아티팩트 (S3)https://hybrid-assets.eks.amazonaws.comnodeadm 바이너리 및 의존성
EKS 서비스https://eks.<region>.amazonaws.com클러스터 정보 조회
ECR 서비스https://api.ecr.<region>.amazonaws.com컨테이너 이미지 풀
SSM 바이너리https://amazon-ssm-<region>.s3.<region>.amazonaws.comSSM 자격 증명 프로바이더 사용 시
SSM 서비스https://ssm.<region>.amazonaws.comSSM 자격 증명 프로바이더 사용 시
IAM Roles Anywherehttps://rolesanywhere.<region>.amazonaws.comIAM RA 자격 증명 프로바이더 사용 시
OS 패키지 관리자리전별 엔드포인트시스템 패키지 설치

지속 운영 시 필요한 엔드포인트

용도소스대상비고
Kubelet → API 서버노드 CIDREKS 클러스터 IP포트 443
Pod → API 서버파드 CIDREKS 클러스터 IP포트 443
SSM 자격 증명 갱신노드 CIDRSSM 엔드포인트5분 간격 하트비트
IAM RA 자격 증명 갱신노드 CIDRIAM Anywhere 엔드포인트주기적 갱신
EKS Pod Identity노드 CIDREKS Auth 엔드포인트Pod Identity 사용 시

EKS 클러스터 네트워크 인터페이스 IP 확인

방화벽 규칙에 EKS 클러스터 IP가 필요한 경우 다음 명령으로 확인합니다:

bash
aws ec2 describe-network-interfaces \
  --filters "Name=vpc-id,Values=<VPC_ID>" "Name=description,Values=Amazon EKS*" \
  --query 'NetworkInterfaces[].PrivateIpAddress' \
  --output text

참고: EKS 네트워크 인터페이스는 클러스터 업데이트(예: 버전 업그레이드) 시 삭제 및 재생성될 수 있습니다. 제한된 서브넷 크기를 사용하면 IP 범위를 예측하기 쉬워 방화벽 구성에 유리합니다.


VPC 프라이빗 엔드포인트 (에어갭/프라이빗 환경)

VPN 또는 Direct Connect를 통해 AWS에 연결된 온프레미스 환경에서 인터넷 없이 AWS 서비스에 접근하려면 VPC Interface Endpoint (PrivateLink)를 구성해야 합니다.

왜 VPC 엔드포인트가 필요한가

일반적인 AWS API 호출은 퍼블릭 인터넷을 경유합니다. 하지만 에어갭 또는 프라이빗 전용 환경에서는 인터넷 경로가 없으므로 AWS 서비스에 접근할 수 없습니다. VPC Interface Endpoint는 VPC 내부에 ENI(Elastic Network Interface)를 생성하여, 온프레미스에서 VPN/Direct Connect를 통해 AWS API에 직접 접근할 수 있게 합니다.

온프레미스 노드
  → VPN / Direct Connect
    → VPC 내부 Interface Endpoint ENI (프라이빗 IP)
      → AWS 서비스 (EKS, ECR, STS, SSM 등)

핵심: Gateway 엔드포인트(S3, DynamoDB용)는 VPC 라우트 테이블에 경로만 추가하므로, VPN/Direct Connect로 연결된 온프레미스에서는 접근할 수 없습니다. 온프레미스에서 S3에 접근하려면 반드시 Interface 타입 S3 엔드포인트를 사용해야 합니다.

필수 Interface VPC 엔드포인트

서비스엔드포인트 서비스 이름Private DNS용도
EKScom.amazonaws.<region>.eksYesKubernetes API 서버 통신
EKS Authcom.amazonaws.<region>.eks-authYesPod Identity 인증
ECR APIcom.amazonaws.<region>.ecr.apiYes이미지 메타데이터 조회
ECR DKRcom.amazonaws.<region>.ecr.dkrYes이미지 Pull (Docker 레지스트리)
S3com.amazonaws.<region>.s3이미지 레이어, nodeadm 아티팩트 (Interface 타입)
STScom.amazonaws.<region>.stsYesIAM 자격 증명 교환
SSMcom.amazonaws.<region>.ssmYesSSM 자격 증명 프로바이더 사용 시
SSM Messagescom.amazonaws.<region>.ssmmessagesYesSSM 세션 매니저 통신

참고: S3 Interface 엔드포인트는 private_dns_enabled를 자동으로 지원하지 않습니다. S3 도메인의 프라이빗 DNS 해석이 필요한 경우 별도의 Private Hosted Zone(PHZ)을 구성해야 합니다. hybrid-assets.eks.amazonaws.com의 프라이빗 미러링 구성은 에어갭 환경 구성 - hybrid-assets 프라이빗 미러링을 참조하세요.

Terraform으로 VPC 엔드포인트 생성

보안 그룹

hcl
resource "aws_security_group" "vpc_endpoints" {
  name_prefix = "vpc-endpoints-"
  vpc_id      = var.vpc_id
  description = "Security group for VPC Interface Endpoints"

  ingress {
    description = "HTTPS from VPC and on-premises"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = [
      var.vpc_cidr,           # VPC 내부 트래픽
      var.remote_node_cidr,   # 온프레미스 노드 CIDR
      var.remote_pod_cidr     # 온프레미스 파드 CIDR
    ]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "vpc-endpoints-sg"
  }
}

Interface VPC 엔드포인트

hcl
# 생성할 Interface 엔드포인트 목록
locals {
  interface_endpoints = {
    eks          = "com.amazonaws.${var.region}.eks"
    eks-auth     = "com.amazonaws.${var.region}.eks-auth"
    ecr-api      = "com.amazonaws.${var.region}.ecr.api"
    ecr-dkr      = "com.amazonaws.${var.region}.ecr.dkr"
    sts          = "com.amazonaws.${var.region}.sts"
    ssm          = "com.amazonaws.${var.region}.ssm"
    ssmmessages  = "com.amazonaws.${var.region}.ssmmessages"
  }
}

resource "aws_vpc_endpoint" "interface" {
  for_each = local.interface_endpoints

  vpc_id              = var.vpc_id
  service_name        = each.value
  vpc_endpoint_type   = "Interface"
  private_dns_enabled = true

  subnet_ids         = var.private_subnet_ids
  security_group_ids = [aws_security_group.vpc_endpoints.id]

  tags = {
    Name = "vpce-${each.key}"
  }
}

# S3 Interface 엔드포인트 (Gateway가 아닌 Interface 타입)
resource "aws_vpc_endpoint" "s3_interface" {
  vpc_id              = var.vpc_id
  service_name        = "com.amazonaws.${var.region}.s3"
  vpc_endpoint_type   = "Interface"
  private_dns_enabled = false  # S3는 Interface 타입에서 자동 Private DNS 미지원

  subnet_ids         = var.private_subnet_ids
  security_group_ids = [aws_security_group.vpc_endpoints.id]

  tags = {
    Name = "vpce-s3-interface"
  }
}

AWS CLI로 VPC 엔드포인트 생성

bash
# 1. VPC 엔드포인트용 보안 그룹 생성
SG_ID=$(aws ec2 create-security-group \
  --group-name vpc-endpoints-sg \
  --description "Security group for VPC Interface Endpoints" \
  --vpc-id <VPC_ID> \
  --query 'GroupId' --output text)

# 보안 그룹에 443 포트 허용
aws ec2 authorize-security-group-ingress \
  --group-id $SG_ID \
  --ip-permissions '[
    {"IpProtocol": "tcp", "FromPort": 443, "ToPort": 443,
     "IpRanges": [
       {"CidrIp": "<VPC_CIDR>", "Description": "VPC internal"},
       {"CidrIp": "<REMOTE_NODE_CIDR>", "Description": "On-prem nodes"},
       {"CidrIp": "<REMOTE_POD_CIDR>", "Description": "On-prem pods"}
     ]}
  ]'

# 2. Interface VPC 엔드포인트 생성 (EKS 예시)
aws ec2 create-vpc-endpoint \
  --vpc-id <VPC_ID> \
  --vpc-endpoint-type Interface \
  --service-name com.amazonaws.<REGION>.eks \
  --subnet-ids <SUBNET_ID_1> <SUBNET_ID_2> \
  --security-group-ids $SG_ID \
  --private-dns-enabled

# 3. 나머지 서비스도 동일하게 생성
for SERVICE in eks-auth ecr.api ecr.dkr sts ssm ssmmessages; do
  echo "Creating endpoint for: $SERVICE"
  aws ec2 create-vpc-endpoint \
    --vpc-id <VPC_ID> \
    --vpc-endpoint-type Interface \
    --service-name com.amazonaws.<REGION>.$SERVICE \
    --subnet-ids <SUBNET_ID_1> <SUBNET_ID_2> \
    --security-group-ids $SG_ID \
    --private-dns-enabled
done

# 4. S3 Interface 엔드포인트 (private-dns-enabled 없이)
aws ec2 create-vpc-endpoint \
  --vpc-id <VPC_ID> \
  --vpc-endpoint-type Interface \
  --service-name com.amazonaws.<REGION>.s3 \
  --subnet-ids <SUBNET_ID_1> <SUBNET_ID_2> \
  --security-group-ids $SG_ID

# 5. 생성된 엔드포인트 확인
aws ec2 describe-vpc-endpoints \
  --filters "Name=vpc-id,Values=<VPC_ID>" \
  --query 'VpcEndpoints[].{ID:VpcEndpointId, Service:ServiceName, State:State}' \
  --output table

온프레미스 DNS 확인 흐름

VPC 엔드포인트의 private_dns_enabled 옵션은 VPC 내부에서만 작동합니다. 온프레미스에서 AWS 서비스 도메인(예: eks.ap-northeast-2.amazonaws.com)을 VPC 엔드포인트의 프라이빗 IP로 해석하려면, Route 53 Resolver Inbound Endpoint를 통해 VPC의 DNS를 쿼리해야 합니다.

온프레미스 노드
  → 온프레미스 DNS 서버 (조건부 포워딩 설정)
    → Route 53 Resolver Inbound Endpoint (VPC 내)
      → Route 53이 Private Hosted Zone / VPC DNS 검색
        → VPC Endpoint ENI의 프라이빗 IP 반환
          → 온프레미스 노드가 VPN/DX를 통해 ENI에 직접 접근

온프레미스 DNS 서버 조건부 포워딩 설정

온프레미스 DNS 서버(예: BIND, Windows DNS, dnsmasq)에서 AWS 도메인을 Route 53 Inbound Endpoint로 전달하도록 구성합니다.

# BIND 예시 (/etc/named.conf)
zone "amazonaws.com" {
    type forward;
    forward only;
    forwarders {
        10.0.1.10;    # Route 53 Inbound Endpoint IP #1
        10.0.2.10;    # Route 53 Inbound Endpoint IP #2
    };
};

zone "eks.amazonaws.com" {
    type forward;
    forward only;
    forwarders {
        10.0.1.10;
        10.0.2.10;
    };
};

참고: Route 53 Resolver Inbound Endpoint 생성 방법은 이 문서의 DNS 구성 섹션을 참조하세요. VPC 엔드포인트 구성 후 반드시 nslookup eks.<region>.amazonaws.com으로 프라이빗 IP가 반환되는지 확인하세요.


AWS 보안 그룹 구성

EKS는 클러스터 생성 시 보안 그룹을 자동으로 구성하지만, 아웃바운드 규칙은 자동 생성되지 않습니다 (보안 그룹은 기본적으로 모든 아웃바운드를 허용).

자동 생성되는 인바운드 규칙

프로토콜포트소스용도
TCP443원격 노드 CIDRKubelet에서 Kubernetes API로
TCP443원격 파드 CIDR파드에서 Kubernetes API로 (NAT 미사용 CNI)

수동 추가 필요한 아웃바운드 규칙

프로토콜포트대상용도
TCP10250원격 노드 CIDRAPI 서버에서 Kubelet으로
TCP웹훅 포트원격 파드 CIDRAPI 서버에서 웹훅으로
bash
# 커스텀 보안 그룹 생성 예시
aws ec2 create-security-group \
  --group-name hybrid-nodes-sg \
  --description "Security group for EKS Hybrid Nodes" \
  --vpc-id <VPC_ID>

# 인바운드 규칙 추가
aws ec2 authorize-security-group-ingress \
  --group-id <SG_ID> \
  --ip-permissions '[
    {"IpProtocol": "tcp", "FromPort": 443, "ToPort": 443,
     "IpRanges": [{"CidrIp": "<REMOTE_NODE_CIDR>"}, {"CidrIp": "<REMOTE_POD_CIDR>"}]}
  ]'

주의: 보안 그룹당 기본 인바운드 규칙 제한은 60개입니다. 또한 EKS는 원격 네트워크를 제거할 때 규칙을 자동으로 삭제하지 않으므로 수동 정리가 필요합니다.


Pod CIDR 방화벽 전략

Pod 간 통신을 위해 전체 Pod CIDR 범위에 대한 방화벽 규칙을 등록해야 합니다.

bash
# Pod CIDR 범위 예시: 10.244.0.0/16
# 클러스터의 Pod CIDR 확인
kubectl cluster-info dump | grep -m 1 cluster-cidr

# Pod CIDR에 대한 방화벽 규칙 추가
sudo iptables -A INPUT -s 10.244.0.0/16 -j ACCEPT
sudo iptables -A OUTPUT -d 10.244.0.0/16 -j ACCEPT
sudo iptables -A FORWARD -s 10.244.0.0/16 -j ACCEPT
sudo iptables -A FORWARD -d 10.244.0.0/16 -j ACCEPT

# Service CIDR도 추가 (예: 172.20.0.0/16)
sudo iptables -A INPUT -s 172.20.0.0/16 -j ACCEPT
sudo iptables -A OUTPUT -d 172.20.0.0/16 -j ACCEPT

DNS 구성

Route 53 Resolver Inbound Endpoint

온프레미스에서 AWS 도메인을 쿼리할 수 있도록 Inbound Endpoint를 생성합니다.

bash
# Inbound Endpoint 생성
aws route53resolver create-resolver-endpoint \
  --creator-request-id "hybrid-inbound-$(date +%s)" \
  --name "hybrid-inbound-endpoint" \
  --security-group-ids sg-0123456789abcdef0 \
  --direction INBOUND \
  --ip-addresses SubnetId=subnet-111111111,Ip=10.0.1.10 SubnetId=subnet-222222222,Ip=10.0.2.10

# Endpoint IP 확인
aws route53resolver list-resolver-endpoint-ip-addresses \
  --resolver-endpoint-id rslvr-in-xxxxxxxxxxxxx

Route 53 Resolver Outbound Endpoint

AWS에서 온프레미스 도메인을 쿼리할 수 있도록 Outbound Endpoint와 전달 규칙을 생성합니다.

bash
# Outbound Endpoint 생성
aws route53resolver create-resolver-endpoint \
  --creator-request-id "hybrid-outbound-$(date +%s)" \
  --name "hybrid-outbound-endpoint" \
  --security-group-ids sg-0123456789abcdef0 \
  --direction OUTBOUND \
  --ip-addresses SubnetId=subnet-111111111 SubnetId=subnet-222222222

# 전달 규칙 생성 (온프레미스 도메인)
aws route53resolver create-resolver-rule \
  --creator-request-id "forward-onprem-$(date +%s)" \
  --name "forward-to-onprem" \
  --rule-type FORWARD \
  --domain-name "internal.company.io" \
  --resolver-endpoint-id rslvr-out-xxxxxxxxxxxxx \
  --target-ips "Ip=192.168.1.10,Port=53" "Ip=192.168.1.11,Port=53"

# VPC에 규칙 연결
aws route53resolver associate-resolver-rule \
  --resolver-rule-id rslvr-rr-xxxxxxxxxxxxx \
  --vpc-id vpc-0123456789abcdef0

CoreDNS 커스텀 도메인 구성

온프레미스 도메인에 대한 DNS 쿼리를 온프레미스 DNS 서버로 전달합니다.

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health {
            lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        forward . /etc/resolv.conf {
            max_concurrent 1000
        }
        cache 30
        loop
        reload
        loadbalance
    }
    internal.company.io:53 {
        errors
        cache 30
        forward . 192.168.1.10 192.168.1.11 {
            max_concurrent 1000
        }
    }
bash
# CoreDNS ConfigMap 적용
kubectl apply -f coredns-configmap.yaml

# CoreDNS 재시작
kubectl rollout restart deployment coredns -n kube-system

# DNS 해석 테스트
kubectl run dns-test --rm -it --image=busybox --restart=Never -- nslookup internal.company.io

CoreDNS 이중 배치 구성 (온프레미스 + 클라우드)

왜 이중 배치가 필요한가?

EKS Hybrid Nodes 환경에서 CoreDNS가 클라우드 노드에만 실행되면, 온프레미스 Pod의 DNS 쿼리가 VPN/Direct Connect를 거쳐 클라우드까지 왕복해야 합니다. 반대로 CoreDNS가 온프레미스 노드에만 실행되면, 클라우드 Pod의 DNS 쿼리가 역방향으로 왕복합니다.

양쪽 모두에 CoreDNS Pod가 존재해야 DNS 지연이 최소화되고, 한쪽 네트워크 장애 시에도 DNS 서비스가 유지됩니다.

레플리카 수 권장

최소 4개 (클라우드 2개 + 온프레미스 2개)를 권장합니다. 각 위치에 2개 이상의 레플리카를 배치하여 고가용성을 확보합니다.

CoreDNS Deployment 패치

topologySpreadConstraintstolerations를 사용하여 CoreDNS Pod를 클라우드와 온프레미스 노드에 균등하게 분산합니다.

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coredns
  namespace: kube-system
spec:
  replicas: 4
  template:
    spec:
      tolerations:
        - key: "eks.amazonaws.com/compute-type"
          value: "hybrid"
          effect: "NoSchedule"
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: "eks.amazonaws.com/compute-type"
          whenUnsatisfiable: ScheduleAnyway
          labelSelector:
            matchLabels:
              k8s-app: kube-dns

kubectl patch 명령어

bash
kubectl patch deployment coredns -n kube-system --type=strategic -p '{
  "spec": {
    "replicas": 4,
    "template": {
      "spec": {
        "tolerations": [
          {
            "key": "eks.amazonaws.com/compute-type",
            "value": "hybrid",
            "effect": "NoSchedule"
          }
        ],
        "topologySpreadConstraints": [
          {
            "maxSkew": 1,
            "topologyKey": "eks.amazonaws.com/compute-type",
            "whenUnsatisfiable": "ScheduleAnyway",
            "labelSelector": {
              "matchLabels": {
                "k8s-app": "kube-dns"
              }
            }
          }
        ]
      }
    }
  }
}'

배치 확인

bash
# CoreDNS Pod가 양쪽 노드에 분산되었는지 확인
kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide

# 노드별 compute-type 레이블 확인
kubectl get nodes -L eks.amazonaws.com/compute-type

참고:

  • EKS 관리형 CoreDNS 애드온을 사용하는 경우, 애드온의 configurationValues를 통해 동일한 설정을 적용할 수 있습니다.
  • whenUnsatisfiable: ScheduleAnyway를 사용하므로 한쪽에 노드가 없어도 스케줄링이 차단되지 않습니다. 이는 클러스터 초기 부트스트랩 시 CoreDNS가 정상적으로 시작될 수 있도록 보장합니다.

트래픽 플로우 패턴

AWS와 온프레미스 간의 트래픽 흐름 패턴을 이해하는 것은 방화벽 구성과 문제 해결에 필수적입니다. 다음 섹션에서는 AWS 공식 아키텍처 다이어그램과 함께 각 트래픽 패턴을 상세히 설명합니다.

출처: AWS EKS Hybrid Nodes Traffic Flows

패턴 1: Kubelet → EKS 컨트롤 플레인

Kubelet은 DNS 조회를 통해 API 서버 엔드포인트로 HTTPS 요청을 시작합니다. 퍼블릭 액세스 모드에서는 트래픽이 퍼블릭 인터넷을 통과합니다. 프라이빗 모드에서는 VPN/DX를 통해 VPC ENI로 트래픽이 흐릅니다.

Kubelet에서 컨트롤 플레인으로

패턴 2: EKS 컨트롤 플레인 → Kubelet

API 서버는 노드 상태 객체에서 노드 IP를 가져옵니다. 트래픽은 VPC를 통해 라우팅된 후 Direct Connect 또는 VPN을 통해 클라우드 경계를 넘어 포트 10250의 kubelet에 도달합니다. 이는 kubectl logs, kubectl exec, kubectl port-forward 등에 사용됩니다.

컨트롤 플레인에서 Kubelet으로

패턴 3: Pod → EKS 컨트롤 플레인

Pod는 kubernetes Service(ClusterIP)를 통해 Kubernetes API와 통신합니다. kube-proxy가 DNAT를 적용하여 서비스 IP를 컨트롤 플레인 ENI IP로 변환한 후, 패킷이 VPN/DX를 통해 VPC로 라우팅됩니다.

  • CNI NAT 미사용 시: Pod가 kubernetes 서비스 IP(예: 172.16.0.1)로 전송하면 kube-proxy가 컨트롤 플레인 ENI IP로 DNAT를 적용합니다. 반환 트래픽은 파드 CIDR을 통한 역방향 라우팅이 필요합니다.
  • CNI NAT 사용 시: CNI가 노드 처리 전에 SNAT를 적용하여 반환 라우팅을 단순화합니다(추가 파드 CIDR 라우팅 불필요).

Pod에서 컨트롤 플레인으로

패턴 4: EKS 컨트롤 플레인 → Pod (웹훅)

API 서버가 하이브리드 노드에서 실행 중인 웹훅 Pod에 직접 연결을 시작합니다. 트래픽은 원격 파드 CIDR에 대해 VPC를 통해 라우팅되고, 게이트웨이를 통해 경계를 넘습니다. 이는 라우팅 가능한 파드 CIDR이 필요합니다.

컨트롤 플레인에서 Pod로

중요: 온프레미스 파드 CIDR이 라우팅 불가능한 경우, 모든 웹훅을 클라우드 노드에서 실행해야 합니다. 아래 웹훅 구성 섹션을 참조하세요.

패턴 5: 하이브리드 노드 간 Pod ↔ Pod

서로 다른 하이브리드 노드의 Pod는 VXLAN 캡슐화(또는 Geneve, IP-in-IP와 같은 유사한 오버레이 프로토콜)를 사용하여 통신합니다. CNI는 소스/대상 노드 IP를 사용하여 외부 헤더로 원본 Pod-to-Pod 패킷을 캡슐화합니다. 수신 노드의 CNI가 캡슐을 해제하고 대상 Pod로 전달합니다.

하이브리드 노드 간 Pod-to-Pod

VXLAN 캡슐화 상세

VXLAN(Virtual Extensible LAN)은 L2 프레임을 L3 패킷으로 캡슐화하여 오버레이 네트워크를 구성합니다. 하이브리드 노드 간 Pod 통신에서 패킷 구조가 어떻게 변환되는지 살펴봅니다.

원본 패킷 (캡슐화 전)

┌────────────────────────────────────────────────┐
│  Pod-A IP (src) → Pod-B IP (dst) │   Payload   │
│    10.85.0.10       10.85.1.20   │   (data)    │
└────────────────────────────────────────────────┘

VXLAN 캡슐화 후

┌──────────────────────────────────────────────────────────────────────────────┐
│ Outer IP Header │ UDP Header │ VXLAN Header │      Original Packet          │
│ Node-A → Node-B │ Port 8472  │    (VNI)     │ Pod-A IP → Pod-B IP │ Payload │
│ 10.80.1.10      │            │              │ 10.85.0.10  10.85.1.20        │
│   → 10.80.1.11  │            │              │                               │
└──────────────────────────────────────────────────────────────────────────────┘

캡슐화 프로세스 (송신 노드)

  1. Pod-A가 Pod-B로 패킷을 전송합니다
  2. 송신 노드의 CNI(Cilium)가 대상 Pod IP를 확인하고 해당 노드를 조회합니다
  3. CNI가 원본 패킷을 VXLAN 헤더와 외부 IP 헤더로 래핑합니다
  4. 외부 헤더의 소스/대상 IP는 노드 IP를 사용합니다
  5. 캡슐화된 패킷이 UDP 포트 8472로 전송됩니다

역캡슐화 프로세스 (수신 노드)

  1. 수신 노드가 UDP 8472 포트에서 VXLAN 패킷을 수신합니다
  2. CNI가 VXLAN 헤더와 외부 IP 헤더를 제거합니다
  3. 원본 패킷이 대상 Pod로 전달됩니다

주요 구성 요소

구성 요소설명
VNI (VXLAN Network Identifier)파드 네트워크 트래픽을 격리하는 24비트 식별자 (기본값: 자동 할당)
UDP 포트Cilium 기본값: 8472, 표준 VXLAN: 4789
MTUVXLAN 오버헤드(50바이트)를 고려하여 설정 필요 (예: 1500 → 1450)

참고: Cilium은 VXLAN 외에도 Geneve, IP-in-IP 등 다른 터널 프로토콜을 지원합니다. --tunnel 옵션으로 터널 모드를 선택할 수 있습니다.

패턴 6: 클라우드 Pod ↔ 하이브리드 Pod (East-West)

VPC Pod(VPC CNI 사용)가 하이브리드 Pod로 직접 전송합니다. VPC 라우팅이 트래픽을 온프레미스 게이트웨이로 보냅니다. 패킷이 경계를 넘어 하이브리드 노드에 도착합니다. 이는 라우팅 가능한 파드 CIDR과 적절한 VPC 라우트 테이블 항목이 필요합니다.

East-West 트래픽

트래픽 플로우 요약

#플로우방향포트요구 사항
1Kubelet → API 서버On-Prem → AWSTCP 443VPN/DX 또는 인터넷
2API 서버 → KubeletAWS → On-PremTCP 10250SG 아웃바운드 규칙
3Pod → API 서버On-Prem → AWSTCP 443kube-proxy DNAT
4API 서버 → Webhook PodAWS → On-PremTCP 8443+라우팅 가능 파드 CIDR
5Hybrid Pod ↔ Hybrid PodOn-Prem 내부UDP 8472Cilium VXLAN
6Cloud Pod ↔ Hybrid PodAWS ↔ On-PremVPC 라우트라우팅 가능 파드 CIDR + VPC 라우트

kube-proxy iptables 체인 구조

kube-proxy는 Kubernetes Service 트래픽을 실제 Pod로 라우팅하기 위해 iptables 규칙을 사용합니다. 하이브리드 노드에서도 동일한 3단계 체인 구조가 적용됩니다.

KUBE-SERVICES (진입점)
  └─→ KUBE-SVC-xxxx (서비스별 체인, 로드 밸런싱)
        └─→ KUBE-SEP-xxxx (엔드포인트별 체인, Pod IP로 DNAT)

체인별 역할

체인역할예시
KUBE-SERVICES모든 ClusterIP 서비스의 목적지 IP:Port를 매칭172.20.0.1:443KUBE-SVC-NPX...
KUBE-SVC-xxxx확률 기반 로드 밸런싱으로 엔드포인트 선택3개 Pod → 각각 33% 확률
KUBE-SEP-xxxx특정 Pod IP:Port로 DNAT 수행DNAT to 10.85.0.15:8080

실제 iptables 규칙 예시

bash
# KUBE-SERVICES 체인 (nat 테이블)
-A KUBE-SERVICES -d 172.20.0.10/32 -p tcp -m tcp --dport 80 -j KUBE-SVC-XXXXXX

# KUBE-SVC 체인 (로드 밸런싱)
-A KUBE-SVC-XXXXXX -m statistic --mode random --probability 0.33333 -j KUBE-SEP-AAAAAA
-A KUBE-SVC-XXXXXX -m statistic --mode random --probability 0.50000 -j KUBE-SEP-BBBBBB
-A KUBE-SVC-XXXXXX -j KUBE-SEP-CCCCCC

# KUBE-SEP 체인 (DNAT)
-A KUBE-SEP-AAAAAA -p tcp -j DNAT --to-destination 10.85.0.15:8080
-A KUBE-SEP-BBBBBB -p tcp -j DNAT --to-destination 10.85.0.16:8080
-A KUBE-SEP-CCCCCC -p tcp -j DNAT --to-destination 10.85.1.20:8080

하이브리드 환경에서의 의미: 위 예시에서 10.85.1.20이 다른 하이브리드 노드에 있는 Pod라면, DNAT 후 패킷은 VXLAN 캡슐화를 거쳐 해당 노드로 전송됩니다. kube-proxy가 Service 트래픽을 Pod IP로 변환하고, CNI가 실제 네트워크 라우팅을 담당합니다.

kubelet 엔드포인트

kubelet은 각 노드에서 실행되며 API 서버와의 통신을 위해 REST 엔드포인트를 노출합니다.

kubelet API 포트 및 엔드포인트

포트엔드포인트용도
10250/pods노드에서 실행 중인 Pod 목록 조회
10250/exec/{namespace}/{pod}/{container}컨테이너에서 명령 실행 (kubectl exec)
10250/logs/{namespace}/{pod}/{container}컨테이너 로그 스트리밍 (kubectl logs)
10250/metricskubelet 메트릭 노출 (Prometheus 수집용)
10250/healthzkubelet 헬스 체크

노드 등록 및 주소 보고

kubelet이 클러스터에 노드를 등록할 때 Node.status.addresses에 주소 정보를 보고합니다:

yaml
status:
  addresses:
  - address: 10.80.1.10        # 실제 온프레미스 IP
    type: InternalIP
  - address: hybrid-node-001   # 노드 호스트명
    type: Hostname
  • InternalIP: 노드의 실제 온프레미스 IP 주소입니다. API 서버는 이 주소를 사용하여 kubelet에 연결합니다.
  • Hostname: 노드의 호스트명입니다.

방화벽 규칙의 핵심: API 서버가 kubelet에 연결할 때 InternalIP를 사용하므로, AWS → On-Prem 방향으로 TCP 10250 포트가 반드시 열려 있어야 합니다. 이 연결이 차단되면 kubectl exec, kubectl logs, kubectl port-forward 등의 명령이 실패합니다.


라우팅 가능한 Pod CIDR 구성

온프레미스 파드 CIDR을 라우팅 가능하게 만드는 것은 웹훅, East-West 트래픽, AWS 서비스 통합(ALB, Prometheus 등)에 필수적입니다.

원격 Pod CIDR

옵션 1: BGP (권장)

CNI가 가상 라우터 역할을 하며 노드별 파드 CIDR 라우트를 로컬 온프레미스 라우터에 전파합니다. 가장 동적이고 유지보수하기 쉬운 접근 방식입니다.

BGP 라우팅

Cilium BGP Control Plane 구성

yaml
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPClusterConfig
metadata:
  name: hybrid-bgp-config
spec:
  bgpInstances:
  - name: hybrid-instance
    localASN: 65001
    peers:
    - name: on-prem-router
      peerASN: 65000
      peerAddress: 10.80.0.1
      peerConfigRef:
        name: on-prem-peer
---
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPPeerConfig
metadata:
  name: on-prem-peer
spec:
  families:
  - afi: ipv4
    safi: unicast
  gracefulRestart:
    enabled: true
---
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPAdvertisement
metadata:
  name: pod-cidr-advert
spec:
  advertisements:
  - advertisementType: PodCIDR
  - advertisementType: Service
    service:
      addresses:
      - ClusterIP

ASN (Autonomous System Number) 이해하기

위 Cilium BGP 구성에서 localASNpeerASN자율 시스템 번호(Autonomous System Number)입니다. 각 BGP 참여자(라우터, 스위치, 또는 여기서는 각 노드의 Cilium)에게 할당되는 고유 식별자로, BGP 피어링의 양쪽 모두 ASN이 필요합니다.

Private vs Public ASN 범위

범위유형사용 사례
64512 – 6553416비트 Private내부 네트워크, 데이터센터, 랩 환경. EKS Hybrid Nodes에서는 이 범위를 사용합니다.
4200000000 – 429496729432비트 Private많은 고유 ASN이 필요한 대규모 내부 배포
1 – 6451116비트 PublicRIR(ARIN, RIPE, APNIC)에 등록된 인터넷 대면 네트워크

EKS Hybrid Nodes의 경우: 항상 Private ASN 범위(64512–65534)를 사용하세요. Public ASN은 필요하지 않습니다 — 여기서 BGP는 Cilium 노드와 온프레미스 라우터 간의 내부 네트워크에서만 사용됩니다.

ASN 값 선택 방법

  • localASN (예: 65001): 하이브리드 노드에서 실행되는 Cilium에 할당된 ASN. 동일 클러스터의 모든 Cilium 노드는 일반적으로 하나의 ASN을 공유합니다.
  • peerASN (예: 65000): Cilium과 피어링하는 온프레미스 라우터의 ASN. 라우터의 BGP 구성에서 이 값을 확인합니다.

환경에 BGP가 아직 구성되어 있지 않다면, Private 범위에서 서로 다른 두 숫자를 선택하면 됩니다 (예: 라우터에 65000, Cilium에 65001). 네트워크 팀이 이미 내부적으로 BGP를 사용하고 있다면, ASN 충돌을 방지하기 위해 조율이 필요합니다.

온프레미스 라우터 BGP 구성 예시

아래는 위 Cilium 구성과 매칭되는 라우터 측 BGP 피어링 구성 예시입니다. 각 예시에서 라우터는 ASN 65000을 사용하고, 10.80.1.10(ASN 65001)의 Cilium 노드와 피어링합니다.

Cisco IOS / IOS-XE

router bgp 65000
 neighbor 10.80.1.10 remote-as 65001
 neighbor 10.80.1.10 description "EKS Hybrid Node - Cilium BGP"
 !
 address-family ipv4 unicast
  neighbor 10.80.1.10 activate
  neighbor 10.80.1.10 soft-reconfiguration inbound
 exit-address-family

Cisco NX-OS (Nexus)

router bgp 65000
  address-family ipv4 unicast
  neighbor 10.80.1.10
    remote-as 65001
    description EKS-Hybrid-Cilium
    address-family ipv4 unicast
      soft-reconfiguration inbound

Juniper Junos (MX / QFX / SRX)

set protocols bgp group eks-hybrid type external
set protocols bgp group eks-hybrid peer-as 65001
set protocols bgp group eks-hybrid neighbor 10.80.1.10 description "EKS Hybrid Node"
set protocols bgp group eks-hybrid family inet unicast
set routing-options autonomous-system 65000

Arista EOS

router bgp 65000
   neighbor 10.80.1.10 remote-as 65001
   neighbor 10.80.1.10 description EKS-Hybrid-Cilium
   !
   address-family ipv4
      neighbor 10.80.1.10 activate

MikroTik RouterOS

/routing bgp connection
add name=eks-hybrid remote.address=10.80.1.10 remote.as=65001 \
    local.role=ebgp as=65000 address-families=ip

FRRouting (FRR) — 소프트웨어 라우터 (Linux)

FRRouting은 Linux 서버 및 VM에서 소프트웨어 BGP 라우터로 널리 사용됩니다:

router bgp 65000
 neighbor 10.80.1.10 remote-as 65001
 neighbor 10.80.1.10 description EKS-Hybrid-Cilium
 !
 address-family ipv4 unicast
  neighbor 10.80.1.10 activate
 exit-address-family

AWS Transit Gateway (TGW)

AWS Transit Gateway와 Site-to-Site VPN을 사용하는 경우, TGW 측 ASN은 TGW 생성 시 구성됩니다:

bash
# 커스텀 ASN으로 TGW 생성
aws ec2 create-transit-gateway \
  --options AmazonSideAsn=65000

# VPN 터널은 TGW ASN으로 자동으로 BGP를 설정합니다
# 온프레미스 라우터(또는 Cilium)는 자체 ASN을 사용하여 TGW와 피어링합니다

참고: AWS TGW의 기본 ASN은 64512입니다. Cilium 노드가 65001을 사용하는 경우, Cilium 구성의 피어 ASN은 TGW(또는 VGW)의 ASN과 일치해야 합니다.

다수의 하이브리드 노드 구성

여러 하이브리드 노드가 있는 경우, 각 노드는 동일한 localASN 으로 자체 Cilium BGP 스피커를 실행합니다. 온프레미스 라우터는 각 노드와 개별적으로 피어링합니다:

# 라우터 구성 — 각 하이브리드 노드와 피어링
router bgp 65000
 neighbor 10.80.1.10 remote-as 65001   ! hybrid-node-001
 neighbor 10.80.1.11 remote-as 65001   ! hybrid-node-002
 neighbor 10.80.1.12 remote-as 65001   ! hybrid-node-003

각 노드는 자신의 파드 CIDR 조각을 광고합니다 (예: node-001은 10.85.0.0/25, node-002는 10.85.0.128/25를 광고). 이를 통해 라우터는 모든 파드 CIDR에 대한 완전한 라우팅 테이블을 구성합니다.

BGP 피어링 확인

bash
cilium bgp peers
cilium bgp routes

하이브리드 노드에서 Session State가 established로 표시되어야 합니다.

옵션 2: 정적 라우트

파드 CIDR을 사용한 수동 라우터 구성입니다. 가장 간단하지만 오류가 발생하기 쉽고 노드가 변경될 때 수동 업데이트가 필요합니다.

정적 라우트

Cluster-Pool IPAM 할당 이해

Cilium의 cluster-pool IPAM 모드에서는 전체 파드 CIDR 풀을 노드별로 고정 크기 블록으로 분할합니다. 04-node-bootstrap.md의 Cilium values에서 설정하는 두 가지 핵심 파라미터가 있습니다:

파라미터예시 값설명
clusterPoolIPv4PodCIDRList10.85.0.0/16전체 파드 CIDR 풀
clusterPoolIPv4MaskSize25노드당 할당되는 서브넷 크기 (/25 = 128 IP)

예를 들어, 풀이 10.85.0.0/16이고 마스크 크기가 /25이면 최대 512개 노드에 각각 128개의 파드 IP를 할당할 수 있습니다. Cilium Operator가 노드 등록 순서대로 블록을 할당합니다:

노드할당된 PodCIDR사용 가능한 파드 IP
hybrid-node-00110.85.0.0/2510.85.0.110.85.0.126
hybrid-node-00210.85.0.128/2510.85.0.12910.85.0.254
hybrid-node-00310.85.1.0/2510.85.1.110.85.1.126

중요: 이 할당 정보는 CiliumNode CR에 기록됩니다. Kubernetes Node 객체의 spec.podCIDR과 다를 수 있으므로, 정적 라우트 구성 시 반드시 CiliumNode CR을 참조하세요.

노드별 PodCIDR 조회

정적 라우트를 구성하려면 각 노드에 할당된 PodCIDR과 노드 IP(넥스트 홉)를 확인해야 합니다. CNI별 조회 방법은 다음과 같습니다:

CiliumCiliumNode CR의 spec.ipam.podCIDRs가 권위 있는 소스입니다:

bash
kubectl get ciliumnodes -o custom-columns='\
NAME:.metadata.name,\
NODE_IP:.spec.addresses[0].ip,\
POD_CIDR:.spec.ipam.podCIDRs[0]'
NAME                NODE_IP       POD_CIDR
hybrid-node-001     10.80.1.10    10.85.0.0/25
hybrid-node-002     10.80.1.11    10.85.0.128/25
hybrid-node-003     10.80.1.12    10.85.1.0/25

CiliumNode CR 구조, 스크립팅 활용 등 자세한 내용은 Cilium IPAM — CiliumNode CR을 활용한 노드별 PodCIDR 조회를 참조하세요.

CalicoBlockAffinity CR로 노드별 CIDR 블록을 추적합니다:

bash
kubectl get blockaffinities -o custom-columns='\
NAME:.metadata.name,\
CIDR:.spec.cidr,\
NODE:.spec.node'

⚠ Deprecation: Calico는 EKS Hybrid Nodes에서 공식 지원이 중단되었습니다. 신규 배포에는 Cilium을 사용하세요. BlockAffinity 조회 상세 내용은 Calico 고급 주제 — BlockAffinity를 활용한 노드별 PodCIDR 조회를 참조하세요.

정적 라우트 구성

CiliumNode(또는 Calico BlockAffinity)에서 확인한 정보를 바탕으로 라우터에 정적 라우트를 추가합니다. 공통 패턴은 다음과 같습니다:

목적지(Destination) = 노드의 PodCIDR
넥스트 홉(Next Hop)  = 노드의 InternalIP

Linux (ip route)

bash
# 각 노드의 파드 CIDR에 대한 라우트 추가
ip route add 10.85.0.0/25 via 10.80.1.10    # hybrid-node-001
ip route add 10.85.0.128/25 via 10.80.1.11  # hybrid-node-002
ip route add 10.85.1.0/25 via 10.80.1.12    # hybrid-node-003

재부팅 후에도 유지하려면 영구 설정이 필요합니다:

bash
# /etc/network/interfaces.d/hybrid-routes (Debian/Ubuntu)
up ip route add 10.85.0.0/25 via 10.80.1.10
up ip route add 10.85.0.128/25 via 10.80.1.11
up ip route add 10.85.1.0/25 via 10.80.1.12

# 또는 NetworkManager (RHEL/Rocky)
# /etc/NetworkManager/dispatcher.d/99-hybrid-routes

Cisco IOS / IOS-XE

ip route 10.85.0.0 255.255.255.128 10.80.1.10 name hybrid-node-001-pods
ip route 10.85.0.128 255.255.255.128 10.80.1.11 name hybrid-node-002-pods
ip route 10.85.1.0 255.255.255.128 10.80.1.12 name hybrid-node-003-pods

FRRouting (FRR)

ip route 10.85.0.0/25 10.80.1.10
ip route 10.85.0.128/25 10.80.1.11
ip route 10.85.1.0/25 10.80.1.12

AWS VPC 라우트 테이블

VPN/Direct Connect를 통해 연결된 AWS VPC에서 파드 CIDR에 접근해야 하는 경우, 집계(aggregate) CIDR을 사용합니다:

bash
# 집계 CIDR로 VPC 라우트 추가 (VPN Gateway 또는 TGW를 넥스트 홉으로)
aws ec2 create-route \
  --route-table-id rtb-0123456789abcdef0 \
  --destination-cidr-block 10.85.0.0/16 \
  --gateway-id vgw-0123456789abcdef0
hcl
# Terraform
resource "aws_route" "hybrid_pod_cidr" {
  route_table_id         = aws_route_table.main.id
  destination_cidr_block = "10.85.0.0/16"
  gateway_id             = aws_vpn_gateway.main.id
}

자동화 및 BGP 비교

CiliumNode CR에서 자동으로 ip route 명령을 생성하는 스크립트 예시:

bash
#!/bin/bash
# generate-static-routes.sh — CiliumNode CR에서 정적 라우트 명령 생성
kubectl get ciliumnodes -o json | jq -r \
  '.items[] | "ip route add \(.spec.ipam.podCIDRs[0]) via \(.spec.addresses[0].ip)"'

출력 예시:

ip route add 10.85.0.0/25 via 10.80.1.10
ip route add 10.85.0.128/25 via 10.80.1.11
ip route add 10.85.1.0/25 via 10.80.1.12

정적 라우트 vs BGP 비교

항목정적 라우트BGP (옵션 1)
노드 추가 시라우터에 수동으로 라우트 추가 필요자동으로 라우트 전파
노드 제거 시라우터에서 수동으로 라우트 삭제 필요자동으로 라우트 철회
노드 IP 변경 시모든 라우트 수동 업데이트 필요자동으로 업데이트 전파
장애 감지없음 (stale 라우트 남음)BGP keepalive로 자동 감지
구성 복잡도낮음중간 (BGP 피어링 설정 필요)
확장성1–5 노드에 적합수십~수백 노드까지 확장 가능

권장사항:

  • PoC / 소규모 환경 (1–5 노드): 정적 라우트로 빠르게 시작할 수 있습니다
  • 프로덕션 / 5+ 노드: BGP (옵션 1)를 사용하세요. 노드 변경에 자동으로 대응하며 운영 부담이 크게 줄어듭니다
  • BGP가 정책적으로 허용되지 않는 환경: 정적 라우트를 사용하되, 위의 자동화 스크립트로 라우트 변경을 관리하세요

옵션 3: ARP 프록시

노드가 호스팅된 파드 IP에 대한 ARP 요청에 응답합니다. 로컬 라우터와 레이어 2 네트워크 근접성이 필요합니다. Cilium에는 프록시 ARP 지원이 내장되어 있습니다. 라우터 BGP나 정적 라우트 구성이 필요 없지만, 파드 CIDR이 다른 네트워크와 겹치면 안 됩니다.

ARP 프록시


네트워크 정책

하이브리드 노드 환경에서 Pod 간 트래픽을 제어하기 위해 네트워크 정책을 사용할 수 있습니다. Cilium CNI를 사용하면 표준 Kubernetes NetworkPolicy와 확장된 CiliumNetworkPolicy 모두 지원됩니다.

Kubernetes NetworkPolicy

표준 Kubernetes NetworkPolicy는 L3/L4 수준의 기본적인 트래픽 필터링을 제공합니다.

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: bookinfo
spec:
  podSelector:
    matchLabels:
      app: reviews
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: productpage
    ports:
    - protocol: TCP
      port: 9080

이 정책은 bookinfo 네임스페이스에서 app: productpage 레이블이 있는 Pod만 app: reviews Pod의 9080 포트에 접근할 수 있도록 허용합니다.

CiliumNetworkPolicy

CiliumNetworkPolicy는 Kubernetes NetworkPolicy의 기능을 확장하여 L7 필터링, DNS 인식 정책, 아이덴티티 기반 매칭 등을 제공합니다.

yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: bookinfo
spec:
  endpointSelector:
    matchLabels:
      app: reviews
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: productpage
    toPorts:
    - ports:
      - port: "9080"
        protocol: TCP

CiliumNetworkPolicy 고급 기능

L7 HTTP 필터링

yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l7-rule
  namespace: bookinfo
spec:
  endpointSelector:
    matchLabels:
      app: reviews
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: productpage
    toPorts:
    - ports:
      - port: "9080"
        protocol: TCP
      rules:
        http:
        - method: "GET"
          path: "/api/v1/.*"

DNS 기반 Egress 정책

yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-external-api
  namespace: bookinfo
spec:
  endpointSelector:
    matchLabels:
      app: productpage
  egress:
  - toFQDNs:
    - matchName: "api.example.com"
    toPorts:
    - ports:
      - port: "443"
        protocol: TCP

하이브리드 환경에서의 네트워크 정책 고려사항

고려사항설명
기본 동작네트워크 정책이 없으면 모든 트래픽이 허용됩니다. NetworkPolicy가 적용되면 명시적으로 허용된 트래픽만 통과합니다.
크로스 바운더리 트래픽클라우드 노드의 Pod와 하이브리드 노드의 Pod 간 통신을 정책에 반영해야 합니다.
CNI 요구 사항Cilium이 CNI로 설정되어 있어야 두 정책 유형 모두 작동합니다.
정책 적용 범위CiliumNetworkPolicy는 해당 네임스페이스에만 적용됩니다. 클러스터 전체 정책은 CiliumClusterwideNetworkPolicy를 사용하세요.

권장 사항: 하이브리드 환경에서는 명시적인 네트워크 정책을 정의하여 의도하지 않은 크로스 바운더리 트래픽을 방지하세요. 특히 민감한 워크로드는 엄격한 Ingress/Egress 정책으로 보호해야 합니다.


웹훅 구성

웹훅은 Kubernetes 애플리케이션과 오픈소스 프로젝트(AWS Load Balancer Controller, CloudWatch Observability Agent)에서 변환(mutating) 및 검증(validation) 기능에 사용됩니다.

라우팅 가능한 파드 네트워크 사용 시

온프레미스 파드 CIDR이 라우팅 가능한 경우(BGP, 정적 라우트 또는 ARP 프록시를 통해), 웹훅을 하이브리드 노드에서 실행할 수 있습니다.

라우팅 불가능한 파드 네트워크 사용 시

온프레미스 파드 CIDR이 라우팅 불가능한 경우, 노드 어피니티를 사용하여 모든 웹훅을 클라우드 노드에서 실행하세요:

yaml
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: eks.amazonaws.com/compute-type
          operator: NotIn
          values:
          - hybrid

웹훅을 사용하는 애드온

다음 애드온은 웹훅 배치를 고려해야 합니다:

애드온웹훅 배치 (라우팅 불가능 파드 CIDR)
AWS Load Balancer Controller클라우드 노드만
CloudWatch Observability Agent클라우드 노드만
ADOT (OpenTelemetry)클라우드 노드만
cert-manager클라우드 노드만
Kubernetes Metrics Server라우팅 가능 파드 CIDR 필요

< 이전: 사전 요구 사항 | 목차 | 다음: 에어갭 환경 구성 >