서비스
쿠버네티스를 사용하면 익숙하지 않은 서비스 디스커버리 메커니즘을 사용하기 위해 애플리케이션을 수정할 필요가 없다. 쿠버네티스는 파드에게 고유한 IP 주소와 파드 집합에 대한 단일 DNS 명을 부여하고, 그것들 간에 로드-밸런스를 수행할 수 있다.
동기
쿠버네티스 파드는 클러스터 목표 상태(desired state)와 일치하도록 생성되고 삭제된다. 파드는 비영구적 리소스이다. 만약 앱을 실행하기 위해 디플로이먼트를 사용한다면, 동적으로 파드를 생성하고 제거할 수 있다.
각 파드는 고유한 IP 주소를 갖지만, 디플로이먼트에서는 한 시점에 실행되는 파드 집합이 잠시 후 실행되는 해당 파드 집합과 다를 수 있다.
이는 다음과 같은 문제를 야기한다. ("백엔드"라 불리는) 일부 파드 집합이 클러스터의 ("프론트엔드"라 불리는) 다른 파드에 기능을 제공하는 경우, 프론트엔드가 워크로드의 백엔드를 사용하기 위해, 프론트엔드가 어떻게 연결할 IP 주소를 찾아서 추적할 수 있는가?
서비스 로 들어가보자.
서비스 리소스
쿠버네티스에서 서비스는 파드의 논리적 집합과 그것들에 접근할 수 있는 정책을 정의하는 추상적 개념이다. (때로는 이 패턴을 마이크로-서비스라고 한다.) 서비스가 대상으로 하는 파드 집합은 일반적으로 셀렉터가 결정한다. 서비스 엔드포인트를 정의하는 다른 방법에 대한 자세한 내용은 셀렉터가 없는 서비스를 참고한다.
예를 들어, 3개의 레플리카로 실행되는 스테이트리스 이미지-처리 백엔드를 생각해보자. 이러한 레플리카는 대체 가능하다. 즉, 프론트엔드는 그것들이 사용하는 백엔드를 신경쓰지 않는다. 백엔드 세트를 구성하는 실제 파드는 변경될 수 있지만, 프론트엔드 클라이언트는 이를 인식할 필요가 없으며, 백엔드 세트 자체를 추적해야 할 필요도 없다.
서비스 추상화는 이러한 디커플링을 가능하게 한다.
클라우드-네이티브 서비스 디스커버리
애플리케이션에서 서비스 디스커버리를 위해 쿠버네티스 API를 사용할 수 있는 경우, 매치되는 엔드포인트슬라이스를 API 서버에 질의할 수 있다. 쿠버네티스는 서비스의 파드가 변경될 때마다 서비스의 엔드포인트슬라이스를 업데이트한다.
네이티브 애플리케이션이 아닌 (non-native applications) 경우, 쿠버네티스는 애플리케이션과 백엔드 파드 사이에 네트워크 포트 또는 로드 밸런서를 배치할 수 있는 방법을 제공한다.
서비스 정의
쿠버네티스의 서비스는 파드와 비슷한 REST 오브젝트이다. 모든 REST 오브젝트와
마찬가지로, 서비스 정의를 API 서버에 POST
하여
새 인스턴스를 생성할 수 있다.
서비스 오브젝트의 이름은 유효한
RFC 1035 레이블 이름이어야 한다.
예를 들어, 각각 TCP 포트 9376에서 수신하고
app.kubernetes.io/name=MyApp
레이블을 가지고 있는 파드 세트가 있다고 가정해 보자.
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
이 명세는 "my-service"라는 새로운 서비스 오브젝트를 생성하고,
app.kubernetes.io/name=MyApp
레이블을 가진 파드의 TCP 9376 포트를 대상으로 한다.
쿠버네티스는 이 서비스에 서비스 프록시가 사용하는 IP 주소 ("cluster IP"라고도 함) 를 할당한다. (이하 가상 IP와 서비스 프록시 참고)
서비스 셀렉터의 컨트롤러는 셀렉터와 일치하는 파드를 지속적으로 검색하고, "my-service"라는 엔드포인트 오브젝트에 대한 모든 업데이트를 POST한다.
참고:
서비스는 모든 수신port
를 targetPort
에 매핑할 수 있다. 기본적으로 그리고
편의상, targetPort
는 port
필드와 같은 값으로 설정된다.파드의 포트 정의에 이름이 있으므로,
서비스의 targetPort
속성에서 이 이름을 참조할 수 있다.
예를 들어, 다음과 같은 방법으로 서비스의 targetPort
를 파드 포트에 바인딩할 수 있다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app.kubernetes.io/name: proxy
spec:
containers:
- name: nginx
image: nginx:stable
ports:
- containerPort: 80
name: http-web-svc
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app.kubernetes.io/name: proxy
ports:
- name: name-of-service-port
protocol: TCP
port: 80
targetPort: http-web-svc
이것은 서로 다른 포트 번호를 통해 가용한 동일 네트워크 프로토콜이 있고, 단일 구성 이름을 사용하는 서비스 내에 혼합된 파드가 존재해도 가능하다. 이를 통해 서비스를 배포하고 진전시키는 데 많은 유연성을 제공한다. 예를 들어, 클라이언트를 망가뜨리지 않고, 백엔드 소프트웨어의 다음 버전에서 파드가 노출시키는 포트 번호를 변경할 수 있다.
서비스의 기본 프로토콜은 TCP이다. 다른 지원되는 프로토콜을 사용할 수도 있다.
많은 서비스가 하나 이상의 포트를 노출해야 하기 때문에, 쿠버네티스는 서비스 오브젝트에서 다중
포트 정의를 지원한다.
각 포트는 동일한 프로토콜
또는 다른 프로토콜로 정의될 수 있다.
셀렉터가 없는 서비스
서비스는 일반적으로 셀렉터를 이용하여 쿠버네티스 파드에 대한 접근을 추상화하지만, 셀렉터 대신 매칭되는(corresponding) 엔드포인트슬라이스 오브젝트와 함께 사용되면 다른 종류의 백엔드도 추상화할 수 있으며, 여기에는 클러스터 외부에서 실행되는 것도 포함된다.
예시는 다음과 같다.
- 프로덕션 환경에서는 외부 데이터베이스 클러스터를 사용하려고 하지만, 테스트 환경에서는 자체 데이터베이스를 사용한다.
- 한 서비스에서 다른 네임스페이스 또는 다른 클러스터의 서비스를 지정하려고 한다.
- 워크로드를 쿠버네티스로 마이그레이션하고 있다. 해당 방식을 평가하는 동안, 쿠버네티스에서는 백엔드의 일부만 실행한다.
이러한 시나리오에서는 파드 셀렉터 없이 서비스를 정의 할 수 있다. 예를 들면
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
이 서비스에는 셀렉터가 없으므로, 매칭되는 엔드포인트슬라이스 (및 레거시 엔드포인트) 오브젝트가 자동으로 생성되지 않는다. 엔드포인트슬라이스 오브젝트를 수동으로 추가하여, 서비스를 실행 중인 네트워크 주소 및 포트에 서비스를 수동으로 매핑할 수 있다. 예시는 다음과 같다.
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: my-service-1 # 관행적으로, 서비스의 이름을
# 엔드포인트슬라이스 이름의 접두어로 사용한다.
labels:
# "kubernetes.io/service-name" 레이블을 설정해야 한다.
# 이 레이블의 값은 서비스의 이름과 일치하도록 지정한다.
kubernetes.io/service-name: my-service
addressType: IPv4
ports:
- name: '' # 9376 포트는 (IANA에 의해) 잘 알려진 포트로 할당되어 있지 않으므로
# 이 칸은 비워 둔다.
appProtocol: http
protocol: TCP
port: 9376
endpoints:
- addresses:
- "10.4.5.6" # 이 목록에 IP 주소를 기재할 때 순서는 상관하지 않는다.
- "10.1.2.3"
커스텀 엔드포인트슬라이스
서비스를 위한 엔드포인트슬라이스 오브젝트를 생성할 때,
엔드포인트슬라이스 이름으로는 원하는 어떤 이름도 사용할 수 있다.
네임스페이스 내의 각 엔드포인트슬라이스 이름은 고유해야 한다.
해당 엔드포인트슬라이스에 kubernetes.io/service-name
레이블을 설정하여
엔드포인트슬라이스를 서비스와 연결할 수 있다.
참고:
엔드포인트 IP는 루프백(loopback) (IPv4의 경우 127.0.0.0/8, IPv6의 경우 ::1/128), 또는 링크-로컬 (IPv4의 경우 169.254.0.0/16와 224.0.0.0/24, IPv6의 경우 fe80::/64)이 되어서는 안된다.
엔드포인트 IP 주소는 다른 쿠버네티스 서비스의 클러스터 IP일 수 없는데, kube-proxy는 가상 IP를 목적지(destination)로 지원하지 않기 때문이다.
직접 생성했거나 직접 작성한 코드에 의해 생성된 엔드포인트슬라이스를 위해,
endpointslice.kubernetes.io/managed-by
레이블에 사용할 값을 골라야 한다.
엔드포인트슬라이스를 관리하는 컨트롤러 코드를 직접 작성하는 경우,
"my-domain.example/name-of-controller"
와 같은 값을 사용할 수 있다.
써드파티 도구를 사용하는 경우, 도구의 이름에서 대문자는 모두 소문자로 바꾸고
공백 및 다른 문장 부호는 하이픈(-
)으로 대체한 문자열을 사용한다.
kubectl
과 같은 도구를 사용하여 직접 엔드포인트슬라이스를 관리하는 경우,
"staff"
또는 "cluster-admins"
와 같이 이러한 수동 관리를 명시하는 이름을 사용한다.
쿠버네티스 자체 컨트롤 플레인이 관리하는 엔드포인트슬라이스를 가리키는
"controller"
라는 예약된 값은 사용하지 말아야 한다.
셀렉터가 없는 서비스에 접근하기
셀렉터가 없는 서비스에 접근하는 것은 셀렉터가 있는 서비스에 접근하는 것과 동일하게 동작한다. 셀렉터가 없는 서비스 예시에서, 트래픽은 엔드포인트슬라이스 매니페스트에 정의된 두 엔드포인트 중 하나로 라우트된다(10.1.2.3:9376 또는 10.4.5.6:9376으로의 TCP 연결).
ExternalName 서비스는 셀렉터가 없고 대신 DNS 이름을 사용하는 특이 케이스 서비스이다. 자세한 내용은 이 문서 뒷부분의 ExternalName 섹션을 참조한다.
엔드포인트슬라이스
Kubernetes v1.21 [stable]
엔드포인트슬라이스는 특정 서비스의 하위(backing) 네트워크 엔드포인트 부분집합(슬라이스)을 나타내는 오브젝트이다.
쿠버네티스 클러스터는 각 엔드포인트슬라이스가 얼마나 많은 엔드포인트를 나타내는지를 추적한다. 한 서비스의 엔드포인트가 너무 많아 역치에 도달하면, 쿠버네티스는 빈 엔드포인트슬라이스를 생성하고 여기에 새로운 엔드포인트 정보를 저장한다. 기본적으로, 쿠버네티스는 기존의 모든 엔드포인트슬라이스가 엔드포인트를 최소 100개 이상 갖게 되면 새 엔드포인트슬라이스를 생성한다. 쿠버네티스는 새 엔드포인트가 추가되어야 하는 상황이 아니라면 새 엔드포인트슬라이스를 생성하지 않는다.
이 API에 대한 더 많은 정보는 엔드포인트슬라이스를 참고한다.
엔드포인트
쿠버네티스 API에서, 엔드포인트(Endpoints)(리소스 명칭이 복수형임)는 네트워크 엔드포인트의 목록을 정의하며, 일반적으로 트래픽이 어떤 파드에 보내질 수 있는지를 정의하기 위해 서비스가 참조한다.
엔드포인트 대신 엔드포인트슬라이스 API를 사용하는 것을 권장한다.
용량 한계를 넘어선 엔드포인트
쿠버네티스는 단일 엔드포인트(Endpoints) 오브젝트에 포함될 수 있는 엔드포인트(endpoints)의 수를 제한한다. 단일 서비스에 1000개 이상의 하위(backing) 엔드포인트가 있으면, 쿠버네티스는 엔드포인트 오브젝트의 데이터를 덜어낸다(truncate). 서비스는 하나 이상의 엔드포인트슬라이스와 연결될 수 있기 때문에, 하위 엔드포인트 1000개 제한은 기존(legacy) 엔드포인트 API에만 적용된다.
이러한 경우, 쿠버네티스는 엔드포인트(Endpoints) 오브젝트에 저장될 수 있는
백엔드 엔드포인트(endpoints)를 최대 1000개 선정하고,
엔드포인트 오브젝트에 endpoints.kubernetes.io/over-capacity: truncated
어노테이션을 설정한다.
컨트롤 플레인은 또한 백엔드 파드 수가 1000 미만으로 내려가면
해당 어노테이션을 제거한다.
트래픽은 여전히 백엔드로 전송되지만, 기존(legacy) 엔드포인트 API에 의존하는 모든 로드 밸런싱 메커니즘은 사용 가능한 하위(backing) 엔드포인트 중에서 최대 1000개까지에만 트래픽을 전송한다.
동일한 API 상한은 곧 하나의 엔드포인트(Endpoints) 객체가 1000개 이상의 엔드포인트(endpoints)를 갖도록 수동으로 업데이트할 수는 없음을 의미한다.
애플리케이션 프로토콜
Kubernetes v1.20 [stable]
appProtocol
필드는 각 서비스 포트에 대한 애플리케이션 프로토콜을 지정하는 방법을 제공한다.
이 필드의 값은 상응하는 엔드포인트와 엔드포인트슬라이스
오브젝트에 의해 미러링된다.
이 필드는 표준 쿠버네티스 레이블 구문을 따른다. 값은
IANA 표준 서비스 이름 또는
mycompany.com/my-custom-protocol
과 같은 도메인 접두사 이름 중 하나여야 한다.
멀티-포트 서비스
일부 서비스의 경우, 둘 이상의 포트를 노출해야 한다. 쿠버네티스는 서비스 오브젝트에서 멀티 포트 정의를 구성할 수 있도록 지원한다. 서비스에 멀티 포트를 사용하는 경우, 모든 포트 이름을 명확하게 지정해야 한다. 예를 들면 다음과 같다.
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
- name: https
protocol: TCP
port: 443
targetPort: 9377
참고:
쿠버네티스의 일반적인 이름과 마찬가지로, 포트 이름은
소문자 영숫자와 -
만 포함해야 한다. 포트 이름은
영숫자로 시작하고 끝나야 한다.
예를 들어, 123-abc
와 web
은 유효하지만, 123_abc
와 -web
은 유효하지 않다.
자신의 IP 주소 선택
서비스
생성 요청시 고유한 클러스터 IP 주소를 지정할 수
있다. 이를 위해, .spec.clusterIP
필드를 설정한다. 예를 들어,
재사용하려는 기존 DNS 항목이 있거나, 특정 IP 주소로 구성되어
재구성이 어려운 레거시 시스템인 경우이다.
선택한 IP 주소는 API 서버에 대해 구성된 service-cluster-ip-range
CIDR 범위 내의 유효한 IPv4 또는 IPv6 주소여야 한다.
유효하지 않은 clusterIP 주소 값으로 서비스를 생성하려고 하면, API 서버는
422 HTTP 상태 코드를 리턴하여 문제점이 있음을 알린다.
서비스 디스커버리하기
쿠버네티스는 서비스를 찾는 두 가지 기본 모드를 지원한다. - 환경 변수와 DNS
환경 변수
파드가 노드에서 실행될 때, kubelet은 각 활성화된 서비스에 대해 환경 변수 세트를 추가한다.
{SVCNAME}_SERVICE_HOST
및 {SVCNAME}_SERVICE_PORT
환경 변수가 추가되는데,
이 때 서비스 이름은 대문자로, 하이픈(-
)은 언더스코어(_
)로 변환하여 사용한다.
또한 도커 엔진의 "레거시 컨테이너 연결" 기능과
호환되는 변수(makeLinkVariables 참조)도
지원한다.
예를 들어, TCP 포트 6379를 개방하고
클러스터 IP 주소 10.0.0.11이 할당된 서비스 redis-primary
는,
다음 환경 변수를 생성한다.
REDIS_PRIMARY_SERVICE_HOST=10.0.0.11
REDIS_PRIMARY_SERVICE_PORT=6379
REDIS_PRIMARY_PORT=tcp://10.0.0.11:6379
REDIS_PRIMARY_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_PRIMARY_PORT_6379_TCP_PROTO=tcp
REDIS_PRIMARY_PORT_6379_TCP_PORT=6379
REDIS_PRIMARY_PORT_6379_TCP_ADDR=10.0.0.11
참고:
서비스에 접근이 필요한 파드가 있고, 환경 변수를 사용해 포트 및 클러스터 IP를 클라이언트 파드에 부여하는 경우, 클라이언트 파드가 생성되기 전에 서비스를 만들어야 한다. 그렇지 않으면, 해당 클라이언트 파드는 환경 변수를 생성할 수 없다.
DNS 만 사용하여 서비스의 클러스터 IP를 검색하는 경우, 이 순서 이슈에 대해 신경 쓸 필요가 없다.
DNS
애드-온을 사용하여 쿠버네티스 클러스터의 DNS 서비스를 설정할 수(대개는 필수적임) 있다.
CoreDNS와 같은, 클러스터-인식 DNS 서버는 새로운 서비스를 위해 쿠버네티스 API를 감시하고 각각에 대한 DNS 레코드 세트를 생성한다. 클러스터 전체에서 DNS가 활성화된 경우 모든 파드는 DNS 이름으로 서비스를 자동으로 확인할 수 있어야 한다.
예를 들면, 쿠버네티스 네임스페이스 my-ns
에 my-service
라는
서비스가 있는 경우, 컨트롤 플레인과 DNS 서비스가 함께 작동하여
my-service.my-ns
에 대한 DNS 레코드를 만든다. my-ns
네임 스페이스의 파드들은
my-service
(my-service.my-ns
역시 동작함)에 대한 이름 조회를
수행하여 서비스를 찾을 수 있어야 한다.
다른 네임스페이스의 파드들은 이름을 my-service.my-ns
으로 사용해야 한다. 이 이름은
서비스에 할당된 클러스터 IP로 변환된다.
쿠버네티스는 또한 알려진 포트에 대한 DNS SRV (서비스) 레코드를 지원한다.
my-service.my-ns
서비스에 프로토콜이 TCP
로 설정된 http
라는 포트가 있는 경우,
IP 주소와 http
에 대한 포트 번호를 검색하기 위해 _http._tcp.my-service.my-ns
에 대한
DNS SRV 쿼리를 수행할 수 있다.
쿠버네티스 DNS 서버는 ExternalName
서비스에 접근할 수 있는 유일한 방법이다.
DNS 파드와 서비스에서
ExternalName
검색에 대한 자세한 정보를 찾을 수 있다.
헤드리스(Headless) 서비스
때때로 로드-밸런싱과 단일 서비스 IP는 필요치 않다. 이 경우,
"헤드리스" 서비스라는 것을 만들 수 있는데, 명시적으로
클러스터 IP (.spec.clusterIP
)에 "None"을 지정한다.
쿠버네티스의 구현에 묶이지 않고, 헤드리스 서비스를 사용하여 다른 서비스 디스커버리 메커니즘과 인터페이스할 수 있다.
헤드리스 서비스
의 경우, 클러스터 IP가 할당되지 않고, kube-proxy가
이러한 서비스를 처리하지 않으며, 플랫폼에 의해 로드 밸런싱 또는 프록시를
하지 않는다. DNS가 자동으로 구성되는 방법은 서비스에 셀렉터가 정의되어 있는지
여부에 달려있다.
셀렉터가 있는 경우
셀렉터를 정의하는 헤드리스 서비스의 경우, 쿠버네티스 컨트롤 플레인은 쿠버네티스 API 내에서 엔드포인트슬라이스 오브젝트를 생성하고, 서비스 하위(backing) 파드들을 직접 가리키는 A 또는 AAAA 레코드(IPv4 또는 IPv6 주소)를 반환하도록 DNS 구성을 변경한다.
셀렉터가 없는 경우
셀렉터를 정의하지 않는 헤드리스 서비스의 경우, 쿠버네티스 컨트롤 플레인은 엔드포인트슬라이스 오브젝트를 생성하지 않는다. 하지만, DNS 시스템은 다음 중 하나를 탐색한 뒤 구성한다.
type: ExternalName
서비스에 대한 DNS CNAME 레코드ExternalName
이외의 모든 서비스 타입에 대해, 서비스의 활성(ready) 엔드포인트의 모든 IP 주소에 대한 DNS A / AAAA 레코드- IPv4 엔드포인트에 대해, DNS 시스템은 A 레코드를 생성한다.
- IPv6 엔드포인트에 대해, DNS 시스템은 AAAA 레코드를 생성한다.
서비스 퍼블리싱 (ServiceTypes)
애플리케이션 중 일부(예: 프론트엔드)는 서비스를 클러스터 밖에 위치한 외부 IP 주소에 노출하고 싶은 경우가 있을 것이다.
쿠버네티스 ServiceTypes
는 원하는 서비스 종류를 지정할 수 있도록 해 준다.
Type
값과 그 동작은 다음과 같다.
ClusterIP
: 서비스를 클러스터-내부 IP에 노출시킨다. 이 값을 선택하면 클러스터 내에서만 서비스에 도달할 수 있다. 이것은 서비스의type
을 명시적으로 지정하지 않았을 때의 기본값이다.NodePort
: 고정 포트 (NodePort
)로 각 노드의 IP에 서비스를 노출시킨다. 노드 포트를 사용할 수 있도록 하기 위해, 쿠버네티스는type: ClusterIP
인 서비스를 요청했을 때와 마찬가지로 클러스터 IP 주소를 구성한다.LoadBalancer
: 클라우드 공급자의 로드 밸런서를 사용하여 서비스를 외부에 노출시킨다.ExternalName
: 값과 함께 CNAME 레코드를 리턴하여, 서비스를externalName
필드의 내용(예:foo.bar.example.com
)에 매핑한다. 어떠한 종류의 프록시도 설정되지 않는다.참고:
ExternalName
유형을 사용하려면kube-dns
버전 1.7 또는 CoreDNS 버전 0.0.8 이상이 필요하다.
type
필드는 중첩(nested) 기능으로 설계되어, 각 단계는 이전 단계에 더해지는 형태이다.
이는 모든 클라우드 공급자에 대해 엄격히 요구되는 사항은 아니다(예:
Google Compute Engine에서는 type: LoadBalancer
가 동작하기 위해 노드 포트를 할당할 필요가 없지만,
다른 클라우드 공급자 통합 시에는 필요할 수 있음).
엄격한 중첩이 필수 사항은 아니지만, 서비스에 대한 쿠버네티스 API 디자인은 이와 상관없이 엄격한 중첩 구조를 가정한다.
인그레스를 사용하여 서비스를 노출시킬 수도 있다. 인그레스는 서비스 유형은 아니지만, 클러스터의 진입점 역할을 한다. 동일한 IP 주소로 여러 서비스를 노출시킬 수 있기 때문에 라우팅 규칙을 단일 리소스로 통합할 수 있다.
NodePort 유형
type
필드를 NodePort
로 설정하면, 쿠버네티스 컨트롤 플레인은
--service-node-port-range
플래그로 지정된 범위에서 포트를 할당한다 (기본값 : 30000-32767).
각 노드는 해당 포트 (모든 노드에서 동일한 포트 번호)를 서비스로 프록시한다.
서비스는 할당된 포트를 .spec.ports[*].nodePort
필드에 나타낸다.
NodePort를 사용하면 자유롭게 자체 로드 밸런싱 솔루션을 설정하거나, 쿠버네티스가 완벽하게 지원하지 않는 환경을 구성하거나, 하나 이상의 노드 IP를 직접 노출시킬 수 있다.
NodePort 서비스에 대해, 쿠버네티스는 포트를 추가로
할당한다(서비스의 프로토콜에 매치되도록 TCP, UDP, SCTP 중 하나).
클러스터의 모든 노드는 할당된 해당 포트를 리슨하고
해당 서비스에 연결된 활성(ready) 엔드포인트 중 하나로 트래픽을 전달하도록 자기 자신을 구성한다.
적절한 프로토콜(예: TCP) 및 적절한 포트(해당 서비스에 할당된 대로)로
클러스터 외부에서 클러스터의 아무 노드에 연결하여 type: NodePort
서비스로 접근할 수 있다.
포트 직접 선택하기
특정 포트 번호를 원한다면, nodePort
필드에 값을 명시할 수 있다.
컨트롤 플레인은 해당 포트를 할당해 주거나 또는
해당 API 트랜젝션이 실패했다고 알려줄 것이다.
이는 사용자 스스로 포트 충돌의 가능성을 고려해야 한다는 의미이다.
또한 유효한(NodePort용으로 사용할 수 있도록 구성된 범위 내의)
포트 번호를 사용해야 한다.
다음은 NodePort 값을 명시하는(이 예시에서는 30007)
type: NodePort
서비스에 대한 예시 매니페스트이다.
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app.kubernetes.io/name: MyApp
ports:
# 기본적으로 그리고 편의상 `targetPort` 는 `port` 필드와 동일한 값으로 설정된다.
- port: 80
targetPort: 80
# 선택적 필드
# 기본적으로 그리고 편의상 쿠버네티스 컨트롤 플레인은 포트 범위에서 할당한다(기본값: 30000-32767)
nodePort: 30007
type: NodePort
서비스를 위한 커스텀 IP 주소 구성
NodePort 서비스 노출에 특정 IP 주소를 사용하도록 클러스터의 노드를 설정할 수 있다. 각 노드가 여러 네트워크(예: 애플리케이션 트래픽용 네트워크 및 노드/컨트롤 플레인 간 트래픽용 네트워크)에 연결되어 있는 경우에 이러한 구성을 고려할 수 있다.
포트를 프록시하기 위해 특정 IP를 지정하려면, kube-proxy에 대한
--nodeport-addresses
플래그 또는
kube-proxy 구성 파일의
동등한 nodePortAddresses
필드를
특정 IP 블록으로 설정할 수 있다.
이 플래그는 쉼표로 구분된 IP 블록 목록(예: 10.0.0.0/8
, 192.0.2.0/25
)을 사용하여
kube-proxy가 로컬 노드로 고려해야 하는 IP 주소 범위를 지정한다.
예를 들어, --nodeport-addresses=127.0.0.0/8
플래그로 kube-proxy를 시작하면,
kube-proxy는 NodePort 서비스에 대하여 루프백(loopback) 인터페이스만 선택한다.
--nodeport-addresses
의 기본 값은 비어있는 목록이다.
이것은 kube-proxy가 NodePort에 대해 사용 가능한 모든 네트워크 인터페이스를 고려해야 한다는 것을 의미한다.
(이는 이전 쿠버네티스 릴리스와도 호환된다).
참고:
이 서비스는<NodeIP>:spec.ports[*].nodePort
와 .spec.clusterIP:spec.ports[*].port
로 표기된다.
kube-proxy에 대한 --nodeport-addresses
플래그 또는 kube-proxy 구성 파일의 동등한 필드가 설정된 경우,
<NodeIP>
는 노드 IP를 필터링한다.로드밸런서 유형
외부 로드 밸런서를 지원하는 클라우드 공급자 상에서, type
필드를 LoadBalancer
로 설정하면 서비스에 대한 로드 밸런서를 프로비저닝한다.
로드 밸런서의 실제 생성은 비동기적으로 수행되고,
프로비저닝된 밸런서에 대한 정보는 서비스의
.status.loadBalancer
필드에 발행된다.
예를 들면 다음과 같다.
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 192.0.2.127
외부 로드 밸런서의 트래픽은 백엔드 파드로 전달된다. 클라우드 공급자는 로드 밸런싱 방식을 결정한다.
일부 클라우드 공급자는 loadBalancerIP
를 지정할 수 있도록 허용한다. 이 경우, 로드 밸런서는
사용자 지정 loadBalancerIP
로 생성된다. loadBalancerIP
필드가 지정되지 않으면,
임시 IP 주소로 loadBalancer가 설정된다. loadBalancerIP
를 지정했지만
클라우드 공급자가 이 기능을 지원하지 않는 경우, 설정한 loadbalancerIP
필드는
무시된다.
type: LoadBalancer
인 서비스를 구현하기 위해,
쿠버네티스는 일반적으로 type: NodePort
서비스를 요청했을 때와 동일한 변경사항을 적용하면서 시작한다.
그런 다음 cloud-controller-manager 컴포넌트는
할당된 해당 NodePort로 트래픽을 전달하도록 외부 로드 밸런서를 구성한다.
알파 기능으로서, 로드 밸런스된 서비스가 NodePort 할당을 생략하도록 구성할 수 있는데, 이는 클라우드 공급자의 구현이 이를 지원할 때에만 가능하다.
참고:
Azure 에서 사용자 지정 공개(public) 유형 loadBalancerIP
를 사용하려면, 먼저
정적 유형 공개 IP 주소 리소스를 생성해야 한다. 이 공개 IP 주소 리소스는
클러스터에서 자동으로 생성된 다른 리소스와 동일한 리소스 그룹에 있어야 한다.
예를 들면, MC_myResourceGroup_myAKSCluster_eastus
이다.
할당된 IP 주소를 loadBalancerIP로 지정한다. 클라우드 공급자 구성 파일에서
securityGroupName
을 업데이트했는지 확인한다.
CreatingLoadBalancerFailed
권한 문제 해결에 대한 자세한 내용은
Azure Kubernetes Service (AKS) 로드 밸런서에서 고정 IP 주소 사용
또는 고급 네트워킹 AKS 클러스터에서 CreateLoadBalancerFailed를 참고한다.
프로토콜 유형이 혼합된 로드밸런서
Kubernetes v1.24 [beta]
기본적으로 로드밸런서 서비스 유형의 경우 둘 이상의 포트가 정의되어 있을 때 모든 포트는 동일한 프로토콜을 가져야 하며 프로토콜은 클라우드 공급자가 지원하는 프로토콜이어야 한다.
MixedProtocolLBService
기능 게이트(v1.24에서 kube-apiserver에 대해 기본적으로 활성화되어 있음)는
둘 이상의 포트가 정의되어 있는 경우에 로드밸런서 타입의 서비스에 대해 서로 다른 프로토콜을 사용할 수 있도록 해 준다.
참고:
로드밸런서 서비스 유형에 사용할 수 있는 프로토콜 세트는 여전히 클라우드 제공 업체에서 정의한다. 클라우드 제공자가 혼합 프로토콜을 지원하지 않는다면 이는 단일 프로토콜만을 제공한다는 것을 의미한다.로드밸런서 NodePort 할당 비활성화
Kubernetes v1.24 [stable]
type=LoadBalancer
서비스에 대한 노드 포트 할당을 선택적으로 비활성화할 수 있으며,
이는 spec.allocateLoadBalancerNodePorts
필드를 false
로 설정하면 된다.
노드 포트를 사용하지 않고 트래픽을 파드로 직접 라우팅하는 로드 밸런서 구현에만 사용해야 한다.
기본적으로 spec.allocateLoadBalancerNodePorts
는 true
이며 로드밸런서 서비스 유형은 계속해서 노드 포트를 할당할 것이다.
노드 포트가 할당된 기존 서비스에서 spec.allocateLoadBalancerNodePorts
가 false
로 설정된 경우 해당 노드 포트는 자동으로 할당 해제되지 않는다.
이러한 노드 포트를 할당 해제하려면 모든 서비스 포트에서 nodePorts
항목을 명시적으로 제거해야 한다.
로드 밸런서 구현 클래스 지정
Kubernetes v1.24 [stable]
spec.loadBalancerClass
필드를 설정하여 클라우드 제공자가 설정한 기본값 이외의 로드 밸런서 구현을 사용할 수 있다.
기본적으로, spec.loadBalancerClass
는 nil
이고,
클러스터가 클라우드 제공자의 로드밸런서를 이용하도록 --cloud-provider
컴포넌트 플래그를 이용하여 설정되어 있으면
LoadBalancer
유형의 서비스는 클라우드 공급자의 기본 로드 밸런서 구현을 사용한다.
spec.loadBalancerClass
가 지정되면, 지정된 클래스와 일치하는 로드 밸런서
구현이 서비스를 감시하고 있다고 가정한다.
모든 기본 로드 밸런서 구현(예: 클라우드 공급자가 제공하는
로드 밸런서 구현)은 이 필드가 설정된 서비스를 무시한다.
spec.loadBalancerClass
는 LoadBalancer
유형의 서비스에서만 설정할 수 있다.
한 번 설정하면 변경할 수 없다.
spec.loadBalancerClass
의 값은 "internal-vip
" 또는
"example.com/internal-vip
" 와 같은 선택적 접두사가 있는 레이블 스타일 식별자여야 한다.
접두사가 없는 이름은 최종 사용자를 위해 예약되어 있다.
내부 로드 밸런서
혼재된 환경에서는 서비스의 트래픽을 동일한 (가상) 네트워크 주소 블록 내로 라우팅해야 하는 경우가 있다.
수평 분할 DNS 환경에서는 외부와 내부 트래픽을 엔드포인트로 라우팅 할 수 있는 두 개의 서비스가 필요하다.
내부 로드 밸런서를 설정하려면, 사용 중인 클라우드 서비스 공급자에 따라 다음의 어노테이션 중 하나를 서비스에 추가한다.
탭 중 하나를 선택
[...]
metadata:
name: my-service
annotations:
cloud.google.com/load-balancer-type: "Internal"
[...]
[...]
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
[...]
[...]
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
[...]
[...]
metadata:
name: my-service
annotations:
service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type: "private"
[...]
[...]
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/openstack-internal-load-balancer: "true"
[...]
[...]
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/cce-load-balancer-internal-vpc: "true"
[...]
[...]
metadata:
annotations:
service.kubernetes.io/qcloud-loadbalancer-internal-subnetid: subnet-xxxxx
[...]
[...]
metadata:
annotations:
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: "intranet"
[...]
[...]
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/oci-load-balancer-internal: true
[...]
AWS에서 TLS 지원
AWS에서 실행되는 클러스터에서 부분적으로 TLS / SSL을 지원하기 위해, LoadBalancer
서비스에 세 가지
어노테이션을 추가할 수 있다.
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012
첫 번째는 사용할 인증서의 ARN을 지정한다. IAM에 업로드된 써드파티 발급자의 인증서이거나 AWS Certificate Manager에서 생성된 인증서일 수 있다.
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: (https|http|ssl|tcp)
두 번째 어노테이션은 파드가 알려주는 프로토콜을 지정한다. HTTPS와 SSL의 경우, ELB는 인증서를 사용하여 암호화된 연결을 통해 파드가 스스로를 인증할 것으로 예상한다.
HTTP와 HTTPS는 7 계층 프록시를 선택한다. ELB는 요청을 전달할 때
사용자와의 연결을 종료하고, 헤더를 파싱하고 사용자의 IP 주소로 X-Forwarded-For
헤더를 삽입한다. (파드는 해당 연결의 다른 종단에서의
ELB의 IP 주소만 참조)
TCP 및 SSL은 4 계층 프록시를 선택한다. ELB는 헤더를 수정하지 않고 트래픽을 전달한다.
일부 포트는 보안성을 갖추고 다른 포트는 암호화되지 않은 혼재된 사용 환경에서는 다음 어노테이션을 사용할 수 있다.
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443,8443"
위의 예에서, 서비스에 80
, 443
, 8443
의 3개 포트가 포함된 경우,
443
, 8443
은 SSL 인증서를 사용하지만, 80
은 프록시하는 HTTP이다.
쿠버네티스 v1.9부터는 서비스에 대한
HTTPS 또는 SSL 리스너와 함께
사전에 정의된 AWS SSL 정책을 사용할 수 있다.
사용 가능한 정책을 확인하려면, aws
커맨드라인 툴을 사용한다.
aws elb describe-load-balancer-policies --query 'PolicyDescriptions[].PolicyName'
그리고
"service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy
"
어노테이션을 사용하여 이러한 정책 중 하나를 지정할 수 있다. 예를 들면
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: "ELBSecurityPolicy-TLS-1-2-2017-01"
AWS에서 지원하는 프록시 프로토콜
AWS에서 실행되는 클러스터에 대한 프록시 프로토콜 지원을 활성화하려면, 다음의 서비스 어노테이션을 사용할 수 있다.
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
버전 1.3.0 부터, 이 어노테이션의 사용은 ELB에 의해 프록시되는 모든 포트에 적용되며 다르게 구성할 수 없다.
AWS의 ELB 접근 로그
AWS ELB 서비스의 접근 로그를 관리하기 위한 몇 가지 어노테이션이 있다.
service.beta.kubernetes.io/aws-load-balancer-access-log-enabled
어노테이션은
접근 로그의 활성화 여부를 제어한다.
service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval
어노테이션은
접근 로그를 게시하는 간격을 분 단위로 제어한다. 5분 또는 60분의
간격으로 지정할 수 있다.
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name
어노테이션은
로드 밸런서 접근 로그가 저장되는 Amazon S3 버킷의 이름을
제어한다.
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix
어노테이션은
Amazon S3 버킷을 생성한 논리적 계층을 지정한다.
metadata:
name: my-service
annotations:
# 로드 밸런서의 접근 로그 활성화 여부를 명시.
service.beta.kubernetes.io/aws-load-balancer-access-log-enabled: "true"
# 접근 로그를 게시하는 간격을 분 단위로 제어. 5분 또는 60분의 간격을 지정.
service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval: "60"
# 로드 밸런서 접근 로그가 저장되는 Amazon S3 버킷의 이름 명시.
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name: "my-bucket"
# Amazon S3 버킷을 생성한 논리적 계층을 지정. 예: `my-bucket-prefix/prod`
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix: "my-bucket-prefix/prod"
AWS의 연결 드레이닝(Draining)
Classic ELB의 연결 드레이닝은
service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled
어노테이션을
"true"
값으로 설정하여 관리할 수 있다. service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout
어노테이션을
사용하여 인스턴스를 해제하기 전에,
기존 연결을 열어 두는 목적으로 최대 시간을 초 단위로
설정할 수도 있다.
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout: "60"
다른 ELB 어노테이션
이하는 클래식 엘라스틱 로드 밸런서(Classic Elastic Load Balancers)를 관리하기 위한 다른 어노테이션이다.
metadata:
name: my-service
annotations:
# 로드 밸런서가 연결을 닫기 전에, 유휴 상태(연결을 통해 전송 된
# 데이터가 없음)의 연결을 허용하는 초단위 시간
service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "60"
# 로드 밸런서에 교차-영역(cross-zone) 로드 밸런싱을 사용할 지 여부를 지정
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
# 쉼표로 구분된 key-value 목록은 ELB에
# 추가 태그로 기록됨
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: "environment=prod,owner=devops"
# 백엔드가 정상인 것으로 간주되는데 필요한 연속적인
# 헬스 체크 성공 횟수이다. 기본값은 2이며, 2와 10 사이여야 한다.
service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: ""
# 백엔드가 비정상인 것으로 간주되는데 필요한
# 헬스 체크 실패 횟수이다. 기본값은 6이며, 2와 10 사이여야 한다.
service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: "3"
# 개별 인스턴스의 상태 점검 사이의
# 대략적인 간격 (초 단위). 기본값은 10이며, 5와 300 사이여야 한다.
service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: "20"
# 헬스 체크 실패를 의미하는 무 응답의 총 시간 (초 단위)
# 이 값은 service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval
# 값 보다 작아야한다. 기본값은 5이며, 2와 60 사이여야 한다.
service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout: "5"
# 생성된 ELB에 설정할 기존 보안 그룹(security group) 목록.
# service.beta.kubernetes.io/aws-load-balancer-extra-security-groups 어노테이션과 달리,
# 이는 이전에 ELB에 할당된 다른 모든 보안 그룹을 대체하며,
# '해당 ELB를 위한 고유 보안 그룹 생성'을 오버라이드한다.
# 목록의 첫 번째 보안 그룹 ID는 인바운드 트래픽(서비스 트래픽과 헬스 체크)이
# 워커 노드로 향하도록 하는 규칙으로 사용된다.
# 여러 ELB가 하나의 보안 그룹 ID와 연결되면, 1줄의 허가 규칙만이
# 워커 노드 보안 그룹에 추가된다.
# 즉, 만약 여러 ELB 중 하나를 지우면, 1줄의 허가 규칙이 삭제되어, 같은 보안 그룹 ID와 연결된 모든 ELB에 대한 접속이 막힌다.
# 적절하게 사용되지 않으면 이는 다수의 서비스가 중단되는 상황을 유발할 수 있다.
service.beta.kubernetes.io/aws-load-balancer-security-groups: "sg-53fae93f"
# 생성된 ELB에 추가할 추가 보안 그룹 목록
# 이 방법을 사용하면 이전에 생성된 고유 보안 그룹이 그대로 유지되므로,
# 각 ELB가 고유 보안 그룹 ID와 그에 매칭되는 허가 규칙 라인을 소유하여
# 트래픽(서비스 트래픽과 헬스 체크)이 워커 노드로 향할 수 있도록 한다.
# 여기에 기재되는 보안 그룹은 여러 서비스 간 공유될 수 있다.
service.beta.kubernetes.io/aws-load-balancer-extra-security-groups: "sg-53fae93f,sg-42efd82e"
# 로드 밸런서의 대상 노드를 선택하는 데
# 사용되는 키-값 쌍의 쉼표로 구분된 목록
service.beta.kubernetes.io/aws-load-balancer-target-node-labels: "ingress-gw,gw-name=public-api"
AWS의 네트워크 로드 밸런서 지원
Kubernetes v1.15 [beta]
AWS에서 네트워크 로드 밸런서를 사용하려면, nlb
값이 설정된 service.beta.kubernetes.io/aws-load-balancer-type
어노테이션을 사용한다.
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
참고:
NLB는 특정 인스턴스 클래스에서만 작동한다. 지원되는 인스턴스 유형 목록은 엘라스틱 로드 밸런싱에 대한 AWS 문서 를 참고한다.클래식 엘라스틱 로드 밸런서와 달리, 네트워크 로드 밸런서 (NLB)는
클라이언트의 IP 주소를 노드로 전달한다. 서비스의 .spec.externalTrafficPolicy
가
Cluster
로 설정되어 있으면, 클라이언트의 IP 주소가 종단 파드로
전파되지 않는다.
.spec.externalTrafficPolicy
를 Local
로 설정하면, 클라이언트 IP 주소가
종단 파드로 전파되지만, 트래픽이 고르지 않게
분배될 수 있다. 특정 로드밸런서 서비스를 위한 파드가 없는 노드는 자동 할당된
.spec.healthCheckNodePort
에 의해서 NLB 대상 그룹의
헬스 체크에 실패하고 트래픽을 수신하지 못하게 된다.
트래픽을 균일하게 하려면, DaemonSet을 사용하거나, 파드 안티어피니티(pod anti-affinity) 를 지정하여 동일한 노드에 위치하지 않도록 한다.
내부 로드 밸런서 어노테이션과 함께 NLB 서비스를 사용할 수도 있다.
클라이언트 트래픽이 NLB 뒤의 인스턴스에 도달하기 위해, 노드 보안 그룹은 다음 IP 규칙으로 수정된다.
규칙 | 프로토콜 | 포트 | IP 범위 | IP 범위 설명 |
---|---|---|---|---|
헬스 체크 | TCP | NodePort(s) (.spec.healthCheckNodePort for .spec.externalTrafficPolicy = Local ) | Subnet CIDR | kubernetes.io/rule/nlb/health=<loadBalancerName> |
클라이언트 트래픽 | TCP | NodePort(s) | .spec.loadBalancerSourceRanges (defaults to 0.0.0.0/0 ) | kubernetes.io/rule/nlb/client=<loadBalancerName> |
MTU 탐색 | ICMP | 3,4 | .spec.loadBalancerSourceRanges (defaults to 0.0.0.0/0 ) | kubernetes.io/rule/nlb/mtu=<loadBalancerName> |
네트워크 로드 밸런서에 접근할 수 있는 클라이언트 IP를 제한하려면,
loadBalancerSourceRanges
를 지정한다.
spec:
loadBalancerSourceRanges:
- "143.231.0.0/16"
참고:
.spec.loadBalancerSourceRanges
가 설정되어 있지 않으면, 쿠버네티스는
0.0.0.0/0
에서 노드 보안 그룹으로의 트래픽을 허용한다. 노드에 퍼블릭 IP 주소가
있는 경우, 비(non)-NLB 트래픽도 해당 수정된 보안 그룹의
모든 인스턴스에 도달할 수 있다.엘라스틱 IP에 대한 설명 문서와 기타 일반적 사용 사례를 AWS 로드 밸런서 컨트롤러 문서에서 볼 수 있다.
Tencent Kubernetes Engine (TKE)의 다른 CLB 어노테이션
아래 표시된 것처럼 TKE에서 클라우드 로드 밸런서를 관리하기 위한 다른 어노테이션이 있다.
metadata:
name: my-service
annotations:
# 지정된 노드로 로드 밸런서 바인드
service.kubernetes.io/qcloud-loadbalancer-backends-label: key in (value1, value2)
# 기존 로드 밸런서의 ID
service.kubernetes.io/tke-existed-lbid:lb-6swtxxxx
# 로드 밸런서 (LB)에 대한 사용자 지정 매개 변수는 아직 LB 유형 수정을 지원하지 않음
service.kubernetes.io/service.extensiveParameters: ""
# LB 리스너의 사용자 정의 매개 변수
service.kubernetes.io/service.listenerParameters: ""
# 로드 밸런서 유형 지정
# 유효 값 : 클래식 (클래식 클라우드 로드 밸런서) 또는 애플리케이션 (애플리케이션 클라우드 로드 밸런서)
service.kubernetes.io/loadbalance-type: xxxxx
# 퍼블릭 네트워크 대역폭 청구 방법 지정
# 유효 값: TRAFFIC_POSTPAID_BY_HOUR (트래픽 별) 및 BANDWIDTH_POSTPAID_BY_HOUR (대역폭 별)
service.kubernetes.io/qcloud-loadbalancer-internet-charge-type: xxxxxx
# 대역폭 값 지정 (값 범위 : [1,2000] Mbps).
service.kubernetes.io/qcloud-loadbalancer-internet-max-bandwidth-out: "10"
# 이 어느테이션이 설정되면, 로드 밸런서는 파드가
# 실행중인 노드만 등록하고, 그렇지 않으면 모든 노드가 등록됨
service.kubernetes.io/local-svc-only-bind-node-with-pod: true
ExternalName 유형
ExternalName 유형의 서비스는 my-service
또는 cassandra
와 같은 일반적인 셀렉터에 대한 서비스가 아닌,
DNS 이름에 대한 서비스에 매핑한다. spec.externalName
파라미터를 사용하여 이러한 서비스를 지정한다.
예를 들면, 이 서비스 정의는 prod
네임 스페이스의
my-service
서비스를 my.database.example.com
에 매핑한다.
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
참고:
ExternalName은 IPv4 주소 문자열을 허용하지만, IP 주소가 아닌 숫자로 구성된 DNS 이름을 허용한다. IPv4 주소와 유사한 ExternalName은 CoreDNS 또는 ingress-nginx에 의해 확인되지 않는데, ExternalName은 정식(canonical) DNS 이름을 지정하기 때문이다. IP 주소를 하드 코딩하려면, 헤드리스(headless) 서비스 사용을 고려한다.my-service.prod.svc.cluster.local
호스트를 검색하면, 클러스터 DNS 서비스는
my.database.example.com
값의 CNAME
레코드를 반환한다. my-service
에 접근하는 것은
다른 서비스와 같은 방식으로 작동하지만, 리다이렉션은 프록시 또는
포워딩을 통하지 않고 DNS 수준에서 발생한다는 중요한
차이점이 있다. 나중에 데이터베이스를 클러스터로 이동하기로 결정한 경우, 해당
파드를 시작하고 적절한 셀렉터 또는 엔드포인트를 추가하고,
서비스의 유형(type)
을 변경할 수 있다.
경고:
HTTP 및 HTTPS를 포함한, 몇몇 일반적인 프로토콜에 ExternalName을 사용하는 것은 문제가 있을 수 있다. ExternalName을 사용하는 경우, 클러스터 내부의 클라이언트가 사용하는 호스트 이름(hostname)이 ExternalName이 참조하는 이름과 다르다.
호스트 이름을 사용하는 프로토콜의 경우, 이러한 차이로 인해 오류가 발생하거나 예기치 않은 응답이 발생할 수 있다.
HTTP 요청에는 오리진(origin) 서버가 인식하지 못하는 Host :
헤더가 있다.
TLS 서버는 클라이언트가 연결된 호스트 이름과 일치하는 인증서를 제공할 수 없다.
외부 IP
하나 이상의 클러스터 노드로 라우팅되는 외부 IP가 있는 경우, 쿠버네티스 서비스는 이러한
externalIPs
에 노출될 수 있다. 서비스 포트에서 외부 IP (목적지 IP)를 사용하여 클러스터로 들어오는 트래픽은
서비스 엔드포인트 중 하나로 라우팅된다. externalIPs
는 쿠버네티스에 의해 관리되지 않으며
클러스터 관리자에게 책임이 있다.
서비스 명세에서, externalIPs
는 모든 ServiceTypes
와 함께 지정할 수 있다.
아래 예에서, 클라이언트는 "80.11.12.10:80
"(외부 IP:포트
)로 "my-service
"에 접근할 수 있다.
apiVersion: v1
kind: Service
metadata:
app.kubernetes.io/name: MyApp
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
externalIPs:
- 80.11.12.10
세션 스티킹(stickiness)
특정 클라이언트로부터의 연결이 매번 동일한 파드로 전달되도록 하고 싶다면, 클라이언트의 IP 주소 기반으로 세션 어피니티를 구성할 수 있다. 더 자세한 정보는 세션 어피니티를 참고한다.
API 오브젝트
서비스는 쿠버네티스 REST API의 최상위 리소스이다. 서비스 API 오브젝트에 대한 자세한 내용을 참고할 수 있다.
가상 IP 주소 메커니즘
가상 IP 및 서비스 프록시에서 가상 IP 주소를 갖는 서비스를 노출하기 위해 쿠버네티스가 제공하는 메커니즘에 대해 알아본다.
다음 내용
- 서비스와 애플리케이션 연결 알아보기
- 인그레스에 대해 알아보기
- 엔드포인트슬라이스에 대해 알아보기
추가적으로,
- 가상 IP 및 서비스 프록시를 살펴보기
- 서비스(Service) API에 대한 API 레퍼런스 살펴보기
- 엔드포인트(Endpoints) API에 대한 API 레퍼런스 살펴보기
- 엔드포인트슬라이스 API에 대한 API 레퍼런스 살펴보기