Share
Embed
Kubernetes 네트워크 이해하기 (2) : 서비스 개념과 동작 원리
Short link - https://hyojun.me/~k8s-network-2
Blog - https://blog.hyojun.me
# 다른 슬라이드들
* Container부터 다시 살펴보는 Kubernetes Pod 동작 원리
https://hyojun.me/~k8s-pod-internal
* Kubernetes 네트워크 이해하기 (1) : 컨테이너 네트워크부터 CNI까지
https://hyojun.me/~k8s-network-1
Hyojun Jeon
April 22, 2021
Transcript
90 slides
-
Kubernetes 네트워크 이해하기 (2) : 서비스 개념과 동작 원리 전효준
(https://hyojun.me) -
Kubernetes에 배포된 두 개의 Application Kubernetes Cluster bar app Pod
10.244.1.2 Pod 10.244.2.2 foo app -
Kubernetes Cluster Pod들은 클러스터 내에서 고유한 IP로 서로 통신 Pod
10.244.1.2 Pod 10.244.2.2 bar app foo app -
Kubernetes Cluster Pod 10.244.1.2 Pod 10.244.2.2 bar app Pod 10.244.2.3
bar app의 Pod이 변경 또는 종료되어 새로운 Pod이 생성되면? 변경된 Pod IP를 어떻게 알려주지? foo app -
Kubernetes Cluster bar app이 여러 개의 Pod으로 구성된 경우 Pod
10.244.1.2 foo app Pod 10.244.2.2 bar app Pod 10.244.2.3 로드 밸런싱? -
서비스(Service) • Pod 집합에 대한 접근을 추상화 ◦ Selector를 통한
대상 Pod 집합 정의 ◦ 단일 고정 Endpoint를 제공 (IP + Port) • 클러스터 외부에 존재하는 백엔드에 대한 추상화도 제공 ◦ Services without selector • 로드 밸런싱 지원 -
apiVersion: apps/v1 kind: ReplicaSet metadata: name: hello spec: replicas: 3
selector: matchLabels: app: hello template: metadata: labels: app: hello spec: containers: - name: hello-world image: gcr.io/google-samples/node-hello:1.0 ports: - containerPort: 8080 protocol: TCP replicaset.yaml apiVersion: v1 kind: Service metadata: name: hello-service spec: selector: app: hello ports: - protocol: TCP port: 80 targetPort: 8080 service.yaml -
apiVersion: apps/v1 kind: ReplicaSet metadata: name: hello spec: replicas: 3
selector: matchLabels: app: hello template: metadata: labels: app: hello spec: containers: - name: hello-world image: gcr.io/google-samples/node-hello:1.0 ports: - containerPort: 8080 protocol: TCP replicaset.yaml apiVersion: v1 kind: Service metadata: name: hello-service spec: selector: app: hello ports: - protocol: TCP port: 80 targetPort: 8080 service.yaml Selector를 이용한 대상 Pod 집합 설정 -
apiVersion: apps/v1 kind: ReplicaSet metadata: name: hello spec: replicas: 3
selector: matchLabels: app: hello template: metadata: labels: app: hello spec: containers: - name: hello-world image: gcr.io/google-samples/node-hello:1.0 ports: - containerPort: 8080 protocol: TCP replicaset.yaml apiVersion: v1 kind: Service metadata: name: hello-service spec: selector: app: hello ports: - name: http protocol: TCP port: 80 targetPort: 8080 service.yaml <Service IP>:80 → <Pod IP>:8080 -
Selector와 일치하는 Pod 집합의 IP/Port를 Endpoints 리소스로 관리 Endpoint 리소스는
Service와 같은 이름으로 생성됨 -
apiVersion: v1 kind: Service metadata: name: hello-service-no-selector spec: ports: -
protocol: TCP port: 80 targetPort: 8080 --- apiVersion: v1 kind: Endpoints metadata: name: hello-service-no-selector subsets: - addresses: - ip: 10.244.1.3 ports: - port: 8080 Endpoint는 항상 Service 이름과 동일하게 지정해 주어야 한다. Selector가 없는 경우 (Endpoint 수동 생성) -
apiVersion: v1 kind: Service metadata: name: hello-service-no-selector spec: ports: -
protocol: TCP port: 80 targetPort: 8080 --- apiVersion: v1 kind: Endpoints metadata: name: hello-service-no-selector subsets: - addresses: - ip: 10.244.1.3 ports: - port: 8080 Selector가 없는 경우 (Endpoint 수동 생성) 참고: Endpoint에 지정된 IP는 외부에 존재하는 서버의 IP가 될 수 있다. (클러스터 외부 IP로 트래픽을 전달하는 서비스) -
Pod에서 서비스 식별 방법 (Service discovery) 1. 환경 변수(Environment variable)
◦ “서비스가 생성된 이후”에 만들어진 Pod에서만 사용 가능 ◦ {SVCNAME}_SERVICE_HOST / {SVCNAME}_SERVICE_PORT ▪ e.g. Service name: “foo-bar” → FOO_BAR_SERVICE_HOST / FOO_BAR_SERVICE_PORT -
Pod에서 서비스 식별 방법 (Service discovery) 2. DNS 사용 ◦
클러스터 내에서 DNS 서버 역할을 수행하는 CoreDNS(또는 kube-dns)가 존재하는 경우 ◦ DNS name format ▪ <service-name>.<namespace>.svc.cluster.local ▪ <service-name>.<namespace> (같은 로컬 클러스터인 경우) ▪ <service-name> (같은 namespace인 경우) ◦ SRV Record 지원 (RFC 2782) ▪ 서비스 port에 이름을 지정한 경우, SRV Record 조회를 통해 IP 주소와 함께 사용 가능한 port도 같이 확인 가능 -
Pod에서 서비스 식별 방법 (Service discovery) 2. DNS 사용 ◦
클러스터 내에서 DNS 서버 역할을 수행하는 CoreDNS(또는 kube-dns)가 존재하는 경우 ◦ DNS name format ▪ <service-name>.<namespace>.svc.cluster.local ▪ <service-name>.<namespace> (같은 로컬 클러스터인 경우) ▪ <service-name> (같은 namespace인 경우) ◦ SRV Record 지원 (RFC 2782) ▪ 서비스 port에 이름을 지정한 경우, SRV Record 조회를 통해 IP 주소와 함께 사용 가능한 port도 같이 확인 가능 service = <priority> <weight> <port> <RECORD> SRV Record 조회하기 -
서비스로 들어온 트래픽을 Pod으로 전달하기까지 • 각 노드에는 kube-proxy Pod가
실행(daemonset) ◦ kube-proxy는 Proxy mode에 따라 역할이 달라진다. • Proxy mode ◦ userspace mode ◦ iptables mode ◦ ipvs mode • 필요한 사전 지식 ◦ iptables -
서비스로 들어온 트래픽을 Pod으로 전달하기까지 • 각 노드에는 kube-proxy Pod가
실행(daemonset) ◦ kube-proxy는 Proxy mode에 따라 역할이 달라진다. • Proxy mode ◦ userspace mode ◦ iptables mode ◦ ipvs mode • 필요한 사전 지식 ◦ iptables -
iptables • Netfilter 기반으로 패킷을 필터링하거나 변환하는 방화벽 규칙을 정의
◦ Netfilter - Linux 커널의 네트워크 관련 작업을 구현하기 위한 프레임워크 • 여러 종류의 Table 이 존재 ◦ Filter - 패킷을 필터링하거나 차단하는 규칙을 정의 ◦ NAT - 네트워크 주소 변환에 대한 규칙을 정의 ◦ mangle - 패킷 헤더 정보를 변경하는 규칙을 정의 ◦ 그 외 raw, security -
• 각 Table 안에는 각각의 규칙을 정의하는 Chain들이 존재 •
iptables에서 기본적으로 정의된 Chain들 ◦ PREROUTING - 패킷이 네트워크 인터페이스로 유입되면 가장 먼저 적용 ◦ FORWARD - 현재 호스트를 통해 라우팅 되는 패킷에 적용 ◦ INPUT - 해당 호스트에 존재하는 로컬 프로세스에 패킷이 유입될 때 적용 ◦ POSTROUTING - 패킷이 호스트 외부로 나갈 때 적용 ◦ OUTPUT - 로컬 프로세스에서 패킷이 생성된 직후 적용 iptables -
• 각 Table 안에는 각각의 규칙을 정의하는 Chain들이 존재 •
iptables에서 기본적으로 정의된 Chain들 ◦ PREROUTING - 패킷이 네트워크 인터페이스로 유입되면 가장 먼저 적용 ◦ FORWARD - 현재 호스트를 통해 라우팅 되는 패킷에 적용 ◦ INPUT - 해당 호스트에 존재하는 로컬 프로세스에 패킷이 유입될 때 적용 ◦ POSTROUTING - 패킷이 호스트 외부로 나갈 때 적용 ◦ OUTPUT - 로컬 프로세스에서 패킷이 생성된 직후 적용 iptables iptables 패킷 흐름 … 🤮 https://en.wikipedia.org/wiki/Iptables -
• 각 Table 안에는 각각의 규칙을 정의하는 Chain들이 존재 •
iptables에서 기본적으로 정의된 Chain들 ◦ PREROUTING - 패킷이 네트워크 인터페이스로 유입되면 가장 먼저 적용 ◦ FORWARD - 현재 호스트를 통해 라우팅 되는 패킷에 적용 ◦ INPUT - 해당 호스트에 존재하는 로컬 프로세스에 패킷이 유입될 때 적용 ◦ POSTROUTING - 패킷이 호스트 외부로 나갈 때 적용 ◦ OUTPUT - 로컬 프로세스에서 패킷이 생성된 직후 적용 PREROUTING INPUT OUPUT POSTROUTING FORWARD “간단하게 살펴보는” iptables Packet 흐름 Local Process Application Layer -
• 각 Table 안에는 각각의 규칙을 정의하는 Chain들이 존재 •
iptables에서 기본적으로 정의된 Chain들 ◦ PREROUTING - 패킷이 네트워크 인터페이스로 유입되면 가장 먼저 적용 ◦ FORWARD - 현재 호스트를 통해 라우팅 되는 패킷에 적용 ◦ INPUT - 해당 호스트에 존재하는 로컬 프로세스에 패킷이 유입될 때 적용 ◦ POSTROUTING - 패킷이 호스트 외부로 나갈 때 적용 ◦ OUTPUT - 로컬 프로세스에서 패킷이 생성된 직후 적용 PREROUTING INPUT OUPUT POSTROUTING FORWARD 호스트로 들어온 패킷이 다른 호스트로 포워딩되는 경우 “간단하게 살펴보는” iptables Packet 흐름 Local Process Application Layer -
• 각 Table 안에는 각각의 규칙을 정의하는 Chain들이 존재 •
iptables에서 기본적으로 정의된 Chain들 ◦ PREROUTING - 패킷이 네트워크 인터페이스로 유입되면 가장 먼저 적용 ◦ FORWARD - 현재 호스트를 통해 라우팅 되는 패킷에 적용 ◦ INPUT - 해당 호스트에 존재하는 로컬 프로세스에 패킷이 유입될 때 적용 ◦ POSTROUTING - 패킷이 호스트 외부로 나갈 때 적용 ◦ OUTPUT - 로컬 프로세스에서 패킷이 생성된 직후 적용 PREROUTING INPUT Local Process OUPUT POSTROUTING FORWARD 호스트로 들어온 패킷이 로컬 프로세스로 전달되는 경우 Application Layer “간단하게 살펴보는” iptables Packet 흐름 -
• 각 Table 안에는 각각의 규칙을 정의하는 Chain들이 존재 •
iptables에서 기본적으로 정의된 Chain들 ◦ PREROUTING - 패킷이 네트워크 인터페이스로 유입되면 가장 먼저 적용 ◦ FORWARD - 현재 호스트를 통해 라우팅 되는 패킷에 적용 ◦ INPUT - 해당 호스트에 존재하는 로컬 프로세스에 패킷이 유입될 때 적용 ◦ POSTROUTING - 패킷이 호스트 외부로 나갈 때 적용 ◦ OUTPUT - 로컬 프로세스에서 패킷이 생성된 직후 적용 PREROUTING INPUT OUPUT POSTROUTING FORWARD 로컬 프로세스에서 생성된 패킷이 호스트 밖으로 나가는 경우 “간단하게 살펴보는” iptables Packet 흐름 Local Process Application Layer -
• 네트워크 주소 변환 ◦ DNAT (Destination Network Address Translation)
▪ 목적지 네트워크 주소 변환 ▪ 예) 로드 밸런싱, 포트 포워딩 ◦ SNAT (Source Network Address Translation) ▪ 출발지 네트워크 주소 변환 ▪ 예) 외부 네트워크(인터넷) 접속 시 패킷 Source IP를 Public IP로 변환 NAT (Network Address Translation) -
$ iptables -t nat -A PREROUTING \ -d 192.168.101.2 --dport
80 -p tcp \ -j DNAT --to 1.2.3.4:80 NAT Table(-t nat)의 PREROUTING Chain에 규칙 추가(-A PREROUTING) iptables를 이용한 DNAT 규칙 생성 예시 -
$ iptables -t nat -A PREROUTING \ -d 192.168.101.2 --dport
80 -p tcp \ -j DNAT --to 1.2.3.4:80 192.168.101.2:80을 목적지 주소로 하는, TCP 패킷이 유입되면 iptables를 이용한 DNAT 규칙 생성 예시 -
$ iptables -t nat -A PREROUTING \ -d 192.168.101.2 --dport
80 -p tcp \ -j DNAT --to 1.2.3.4:80 목적지 주소를 1.2.3.4:80으로 변환한다. iptables를 이용한 DNAT 규칙 생성 예시 -
• kube-proxy는 API server로부터 Service 변경 감시하며 서비스 IP/Port로 향하는
패킷이 자신에게 전달되도록 iptables 업데이트 • 전달된 패킷은 kube-proxy가 백엔드 Pod로 직접 중개(Proxy) Proxy mode - (1) userspace -
API server Proxy mode - (1) userspace Pod 1 Pod
2 Pod 3 Pod 4 Client iptables kube-proxy (daemonset) 각 노드의 kube-proxy는 API server를 모니터링하여 서비스가 생성, 변경되면 iptables를 업데이트 -
API server Proxy mode - (1) userspace Pod 1 Pod
2 Pod 3 Pod 4 Client kube-proxy (daemonset) Client로부터 Service(e.g. 10.101.96.60:80)로 트래픽 발생 iptables -
API server Proxy mode - (1) userspace Pod 1 Pod
2 Pod 3 Pod 4 Client kube-proxy (daemonset) 서비스 IP/Port(e.g. 10.101.96.60:80)로 들어온 트래픽은 iptables 규칙에 의해 kube-proxy Pod의 특정 포트로 전달 iptables -
API server Proxy mode - (1) userspace Pod 1 Pod
2 Pod 3 Pod 4 Client kube-proxy (daemonset) kube-proxy가 백엔드 Pod의 지정된 포트로 직접 프록시(Round-robin) iptables -
Proxy mode - (2) iptables • 백엔드 Pod로 트래픽을 전달하는
것까지 모두 iptables 규칙으로 처리 ◦ 서비스 IP/Port로 향하는 트래픽은 iptables로 정의된 목적지 주소 변환(DNAT)에 의해 백엔드 Pod에 전달 ▪ DNAT = Destination Network Address Translation • kube-proxy는 Kubernetes API server로부터 Service, Endpoint의 변경을 감지하여 iptables를 업데이트 -
Proxy mode - (2) iptables • userspace mode와 비교 ◦
iptables mode에서는 kube-proxy가 Proxy 서버 역할을 하지 않음 ◦ 커널 공간에서 처리되기 때문에 userspace 대비 오버헤드 감소 ◦ Pod이 응답하지 않는 경우? ▪ userspace mode • kube-proxy가 다른 Pod에 Proxy ▪ iptables mode • iptables 규칙으로 목적지 IP 주소가 이미 변환되었기 때문에, 다른 Pod로 트래픽 전달이 불가 -
Proxy mode - (2) iptables API server kube-proxy (daemonset) iptables
Pod 1 Pod 2 Pod 3 Pod 4 Client 각 노드의 kube-proxy는 API server를 모니터링하여 Service 및 Endpoint가 생성, 변경되면 iptables를 업데이트 -
Proxy mode - (2) iptables API server kube-proxy (daemonset) Pod
1 Pod 2 Pod 3 Pod 4 Client Client로부터 Service(10.101.96.60:80)로 트래픽 발생 iptables -
Proxy mode - (2) iptables API server kube-proxy (daemonset) Pod
1 Pod 2 Pod 3 Pod 4 Client iptables 규칙에 의해 백엔드 Pod로 로드밸런싱 → 패킷의 목적지 주소 및 포트가 백엔드 Pod로 변환되기 때문에, Client는 대상 Pod와 직접 통신하게 된다. iptables -
Proxy mode - (2) iptables $ sudo iptables -L -t
nat 확인해봅시다 😎 NAT table(-t nat)에 존재하는 모든 Chain을 listing(-L) -
Proxy mode - (2) iptables hello-service(10.101.96.60 + 80/tcp)로 들어온 패킷들에
대한 규칙 → 서비스에 할당된 IP는 iptables로 정의된 가상의 IP 임을 알 수 있다. 항상 port와 함께 동작한다. -
Proxy mode - (2) iptables KUBE-MARK-MASQ • 클러스터 외부에서 서비스로
들어온 패킷에 대해 SNAT 처리하도록 Marking • Marking된 패킷은 호스트 밖으로 라우팅 되는 경우, POSTROUTING chain을 통과하며 패킷의 출발지 IP가 현재 호스트 IP로 변환 (= Masquerade) -
Proxy mode - (2) iptables hello-service(10.101.96.60 + 80/tcp)로 들어온 패킷은
“KUBE-SVC-WR2LASOULGGSX3JN” Chain으로 전달 -
Proxy mode - (2) iptables Pod 별로 생성되는 “KUBE-SEP-...” Chain에는
Pod IP/Port로 DNAT 규칙이 정의됨. 서비스의 백엔드 Pod가 현재 2개인 상태로, 2개 Pod Chain 중에 50% 확률로 무작위 선택 -
Proxy mode - (2) iptables Packet In PREROUTING KUBE-SERVICES KUBE-SVC-BAZ
KUBE-SVC-BAR KUBE-SVC-FOO KUBE-SEP-POD2 KUBE-SEP-POD1 각 서비스별 Chain 서비스 Endpoint 별 Chain (DNAT) 무작위 선택하여 DNAT -
• IPVS(IP Virtual Server)란? ◦ IPVS는 커널 계층에서 제공되는 L4
Load Balancer ▪ iptables는 패킷 필터링과 패킷 조작을 통한 유연성으로 방화벽을 구현하기 위해 설계됨 ▪ 반면에, ipvs는 로드밸런싱을 위해 설계된 커널 기능 ◦ iptables와 동일하게 Netfilter를 기반 ◦ 커널 내부의 해시테이블을 기반으로, 많은 수의 서비스와 Pod에도 일관된 성능 ▪ iptables의 경우 순차적으로 규칙들을 따라가면서 처리하다 보니 성능에 한계가 있음 ◦ 최단 예상 지연시간, 최소 연결 등 좀 더 정교한 로드 밸런싱 알고리즘 제공 Proxy mode - (3) IPVS -
Proxy mode - (3) IPVS API server kube-proxy (daemonset) Pod
1 Pod 2 Pod 3 Pod 4 IPVS Client iptables ipset -
Proxy mode - (3) IPVS API server kube-proxy (daemonset) Pod
1 Pod 2 Pod 3 Pod 4 IPVS Client 각 노드의 kube-proxy는 API server를 모니터링하다가 Service 및 Endpoint가 생성 또는 변경되면 iptables, ipset, IPVS를 업데이트 iptables ipset -
Proxy mode - (3) IPVS API server kube-proxy (daemonset) Pod
1 Pod 2 Pod 3 Pod 4 IPVS Client Client로부터 Service(e.g. 10.101.96.60:80)로 트래픽 발생 iptables ipset -
Proxy mode - (3) IPVS API server kube-proxy (daemonset) Pod
1 Pod 2 Pod 3 Pod 4 IPVS Client iptables는 ipset에 설정된 서비스 IP에 대한 트래픽을 IPVS로 전달 iptables ipset -
Proxy mode - (3) IPVS API server kube-proxy (daemonset) Pod
1 Pod 2 Pod 3 Pod 4 IPVS Client IPVS는 정의된 규칙에 따라 백엔드 Pod로 로드 밸런싱 iptables ipset -
Proxy mode - (3) IPVS 클러스터에 정의된 서비스들의 IP, Protocol:Port
ipset 을 사용하여 각 서비스마다 너무 많은 iptables Chain이 생기는 것을 방지 iptables proxy mode에서... -
Proxy mode - (3) IPVS 각 서비스 IP가 Dummy NIC(Network
Interface Controller)에 binding 된 것을 알 수 있다. -
Proxy mode - (3) IPVS 10.225.122.243:80로 들어온 트래픽은 Pod IP와
정의된 targetPort로 로드 밸런싱 rr = Round robin -
Round-robin DNS를 사용하지 않는 이유 • Round-robin DNS ◦ 서비스마다
DNS를 부여하고 백엔드 Pod들의 IP를 Record로 나열하여 DNS Round-robin 방식으로 로드 밸런싱하는 방법 • Kubernetes에서는 DNS Round-robin을 정식 Proxy-mode로 지원하지 않는다. ◦ DNS Record TTL를 고려하지 않고, DNS 검색 결과를 캐싱하는 경우가 있음 ◦ 일부 앱은 무기한으로 캐싱하는 경우도... ◦ TTL이 낮은 경우 DNS 서버의 부하가 높아질 수 있음 -
클러스터 외부에서 접근 가능한 서비스 • 서비스는 기본적으로 클러스터 내부
IP로 노출 (서비스 타입: Cluster IP) • 클러스터 외부로 서비스를 노출하려면? ◦ 서비스 타입 ▪ NodePort ▪ LoadBalancer ◦ External IP 설정 -
Service Type - (1) NodePort apiVersion: v1 kind: Service metadata:
name: hello-nodeport-service spec: type: NodePort selector: app: hello ports: - name: http protocol: TCP port: 80 targetPort: 8080 nodePort: 30080 # optional service-nodeport.yaml • 클러스터 외부에서 “<NodeIP>:<NodePort>”로 서비스에 접근 가능한 서비스 타입 • nodePort를 지정하는 경우 ◦ 노드 IP들의 지정된 포트로 서비스 노출 • nodePort를 지정하지 않는 경우 ◦ --service-node-port-range로 지정된 포트 범위 안에서 노드 IP에 포트를 자동 할당 (기본값 : 30000-32767) ◦ 포트 충돌을 방지하기 위해, 따로 포트를 설정하지 않고 Kubernetes에 포트 할당을 위임하는 것 이 좋다. -
Service Type - (1) NodePort Pod 1 Pod 2 Pod
3 Pod 4 Node1 IP:Port Node2 IP:Port Node3 IP:Port Client 클러스터 외부에서 각 노드 IP의 할당된 포트로 트래픽 발생 (iptables proxy mode 기준, kube-proxy는 편의상 생략) iptables -
Service Type - (1) NodePort Pod 1 Pod 2 Pod
3 Pod 4 Node1 IP:Port Node2 IP:Port Node3 IP:Port Client iptables 규칙에 의해 서비스 백엔드 Pod로 로드 밸런싱 (iptables proxy mode 기준, kube-proxy는 편의상 생략) iptables -
Service Type - (1) NodePort 노드 IP + nodePort로 유입된
트래픽은 KUBE-NODEPORTS Chain으로 전달 -
Service Type - (1) NodePort 지정된 nodePort로 유입된 TCP Packet은
해당 서비스 Chain으로 전달 -
Service Type - (2) LoadBalancer • 외부 로드 밸런서를 지원하는
Cloud Service (AWS, GCP, Azure, etc.)에서, 로드 밸런서를 프로비저닝 하여 서비스를 외부에 노출 ◦ AWS EKS ▪ https://docs.aws.amazon.com/eks/latest/userguide/load-balancing.html ◦ GCP GKE ▪ https://cloud.google.com/kubernetes-engine/docs/how-to/exposing-apps#cre ating_a_service_of_type_loadbalancer ◦ Azure ▪ https://docs.microsoft.com/azure/aks/load-balancer-standard -
External IP 설정 • NodePort, LoadBalancer 타입의 서비스를 정의하지 않고도,
클러스터로 트래픽을 전달하는 특정 외부 IP로 서비스를 노출할 수 있다. ◦ External IP는 Kubernetes에서 관리하지 않는다. • 외부 IP가 목적지이면서, 목적지 포트가 특정 서비스 포트와 일치하는 패킷이 클러스터로 들어오면 해당 서비스의 백엔드 Pod으로 전달된다. -
External IP 설정 apiVersion: v1 kind: Service metadata: name: hello-external-ip-service
spec: selector: app: hello ports: - protocol: TCP port: 34080 targetPort: 8080 externalIPs: - 192.168.102.4 Pod 1 Pod 2 Pod 3 Pod 4 iptables Packet Dest IP: 192.168.102.4 Dest port: 34080 Cluster 패킷의 목적지 IP가 서비스의 External IP와 일치하고, 목적지 Port가 서비스 Port와 일치하는 패킷이 클러스터로 유입 Client -
External IP 설정 apiVersion: v1 kind: Service metadata: name: hello-external-ip-service
spec: selector: app: hello ports: - protocol: TCP port: 34080 targetPort: 8080 externalIPs: - 192.168.102.4 Pod 1 Pod 2 Pod 3 Pod 4 iptables Packet Dest IP: 192.168.102.4 Dest port: 34080 Cluster 패킷은 서비스의 백엔드 Pod으로 전달(DNAT) Client -
External IP 설정 apiVersion: v1 kind: Service metadata: name: hello-external-ip-service
spec: selector: app: hello ports: - protocol: TCP port: 34080 targetPort: 8080 externalIPs: - 192.168.102.4 Pod 1 Pod 2 Pod 3 Pod 4 iptables Packet Dest IP: 192.168.102.4 Dest port: 34080 Cluster Client IPVS Proxy mode에서 External IP 설정 시 주의 사항 • IPVS proxy mode에서는 External IP도 서비스 Cluster IP와 마찬가지로 IPVS 로드 밸런싱을 위해 Dummy NIC에 binding 된다. • 따라서, 서비스 External IP로 Node IP가 지정된 경우, 해당 노드로 전달되어야 할 트래픽이 Dummy NIC로 전달되기 때문에 문제가 발생한다. worker-node3 (Node IP: 192.168.101.5)가 Service External IP로 지정됨 → 모든 노드에서 worker-node3 IP가 IPVS Dummy NIC에 binding → 다른 노드에서 worker-node3로 전달되어야 할 트래픽이 Dummy NIC로 전달 -
apiVersion: v1 kind: Service metadata: name: search-engine spec: type: ExternalName
externalName: google.com 외부 도메인을 참조하는 Service Type - ExternalName • 클러스터 외부의 FQDN(Fully Qualified Domain Name)를 참조하는 서비스를 정의하여, 서비스 DNS Name으로 접근 가능 • Cluster IP가 할당되지 않고, DNS level에서 구현 -
• 클러스터 외부의 FQDN(Fully Qualified Domain Name)를 참조하는 서비스를 정의하여,
서비스 DNS Name으로 접근 가능 • Cluster IP가 할당되지 않고, DNS level에서 구현 apiVersion: v1 kind: Service metadata: name: search-engine spec: type: ExternalName externalName: google.com 서비스 DNS search-engine.default.svc.cluster.local search-engine.default (같은 로컬 클러스터인 경우) search-engine (같은 namespace인 경우) CNAME google.com 외부 도메인을 참조하는 Service Type - ExternalName -
• Cluster IP를 명시적으로 할당하지 않는 서비스 ◦ 서비스 IP,
로드 밸런싱이 필요하지 않은 경우 사용 예) 서비스 DNS Name가 EndPoint IP를 직접 반환하도록 함 ◦ Kubernetes 서비스 구현에 의존하지 않고 다른 Service discovery mechanism을 사용할 수 있도록 보장 Headless 서비스 apiVersion: v1 kind: Service metadata: name: hello-headless-service spec: clusterIP: None selector: app: hello Headless 서비스는 selector에 일치하는 Pod IP들이 DNS Record로 반환 일반적인 서비스의 경우, 서비스 IP가 DNS Record로 반환 -
• 특정 클라이언트의 연결이 매번 동일한 파드로 전달되도록 설정 ◦
sessionAffinity를 "ClientIP"로 설정(기본값: None) ▪ 클라이언트의 IP 주소를 기반 ◦ sessionAffinityConfig.clientIP.timeoutSeconds ▪ 최대 세션 고정시간 (기본값: 3시간) Session Affinity - Client IP -
Session Affinity - Client IP • “recent” 모듈로 SessionAffinity 구현
◦ 동적으로 IP 주소 목록을 생성하고 확인 가능한 iptables 모듈 ◦ recent 모듈을 사용한 방화벽 구현 사례) 특정 목적지 IP로 전달된 패킷들의 Source IP 목록을 저장해두고, 1분 동안 100번 이상 패킷을 전송한 Source IP를 차단 Session Affinity - Client IP iptables proxy mode에서 동작 원리 -
Packet In Source IP 7.7.7.7 Session Affinity - Client IP
iptables proxy mode에서 동작 원리 PREROUTING KUBE-SERVICES KUBE-SVC-BAZ KUBE-SVC-BAR KUBE-SVC-FOO KUBE-SEP-POD2 KUBE-SEP-POD1 각 서비스별 Chain 서비스 Endpoint 별 Chain (DNAT) DNAT to Pod2 최근 Source IP 목록 1.1.1.1 3.4.5.6 4.5.6.7 DNAT to Pod1 최근 Source IP 목록 1.1.1.1 1.2.3.4 2.3.4.5 7.7.7.7 -
Packet In Source IP 7.7.7.7 DNAT to Pod2 최근 Source
IP 목록 1.1.1.1 3.4.5.6 4.5.6.7 Session Affinity - Client IP iptables proxy mode에서 동작 원리 PREROUTING KUBE-SERVICES KUBE-SVC-BAZ KUBE-SVC-BAR KUBE-SVC-FOO KUBE-SEP-POD2 KUBE-SEP-POD1 각 서비스별 Chain DNAT to Pod1 최근 Source IP 목록 1.1.1.1 1.2.3.4 2.3.4.5 7.7.7.7 서비스 Endpoint 별 Chain (DNAT) 각 Chain 별로 최근 Source IP 목록에서 현재 패킷의 Source IP가 존재하는지 확인 -
Packet In Source IP 7.7.7.7 DNAT to Pod2 최근 Source
IP 목록 1.1.1.1 3.4.5.6 4.5.6.7 Session Affinity - Client IP iptables proxy mode에서 동작 원리 PREROUTING KUBE-SERVICES KUBE-SVC-BAZ KUBE-SVC-BAR KUBE-SVC-FOO KUBE-SEP-POD2 KUBE-SEP-POD1 각 서비스별 Chain DNAT to Pod1 최근 Source IP 목록 1.1.1.1 1.2.3.4 2.3.4.5 7.7.7.7 서비스 Endpoint 별 Chain (DNAT) 최근 Source IP 목록에서 현재 Packet의 Source IP를 발견하면 해당 Chain으로 패킷 전달 -
DNAT to Pod2 최근 Source IP 목록 1.1.1.1 3.4.5.6 4.5.6.7
Session Affinity - Client IP iptables proxy mode에서 동작 원리 PREROUTING KUBE-SERVICES KUBE-SVC-BAZ KUBE-SVC-BAR KUBE-SVC-FOO KUBE-SEP-POD2 KUBE-SEP-POD1 각 서비스별 Chain DNAT to Pod1 최근 Source IP 목록 1.1.1.1 1.2.3.4 2.3.4.5 서비스 Endpoint 별 Chain (DNAT) 최근 Source IP 목록에서 현재 Packet의 Source IP가 발견되지 않으면 기존처럼 무작위 전달 Packet In Source IP 7.7.7.7 -
Packet In Source IP 7.7.7.7 DNAT to Pod2 최근 Source
IP 목록 1.1.1.1 3.4.5.6 4.5.6.7 Session Affinity - Client IP iptables proxy mode에서 동작 원리 PREROUTING KUBE-SERVICES KUBE-SVC-BAZ KUBE-SVC-BAR KUBE-SVC-FOO KUBE-SEP-POD2 KUBE-SEP-POD1 각 서비스별 Chain DNAT to Pod1 최근 Source IP 목록 1.1.1.1 1.2.3.4 2.3.4.5 7.7.7.7 서비스 Endpoint 별 Chain (DNAT) 최근 Source IP 목록에서 현재 Packet의 Source IP를 발견하면 해당 Chain으로 패킷 전달 Pod 별 Chain으로 전달하기 전에, recent 모듈로부터 기록된 최근 Source IP를 확인 (최대 세션 고정시간 10800초 = 3시간) → 현재 패킷의 Source IP가 최근 Source IP 목록에 존재하는 경우, 해당 Pod Chain으로 전달 iptables로 확인하기 -
DNAT to Pod2 최근 Source IP 목록 1.1.1.1 3.4.5.6 4.5.6.7
Session Affinity - Client IP iptables proxy mode에서 동작 원리 PREROUTING KUBE-SERVICES KUBE-SVC-BAZ KUBE-SVC-BAR KUBE-SVC-FOO KUBE-SEP-POD2 KUBE-SEP-POD1 각 서비스별 Chain DNAT to Pod1 최근 Source IP 목록 1.1.1.1 1.2.3.4 2.3.4.5 서비스 Endpoint 별 Chain (DNAT) 최근 Source IP 목록에서 현재 Packet의 Source IP가 발견되지 않으면 기존처럼 무작위 전달 Packet In Source IP 7.7.7.7 최근 Source IP에 존재하지 않으면, 기존처럼 무작위 전달 iptables로 확인하기 -
Packet In Source IP 7.7.7.7 DNAT to Pod2 최근 Source
IP 목록 1.1.1.1 3.4.5.6 4.5.6.7 Session Affinity - Client IP iptables proxy mode에서 동작 원리 PREROUTING KUBE-SERVICES KUBE-SVC-BAZ KUBE-SVC-BAR KUBE-SVC-FOO KUBE-SEP-POD2 KUBE-SEP-POD1 각 서비스별 Chain DNAT to Pod1 최근 Source IP 목록 1.1.1.1 1.2.3.4 2.3.4.5 7.7.7.7 서비스 Endpoint 별 Chain (DNAT) DNAT를 적용한 Chain에서 최근 Source IP 목록에 저장 -
Packet In Source IP 7.7.7.7 DNAT to Pod2 최근 Source
IP 목록 1.1.1.1 3.4.5.6 4.5.6.7 Session Affinity - Client IP iptables proxy mode에서 동작 원리 PREROUTING KUBE-SERVICES KUBE-SVC-BAZ KUBE-SVC-BAR KUBE-SVC-FOO KUBE-SEP-POD2 KUBE-SEP-POD1 각 서비스별 Chain DNAT to Pod1 최근 Source IP 목록 1.1.1.1 1.2.3.4 2.3.4.5 7.7.7.7 서비스 Endpoint 별 Chain (DNAT) DNAT를 적용한 Chain에서 최근 Source IP 목록에 기록 Pod Chain에서 DNAT 적용된 패킷의 Source IP(Client IP)를 저장 iptables로 확인하기