서비스


이 페이지에서는 Kubernetes 서비스를 설명하고 Google Kubernetes Engine(GKE)에서의 사용 방법을 보여줍니다. 포드 엔드포인트 집합을 단일 리소스로 그룹화하는 데 사용할 수 있는 여러 유형의 서비스가 있습니다. 서비스를 만드는 방법을 알아보려면 서비스를 사용하여 애플리케이션 노출을 참조하세요.

Kubernetes 서비스란 무엇인가요?

서비스의 개념은 일련의 포드 엔드포인트를 단일 리소스로 그룹화하는 것입니다. 그룹화는 여러 방법으로 구성할 수 있습니다. 기본적으로는 클러스터 내부의 클라이언트가 서비스에서 포드에 연락하기 위해 사용할 수 있는 안정적인 클러스터 IP 주소를 사용합니다. 클라이언트는 안정적인 IP 주소로 요청을 전송하고, 요청이 서비스에 있는 포드 중 하나로 라우팅됩니다.

서비스는 선택기를 사용해서 해당 구성원 포드를 식별합니다. 포드가 서비스 구성원이 되기 위해서는 선택기에 지정된 모든 라벨이 포드에 포함되어야 합니다. 라벨은 객체에 연결된 임의의 키/값 쌍입니다.

다음 서비스 매니페스트에는 2개의 라벨을 지정하는 선택기가 포함되어 있습니다. selector 필드는 app: metrics 라벨 및 department:engineering 라벨을 모두 포함하는 모든 포드를 이 서비스의 구성원으로 지정합니다.

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: metrics
    department: engineering
  ports:
  ...

Kubernetes 서비스를 사용하는 이유는 무엇인가요?

Kubernetes 클러스터에서 각 포드에는 내부 IP 주소가 포함됩니다. 하지만 배포에 포드가 들어오고 나가면서 해당 IP 주소가 변경됩니다. 따라서 포드 IP 주소를 직접 사용하는 것은 적합하지 않습니다. 서비스를 사용하면 구성원 포드의 IP 주소가 변경되더라도 서비스 수명 동안 지속되는 안정적인 IP 주소를 얻을 수 있습니다.

서비스는 또한 부하 분산을 제공합니다. 클라이언트가 단일한 안정적인 IP 주소를 호출하고, 해당 요청이 서비스의 구성원인 포드 간에 분산됩니다.

Kubernetes 서비스 유형

서비스의 5가지 유형은 다음과 같습니다.

  • ClusterIP(기본값): 내부 클라이언트가 안정적인 내부 IP 주소로 요청을 전송합니다.

  • NodePort: 서비스에 의해 지정되는 하나 이상의 nodePort 값에서 클라이언트가 노드의 IP 주소로 요청을 전송합니다.

  • LoadBalancer: 클라이언트가 네트워크 부하 분산기의 IP 주소로 요청을 전송합니다.

  • ExternalName: 내부 클라이언트가 서비스의 DNS 이름을 외부 DNS 이름의 별칭으로 사용합니다.

  • Headless: 포드를 그룹화하려고 하지만 안정적인 IP 주소가 필요하지 않은 경우에 Headless 서비스를 사용할 수 있습니다.

NodePort 유형은 ClusterIP 유형의 확장입니다. 따라서 NodePort 유형의 서비스에 클러스터 IP 주소가 포함됩니다.

LoadBalancer 유형은 NodePort 유형의 확장입니다. 따라서 LoadBalancer 유형의 서비스에 클러스터 IP 주소 및 하나 이상의 nodePort 값이 포함됩니다.

ClusterIP 유형의 서비스

ClusterIP 유형의 서비스를 만들면 Kubernetes가 클러스터의 노드에서 액세스할 수 있는 안정적인 IP 주소를 만듭니다.

ClusterIP 유형 서비스의 매니페스트는 다음과 같습니다.

apiVersion: v1
kind: Service
metadata:
  name: my-cip-service
spec:
  selector:
    app: metrics
    department: sales
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

kubectl apply -f [MANIFEST_FILE]을 사용하여 서비스를 생성할 수 있습니다. 서비스를 만든 후에는 kubectl get service를 사용하여 안정적인 IP 주소를 확인할 수 있습니다.

NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)
my-cip-service   ClusterIP   10.11.247.213   none          80/TCP

클러스터에 있는 클라이언트는 서비스 매니페스트의 port 필드에 지정된 클러스터 IP 주소 및 TCP 포트를 사용하여 서비스를 호출합니다. 요청은 targetPort 필드에 지정된 TCP 포트의 구성원 포드 중 하나로 전달됩니다. 이전 예시에서 클라이언트가 TCP 포트 80으로 10.11.247.213에서 서비스를 호출합니다. 요청은 TCP 포트 8080에서 구성원 포드 중 하나로 전달됩니다. 구성원 포드에는 TCP 포트 8080에서 리슨하는 컨테이너가 있어야 합니다. 포트 8080에서 수신 대기하는 컨테이너가 없으면 '연결 실패' 또는 '이 사이트에 연결할 수 없습니다'와 같은 메시지가 클라이언트에 표시됩니다.

NodePort 유형의 서비스

NodePort 유형의 서비스를 만들면 Kubernetes가 nodePort 값을 제공합니다. 그런 후 nodePort 값과 함께 노드의 IP 주소를 사용해서 서비스에 액세스할 수 있습니다.

NodePort 유형 서비스의 매니페스트는 다음과 같습니다.

apiVersion: v1
kind: Service
metadata:
  name: my-np-service
spec:
  selector:
    app: products
    department: sales
  type: NodePort
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

서비스를 만든 후에는 kubectl get service -o yaml을 사용해서 해당 사양을 보고 nodePort 값을 확인할 수 있습니다.

spec:
  clusterIP: 10.11.254.114
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 32675
    port: 80
    protocol: TCP
    targetPort: 8080

외부 클라이언트는 nodePort로 지정된 TCP 포트와 함께 노드의 외부 IP 주소를 사용하여 서비스를 호출합니다. 요청은 targetPort 필드로 지정된 TCP 포트에서 구성원 포드 중 하나로 전달됩니다.

예를 들어 클러스터 노드 중 하나의 외부 IP 주소가 203.0.113.2라고 가정해보세요. 이전 예에서는 외부 클라이언트가 TCP 포트 32675로 203.0.113.2에서 서비스를 호출합니다. 요청은 TCP 포트 8080에서 구성원 포드 중 하나로 전달됩니다. 구성원 포드에는 TCP 포트 8080에서 수신 대기하는 컨테이너가 있어야 합니다.

NodePort 서비스 유형은 ClusterIP 서비스 유형의 확장입니다. 따라서 내부 클라이언트는 다음 두 가지 방법으로 서비스를 호출할 수 있습니다.

  • clusterIPport를 사용합니다.
  • 노드의 IP 주소와 nodePort를 사용합니다.

일부 클러스터 구성에서는 외부 애플리케이션 부하 분산기NodePort 유형의 서비스를 사용합니다.

외부 애플리케이션 부하 분산기는 프록시 서버이며 이 주제의 LoadBalancer 유형의 서비스에서 설명하는 외부 패스 스루 네트워크 부하 분산기와 근본적으로 다릅니다.

LoadBalancer 유형의 서비스

LoadBalancer 유형의 서비스에 대한 자세한 내용은 LoadBalancer 서비스 개념을 참조하세요.

ExternalName 유형의 서비스

ExternalName 유형의 서비스는 외부 DNS 이름에 대한 내부 별칭을 제공합니다. 내부 클라이언트는 내부 DNS 이름을 사용하여 요청을 수행하고, 요청이 외부 이름으로 리디렉션됩니다.

ExternalName 유형 서비스의 매니페스트는 다음과 같습니다.

apiVersion: v1
kind: Service
metadata:
  name: my-xn-service
spec:
  type: ExternalName
  externalName: example.com

서비스를 만들면 Kubernetes가 서비스 호출을 위해 내부 클라이언트가 사용할 수 있는 DNS 이름을 만듭니다. 이전 예에서 DNS 이름은 my-xn-service.default.svc.cluster.local입니다. 내부 클라이언트가 my-xn-service.default.svc.cluster.local에 요청을 전송하면 요청이 example.com으로 리디렉션됩니다.

ExternalName 서비스 유형은 기본적으로 다른 서비스 유형과 다릅니다. 실제로 ExternalName 유형의 서비스는 이 항목의 시작 부분에 제공된 서비스 정의에 부합되지 않습니다. ExternalName 유형의 서비스는 포드 집합과 연결되지 않으며 안정적인 IP 주소를 갖지 않습니다. 대신 ExternalName 유형의 서비스는 내부 DNS 이름에서 외부 DNS 이름으로의 매핑입니다.

헤드리스 서비스

헤드리스 서비스는 클러스터 IP 주소를 할당하지 않는 Kubernetes 서비스 유형입니다. 대신 헤드리스 서비스는 DNS를 사용하여 서비스와 연결된 포드의 IP 주소를 노출합니다. 이렇게 하면 프록시를 통하지 않고 포드에 직접 연결할 수 있습니다.

헤드리스 서비스는 다음과 같은 다양한 시나리오에 유용합니다.

  • 포드 간 부하 분산: 헤드리스 서비스를 사용하여 포드 간에 부하를 분산할 수 있습니다. 이를 구현하려면 부하 분산할 포드와 일치하는 선택기로 서비스를 만듭니다. 그런 다음 선택기와 일치하는 모든 포드에 트래픽을 고르게 분산합니다.

  • 서비스 검색: 헤드리스 서비스를 사용하여 서비스 검색을 구현할 수 있습니다. 이를 구현하려면 이름과 선택기를 포함한 서비스를 만듭니다. 헤드리스 서비스의 DNS 레코드에는 선택기와 일치하는 서비스 뒤의 모든 포드 IP가 포함됩니다. 클라이언트는 이러한 DNS 레코드를 사용하여 서비스와 연결된 포드의 IP 주소를 찾을 수 있습니다.

  • 직접 포드 액세스: 클라이언트는 헤드리스 서비스와 연결된 포드에 직접 연결할 수 있습니다. 이는 부하 분산기 및 DNS 서버와 같이 기본 포드에 직접 액세스해야 하는 서비스에 유용합니다.

  • 유연성: 헤드리스 서비스를 사용하여 부하 분산기, DNS 서버, 분산 데이터베이스와 같은 다양한 토폴로지를 만들 수 있습니다.

선택기가 있는 헤드리스 서비스를 사용하여 해결할 수 없는 워크로드에 대한 특수한 네트워크 요구사항이 있는 경우 선택기 없이 헤드리스 서비스를 사용할 수도 있습니다. 헤드리스 서비스는 Kubernetes 클러스터 자체 내에 없는 서비스에 액세스하는 데 유용한 도구입니다. 컨트롤 플레인은 EndpointSlice 객체를 생성하지 않으므로 선택기 없는 서비스에서 이에 대해 자세히 알아보세요.

다음 예시는 헤드리스 서비스의 매니페스트입니다.

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  clusterIP: None
  selector:
    app: nginx
  ports:
  - name: http
    port: 80
    targetPort: 80

헤드리스 서비스를 만들면 DNS를 쿼리하여 서비스와 연결된 포드의 IP 주소를 찾을 수 있습니다. 예를 들어 다음 명령어는 nginx 서비스와 연결된 포드의 IP 주소를 나열합니다.

dig +short nginx.default.svc.cluster.local

Kubernetes 쿼리 확장을 사용하는 또 다른 예시는 다음과 같습니다.

dig +short +search nginx

단일 명령어로 헤드리스 서비스를 만들 수 있으며 헤드리스 서비스는 쉽게 업데이트하고 확장할 수 있습니다.

kubectl create service clusterip my-svc --clusterip="None" --dry-run=client -o yaml > [file.yaml]

서비스 추상화

서비스는 일부 네트워크 인터페이스에서 리슨하는 프로세스가 아니라는 점에서 추상화입니다. 추상화의 일부는 클러스터 노드의 iptables 규칙에서 구현됩니다. 서비스 유형에 따라 추상화의 다른 부분은 외부 패스 스루 네트워크 부하 분산기 또는 외부 애플리케이션 부하 분산기에 의해 구현됩니다.

임의 서비스 포트

서비스 매니페스트에서 port 필드의 값은 임의적입니다. 하지만 targetPort의 값은 임의적이지 않습니다. 각 구성원 포드에는 targetPort에서 수신 대기하는 컨테이너가 있어야 합니다.

port 값 50000을 포함하는 LoadBalancer 유형의 서비스는 다음과 같습니다.

apiVersion: v1
kind: Service
metadata:
  name: my-ap-service
spec:
  clusterIP: 10.11.241.93
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30641
    port: 50000
    protocol: TCP
    targetPort: 8080
  selector:
    app: parts
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.200

클라이언트는 TCP 포트 50000으로 203.0.113.200에서 서비스를 호출합니다. 요청은 TCP 포트 8080에서 구성원 포드 중 하나로 전달됩니다.

다중 포트

서비스의 ports 필드는 ServicePort 객체의 배열입니다. ServicePort 객체에는 다음 필드가 있습니다.

  • name
  • protocol
  • port
  • targetPort
  • nodePort

ServicePort가 두 개 이상 있으면 각 ServicePort의 이름은 고유해야 합니다.

ServicePort 객체 2개가 포함된 LoadBalancer 유형의 서비스는 다음과 같습니다.

apiVersion: v1
kind: Service
metadata:
  name: my-tp-service
spec:
  clusterIP: 10.11.242.196
  externalTrafficPolicy: Cluster
  ports:
  - name: my-first-service-port
    nodePort: 31233
    port: 60000
    protocol: TCP
    targetPort: 50000
  - name: my-second-service-port
    nodePort: 31081
    port: 60001
    protocol: TCP
    targetPort: 8080
  selector:
    app: tests
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.201

이전 예시에서 클라이언트가 TCP 포트 60000으로 203.0.113.201에서 서비스를 호출하면 요청이 TCP 포트 50000의 구성원 포드로 전달됩니다. 하지만 클라이언트가 TCP 포트 60001로 203.0.113.201에서 서비스를 호출하면 요청이 TCP 포트 8080의 구성원 포드로 전달됩니다.

각 구성원 포드에는 TCP 포트 50000으로 수신 대기하는 컨테이너와 TCP 포트 8080으로 수신 대기하는 컨테이너가 있어야 합니다. 2개의 스레드가 포함된 단일 컨테이너 또는 동일 포드에서 실행되는 2개의 컨테이너일 수 있습니다.

서비스 엔드포인트

서비스를 만들면 Kubernetes가 서비스와 같은 이름의 엔드포인트 객체를 만듭니다. Kubernetes는 엔드포인트 객체를 사용해서 서비스의 구성원인 포드를 추적합니다.

단일 스택 및 이중 스택 서비스

ClusterIP 또는 NodePort 유형의 IPv6 서비스를 만들 수 있습니다. GKE는 SLA 또는 기술 지원을 제공하지 않는 미리보기 중에 LoadBalancer 유형의 이중 스택 서비스를 지원합니다.

이러한 서비스 유형마다 ipFamiliesipFamilyPolicy 필드를 IPv4, IPv6 또는 이중 스택 서비스로 정의할 수 있습니다.

다음 단계