본문 바로가기
k8s

k8s #5 networking&namespace

by PudgeKim 2021. 11. 24.

이번 포스팅에서는 쿠버네티스 상에서 두개의 컨테이너 간에 통신에 관련하여 알아보겠습니다.

 

예를 들어서 go언어로 만들어진 서버 컨테이너와 postgresql 데이터베이스 컨테이너가 통신을 하고싶다고 가정해보겠습니다.

첫번째 방법으로는 아래 그림 같은 구조를 생각해볼 수 있습니다.

 

한개의 pod안에 통신을 하려는 두개의 컨테이너를 모두 집어넣는 것입니다.

그러나 이런 방법은 바람직하지 못합니다.

왜냐하면 예를 들어 pod이 모종의 이유로 작동이 안되면 go언어 서버 컨테이너에 문제가 있는지 아니면 postgresql 컨테이너에 문제가 있는지에 대해서도 찾아봐야할 것이기 때문입니다.

이외에도 상당히 복잡해지기 때문에 보통 이런 경우 2개의 pod으로 나누게 됩니다. 그럼 아래와 같은 구조를 생각해 볼 수 있습니다.

 

이런 의문이 들 수 있습니다. Pod을 두개로 나눈건 알겠는데 Pod끼리 통신을 하면되는걸 왜 Service까지 추가해서 통신을 해야하는지에 대해 말입니다.

쿠버네티스에서 pod은 언제든지 다운될 수 있고 그런 경우 재생성될 수 있습니다. 이렇게 재생성된 pod의 IP는 변하게 되기 때문에 pod간의 통신은 위험할 수 있습니다.

그러나 service는 사용자가 직접 지우지 않는한 삭제되지 않기 때문에 위와 같은 구조로 작성하게 됩니다.

service의 타입도 여러가지가 있지만 한 Cluster내에서 통신할 때는 ClusterIP 타입을 사용하게 됩니다.
(Cluster내에서는 해당 service로 접근 가능하지만 외부에서는 접근못하는 타입)

 

그럼 각 service의 IP 주소를 알아내서 service간의 통신을 하면 되는 것인가? 이것 또한 바람직하지 못합니다.

각 service의 IP 주소도 쿠버네티스가 자동으로 부여하는 것이고 그 뜻은 쿠버네티스를 재실행 할 경우 service들의 IP 주소가 변경되기 때문입니다.

이 문제의 해답은 DNS를 담당하는 service를 만드는 것입니다. 구조는 아래와 같습니다.

 

golang webserver를 담당하는 service는 DNS에 질의해서 postgresql을 담당하는 서비스의 IP 주소를 알아낸 후 해당 서비스와 통신하는 구조입니다.

이러한 DNS 서비스는 우리가 직접 만드는 것이 아니고 쿠버네티스에 이미 만들어져 있습니다.

그럼 이 DNS 서비스를 찾아보겠습니다.

 

kubectl get all 명령어를 실행해봐도 dns관련 service를 찾아볼 수가 없습니다. 왜냐하면 namespace를 지정해주지 않았기 때문에 저렇게만 명령어를 치는 것은 default라는 namespace가 적용된 것입니다.

kubectl get ns 명령어를 실행해보면 현재 가지고 있는 namespace 목록을 볼 수 있습니다.

 

이제 kubectl get po -n kube-system 명령어를 실행해봅시다. po는 pod을 뜻하고 -n kube-system은 kube-system namespace를 적용시키는 것입니다.

coredns라는 pod이 보입니다.

그런데 해당 namespace로 service를 검색해보면 coredns가 아닌 kube-dns 서비스가 나오는데 이건 쿠버네티스 특정 버젼 이후로 kube-dns에서 core-dns로 변경되었는데 이전 버젼과의 호환성 때문이라고 합니다.

 

이제 아무 pod이나 하나 만든 후 exec -it 명령어를 통해 해당 pod으로 들어가봅시다.

그리고 cat /etc/resolv.conf 명령어를 실행해봅니다.

여기서 nameserver에 IP 주소는 바로 DNS 쿼리를 보낼 IP 주소를 뜻합니다.

위에서 kubectl get svc -n kube-system 명령어로 얻은 서비스의 CLUSTER-IP주소와 일치합니다.

만약 지금 다른 service가 실해중이라면 현재 pod의 터미널에서 nslookup <실해중인 serviceName> 명령어를 실행해보면 
해당 service의 IP 주소를 얻을 수 있습니다.

nameserver로 nslookup 명령어를 통해 DNS 쿼리를 날린 것입니다.

즉, 통신하고 싶은 service의 IP 주소를 몰라도 metadata의 name만 안다면 DNS 쿼리를 통해 IP 주소를 알아낼 수 있다는 뜻입니다.

 

마지막으로 알아볼 것은 FQDN입니다. FQDN이란 전체 도메인 이름을 뜻합니다.

nslookup 명령어로 아래와 같은 결과를 얻었다고 가정해봅시다.

10.102.76.115 database.default.svc.cluster.local

살펴보아야할 부분은 default 부분입니다. 지금은 default로 되어있어서 단순히 nslookup database 명령어로 쿼리를 날려도 IP 주소를 잘 찾아옵니다. /etc/resolv.conf 파일의 search 부분에 있는 목록들을 붙여가면서 쿼리를 날려보기 때문입니다.

그러나 사용자가 따로 namespace를 주어서 FQDN이 만약 database.special.svc.cluster.local 이렇게 되어있다면
해당 IP 주소를 못찾아올 수도 있습니다.

왜냐하면 search의 목록들을 붙여서 도메인 이름을 조합해봐도 special은 없기 때문입니다.

이런 경우는 nslookup database.special 이런식으로 명령어를 날려보아야 합니다.

'k8s' 카테고리의 다른 글

k8s #4 Deployment&Rollout  (0) 2021.11.23
k8s #3 ReplicaSets  (0) 2021.11.22
k8s #2 무중단 배포 기초  (0) 2021.11.22
k8s #1 hello world  (0) 2021.11.22