본문 바로가기
Tech/Containers

[GCP][K8S] Kubernetes 네트워크 살펴보기

by 타이호 2018. 7. 9.
반응형

Kubernetes에서 어떻게 pod간 네트워크, 외부(ingress, LB)와 네트워크가 동작하는지 살펴본다.


1. 환경 구성

  • Google Cloud Platform에 GKE로 구성(1.9.7 버전)

  • Container address : 10.12.0.0/14 (Overlay Network)

  • Worker node는 3개로 구성

  • 테스트 application으로 sock-shop 배포

https://github.com/microservices-demo/microservices-demo



2. Kubernetes Worker Network

Kubernetes는 POD단위로 배포가 되며 하나의 POD는 Overlay network을 가진다. POD는 하나 이상의 Container를 가지게 되지만 POD에는 하나의 IP만 부여된다. 그말은 여러개의 컨테이너가 하나의 POD안에 존재 할 때 같은 포트를 사용할 수 없다. cbr은 Custom Bridge로써 모든 컨테이너의 gateway 역할을 한다.  


3. Node간 Network Communication

서로 다른 노드에 있는 POD간 통신은 Proxy Container (Kube-proxy)를 통해서 이루어 진다.

배포된 sock-shop의 경우에서 orders와 shipping이라는 pod가 존재하고 둘 사이에 통신을 해야 한다고 가정하면 통신은 service 라는 것을 통해 이루어진다.

위와 같이 orders라는 서비스는 orders-787bf5b89f-slfj5 이라는 pod를 위해 존재하고 다른 곳에서 orders의 서비스를 접근하기 위해서 pod의 ip가 아닌 orders의 서비스 ip로 접근을 하게 되어 있다. 하지만 위의 10.15.255.186 이라는 ip는 worker node에 존재 하지 않는다.

그래서 아래와 같이 shipping pod의 컨테이너가 10.15.255.186로 접근하기 위해서는 자신의 네트워크가 아니기 때문에 위로 계속 던지게 되어 있다. 그래서 실제 물리 network interface까지 가게 되고 이후 설명하겠지만 서비스 ip와 맵핑된 order의 pod ip로 변환해서 gateway로 던지게 된다. 그래서 gateway에서는 해당 ip가 nexthop으로 지정되어 있기 때문에 그 next hop으로 ip가 전달되게 되고 worker #2에서는 해당 pod로 DNAT을 통해 접근하는 것이다.



좀더 자세히 살펴보면 worker #1에서 order의 서비스 ip로 가기 위해서는 kube-proxy의 역할이 중요하다. 물리적으로 존재하는 IP가 아니기 때문에 kube-proxy는 각 worker node에서 동작하면서 iptables의 규칙을 생성하고 삭제하는 역할을 수행한다. 즉 10.15.255.186이라는 ip는 nat table에 등록되어 있어 라우팅이 수행되게 된다.


# iptables -t nat -S | grep 10.15.255.186
-A KUBE-SERVICES ! -s 10.12.0.0/14 -d 10.15.255.186/32 -p tcp -m comment --comment "sock-shop/orders: cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.15.255.186/32 -p tcp -m comment --comment "sock-shop/orders: cluster IP" -m tcp --dport 80 -j KUBE-SVC-BWR2E3DUEHRRCI5E


# iptables -t nat -S | grep KUBE-SVC-BWR2E3DUEHRRCI5E
-N KUBE-SVC-BWR2E3DUEHRRCI5E
-A KUBE-SERVICES -d 10.15.255.186/32 -p tcp -m comment --comment "sock-shop/orders: cluster IP" -m tcp --dport 80 -j KUBE-SVC-BWR2E3DUEHRRCI5E
-A KUBE-SVC-BWR2E3DUEHRRCI5E -m comment --comment "sock-shop/orders:" -j KUBE-SEP-K4ZGYUFWBTSJFVZP


# iptables -t nat -S | grep KUBE-SEP-K4ZGYUFWBTSJFVZP
-N KUBE-SEP-K4ZGYUFWBTSJFVZP
-A KUBE-SEP-K4ZGYUFWBTSJFVZP -s 10.12.2.7/32 -m comment --comment "sock-shop/orders:" -j KUBE-MARK-MASQ
-A KUBE-SEP-K4ZGYUFWBTSJFVZP -p tcp -m comment --comment "sock-shop/orders:" -m tcp -j DNAT --to-destination 10.12.2.7:80
-A KUBE-SVC-BWR2E3DUEHRRCI5E -m comment --comment "sock-shop/orders:" -j KUBE-SEP-K4ZGYUFWBTSJFVZP


복잡한 체인으로 구성되어 있기 때문에 체인을 따라가서 보는 것이 중요하다.


참고로 GCP 내에서 next hop으로 라우팅은 VPC Network에 정의 되어 있다


4. 외부와 Network Communication

클라이언트가 외부에서 해당 서비스에 접근하기 위해서는 크게 NodePort와 LoadBalancer를 사용할 수 있다. NodePort는 말 그대로 해당 Worker 노드의 포트를 외부에 오픈해서 사용자가 직접 Worker 노드의 포트로 직접 접속하는 방식이며, 해당 서비스의 포트는 3000 - 32767 사이의 임의의 포트가 해당 서비스로 할당된다. 그래서 사용자는 해당 Worker의 물리 IP Address의 서비스 포트로 서비스를 접속 할 수 있다.

LoadBalancer의 경우 아래와 같이 서비스를 배포하고 나면 External IP로 LoadBalancer로 셋팅이 된다. 실제로 클라이언트는 해당 외부 IP 35.238.119.72의 80포트로 접속을 하게 되고 LB는 31388로 Worker 노드로 포워딩을 해주게 된다.

GCP내에서는 TCP LoadBalancer를 생성해서 Worker 노드를 백엔드로 가지게 된다

좀더 상세히 해당 front-end의 서비스를 살펴보면 서비스용 내부 IP 10.15.240.135의 80포트로 맵핑을 하고 있고 실제 서비스를 하는 컨테이너인 10.12.1.7의 8079 포트를 가르키고 있다.

전체적인 흐름은 아래와 같이 적용될 수 있으며 공인 IP -> Cluster IP -> Pod IP로 변환은 kube-proxy에 의해 iptables nat 규칙이 적용되어 변환되게 된다.




5. Ingress

서비스와 pod는 클러스터 네트워크에 의해 라우팅이 가능한 IP들을 가진다. Ingress란 클러스터 서비스들에게 연결하기 위한 inbound connection을 허용하는 규칙들의 모음이다.

단순히 트래픽을 로드 밸런싱 해주는 것 이외에도, SSL, Virtual Host 등등의 기능을 제공해 준다. GCP의 GKE는 LoadBalancer로 배포 했을 때 TCP LoadBalancer로 구성이 되었지만, ingress로 구성을 하게 되면 Global LoadBalancer가 생성된다. 아래와 같이 간단하게 ingress를 만들어서 배포한다. 참고로 ingress를 사용 시 NodePort로 서비스를 배포한다.

이렇게 ingress를 배포하고 나면 해당되는 서비스에 공인 IP (LoadBalancer가 가지고 있다)가 할당되고 서비스로 연동이 된다. GCP 내에서 살펴보면 Global LoadBalancer가 생성되고 서비스에 정의된 80포트가 LB로 구성되어 있는 것을 볼 수 있다.

실제로 서비스는 30001번으로 배포가 되어 있기 때문에 LoadBalancer에서는 해당 서비스 포트로 로드밸런싱을 해주게 된다.


이번에는 조금 더 옵션을 추가해서 ingress를 생성해보았다.

위와 같이 ssl, host, path 등을 추가해서 ingress를 생성하였다.

아래와 같이 host가 정의된 ingress가 생성된다.

위 구성으로 ingress를 생성 했을 경우 GCP의 Global LoadBalancer에 반영이 되게 된다.

테스트를 해보면 ip로 접근시 404에러가 나게 된다

LB에 적용된 host로 접근을 해야 아래와 같이 웹 화면이 표시 된다.


https://kubernetes.io/docs/concepts/services-networking/ingress/#terminology

https://cloud.google.com/kubernetes-engine/docs/tutorials/http-balancer




















반응형