이 페이지에서는 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
서비스 유형의 확장입니다. 따라서 내부 클라이언트는 다음 두 가지 방법으로 서비스를 호출할 수 있습니다.
clusterIP
와port
를 사용합니다.- 노드의 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
유형의 이중 스택 서비스를 지원합니다.
이러한 서비스 유형마다 ipFamilies
및 ipFamilyPolicy
필드를 IPv4, IPv6 또는 이중 스택 서비스로 정의할 수 있습니다.
다음 단계
- Kubernetes 서비스 자세히 알아보기
- 서비스를 사용하여 애플리케이션 노출
- StatefulSets 자세히 알아보기
- 인그레스 자세히 알아보기