Infra/Kubernetes
Service - Headless, Endpoint, ExternalName
최-코드
2025. 6. 20. 21:12
Headless 필요성
- 사용자 접근의 경우 서비스가 만들어진 후에 IP를 확인하고 이 IP로 접근하면 된다.
- 하지만 파드에서 파드로, 혹은 서비스로 요청을 보낼 때 각각의 자원들이 동시에 배포가 될 수 있다.
- PodA가 PodB에 접근해야 하는 상황에서 PodA에 IP를 지정하려고 할 때, PodB나 Service가 생성 시에 동적으로 IP가 할당되기 때문에 미리 IP를 알 수 없다.
- PodB의 경우 문제가 생겨서 죽으면 재생성 때 IP가 변경되는 문제가 발생해서 PodA에서 미리 IP를 할당해줄 수 없다.
- 이 문제를 해결하기 위해서는 DNS Server와 Headless가 필요하다.
ExternalName 필요성
- 파드가 외부의 특정 사이트(Google)에 접근해서 데이터를 가져오는 상황에서 접근 주소를 변경(Github)해야 되는 상황이 생기면 파드를 수정하고 재배포해야 한다.
- 이 문제를 해결하기 위해서는 ExternalName을 이용해 외부 연결을 파드의 수정 없이 변경할 수 있도록 할 수 있다.
DNS
- 쿠버네티스 클러스터 안에는 DNS 서버가 별도로 존재한다.
- DNS 서버에는 서비스의 도메인 이름과 IP가 저장되어 있기 때문에 파드가 service1 도메인명을 질의하면 해당 IP를 알려준다.
- 내부망에서도 DNS 서버가 구축되어 있다면 내부 서버들이 생겼을 때 해당 이름들이 DNS 서버에 등록되었을 거고, 파드가 유저1을 찾았을 때 쿠버네티스 DNS에 없다면 DNS 메커니즘 상 상위 DNS를 찾게 되고 해당 이름의 IP를 알려준다.
- 외부 DNS도 마찬가지이다.
Headless 개요
- Pod1이나 Pod2를 선택해서 접근하고 싶을 때는 Pod에 Headless Service를 연결하면 된다.
- 이로 인해 DNS 서버에 파드의 이름과 서비스의 이름이 붙여진 도메인 이름으로 등록된다.
ExternalName 개요
- ExternalName Service를 만들면 그 안에 특정 외부 도메인 주소를 넣을 수 있다.
- 이로 인해 DNS 서버에서 상위 DNS 서버를 탐색하며 외부 도메인에 접근할 수 있다.
- 이때도 마찬가지로 pod에서 ExternalName Service에 접근할 때는 DNS Server를 통해서 접근한다.
Headless
- 클러스터 DNS는 파드건 서비스건 생성하면 도메인 이름과 IP가 저장된다.
- 도메인 이름의 구조는 아래와 같다.
- service의 경우 service명.네임스페이스명.svc(서비스 약어).DNS명
- pod의 경우 IP.네임스페이스명.pod.DNS명
- 이러한 규칙을 Fully Qualified Domain Name(FQDN)이라고 한다.
- DNS를 통해 IP를 가져올 때 같은 네임스페이스 안에서는 service는 앞자리(service명)만, 파드는 전체 도메인명을 입력해야 한다.
- service를 통해 접근할 때는 위와 같은 방식으로도 충분하지만, 특정 파드에 직접 연결을 하고 싶을 때는 Headless Service를 이용해야 한다.
- Headless 서비스를 만드는 방법은 clusterIP에 none이라는 값만 넣으면 된다. -> service의 IP를 안 만들겠다는 의미이다.
- 이때, 파드를 만들 때는 hostname 속성에 도메인 이름(지정하지 않으면 파드명과 동일)을, subdomain 속성에 headless service 명을 넣어줘야 한다.
- 그리하면 DNS 구조는 아래와 같이 된다.
- Service의 도메인 이름은 동일한 방식으로 만들어지지만, service의 IP가 없기 때문에 service와 연결된 pod의 IP를 반환한다.
- Pod의 경우 hostname.subdomain.이하동일 와 같이 만들어지고, service와 마찬가지로 hostname.subdomain만 입력하면 IP를 가져온다. <- IP는 위와 동일
apiVersion: v1
kind: Service
metadata:
name: headless1
spec:
selector:
svc: headless
ports:
- port: 80
targetPort: 8080
clusterIP: None
apiVersion: v1
kind: Pod
metadata:
name: pod4
labels:
svc: headless
spec:
hostname: pod-a
subdomain: headless1
containers:
- name: container
image: kubetm/app
Endpoint
- 사용자 측면에서 service와 pod를 연결할 때 라벨과 셀렉터를 지정해준다. 이에 대한 내부적으로는 Endpoint를 만들어줘서 연결고리를 관리한다.
- Endpoint의 이름은 service 명과 동일하고, Endpoint 안에는 파드의 접속 정보를 넣어준다.
- Endpoint 만드는 방법을 알면 라벨과 셀렉터를 만들지 않고 Endpoint를 만들면 service와 pod를 연결시켜줄 수 있다.
- Endpoint를 만들 때 service의 이름과 파드의 IP, port 정보를 넣게 되면 연결된다.
- 외부 IP 주소를 통해 외부를 가리킬 수도 있다.
- 하지만 Endpoint의 경우 IP 주소가 변경될 수 있기 때문에 주의해야 한다.
apiVersion: v1
kind: Endpoints
metadata:
name: endpoint2
subsets:
- addresses:
- ip: 20.109.5.12
ports:
- port: 8080
ExternalName
- service를 만들 때 ExternalName이라는 속성을 달면 service 내부에 도메인 이름을 넣을 수 있다.
- DNS 캐시가 내부와 외부 DNS를 찾아서 IP를 알아낸다.
- 결국, Pod는 service만 가리키고만 있으면 service에서 필요시마다 해당 도메인 주소를 변경할 수 있어서, Pod를 수정하고 재배포하는 일이 없어진다.
apiVersion: v1
kind: Service
metadata:
name: externalname1
spec:
type: ExternalName
externalName: github.github.io
- externalName에는 연결하고자 하는 외부 도메인 이름을 넣으면 된다.