서비스

이 페이지에서는 Kubernetes 서비스를 설명하고 Google Kubernetes Engine에서의 사용 방법을 보여줍니다. 서비스를 만드는 방법을 알아보려면 서비스를 사용하여 애플리케이션 노출을 참조하세요.

서비스란 무엇인가요?

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

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

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

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

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

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

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

서비스 유형

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

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

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

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

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

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

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를 사용합니다.

일부 클러스터 구성에서는 Google Cloud HTTP(S) 부하 분산기NodePort 유형의 서비스를 사용합니다. 자세한 내용은 Ingress로 HTTP 부하 분산 설정을 참조하세요.

HTTP(S) 부하 분산기는 프록시 서버이며, 이 항목의 LoadBalancer 유형의 서비스에서 설명하는 네트워크 부하 분산기와 근본적으로 다릅니다.

LoadBalancer 유형의 서비스

LoadBalancer 유형의 서비스를 만들면 Google Cloud 컨트롤러가 작동하여 프로젝트에서 네트워크 부하 분산기를 구성합니다. 부하 분산기에는 프로젝트 외부에서 액세스할 수 있는 안정적인 IP 주소가 포함됩니다.

네트워크 부하 분산기는 프록시 서버가 아닙니다. 네트워크 부하 분산기는 변경 없이 소스 및 대상 IP 주소로 패킷을 전달합니다.

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

apiVersion: v1
kind: Service
metadata:
  name: my-nlb-service
spec:
  selector:
    app: metrics
    department: engineering
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080

서비스를 만든 후에는 kubectl get service -o yaml을 사용해서 해당 사양을 보고 안정적인 외부 IP 주소를 확인할 수 있습니다.

spec:
  clusterIP: 10.11.242.115
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 32676
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: metrics
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
  status:
    loadBalancer:
      ingress:
      - ip: 203.0.113.100

출력에서 네트워크 부하 분산기의 IP 주소는 loadBalancer:ingress: 아래에 표시됩니다. 외부 클라이언트는 부하 분산기의 IP 주소 및 port로 지정된 TCP 포트를 사용하여 서비스를 호출합니다. 요청은 targetPort로 지정된 TCP 포트에서 구성원 포드 중 하나로 전달됩니다. 이전 예와 같이, 클라이언트가 TCP 포트 80으로 203.0.113.100에서 서비스를 호출합니다. 요청은 TCP 포트 8080에서 구성원 포드 중 하나로 전달됩니다. 구성원 포드에는 TCP 포트 8080에서 수신 대기하는 컨테이너가 있어야 합니다.

LoadBalancer 서비스 유형은 NodePort 유형의 확장이고, 이 유형은 ClusterIP 유형의 확장입니다.

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 이름으로의 매핑입니다.

서비스 추상화

서비스는 일부 네트워크 인터페이스에서 수신 대기하는 프로세스가 아니라는 점에서 추상화입니다. 추상화의 일부는 클러스터 노드의 iptables 규칙에서 구현됩니다. 서비스 유형에 따라 추상화의 다른 부분은 네트워크 부하 분산 또는 HTTP(S) 부하 분산에 의해 구현됩니다.

임의 서비스 포트

서비스 매니페스트에서 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의 이름이 고유해야 합니다.

2개의 ServicePort 객체가 포함된 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는 엔드포인트 객체를 사용해서 서비스의 구성원인 포드를 추적합니다.

다음 단계

이 페이지가 도움이 되었나요? 평가를 부탁드립니다.

다음에 대한 의견 보내기...

Kubernetes Engine