/
Service Discovery

Service Discovery

개요

Creating a single control-plane cluster with kubeadm | Testing a simple Nginx deployment 에서 실습했던 내용에서 조금 더 확장하여 이해하여 본다.

여기에서 사용되는 config 파일은 https://github.com/snetsystems/K8s-Objects/tree/master/tests 에 업로드 되어 있다.

기본적으로 pod는 내부 IP가 할당되며 외부에서 접근이 불가능 하다.
또한, Pod는 언제든 죽을 수 있다는 것이 k8s의 철학이며 pod가 다시 만들어 질 경우 pod에 할당된 IP가 변경되게 된다. 해서, 내부 Pod간 통신을 위해서도 전통적 방식인 IP addr을 통한 통신으로는 불가능하다.

즉, Service discovery 방식으로 해결하게 되는데, 즉 도메인 방식으로 접근한다.
기본적으로 K8s를 Initialize하게 되면, coredns pod가 생성되며, 생성된 모든 pod는 여기 등록되어 아래와 같이 kube-dns 서비스로 dns 쿼리하여 pod IP를 알아낸 후 통신을 연결하게 된다.

$ kubectl get svc -A NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13d kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 13d

정리하자면, 각각의 Pod는 언제든 IP가 변경될 수 있으며 할당된 IP는 label selector로 지정된 서비스를 통해 도메인으로 통신하게 된다.

이제 아래 예제를 통해 이해를 높여보자.

외부에서의 Pod 접속 테스트

nginx-deployment.yaml

편의를 위해 test namespace를 생성한다.

apiVersion: v1 kind: Namespace metadata: name: test

nginx pod를 2개(replicas: 2)로 생성한다.

apiVersion: apps/v1 kind: Deployment metadata: name: nginx namespace: test labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx # 이 label을 Service object에 지정해야 서비스 도메인을 통한 통신 연결이 수행됨. template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:stable-alpine3.17-slim ports: - containerPort: 80

각각의 타입 별 테스트를 위해,
ClusterIP, LB, NodePort 타입의 서비스들을 각각 생성하여 본다.

모두 문제없이 생성된다면, 아래와 같을 것이다.

위에서 externalIPs를 각각 지정하여 두었기 때문에, 각각의 externalIPs를 통하여 각 80, 8080 포트로 접속이 가능하다.

가능한 조합의 curl 테스트:

또한, 각각의 서비스는 label selector app: nginx로 지정하였기 때문에 deploy로 생성한 2개의 nginx pod에 Load balancing 된다.

nginx-6c8cf466cd-xgbd7 로그:

nginx-6c8cf466cd-mpfz4 로그:

내부 Pod간 통신

앞서 개요에서 언급하였듯이, 모든 Pod들은 IP 대신 도메인으로 통신할 수 있다.
즉, Pod간 internal 통신을 위해서는 서비스명으로 access한다.

관련 테스트를 위해 test namespace에 아래와 같은 pod를 하나 생성하자.

정상 생성되면 아래와 같을 것이다.

busybox 내부 쉘로 진입하여 각 pod ip로 접근해보면, 당연하게도 overlay networking을 통해 잘 접근된다는 것을 볼 수 있다.

CRI-O runtime의 경우 보안 상 pod 내부에서 ping이 나가는 것이 막혀있다.
각 K8s 클러스터 노드들에 /etc/crio/crio.conf.d/default_capabilities.conf를 생성하여,
아래 옵션(“NET_RAW")을 넣어준다.
[crio.runtime] default_capabilities = [ "CHOWN", "DAC_OVERRIDE", "FSETID", "FOWNER", "SETGID", "SETUID", "SETPCAP", "NET_BIND_SERVICE", "KILL", "NET_RAW", ]

이후, systemctl restart crio를 통해 crio를 재시작하고,
ping을 사용하려는 pod(“busybox”)도 재생성해야 한다.

자세한 내용은 https://flavono123.github.io/posts/crio-capabilities-bug/ 을 참고 하기 바란다.

그러나, IP는 언제든 바뀔 수 있으므로, 이번에는 미리 만들어둔 Service를 통해 접근해보도록 하자.

당연한 말이지만, Service는 Pod가 아니라 pod의 특정 포트를 cluster ip와 포트로 연결해주는 일종의 정책이므로, 위의 ping은 도달하지 않는다.

아래와 같이 telnet을 통해 서비스 포트로 접근이 가능하다는 것을 확인할 수 있다.

그럼 어떻게 pod에서 서비스 포트로 접근이 가능할까?

nslookup을 통해 도메인 찾기를 해보자.

위의 10.96.0.10:53kube-dns 서비스의 CLUSTER-IP이다.(kubectl get svc -n kube-system 명령으로 확인할 수 있다.)

10.105.132.127nginx-svc서비스의 CLUSTER-IP이다.

즉, CLUSTER-IP: 10.105.132.127에 대하여 nginx-svc.test.svc.cluster.local으로 도메인이 등록되어 있음을 알 수 있으며, nginx-svc는 label selector로 각 pod와 연결된다는 것을 추정할 수 있을 것이다.

참고로, 다른 domain의 pod에 접근하기 위해서는 서비스명.도메인명으로 사용하면 된다.

Headless Service

위 Service 예제에서는 편의상 externalIPs를 모두 할당하였다.
하지만,

  1. Pod 간 통신 즉 클러스터 내 통신만을 하기 때문에 굳이 externalIPs를 할당할 필요가 없다.

  2. 클러스터된 Pod가 2개 이상이고, 이들 pod들에 load balancing 하여 request할 필요가 없다.

등의 경우, Headless 서비스를 생성하면 되는데, 클러스터 내에서 DNS 쿼리를 하면, 앞 장에서 살펴본 CLUSTER-IP가 할당되지 않기 때문에 해당 Pod의 IP를 직접 제공해준다.

만약 2개 이상의 Pod가 seletor로 연결되어 있다면, 랜덤한 순서로 이 서비스에 연결된 모든 IP 리스트를 리턴하게 된다. 말그대로, DNS 서버 역할만 수행한다.

자세한 내용은 구글 검색 등을 통해 살펴보기를 바라며, 아래와 같이 clusterIP: None을 명시적으로 붙여주면 된다.

생성 후, 앞 장의 내용대로 nslookup 테스트를 해보면 이해가 될 것이다.

정리

이 실습들을 통해 모던 어플리케이션 시스템을 어떻게 K8s 상에 구축할 것 인가에 대한 통상의 개념을 알아보았다.

다음에는 아래와 같은 완성된 형태의 어플리케이션 서비스의 Server side를 deploy 해볼 것이다.

 

Related content

Using Service & Ingress
Using Service & Ingress
More like this
Quickstart Helm
Quickstart Helm
Read with this
Kubernetes Monitoring
Kubernetes Monitoring
More like this
CloudHub Deploy onto K8s(작성중)
CloudHub Deploy onto K8s(작성중)
Read with this
K8s
More like this
Installation for test Env.
Installation for test Env.
Read with this