[kubernetes] Service

728x90

Service: 포드를 연결하고 외부에 노출

다른 디플로이먼트의 포드들이 내부적으로 접근하려면 서비스라고 부르는 별도의 쿠버네티스 오브젝트를 생성해야 한다. 서비스는 포드에 접근하기 위한 규칙을 정의하기 때문에 쿠버네티스에서 애플리케이션을 배포하기 위해서는 반드시 알아야 할 오브젝트이다.

핵심 기능은 다음과 같다.

  1. 여러 개의 포드에 쉽게 접근할 수 있도록 고유한 도메인 이름을 부여한다.
  2. 여러 개의 포드에 접근할 때, 요청을 분산하는 로드 밸런서 기능을 한다.
  3. 클라우드 플랫폼의 로드 밸런서, 클러스터 노드의 포트 등을 통해 포드를 외부로 노출한다.

서비스의 종류

  • ClusterIP 타입: 쿠버네티스 내부에서만 포드들에 접근할 때 사용한다. 외부로 포드를 노출하지 않기 때문에 쿠버네티스 클러스터 내부에서만 사용되는 포드에 적합하다.
  • NodePort 타입: 포드에 접근할 수 있는 포트를 클러스터의 모든 노드에 동일하게 개방한다. 따라서 외부에서 포드에 접근할 수 있는 서비스 타입이다. 접근할 수 있는 포트는 랜덤으로 정해지지만, 특정 포트로 접근하도록 설정할 수도 있다.
  • LoadBalancer 타입: 클라우드 플랫폼에서 제공하는 로드 밸런서를 동적으로 프로비저닝해 포드에 연결한다. NodePort 타입과 마찬가지로 외부에서 포드에 접근할 수 있는 서비스 타입이다. 그렇지만 일반적으로 AWS, GCP 등과 같은 클라우드 플랫폼 환경에서만 사용할 수 있다. nginx 를 사용하여 로드 밸런서 역할을 하게 할 수 있다.

ClusterIP 타입의 서비스 - 쿠버네티스 내부에서만 포드에 접근하기

spec.selector: 이 서비스에서 어떠한 라벨을 가지는 포드에 접근할 수 있게 만들 것인지 결정한다.

spec.ports.port: 서비스는 쿠버네티스 내부에서만 사용할 수 있는 고유한 IP를 할당받는다. 이 때 port 항목에는 서비스의 IP에 접근할 때 사용할 포트를 설정하게 된다.

spec.ports.targetPort: 은 selector 항목에서 정의한 라벨에 의해 접근 대상이 된 포드들이 내부적으로 사용하고 있는 포트를 입력한다. 즉, 포드 템플릿에 정의된 containerPort 와 같은 값으로 설정해야 한다.

 

ClusterIP 타입의 서비스 IP와 포트를 통해 파드에 접근을 할 수 있고 서비스와 연결된 여러 개의 포드에 자동으로 요청이 분산된다. 서비스를 생성할 때 별도의 설정을 하지 않아도 서비스는 연결된 파드에 대해 로드 밸런싱을 수행한다.

서비스에는 IP뿐만 아니라 서비스 이름 그 자체로도 접근할 수 있다. 쿠버네티스는 애플리케이션이 서비스나 파드를 쉽게 찾을 수 있도록 내부 DNS를 구동하고 있고 파드들은 자동으로 이 DNS를 사용하도록 설정되기 때문이다.

실제로 여러 파드가 클러스터 내부에서 서로를 찾아 연결해야 할 때는 서비스의 이름과 같은 도메인 이름을 사용하는 것이 일반적이다. 즉, 파드가 서로 상호 작용할 때는 파드의 IP를 알 필요 없고 파드와 연결된 서비스 이름을 사용함으로써 간단하게 파드에 접근할 수 있다.

 

💡 서비스의 라벨 셀렉터와 파드의 라벨이 매칭돼 연결되면 쿠버네티스는 자동으로 엔드포인트라고 부르는 오브젝트를 별도로 생성한다. 예를 들어, 서비스와 관련된 엔드포인트는 서비스와 동일한 이름으로 존재한다.

엔드 포인트라는 이름이 의미하는 것처럼 엔드포인트 오브젝트는 서비스가 가리키고 있는 도착점을 나타낸다. 서비스를 이용해 파드를 연결한다면 엔드포인트는 자동으로 생성되므로 엔드포인트를 지나치게 알 필요는 없지만, 엔드포인트 자체도 독립된 쿠버네티스의 리소스이기 때문에 이론상으로 서비스와 엔드포인트를 따로 따로 만들 수도 있다.

NodePort 타입의 서비스 - 서비스를 이용해 포드를 외부에 노출하기

NodePort 타입의 서비스는 클러스터 외부에서도 접근을 할 수 있다. NodePort 타입의 서비스는 모든 노드의 특정 포트를 개방해 서비스에 접근하는 방식이다. 도커에서 컨테이너를 외부로 노출하는 방식과 비슷하다고 생각하면 된다.

각 노드에서 개방되는 포트는 기본적으로 30000~32768 포트 주에 랜덤으로 선택되지만 YAML 파일에 nodePort 항목을 정의하면 원하는 포트를 선택할 수 있다.

NodePort 타입의 서비스는 ClusterIP의 기능을 포함하고 있다. NodePort 타입의 서비스는 내부 네트워크와 외부 네트워크 양쪽에서 접근을 할 수 있다.

💡 기본적으로 NodePort 가 사용할 수 있는 포트 범위는 30000~32768 이지만 API 서버 컴포넌트의 실행 옵션을 변경하면 원하는 포트 범위를 설정할 수 있다. 포트 범위를 직접 지정하려면 API 서버의 옵션을 다음과 같이 추가하거나 수정한다.

--service-node-port-range=30000-35000

너무 낮은 포트 번호는 시스템의 의해 예약된 포트일 수 있기 때문에 30000번 이상부터 사용하는 것이 좋다.

 

실제 운영 환경에서 NodePort로 서비스를 외부에 제공하는 경우는 많지 않다. NodePort에서 포트 번호를 80 이나 443으로 설정하기에는 적절하지 않으며, SSL 인증서 적용, 라우팅 등과 같은 복잡한 설정을 서비스에 적용하기가 어렵기 때문이다.

따라서 NodePort 의 경우는 이 자체를 통해 서비스를 외부로 제공하기보다는 인그레스(Ingress)라고 부르는 쿠버네티스의 오브젝트에서 간접적으로 사용되는 경우가 많다.

LoadBalancer 타입의 서비스 - 클라우드 플랫폼의 로드 밸런서와 연동

로드 밸런서 타입의 서비스는 서비스 생성과 동시에 로드 밸런서를 새롭게 생성해 포드와 연결한다. 로드 밸런서 타입의 서비스는 클라우드 플랫폼으로부터 도메인 이름과 IP를 할당받기 때문에 NodePort 보다 더욱 쉽게 파드에 접근할 수 있다.

 

💡 로드밸런서 타입의 서비스는 로드 밸런서를 동적으로 생성하는 기능을 제공하는 환경에서만 사용할 수 있다는 점을 알아야 한다. 일반적인 가상 머신이나, 온프레미스 환경에서는 사용하기 어려울 수 있지만 MetalLB 를 사용하여 온프레미스 환경에서도 돌릴 수 있기는 하다.

 

로드 밸런서 타입의 서비스 또한 NodePort나 ClusterIP와 동일하게 서비스의 IP(CLUSTER-IP)가 할당되며, 파드에서는 서비스의 IP 또는 서비스의 이름으로 서비스에 접근할 수 있다. 눈여겨 볼 부분은 EXTERNER-IP 항목이다. 이 주소는 클라우드 플랫폼인 AWS, GCP 등으로부터 자동으로 할당된 것이며, 이 주소와 서비스의 포트를 통해 포드에 접근할 수 있다.

다른 서비스 타입과 마찬가지로 요청이 여러 개의 파드로 분산되는 로드 밸런싱 기능을 자동으로 사용할 수 있다. 또한 각 노드에서 동일하게 접근할 수 있는 PORT(S) 가 부여되어 NodePort 의 간접적인 기능 또한 자동으로 사용할 수 있다.

만약 NLB나 ALB를 설정하고 싶다면 metadata.annotations 항목을 수정해주면 된다. 자세한 것은 AWS 공식 문서에 잘 나와 있다.

 

💡 쿠버네티스에서 annotations는 라벨처럼 해당 리소스의 추가적인 정보를 나타내기 위한 키-값 쌍으로 이뤄져 있다. 그렇지만 리소스의 종류에 따라 특정 용도로 사용할 수 있게 쿠버네티스에 미리 정의된 몇 가지 주석이 있다. 이 주석들은 리소스에 특별한 설정값을 부여하기 위해 사용된다. 미리 정의된 주석은 라벨과 함께 익숙해지는 것이 좋다.

LoadBalancer 타입의 서비스 - 온프레미스 환경에서 LoadBalancer 타입의 서비스 사용하기

로드 밸런서 타입의 서비스는 일반적으로 AWS와 같은 클라우드 플랫폼에서 사용되지만, 필요하다면 직접 보유하고 있는 온프레미스 환경에서도 MetalLB 나 오픈 스택과 같은 특수한 환경을 직접 구축하여 사용할 수 있다.

그 중에서도 MetalLB 라는 서드파티 제품을 사용하면 로드 밸런서 타입의 서비스를 사용할 수 있다.

요청을 외부로 리다이렉트하는 서비스: ExternalName

쿠버네티스를 외부 시스템과 연동해야 할 때는 ExternalName 타입의 서비스를 사용할 수도 있다.

ExternalName 타입을 사용해 서비스를 생성하면 서비스가 외부 도메인을 가리키도록 설정할 수 있다. 예를 들어 쿠버네티스 내부의 파드들이 externalname-svc 라는 이름으로 요청을 보낼 경우, 쿠버네티스의 DNS 는 my.database.com으로 접근할 수 있도록 CNAME 레코드를 반환한다. 즉, externalname-svc로 요청을 보내면 my.database.com에 접근하게 된다.

ExternalName 타입의 서비스는 쿠버네티스와 별개로 존재하는 레거시 시스템에 연동해야 하는 상황에 유용하게 사용할 수 있다.

728x90