본문 바로가기
Recent Study/Kubernetes 학습과정

13. Basic Object - Service

by Thinking 2024. 1. 16.

 사용자의 접근 경우 Service가 만들어진 후에 IP를 확인하고, 이 IP로 접근을 하면 되는데(10.111.41.1) Pod의 경우 이 자원들이 동시에 배포가 될 수 있습니다. Pod A가 Pod B에 접근을 해야하는 상황인데 Pod A에 IP를 넣기에는 Pod나 Service가 동적으로 할당되기 때문에 미리 알기에는 제약이 있습니다. Pod B의 경우 문제가 생겨 죽으면 자동으로 재생성되면서 IP가 변경되기 때문에 Pod A가 IP를 알더라도 계속 쓸 수 없습니다. 이런 문제를 해결하기 위해 DNS, Headless 서비스가 필요합니다.

 

 Pod가 외부 특정 사이트에 접근해서 데이터를 가져오는 상황에서 접근 주소를 변경해야 되는 상황이 생기면 경로를 변경해주기 위해 Pod를 수정하고 재배포해야 될까요? 이런 문제를 해결하기 위해 Service의 External Name을 이용해서 외부 연결을 Pod 수정없이 변경할 수 있도록 할 수 있습니다.

 

 

 k8s Cluster 안에는 DNS 서버가 별도 존재합니다. 이 DNS 서버에는 Service의 도메인 이름과 IP가 저장되어 있기 때문에 Pod가 Service 1에 대한 도메인 이름을 질의하면 해당 IP를 알려줍니다. 내부망(Internal Network)에서도 DNS 서버가 구축돼있다면 내부 서버들이 생겼을 때 해당 이름들이 DNS에 등록이 되었을 거고, Pod가 user1을 찾았을 때 k8s Dns에 없다면 DNS 메커니즘 상 상위 DNS를 찾게 되고 해당 이름의 IP를 알려줍니다.

 

 마찬가지로 외부에 있는 사이트도 도메인 이름이 외부 DNS에 등록이 되어 있기 때문에, 부모의 부모를 찾아서 결국 구글의 IP 주소를 알 수 있게 되는데요. 이렇게 Pod에서 DNS를 이용해서 원하는 서비스나 외부에 접근을 할 수 있습니다. 그래서 Pod가 IP 주소를 몰라도 이렇게 DNS에 Service 이름으로 IP를 물어봐서 연결을 할 수 있습니다.

 

 

 2번째로 Pod1, Pod2를 선택해서 연결하고 싶을 때는 Pod에 headless Service를 연결하게 되면 DNS 서버에 Pod의 이름과 서비스의 이름이 붙여져서 도메인 이름으로 등록이 되기 때문에, Pod 입장에서는 Pod1에 접근하기 위해 IP 주소는 필요없고 DNS의 이름으로 접근할 수 있습니다. 

 

 

 또한 ExternalNmae이라는 Service를 만들 수 있고, 이 안에 특정 외부 도메인 주소를 넣을 수 있는데, 위처럼 구글 도메인 이름을 넣으면 DNS를 타서 구글 IP를 가져올 수 있습니다. Pod는 이 서비스를 통해서 데이터를 가져오도록 해놓으면, 추후 데이터를 Github에서 가져오도록 변경을 했을 때 Pod 수정없이 ExternalName만 변경해주면 됩니다.

 

 

 

Headless

 Default라는 Namespace에 Pod 2개와 서비스가 연결되어 있습니다. 이름도 부여하고, 각각의 IP도 동적으로 만들어집니다. k8s DNS가 있는데, DNS의 이름은 cluster.local 이에요. 이 DNS는 Pod건 Service건 생성을 하면 위처럼 긴 도메인 이름과 IP가 저장이 됩니다. 이 이름의 구조를 살펴봐요.

 

 Service의 경우 (서비스이름, 네임스페이스이름, 서비스의 약어, 끝으로 DNS 이름) 이렇게 만들어집니다.

Pod의 경우 (IP의 Namespace, pod, DNS 이름) 이렇게 결합돼서 생성이 됩니다. 이것을 FQDN ( Fully Qualified Domain Name) 이라고 하며, 같은 Namespace 안에서 Service는 앞자리만 짧게 써도 되지만, Pod는 전부 다 입력해야 합니다. 

 

 Pod의 입장에서 Service 도메인 이름을 DNS 질의를 통해 IP를 가져오기 때문에 우리는 Service의 이름만 알아도 해당 서비스에 접근할 수 있고, 모든 이름들은 사용자가 직접 만들기에 해당 Pod에 직접(Service 이름) 심어놓을 수 있겠죠. 단순히 Service에만 연결을 하는데는 클러스터 IP로 Service를 만들어도 문제는 없습니다. 

 

 근데 똑같은 상황에서 Pod가, Pod4에 직접 연결을 하고 싶다면, 우리는 위 Serivce를 headless 서비스로 만들어야 합니다. 만드는 방법은 클러스터 ip 속성에 none 이라고만 넣으면 됩니다. Service의 ip를 안만들겠다는 내용이고, 실제로 안만들어집니다. pod를 만들 때도 hostname 이라는 속성에 도메인 이름을 넣어야 하고, subdomain에 해당 Service의 이름을 넣어줘야 합니다. 위와 다른 점은 Service의 IP가 없기 때문에 이 Service 이름을 호출하게 되면 연결되어 있는 모든 Pod의 IP를 줍니다. DNS의 Pod를 보면 Pod의 hostname이 앞에 붙어있고, 뒤 부터는 Service 이름과 똑같아서 간단하게 위처럼 호출하면 됩니다. 그래서 이 Pod는 이름들을 미리 정해놓고, DNS를 통해서 원하는 Pod로 직접 통신을 할 수 있게 됩니다.

 

 

Endpoint

 우리가 Service, Pod를 연결할 때 Label을 통해서 연결했습니다. 하지만 이것은 사용자 측면에서 둘의 연결을 하기 위한 도구일 뿐이지 k8s는 이렇게 매칭이 되었을 때, Endpoint를 만들어줘서 실제 연결고리를 관리를 합니다. k8s가 어떻게 만드냐면, Service의 이름과 동일한 이름으로 Endpoint 이름을 설정하고, Endpoint 안에는 Pod의 접속 정보를 넣어줍니다. 이 규칙으로 Label, Selector를 안 만들어도 직접 연결을 할 수가 있는데, 먼저 Service와 Pod를 만들 때 Label, Selector 설정을 하지 않으면 연결이 안되겠죠.

 

 이 상태에서 Endpoint를 만드는데 Service의 이름과 Pod의 IP 정보를 넣게 되면 똑같이 연결됩니다. Service의 연결 대상을 사용자가 직접 지정해준 것인데, 이렇게 IP와 Port가 내부 포트를 가리킬 수도 있고, 외부 IP 주소를 안다면 외부를 가리킬 수도 있습니다. 근데 IP는 변경 가능성이 있기 때문에 도메인을 사용하는 것인데 Github의 IP 주소도 변경이 될 수 있고, 그래서 도메인 이름을 지정하는 방법도 필요한데 이럴 때 쓰는 것이 ExternalName 입니다.

 

 

ExternalName

 Service에 ExternalName이라는 속성을 달아서 이 안에 도메인 이름을 넣을 수가 있습니다. 이렇게 넣으면 DNS 캐시가 내부, 외부 DNS를 찾아서 IP를 알아냅니다. 그래서 결국 Pod는 Service를 가리키고만 있으면 Service에서 필요시마다 해당 도메인 주소를 변경할 수 있어서 접속할 곳이 변경되더라도 Pod를 수정하고 재배포하는 일은 없어지게 됩니다.