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에는 연결하고자 하는 외부 도메인 이름을 넣으면 된다.