[ko] Update outdated files in dev-1.26-ko.1 M67

pull/39219/head
Jihoon Seo 2023-02-02 17:53:30 +09:00
parent 5ae3aaab5b
commit 5c6199cb0c
5 changed files with 629 additions and 479 deletions

View File

@ -6,7 +6,9 @@ feature:
title: 서비스 디스커버리와 로드 밸런싱
description: >
쿠버네티스를 사용하면 익숙하지 않은 서비스 디스커버리 메커니즘을 사용하기 위해 애플리케이션을 수정할 필요가 없다. 쿠버네티스는 파드에게 고유한 IP 주소와 파드 집합에 대한 단일 DNS 명을 부여하고, 그것들 간에 로드-밸런스를 수행할 수 있다.
description: >-
외부와 접하는 단일 엔드포인트 뒤에 있는 클러스터에서 실행되는 애플리케이션을 노출시키며,
이는 워크로드가 여러 백엔드로 나뉘어 있는 경우에도 가능하다.
content_type: concept
weight: 10
---
@ -59,9 +61,10 @@ _서비스_ 로 들어가보자.
### 클라우드-네이티브 서비스 디스커버리
애플리케이션에서 서비스 디스커버리를 위해 쿠버네티스 API를 사용할 수 있는 경우,
서비스 내 파드 세트가 변경될 때마다 업데이트되는 엔드포인트를 {{< glossary_tooltip text="API 서버" term_id="kube-apiserver" >}}에
질의할 수 있다.
애플리케이션에서 서비스 디스커버리를 위해 쿠버네티스 API를 사용할 수 있는 경우,
매치되는 엔드포인트슬라이스를
{{< glossary_tooltip text="API 서버" term_id="kube-apiserver" >}}에 질의할 수 있다.
쿠버네티스는 서비스의 파드가 변경될 때마다 서비스의 엔드포인트슬라이스를 업데이트한다.
네이티브 애플리케이션이 아닌 (non-native applications) 경우, 쿠버네티스는 애플리케이션과 백엔드 파드 사이에 네트워크 포트 또는 로드
밸런서를 배치할 수 있는 방법을 제공한다.
@ -149,8 +152,9 @@ spec:
예를 들어, 클라이언트를 망가뜨리지 않고,
백엔드 소프트웨어의 다음 버전에서 파드가 노출시키는 포트 번호를 변경할 수 있다.
서비스의 기본 프로토콜은 TCP이다. 다른
[지원되는 프로토콜](#protocol-support)을 사용할 수도 있다.
서비스의 기본 프로토콜은
[TCP](/docs/reference/networking/service-protocols/#protocol-tcp)이다.
다른 [지원되는 프로토콜](#protocol-support)을 사용할 수도 있다.
많은 서비스가 하나 이상의 포트를 노출해야 하기 때문에, 쿠버네티스는 서비스 오브젝트에서 다중
포트 정의를 지원한다.
@ -159,8 +163,12 @@ spec:
### 셀렉터가 없는 서비스
서비스는 일반적으로 셀렉터를 이용하여 쿠버네티스 파드에 대한 접근을 추상화하지만,
셀렉터 대신 매칭되는(corresponding) 엔드포인트와 함께 사용되면 다른 종류의 백엔드도 추상화할 수 있으며,
여기에는 클러스터 외부에서 실행되는 것도 포함된다. 예시는 다음과 같다.
셀렉터 대신 매칭되는(corresponding)
{{<glossary_tooltip term_id="endpoint-slice" text="엔드포인트슬라이스">}}
오브젝트와 함께 사용되면 다른 종류의 백엔드도 추상화할 수 있으며,
여기에는 클러스터 외부에서 실행되는 것도 포함된다.
예시는 다음과 같다.
* 프로덕션 환경에서는 외부 데이터베이스 클러스터를 사용하려고 하지만,
테스트 환경에서는 자체 데이터베이스를 사용한다.
@ -169,7 +177,7 @@ spec:
* 워크로드를 쿠버네티스로 마이그레이션하고 있다. 해당 방식을 평가하는 동안,
쿠버네티스에서는 백엔드의 일부만 실행한다.
이러한 시나리오에서 파드 셀렉터 _없이_ 서비스를 정의 할 수 있다.
이러한 시나리오에서 파드 셀렉터 _없이_ 서비스를 정의 할 수 있다.
예를 들면
```yaml
@ -184,29 +192,41 @@ spec:
targetPort: 9376
```
이 서비스에는 셀렉터가 없으므로, 해당 엔드포인트 오브젝트가 자동으로
생성되지 않는다. 엔드포인트 오브젝트를 수동으로 추가하여, 서비스를 실행 중인 네트워크 주소 및 포트에
서비스를 수동으로 매핑할 수 있다.
이 서비스에는 셀렉터가 없으므로, 매칭되는 엔드포인트슬라이스
(및 레거시 엔드포인트) 오브젝트가 자동으로 생성되지 않는다.
엔드포인트슬라이스 오브젝트를 수동으로 추가하여,
서비스를 실행 중인 네트워크 주소 및 포트에 서비스를 수동으로 매핑할 수 있다. 예시는 다음과 같다.
```yaml
apiVersion: v1
kind: Endpoints
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
# 여기서의 이름은 서비스의 이름과 일치해야 한다.
name: my-service
subsets:
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:
- ip: 192.0.2.42
ports:
- port: 9376
- "10.4.5.6" # 이 목록에 IP 주소를 기재할 때 순서는 상관하지 않는다.
- "10.1.2.3"
```
엔드포인트 오브젝트의 이름은 유효한
[DNS 서브도메인 이름](/ko/docs/concepts/overview/working-with-objects/names/#dns-서브도메인-이름)이어야 한다.
#### 커스텀 엔드포인트슬라이스
서비스를 위한 객체인 [엔드포인트](/docs/reference/kubernetes-api/service-resources/endpoints-v1/)를 만들 때,
새로운 객체의 이름을
그것의 서비스 이름과 같게 설정해야 한다.
서비스를 위한 [엔드포인트슬라이스](#엔드포인트슬라이스) 오브젝트를 생성할 때,
엔드포인트슬라이스 이름으로는 원하는 어떤 이름도 사용할 수 있다.
네임스페이스 내의 각 엔드포인트슬라이스 이름은 고유해야 한다.
해당 엔드포인트슬라이스에 `kubernetes.io/service-name` {{< glossary_tooltip text="레이블" term_id="label" >}}을 설정하여
엔드포인트슬라이스를 서비스와 연결할 수 있다.
{{< note >}}
엔드포인트 IP는 루프백(loopback) (IPv4의 경우 127.0.0.0/8, IPv6의 경우 ::1/128), 또는
@ -217,204 +237,94 @@ subsets:
목적지(destination)로 지원하지 않기 때문이다.
{{< /note >}}
셀렉터가 없는 서비스에 접근하면 셀렉터가 있는 것처럼 동일하게 작동한다.
위의 예에서, 트래픽은 YAML에 정의된 단일 엔드 포인트로
라우팅된다. `192.0.2.42:9376` (TCP)
직접 생성했거나 직접 작성한 코드에 의해 생성된 엔드포인트슬라이스를 위해,
[`endpointslice.kubernetes.io/managed-by`](/ko/docs/reference/labels-annotations-taints/#endpointslicekubernetesiomanaged-by)
레이블에 사용할 값을 골라야 한다.
엔드포인트슬라이스를 관리하는 컨트롤러 코드를 직접 작성하는 경우,
`"my-domain.example/name-of-controller"`와 같은 값을 사용할 수 있다.
써드파티 도구를 사용하는 경우, 도구의 이름에서 대문자는 모두 소문자로 바꾸고
공백 및 다른 문장 부호는 하이픈(`-`)으로 대체한 문자열을 사용한다.
`kubectl`과 같은 도구를 사용하여 직접 엔드포인트슬라이스를 관리하는 경우,
`"staff"` 또는 `"cluster-admins"`와 같이 이러한 수동 관리를 명시하는 이름을 사용한다.
쿠버네티스 자체 컨트롤 플레인이 관리하는 엔드포인트슬라이스를 가리키는
`"controller"`라는 예약된 값은 사용하지 말아야 한다.
{{< note >}}
쿠버네티스 API 서버는 파드에 매핑되지 않은 엔드포인트를 프록시하는 것을 허용하지 않는다.
셀렉터가 없는 서비스에 대해서 `kubectl proxy <service-name>`과 같은 행위는
이런 제약으로 인해 실패할 것이다. 이는 사용자가 쿠버네티스 API 서버를
프록시로 사용하여 허가받지 않은 엔드포인트에 접근하는 것을 막아준다.
{{< /note >}}
#### 셀렉터가 없는 서비스에 접근하기 {#service-no-selector-access}
ExternalName 서비스는 셀렉터가 없고
DNS명을 대신 사용하는 특수한 상황의 서비스이다. 자세한 내용은
이 문서 뒷부분의 [ExternalName](#externalname) 섹션을 참조한다.
셀렉터가 없는 서비스에 접근하는 것은 셀렉터가 있는 서비스에 접근하는 것과 동일하게 동작한다.
셀렉터가 없는 서비스 [예시](#services-without-selectors)에서, 트래픽은
엔드포인트슬라이스 매니페스트에 정의된 두 엔드포인트 중 하나로 라우트된다(10.1.2.3:9376 또는 10.4.5.6:9376으로의 TCP 연결).
### 초과 용량 엔드포인트
엔드포인트 리소스에 1,000개가 넘는 엔드포인트가 있는 경우 쿠버네티스 v1.22(또는 그 이상)
클러스터는 해당 엔드포인트에 `endpoints.kubernetes.io/over-capacity: truncated` 어노테이션을 추가한다.
이 어노테이션은 영향을 받는 엔드포인트 오브젝트가 용량을 초과했으며
엔드포인트 컨트롤러가 엔드포인트의 수를 1000으로 줄였음을 나타낸다.
ExternalName 서비스는 셀렉터가 없고
대신 DNS 이름을 사용하는 특이 케이스 서비스이다.
자세한 내용은 이 문서 뒷부분의 [ExternalName](#externalname) 섹션을 참조한다.
### 엔드포인트슬라이스
{{< feature-state for_k8s_version="v1.21" state="stable" >}}
엔드포인트슬라이스는 엔드포인트에 보다 확장 가능한 대안을 제공할 수 있는
API 리소스이다. 개념적으로 엔드포인트와 매우 유사하지만, 엔드포인트슬라이스를
사용하면 여러 리소스에 네트워크 엔드포인트를 분산시킬 수 있다. 기본적으로,
엔드포인트슬라이스는 100개의 엔드포인트에 도달하면 "가득찬 것"로 간주되며,
추가 엔드포인트를 저장하기 위해서는 추가 엔드포인트슬라이스가
생성된다.
[엔드포인트슬라이스](/ko/docs/concepts/services-networking/endpoint-slices/)는
특정 서비스의 하위(backing) 네트워크 엔드포인트 부분집합(_슬라이스_)을 나타내는 오브젝트이다.
엔드포인트슬라이스는 [엔드포인트슬라이스](/ko/docs/concepts/services-networking/endpoint-slices/)에서
자세하게 설명된 추가적인 속성 및 기능을 제공한다.
쿠버네티스 클러스터는 각 엔드포인트슬라이스가 얼마나 많은 엔드포인트를 나타내는지를 추적한다.
한 서비스의 엔드포인트가 너무 많아 역치에 도달하면,
쿠버네티스는 빈 엔드포인트슬라이스를 생성하고 여기에 새로운 엔드포인트 정보를 저장한다.
기본적으로, 쿠버네티스는 기존의 모든 엔드포인트슬라이스가
엔드포인트를 최소 100개 이상 갖게 되면 새 엔드포인트슬라이스를 생성한다.
쿠버네티스는 새 엔드포인트가 추가되어야 하는 상황이 아니라면
새 엔드포인트슬라이스를 생성하지 않는다.
이 API에 대한 더 많은 정보는
[엔드포인트슬라이스](/ko/docs/concepts/services-networking/endpoint-slices/)를 참고한다.
### 엔드포인트
쿠버네티스 API에서,
[엔드포인트(Endpoints)](/docs/reference/kubernetes-api/service-resources/endpoints-v1/)(리소스 명칭이 복수형임)는
네트워크 엔드포인트의 목록을 정의하며,
일반적으로 트래픽이 어떤 파드에 보내질 수 있는지를 정의하기 위해 서비스가 참조한다.
엔드포인트 대신 엔드포인트슬라이스 API를 사용하는 것을 권장한다.
#### 용량 한계를 넘어선 엔드포인트
쿠버네티스는 단일 엔드포인트(Endpoints) 오브젝트에 포함될 수 있는 엔드포인트(endpoints)의 수를 제한한다.
단일 서비스에 1000개 이상의 하위(backing) 엔드포인트가 있으면,
쿠버네티스는 엔드포인트 오브젝트의 데이터를 덜어낸다(truncate).
서비스는 하나 이상의 엔드포인트슬라이스와 연결될 수 있기 때문에,
하위 엔드포인트 1000개 제한은 기존(legacy) 엔드포인트 API에만 적용된다.
이러한 경우, 쿠버네티스는 엔드포인트(Endpoints) 오브젝트에 저장될 수 있는
백엔드 엔드포인트(endpoints)를 최대 1000개 선정하고,
엔드포인트 오브젝트에 [`endpoints.kubernetes.io/over-capacity: truncated`](/docs/reference/labels-annotations-taints/#endpoints-kubernetes-io-over-capacity)
{{< glossary_tooltip text="어노테이션" term_id="annotation" >}}을 설정한다.
컨트롤 플레인은 또한 백엔드 파드 수가 1000 미만으로 내려가면
해당 어노테이션을 제거한다.
트래픽은 여전히 백엔드로 전송되지만, 기존(legacy) 엔드포인트 API에 의존하는 모든 로드 밸런싱 메커니즘은
사용 가능한 하위(backing) 엔드포인트 중에서 최대 1000개까지에만 트래픽을 전송한다.
동일한 API 상한은 곧 하나의 엔드포인트(Endpoints) 객체가 1000개 이상의 엔드포인트(endpoints)를 갖도록 수동으로 업데이트할 수는 없음을 의미한다.
### 애플리케이션 프로토콜
{{< feature-state for_k8s_version="v1.20" state="stable" >}}
`appProtocol` 필드는 각 서비스 포트에 대한 애플리케이션 프로토콜을 지정하는 방법을 제공한다.
이 필드의 값은 해당 엔드포인트와 엔드포인트슬라이스
이 필드의 값은 상응하는 엔드포인트와 엔드포인트슬라이스
오브젝트에 의해 미러링된다.
이 필드는 표준 쿠버네티스 레이블 구문을 따른다. 값은
[IANA 표준 서비스 이름](https://www.iana.org/assignments/service-names) 또는
`mycompany.com/my-custom-protocol`과 같은 도메인 접두사 이름 중 하나여야 한다.
## 가상 IP와 서비스 프록시
쿠버네티스 클러스터의 모든 노드는 `kube-proxy`를 실행한다. `kube-proxy`
[`ExternalName`](#externalname) 이외의 유형의 `서비스`에 대한
가상 IP 형식을 구현한다.
### 라운드-로빈 DNS를 사용하지 않는 이유
항상 발생하는 질문은 왜 쿠버네티스가 인바운드 트래픽을 백엔드로 전달하기 위해 프록시에
의존하는가 하는 점이다. 다른 접근법이
있는가? 예를 들어, 여러 A 값 (또는 IPv6의 경우 AAAA)을 가진
DNS 레코드를 구성하고, 라운드-로빈 이름 확인 방식을
취할 수 있는가?
서비스에 프록시를 사용하는 데는 몇 가지 이유가 있다.
* 레코드 TTL을 고려하지 않고, 만료된 이름 검색 결과를
캐싱하는 DNS 구현에 대한 오래된 역사가 있다.
* 일부 앱은 DNS 검색을 한 번만 수행하고 결과를 무기한으로 캐시한다.
* 앱과 라이브러리가 적절히 재-확인을 했다고 하더라도, DNS 레코드의 TTL이
낮거나 0이면 DNS에 부하가 높아 관리하기가
어려워 질 수 있다.
본 페이지의 뒷 부분에서 다양한 kube-proxy 구현이 동작하는 방식에 대해 읽을 수 있다.
우선 알아두어야 할 것은, `kube-proxy`를 구동할 때, 커널 수준의 규칙이
수정(예를 들어, iptables 규칙이 생성될 수 있음)될 수 있고,
이는 때로는 리부트 전까지 정리되지 않을 수도 있다.
그래서, kube-proxy는 컴퓨터에서 저수준의, 특권을 가진(privileged) 네트워킹
프록시 서비스가 구동됨으로써 발생하는 결과를 이해하고 있는 관리자에 의해서만 구동되어야 한다.
비록 `kube-proxy` 실행 파일이 `cleanup` 기능을 지원하기는 하지만, 이 기능은 공식적인 기능이
아니기 때문에 구현된 그대로만 사용할 수 있다.
### 구성
kube-proxy는 구성에 따라 결정되는 여러 모드에서 기동될 수 있다.
- kube-proxy의 구성은 컨피그맵(ConfigMap)을 통해 이루어진다. 그리고 해당 kube-proxy를 위한
컨피그맵은 실효성있게 거의 대부분의 kube-proxy의 플래그의 행위를 더 이상 사용하지 않도록 한다.
- kube-proxy를 위한 해당 컨피그맵은 기동 중 구성의 재적용(live reloading)은 지원하지 않는다.
- kube-proxy를 위한 컨피그맵 파라미터는 기동 시에 검증이나 확인을 하지 않는다.
예를 들어, 운영 체계가 iptables 명령을 허용하지 않을 경우,
표준 커널 kube-proxy 구현체는 작동하지 않을 것이다.
마찬가지로, `netsh`을 지원하지 않는 운영 체계에서는,
윈도우 유저스페이스 모드로는 기동하지 않을 것이다.
### 유저 스페이스(User space) 프록시 모드 {#proxy-mode-userspace}
이 모드에서는, kube-proxy는 쿠버네티스 컨트롤 플레인의 서비스 및 엔드포인트 오브젝트의
추가와 제거를 감시한다. 각 서비스는 로컬 노드에서
포트(임의로 선택됨)를 연다. 이 "프록시 포트"에 대한 모든
연결은 (엔드포인트를 통해 보고된 대로) 서비스의 백엔드 파드 중 하나로 프록시된다.
kube-proxy는 사용할 백엔드 파드를 결정할 때 서비스의
`SessionAffinity` 설정을 고려한다.
마지막으로, 유저-스페이스 프록시는 서비스의
`clusterIP` (가상)와 `port` 에 대한 트래픽을 캡처하는 iptables 규칙을 설치한다. 이 규칙은
트래픽을 백엔드 파드를 프록시하는 프록시 포트로 리다이렉션한다.
기본적으로, 유저스페이스 모드의 kube-proxy는 라운드-로빈 알고리즘으로 백엔드를 선택한다.
![유저스페이스 프록시에 대한 서비스 개요 다이어그램](/images/docs/services-userspace-overview.svg)
### `iptables` 프록시 모드 {#proxy-mode-iptables}
이 모드에서는, kube-proxy는 쿠버네티스 컨트롤 플레인의 서비스, 엔드포인트 오브젝트의
추가와 제거를 감시한다. 각 서비스에 대해, 서비스의
`clusterIP``port`에 대한 트래픽을 캡처하고 해당 트래픽을 서비스의
백엔드 세트 중 하나로 리다이렉트(redirect)하는
iptables 규칙을 설치한다. 각 엔드포인트 오브젝트에 대해,
백엔드 파드를 선택하는 iptables 규칙을 설치한다.
기본적으로, iptables 모드의 kube-proxy는 임의의 백엔드를 선택한다.
트래픽을 처리하기 위해 iptables를 사용하면 시스템 오버헤드가 줄어드는데, 유저스페이스와
커널 스페이스 사이를 전환할 필요없이 리눅스 넷필터(netfilter)가 트래픽을 처리하기
때문이다. 이 접근 방식은 더 신뢰할 수 있기도 하다.
kube-proxy가 iptables 모드에서 실행 중이고 선택된 첫 번째 파드가
응답하지 않으면, 연결이 실패한다. 이는 userspace 모드와
다르다. 해당 시나리오에서는, kube-proxy는 첫 번째
파드에 대한 연결이 실패했음을 감지하고 다른 백엔드 파드로 자동으로 재시도한다.
파드 [준비성 프로브(readiness probe)](/ko/docs/concepts/workloads/pods/pod-lifecycle/#컨테이너-프로브-probe)를 사용하여
백엔드 파드가 제대로 작동하는지 확인할 수 있으므로, iptables 모드의 kube-proxy는
정상으로 테스트된 백엔드만 볼 수 있다. 이렇게 하면 트래픽이 kube-proxy를 통해
실패한 것으로 알려진 파드로 전송되는 것을 막을 수 있다.
![iptables 프록시에 대한 서비스 개요 다이어그램](/images/docs/services-iptables-overview.svg)
### IPVS 프록시 모드 {#proxy-mode-ipvs}
{{< feature-state for_k8s_version="v1.11" state="stable" >}}
`ipvs` 모드에서는, kube-proxy는 쿠버네티스 서비스와 엔드포인트를 감시하고,
`netlink` 인터페이스를 호출하여 그에 따라 IPVS 규칙을 생성하고
IPVS 규칙을 쿠버네티스 서비스와 엔드포인트와 주기적으로 동기화한다.
이 제어 루프는 IPVS 상태가 원하는 상태와 일치하도록
보장한다.
서비스에 접근하면, IPVS는 트래픽을 백엔드 파드 중 하나로 보낸다.
IPVS 프록시 모드는 iptables 모드와 유사한 넷필터 후크 기능을
기반으로 하지만, 해시 테이블을 기본 데이터 구조로 사용하고
커널 스페이스에서 동작한다.
이는 IPVS 모드의 kube-proxy는 iptables 모드의 kube-proxy보다
지연 시간이 짧은 트래픽을 리다이렉션하고, 프록시 규칙을 동기화할 때 성능이
훨씬 향상됨을 의미한다. 다른 프록시 모드와 비교했을 때, IPVS 모드는
높은 네트워크 트래픽 처리량도 지원한다.
IPVS는 트래픽을 백엔드 파드로 밸런싱하기 위한 추가 옵션을 제공한다.
다음과 같다.
* `rr`: 라운드-로빈
* `lc`: 최소 연결 (가장 적은 수의 열려있는 연결)
* `dh`: 목적지 해싱
* `sh`: 소스 해싱
* `sed`: 최단 예상 지연 (shortest expected delay)
* `nq`: 큐 미사용 (never queue)
{{< note >}}
IPVS 모드에서 kube-proxy를 실행하려면, kube-proxy를 시작하기 전에 노드에서 IPVS를
사용 가능하도록 해야 한다.
kube-proxy가 IPVS 프록시 모드에서 시작될 때, IPVS 커널 모듈을
사용할 수 있는지 확인한다. IPVS 커널 모듈이 감지되지 않으면, kube-proxy는
iptables 프록시 모드에서 다시 실행된다.
{{< /note >}}
![IPVS 프록시에 대한 서비스 개요 다이어그램](/images/docs/services-ipvs-overview.svg)
이 프록시 모델에서 클라이언트가 쿠버네티스 또는 서비스 또는 파드에
대해 알지 못하는 경우 서비스의 IP:포트로 향하는 트래픽은
적절한 백엔드로 프록시된다.
특정 클라이언트의 연결이 매번 동일한 파드로
전달되도록 하려면, `service.spec.sessionAffinity`를 "ClientIP"로 설정하여
클라이언트의 IP 주소를 기반으로 세션 어피니티(Affinity)를 선택할 수 있다.
(기본값은 "None")
`service.spec.sessionAffinityConfig.clientIP.timeoutSeconds`를 적절히 설정하여
최대 세션 고정 시간을 설정할 수도 있다.
(기본값은 10800으로, 3시간)
{{< note >}}
윈도우에서, 서비스들의 최대 세션 고정 시간(maximum session sticky time)을 설정하는 것은 지원되지 않는다.
{{< /note >}}
## 멀티-포트 서비스
일부 서비스의 경우, 둘 이상의 포트를 노출해야 한다.
쿠버네티스는 서비스 오브젝트에서 멀티 포트 정의를 구성할 수 있도록 지원한다.
서비스에 멀티 포트를 사용하는 경우, 모든 포트 이름을
명확하게 지정해야 한다.
예를 들면
예를 들면 다음과 같다.
```yaml
apiVersion: v1
@ -455,40 +365,6 @@ CIDR 범위 내의 유효한 IPv4 또는 IPv6 주소여야 한다.
유효하지 않은 clusterIP 주소 값으로 서비스를 생성하려고 하면, API 서버는
422 HTTP 상태 코드를 리턴하여 문제점이 있음을 알린다.
## 트래픽 정책
### 외부 트래픽 정책
`spec.externalTrafficPolicy` 필드를 설정하여 외부 소스에서 오는 트래픽이 어떻게 라우트될지를 제어할 수 있다.
이 필드는 `Cluster` 또는 `Local`로 설정할 수 있다. 필드를 `Cluster`로 설정하면 외부 트래픽을 준비 상태의 모든 엔드포인트로 라우트하며,
`Local`로 설정하면 준비 상태의 노드-로컬 엔드포인트로만 라우트한다. 만약 트래픽 정책이 `Local`로 설정되어 있는데 노드-로컬
엔드포인트가 하나도 없는 경우, kube-proxy는 연관된 서비스로의 트래픽을 포워드하지 않는다.
{{< note >}}
{{< feature-state for_k8s_version="v1.22" state="alpha" >}}
kube-proxy에 대해 `ProxyTerminatingEndpoints`
[기능 게이트](/ko/docs/reference/command-line-tools-reference/feature-gates/)를
활성화하면, kube-proxy는 노드에 로컬 엔드포인트가 있는지,
그리고 모든 로컬 엔드포인트가 "종료 중(terminating)"으로 표시되어 있는지 여부를 확인한다.
만약 로컬 엔드포인트가 존재하는데 **모두**가 종료 중이면, kube-proxy는 `Local`로 설정된 모든 외부 트래픽 정책을 무시한다.
대신, 모든 노드-로컬 엔드포인트가 "종료 중" 상태를 유지하는 동안,
kube-proxy는 마치 외부 트래픽 정책이 `Cluster`로 설정되어 있는 것처럼
그 서비스에 대한 트래픽을 정상 상태의 다른 엔드포인트로 포워드한다.
이러한 종료 중인 엔드포인트에 대한 포워딩 정책은 `NodePort` 서비스로 트래픽을 로드밸런싱하던 외부 로드밸런서가
헬스 체크 노드 포트가 작동하지 않을 때에도 연결들을 비돌발적으로(gracefully) 종료시킬 수 있도록 하기 위해 존재한다.
이러한 정책이 없다면, 노드가 여전히 로드밸런서 노드 풀에 있지만
파드 종료 과정에서 트래픽이 제거(drop)되는 상황에서 트래픽이 유실될 수 있다.
{{< /note >}}
### 내부 트래픽 정책
{{< feature-state for_k8s_version="v1.22" state="beta" >}}
`spec.internalTrafficPolicy` 필드를 설정하여 내부 소스에서 오는 트래픽이 어떻게 라우트될지를 제어할 수 있다.
이 필드는 `Cluster` 또는 `Local`로 설정할 수 있다. 필드를 `Cluster`로 설정하면 내부 트래픽을 준비 상태의 모든 엔드포인트로 라우트하며,
`Local`로 설정하면 준비 상태의 노드-로컬 엔드포인트로만 라우트한다. 만약 트래픽 정책이 `Local`로 설정되어 있는데 노드-로컬
엔드포인트가 하나도 없는 경우, kube-proxy는 트래픽을 포워드하지 않는다.
## 서비스 디스커버리하기
쿠버네티스는 서비스를 찾는 두 가지 기본 모드를 지원한다. - 환경
@ -571,50 +447,57 @@ DNS SRV 쿼리를 수행할 수 있다.
### 셀렉터가 있는 경우
셀렉터를 정의하는 헤드리스 서비스의 경우, 엔드포인트 컨트롤러는
API에서 `엔드포인트` 레코드를 생성하고, DNS 구성을 수정하여
`서비스` 를 지원하는 `파드` 를 직접 가리키는 A 레코드(IP 주소)를 반환한다.
셀렉터를 정의하는 헤드리스 서비스의 경우, 쿠버네티스 컨트롤 플레인은
쿠버네티스 API 내에서 엔드포인트슬라이스 오브젝트를 생성하고,
서비스 하위(backing) 파드들을 직접 가리키는
A 또는 AAAA 레코드(IPv4 또는 IPv6 주소)를 반환하도록 DNS 구성을 변경한다.
### 셀렉터가 없는 경우
셀렉터를 정의하지 않는 헤드리스 서비스의 경우, 엔드포인트 컨트롤러는
`엔드포인트` 레코드를 생성하지 않는다. 그러나 DNS 시스템은 다음 중 하나를 찾고
구성한다.
셀렉터를 정의하지 않는 헤드리스 서비스의 경우,
쿠버네티스 컨트롤 플레인은 엔드포인트슬라이스 오브젝트를 생성하지 않는다.
하지만, DNS 시스템은 다음 중 하나를 탐색한 뒤 구성한다.
* [`ExternalName`](#externalname)-유형 서비스에 대한 CNAME 레코드
* 다른 모든 유형에 대해, 서비스의 이름을 공유하는 모든 `엔드포인트`
대한 레코드
* [`type: ExternalName`](#externalname) 서비스에 대한 DNS CNAME 레코드
* `ExternalName` 이외의 모든 서비스 타입에 대해,
서비스의 활성(ready) 엔드포인트의 모든 IP 주소에 대한 DNS A / AAAA 레코드
* IPv4 엔드포인트에 대해, DNS 시스템은 A 레코드를 생성한다.
* IPv6 엔드포인트에 대해, DNS 시스템은 AAAA 레코드를 생성한다.
## 서비스 퍼블리싱 (ServiceTypes) {#publishing-services-service-types}
애플리케이션 중 일부(예: 프론트엔드)는 서비스를 클러스터 밖에
위치한 외부 IP 주소에 노출하고 싶은 경우가 있을 것이다.
쿠버네티스 `ServiceTypes`는 원하는 서비스 종류를 지정할 수 있도록 해준다.
기본 값은 `ClusterIP`이다.
쿠버네티스 `ServiceTypes`는 원하는 서비스 종류를 지정할 수 있도록 해 준다.
`Type` 값과 그 동작은 다음과 같다.
* `ClusterIP`: 서비스를 클러스터-내부 IP에 노출시킨다. 이 값을 선택하면
클러스터 내에서만 서비스에 도달할 수 있다. 이것은
`ServiceTypes`의 기본 값이다.
* [`NodePort`](#type-nodeport): 고정 포트 (`NodePort`)로 각 노드의 IP에 서비스를
노출시킨다. `NodePort` 서비스가 라우팅되는 `ClusterIP` 서비스가
자동으로 생성된다. `<NodeIP>:<NodePort>`를 요청하여,
클러스터 외부에서
`NodePort` 서비스에 접속할 수 있다.
* `ClusterIP`: 서비스를 클러스터-내부 IP에 노출시킨다.
이 값을 선택하면 클러스터 내에서만 서비스에 도달할 수 있다.
이것은 서비스의 `type`을 명시적으로 지정하지 않았을 때의 기본값이다.
* [`NodePort`](#type-nodeport): 고정 포트 (`NodePort`)로 각 노드의 IP에
서비스를 노출시킨다. 노드 포트를 사용할 수 있도록 하기 위해,
쿠버네티스는 `type: ClusterIP`인 서비스를 요청했을 때와 마찬가지로
클러스터 IP 주소를 구성한다.
* [`LoadBalancer`](#loadbalancer): 클라우드 공급자의 로드 밸런서를 사용하여
서비스를 외부에 노출시킨다. 외부 로드 밸런서가 라우팅되는
`NodePort``ClusterIP` 서비스가 자동으로 생성된다.
* [`ExternalName`](#externalname): 값과 함께 CNAME 레코드를 리턴하여, 서비스를
`externalName` 필드의 콘텐츠 (예:`foo.bar.example.com`)에
매핑한다. 어떤 종류의 프록시도 설정되어 있지 않다.
{{< note >}}`ExternalName` 유형을 사용하려면 kube-dns 버전 1.7 또는
CoreDNS 버전 1.7 이상이 필요하다.
서비스를 외부에 노출시킨다.
* [`ExternalName`](#externalname): 값과 함께 CNAME 레코드를 리턴하여,
서비스를 `externalName` 필드의 내용(예:`foo.bar.example.com`)에 매핑한다.
어떠한 종류의 프록시도 설정되지 않는다.
{{< note >}}
`ExternalName` 유형을 사용하려면 `kube-dns` 버전 1.7 또는
CoreDNS 버전 0.0.8 이상이 필요하다.
{{< /note >}}
`type` 필드는 중첩(nested) 기능으로 설계되어, 각 단계는 이전 단계에 더해지는 형태이다.
이는 모든 클라우드 공급자에 대해 엄격히 요구되는 사항은 아니다(예:
Google Compute Engine에서는 `type: LoadBalancer`가 동작하기 위해 노드 포트를 할당할 필요가 없지만,
다른 클라우드 공급자 통합 시에는 필요할 수 있음).
엄격한 중첩이 필수 사항은 아니지만, 서비스에 대한 쿠버네티스 API 디자인은 이와 상관없이 엄격한 중첩 구조를 가정한다.
[인그레스](/ko/docs/concepts/services-networking/ingress/)를 사용하여 서비스를 노출시킬 수도 있다.
인그레스는 서비스 유형이 아니지만, 클러스터의 진입점 역할을 한다.
인그레스는 서비스 유형 아니지만, 클러스터의 진입점 역할을 한다.
동일한 IP 주소로 여러 서비스를 노출시킬 수 있기 때문에
라우팅 규칙을 단일 리소스로 통합할 수 있다.
@ -625,38 +508,28 @@ API에서 `엔드포인트` 레코드를 생성하고, DNS 구성을 수정하
각 노드는 해당 포트 (모든 노드에서 동일한 포트 번호)를 서비스로 프록시한다.
서비스는 할당된 포트를 `.spec.ports[*].nodePort` 필드에 나타낸다.
포트를 프록시하기 위해 특정 IP를 지정하려면, kube-proxy에 대한
`--nodeport-addresses` 플래그 또는
[kube-proxy 구성 파일](/docs/reference/config-api/kube-proxy-config.v1alpha1/)의
동등한 `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에 대해 사용 가능한 모든 네트워크 인터페이스를 고려해야 한다는 것을 의미한다.
(이는 이전 쿠버네티스 릴리스와도 호환된다).
특정 포트 번호를 원한다면, `nodePort` 필드에 값을 지정할 수
있다. 컨트롤 플레인은 해당 포트를 할당하거나 API 트랜잭션이
실패했다고 보고한다.
이는 사용자 스스로 포트 충돌의 가능성을 고려해야 한다는 의미이다.
또한 NodePort 사용을 위해 구성된 범위 내에 있는, 유효한 포트 번호를
사용해야 한다.
NodePort를 사용하면 자유롭게 자체 로드 밸런싱 솔루션을 설정하거나,
쿠버네티스가 완벽하게 지원하지 않는 환경을 구성하거나,
하나 이상의 노드 IP를 직접 노출시킬 수 있다.
이 서비스는 `<NodeIP>:spec.ports[*].nodePort`
`.spec.clusterIP:spec.ports[*].port`로 표기된다.
kube-proxy에 대한 `--nodeport-addresses` 플래그 또는 kube-proxy 구성 파일의
동등한 필드가 설정된 경우, `<NodeIP>` 는 노드 IP를 필터링한다.
NodePort 서비스에 대해, 쿠버네티스는 포트를 추가로
할당한다(서비스의 프로토콜에 매치되도록 TCP, UDP, SCTP 중 하나).
클러스터의 모든 노드는 할당된 해당 포트를 리슨하고
해당 서비스에 연결된 활성(ready) 엔드포인트 중 하나로 트래픽을 전달하도록 자기 자신을 구성한다.
적절한 프로토콜(예: TCP) 및 적절한 포트(해당 서비스에 할당된 대로)로
클러스터 외부에서 클러스터의 아무 노드에 연결하여 `type: NodePort` 서비스로 접근할 수 있다.
예를 들면
#### 포트 직접 선택하기 {#nodeport-custom-port}
특정 포트 번호를 원한다면, `nodePort` 필드에 값을 명시할 수 있다.
컨트롤 플레인은 해당 포트를 할당해 주거나 또는
해당 API 트랜젝션이 실패했다고 알려줄 것이다.
이는 사용자 스스로 포트 충돌의 가능성을 고려해야 한다는 의미이다.
또한 유효한(NodePort용으로 사용할 수 있도록 구성된 범위 내의)
포트 번호를 사용해야 한다.
다음은 NodePort 값을 명시하는(이 예시에서는 30007)
`type: NodePort` 서비스에 대한 예시 매니페스트이다.
```yaml
apiVersion: v1
@ -676,6 +549,33 @@ spec:
nodePort: 30007
```
#### `type: NodePort` 서비스를 위한 커스텀 IP 주소 구성 {#service-nodeport-custom-listen-address}
NodePort 서비스 노출에 특정 IP 주소를 사용하도록
클러스터의 노드를 설정할 수 있다.
각 노드가 여러 네트워크(예: 애플리케이션 트래픽용 네트워크 및
노드/컨트롤 플레인 간 트래픽용 네트워크)에 연결되어 있는 경우에 이러한 구성을 고려할 수 있다.
포트를 프록시하기 위해 특정 IP를 지정하려면, kube-proxy에 대한
`--nodeport-addresses` 플래그 또는
[kube-proxy 구성 파일](/docs/reference/config-api/kube-proxy-config.v1alpha1/)의
동등한 `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에 대해 사용 가능한 모든 네트워크 인터페이스를 고려해야 한다는 것을 의미한다.
(이는 이전 쿠버네티스 릴리스와도 호환된다).
{{< note >}}
이 서비스는 `<NodeIP>:spec.ports[*].nodePort``.spec.clusterIP:spec.ports[*].port`로 표기된다.
kube-proxy에 대한 `--nodeport-addresses` 플래그 또는 kube-proxy 구성 파일의 동등한 필드가 설정된 경우,
`<NodeIP>` 는 노드 IP를 필터링한다.
{{< /note >}}
### 로드밸런서 유형 {#loadbalancer}
외부 로드 밸런서를 지원하는 클라우드 공급자 상에서, `type`
@ -683,7 +583,7 @@ spec:
로드 밸런서의 실제 생성은 비동기적으로 수행되고,
프로비저닝된 밸런서에 대한 정보는 서비스의
`.status.loadBalancer` 필드에 발행된다.
예를 들면
예를 들면 다음과 같다.
```yaml
apiVersion: v1
@ -714,6 +614,16 @@ status:
클라우드 공급자가 이 기능을 지원하지 않는 경우, 설정한 `loadbalancerIP` 필드는
무시된다.
`type: LoadBalancer`인 서비스를 구현하기 위해,
쿠버네티스는 일반적으로 `type: NodePort` 서비스를 요청했을 때와 동일한 변경사항을 적용하면서 시작한다.
그런 다음 cloud-controller-manager 컴포넌트는
할당된 해당 NodePort로 트래픽을 전달하도록 외부 로드 밸런서를 구성한다.
_알파 기능으로서_, 로드 밸런스된 서비스가 NodePort 할당을
[생략](#load-balancer-nodeport-allocation)하도록 구성할 수 있는데,
이는 클라우드 공급자의 구현이 이를 지원할 때에만 가능하다.
{{< note >}}
**Azure** 에서 사용자 지정 공개(public) 유형 `loadBalancerIP`를 사용하려면, 먼저
@ -1273,211 +1183,34 @@ spec:
- 80.11.12.10
```
## 단점
## 세션 스티킹(stickiness)
VIP용 유저스페이스 프록시를 사용하면 중소 규모의 스케일에서는 동작하지만, 수천 개의
서비스가 포함된 대규모 클러스터로는 확장되지 않는다.
[포털에 대한 독창적인 설계 제안](https://github.com/kubernetes/kubernetes/issues/1107)에 이에 대한 자세한 내용이
있다.
유저스페이스 프록시를 사용하면 서비스에 접근하는 패킷의 소스 IP 주소가
가려진다.
이것은 일종의 네트워크 필터링 (방화벽)을 불가능하게 만든다. iptables
프록시 모드는 클러스터 내
소스 IP를 가리지 않지만, 여전히 로드 밸런서 또는 노드-포트를 통해 오는
클라이언트에 영향을 미친다.
`Type` 필드는 중첩된 기능으로 설계되었다. - 각 레벨은 이전 레벨에
추가된다. 이는 모든 클라우드 공급자에 반드시 필요한 것은 아니지만, (예: Google Compute Engine는
`LoadBalancer`를 작동시키기 위해 `NodePort`를 할당할 필요는 없지만, AWS는 필요하다)
현재 API에는 필요하다.
## 가상 IP 구현 {#the-gory-details-of-virtual-ips}
서비스를 사용하려는 많은 사람들에게 이전 정보가
충분해야 한다. 그러나, 이해가 필요한 부분 뒤에는
많은 일이 있다.
### 충돌 방지 {#avoiding-collisions}
쿠버네티스의 주요 철학 중 하나는 잘못한 것이
없는 경우 실패할 수 있는 상황에 노출되어서는
안된다는 것이다. 서비스 리소스 설계 시, 다른 사람의 포트 선택과
충돌할 경우에 대비해 자신의 포트 번호를 선택하지
않아도 된다. 그것은 격리 실패이다.
서비스에 대한 포트 번호를 선택할 수 있도록 하기 위해,
두 개의 서비스가 충돌하지 않도록 해야 한다.
쿠버네티스는 API 서버에 설정되어 있는 `service-cluster-ip-range` CIDR 범위에서
각 서비스에 고유한 IP 주소를 할당하여 이를 달성한다.
각 서비스가 고유한 IP를 받도록 하기 위해, 내부 할당기는
각 서비스를 만들기 전에 {{< glossary_tooltip term_id="etcd" >}}에서
글로벌 할당 맵을 원자적으로(atomically) 업데이트한다. 서비스가 IP 주소 할당을 가져오려면
레지스트리에 맵 오브젝트가 있어야 하는데, 그렇지 않으면
IP 주소를 할당할 수 없다는 메시지와 함께 생성에 실패한다.
컨트롤 플레인에서, 백그라운드 컨트롤러는 해당 맵을
생성해야 한다. (인-메모리 잠금을 사용하는 이전 버전의 쿠버네티스에서 마이그레이션
지원 필요함) 쿠버네티스는 또한 컨트롤러를 사용하여 유효하지 않은
할당 (예: 관리자 개입으로)을 체크하고 더 이상 서비스에서 사용하지 않는 할당된
IP 주소를 정리한다.
#### `type: ClusterIP` 서비스의 IP 주소 범위 {#service-ip-static-sub-range}
{{< feature-state for_k8s_version="v1.25" state="beta" >}}
그러나, 이러한 `ClusterIP` 할당 전략에는 한 가지 문제가 있는데,
그것은 사용자 또한 [서비스의 IP 주소를 직접 고를 수 있기 때문이다](#choosing-your-own-ip-address).
이로 인해 만약 내부 할당기(allocator)가 다른 서비스에 대해 동일한 IP 주소를 선택하면
충돌이 발생할 수 있다.
`ServiceIPStaticSubrange`
[기능 게이트](/ko/docs/reference/command-line-tools-reference/feature-gates/)는 v1.25 이상에서 기본적으로 활성화되며,
이 때 사용하는 할당 전략은 `min(max(16, cidrSize / 16), 256)` 공식을 사용하여 얻어진
`service-cluster-ip-range`의 크기에 기반하여 `ClusterIP` 범위를 두 대역으로 나누며,
여기서 이 공식은 _16 이상 256 이하이며, 그 사이에 계단 함수가 있음_ 으로 설명할 수 있다.
동적 IP 할당은 상위 대역에서 우선적으로 선택하며,
이를 통해 하위 대역에서 할당된 IP와의 충돌 위험을 줄인다.
이렇게 함으로써 사용자가 서비스의 고정 IP를
`service-cluster-ip-range`의 하위 대역에서 할당하면서도
충돌 위험을 줄일 수 있다.
### 서비스 IP 주소 {#ips-and-vips}
실제로 고정된 목적지로 라우팅되는 파드 IP 주소와 달리,
서비스 IP는 실제로 단일 호스트에서 응답하지 않는다. 대신에, kube-proxy는
iptables (리눅스의 패킷 처리 로직)를 필요에 따라
명백하게 리다이렉션되는 _가상_ IP 주소를 정의하기 위해 사용한다. 클라이언트가 VIP에
연결하면, 트래픽이 자동으로 적절한 엔드포인트로 전송된다.
환경 변수와 서비스 용 DNS는 실제로 서비스의
가상 IP 주소 (및 포트)로 채워진다.
kube-proxy는 조금씩 다르게 작동하는 세 가지 프록시 모드&mdash;유저스페이스, iptables and IPVS&mdash;
지원한다.
#### 유저스페이스 (Userspace)
예를 들어, 위에서 설명한 이미지 처리 애플리케이션을 고려한다.
백엔드 서비스가 생성되면, 쿠버네티스 마스터는 가상
IP 주소(예 : 10.0.0.1)를 할당한다. 서비스 포트를 1234라고 가정하면, 서비스는
클러스터의 모든 kube-proxy 인스턴스에서 관찰된다.
프록시가 새 서비스를 발견하면, 새로운 임의의 포트를 열고, 가상 IP 주소에서
이 새로운 포트로 iptables 리다이렉션을 설정한 후,
연결을 수락하기 시작한다.
클라이언트가 서비스의 가상 IP 주소에 연결하면, iptables
규칙이 시작되고, 패킷을 프록시의 자체 포트로 리다이렉션한다.
"서비스 프록시"는 백엔드를 선택하고, 클라이언트에서 백엔드로의 트래픽을 프록시하기 시작한다.
이는 서비스 소유자가 충돌 위험 없이 원하는 어떤 포트든 선택할 수 있음을
의미한다. 클라이언트는 실제로 접근하는 파드를 몰라도, IP와 포트에
연결할 수 있다.
#### iptables
다시 한번, 위에서 설명한 이미지 처리 애플리케이션을 고려한다.
백엔드 서비스가 생성되면, 쿠버네티스 컨트롤 플레인은 가상
IP 주소(예 : 10.0.0.1)를 할당한다. 서비스 포트를 1234라고 가정하면, 서비스는
클러스터의 모든 kube-proxy 인스턴스에서 관찰된다.
프록시가 새로운 서비스를 발견하면, 가상 IP 주소에서 서비스-별 규칙으로
리다이렉션되는 일련의 iptables 규칙을 설치한다. 서비스-별
규칙은 트래픽을 (목적지 NAT를 사용하여) 백엔드로 리다이렉션하는 엔드포인트-별 규칙에
연결한다.
클라이언트가 서비스의 가상 IP 주소에 연결하면 iptables 규칙이 시작한다.
(세션 어피니티(Affinity)에 따라 또는 무작위로) 백엔드가 선택되고 패킷이
백엔드로 리다이렉션된다. 유저스페이스 프록시와 달리, 패킷은 유저스페이스로
복사되지 않으며, 가상 IP 주소가 작동하기 위해 kube-proxy가
실행 중일 필요는 없으며, 노드는 변경되지 않은 클라이언트 IP 주소에서 오는
트래픽을 본다.
트래픽이 노드-포트 또는 로드 밸런서를 통해 들어오는 경우에도,
이와 동일한 기본 흐름이 실행되지만, 클라이언트 IP는 변경된다.
#### IPVS
iptables 작업은 대규모 클러스터 (예: 10,000 서비스)에서 크게 느려진다.
IPVS는 로드 밸런싱을 위해 설계되었고 커널-내부 해시 테이블을 기반으로 한다.
따라서 IPVS 기반 kube-proxy로부터 많은 개수의 서비스에서 일관성 있는 성능을 가질 수 있다.
한편, IPVS 기반 kube-proxy는 보다 정교한 로드 밸런싱 알고리즘
(least conns, locality, weighted, persistence)을 가진다.
특정 클라이언트로부터의 연결이 매번 동일한 파드로 전달되도록 하고 싶다면,
클라이언트의 IP 주소 기반으로 세션 어피니티를 구성할 수 있다.
더 자세한 정보는 [세션 어피니티](/docs/reference/networking/virtual-ips/#session-affinity)를
참고한다.
## API 오브젝트
서비스는 쿠버네티스 REST API의 최상위 리소스이다. [서비스 API 오브젝트](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#service-v1-core)에 대한
자세한 내용을 참고할 수 있다.
## 지원되는 프로토콜 {#protocol-support}
<!-- preserve existing hyperlinks -->
<a id="shortcomings" /><a id="#the-gory-details-of-virtual-ips" />
### TCP
## 가상 IP 주소 메커니즘
모든 종류의 서비스에 TCP를 사용할 수 있으며, 이는 기본 네트워크 프로토콜이다.
### UDP
대부분의 서비스에 UDP를 사용할 수 있다. type=LoadBalancer 서비스의 경우, UDP 지원은
이 기능을 제공하는 클라우드 공급자에 따라 다르다.
### SCTP
{{< feature-state for_k8s_version="v1.20" state="stable" >}}
SCTP 트래픽을 지원하는 네트워크 플러그인을 사용하는 경우 대부분의 서비스에 SCTP를 사용할 수 있다.
type=LoadBalancer 서비스의 경우 SCTP 지원은 이 기능을 제공하는
클라우드 공급자에 따라 다르다. (대부분 그렇지 않음)
#### 경고 {#caveat-sctp-overview}
##### 멀티홈드(multihomed) SCTP 연결을 위한 지원 {#caveat-sctp-multihomed}
{{< warning >}}
멀티홈 SCTP 연결을 위해서는 먼저 CNI 플러그인이 파드에 대해
멀티 인터페이스 및 IP 주소 할당이 지원되어야 한다.
멀티홈 SCTP 연결을 위한 NAT는 해당 커널 모듈 내에 특수한 로직을 필요로 한다.
{{< /warning >}}
##### 윈도우 {#caveat-sctp-windows-os}
{{< warning >}}
SCTP는 윈도우 기반 노드를 지원하지 않는다.
{{< /warning >}}
##### 유저스페이스 kube-proxy {#caveat-sctp-kube-proxy-userspace}
{{< warning >}}
kube-proxy는 유저스페이스 모드에 있을 때 SCTP 연결 관리를 지원하지 않는다.
{{< /warning >}}
### HTTP
클라우드 공급자가 이를 지원하는 경우, LoadBalancer 모드의
서비스를 사용하여 서비스의 엔드포인트로 전달하는 외부 HTTP / HTTPS 리버스 프록시를
설정할 수 있다.
{{< note >}}
서비스 대신 {{< glossary_tooltip term_id="ingress" text="인그레스" >}} 를 사용하여
HTTP/HTTPS 서비스를 노출할 수도 있다.
{{< /note >}}
### PROXY 프로토콜
클라우드 공급자가 지원하는 경우에,
LoadBalancer 모드의 서비스를 사용하여 쿠버네티스 자체 외부에
로드 밸런서를 구성할 수 있으며, 이때 접두사가
[PROXY 프로토콜](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) 인 연결을 전달하게 된다.
로드 밸런서는 들어오는 연결을 설명하는 초기 일련의
옥텟(octets)을 전송하며, 이 예와 유사하게
```
PROXY TCP4 192.0.2.202 10.0.42.7 12345 7\r\n
```
클라이언트 데이터가 뒤따라온다.
[가상 IP 및 서비스 프록시](/ko/docs/reference/networking/virtual-ips/)에서
가상 IP 주소를 갖는 서비스를 노출하기 위해 쿠버네티스가 제공하는 메커니즘에 대해 알아본다.
## {{% heading "whatsnext" %}}
* [서비스와 애플리케이션 연결](/ko/docs/concepts/services-networking/connect-applications-service/) 알아보기
* [인그레스](/ko/docs/concepts/services-networking/ingress/)에 대해 알아보기
* [엔드포인트슬라이스](/ko/docs/concepts/services-networking/endpoint-slices/)에 대해 알아보기
추가적으로,
* [가상 IP 및 서비스 프록시](/ko/docs/reference/networking/virtual-ips/)를 살펴보기
* 서비스(Service) API에 대한 [API 레퍼런스](/docs/reference/kubernetes-api/service-resources/service-v1/) 살펴보기
* 엔드포인트(Endpoints) API에 대한 [API 레퍼런스](/docs/reference/kubernetes-api/service-resources/endpoints-v1/) 살펴보기
* 엔드포인트슬라이스 API에 대한 [API 레퍼런스](/docs/reference/kubernetes-api/service-resources/endpoint-slice-v1/) 살펴보기

View File

@ -0,0 +1,11 @@
---
title: 네트워킹 레퍼런스
content_type: reference
weight: 85
---
<!-- overview -->
이 섹션에서는
쿠버네티스 네트워킹의 레퍼런스 상세를 제공한다.
<!-- body -->

View File

@ -1,7 +1,7 @@
---
title: 포트와 프로토콜
content_type: reference
weight: 50
weight: 40
---
물리적 네트워크 방화벽이 있는 온프레미스 데이터 센터 또는

View File

@ -0,0 +1,122 @@
---
title: 서비스가 지원하는 프로토콜
content_type: reference
weight: 10
---
<!-- overview -->
{{< glossary_tooltip text="서비스" term_id="service" >}}를 구성하여,
쿠버네티스가 지원하는 네트워크 프로토콜 중 하나를 선택할 수 있다.
쿠버네티스는 서비스에 대해 다음의 프로토콜을 지원한다.
- [`SCTP`](#protocol-sctp)
- [`TCP`](#protocol-tcp) _(기본값)_
- [`UDP`](#protocol-udp)
서비스를 정의할 때, 서비스가 사용할
[애플리케이션 프로토콜](/ko/docs/concepts/services-networking/service/#애플리케이션-프로토콜)을
지정할 수도 있다.
이 문서에서는 몇 가지 특수 사례에 대해 설명하며,
이들 모두는 일반적으로 전송 프로토콜(transport protocol)로 TCP를 사용한다.
- [HTTP](#protocol-http-special) 및 [HTTPS](#protocol-http-special)
- [PROXY 프로토콜](#protocol-proxy-special)
- 로드밸런서에서의 [TLS](#protocol-tls-special) 터미네이션
<!-- body -->
## 지원하는 프로토콜 {#protocol-support}
서비스 포트의 `protocol`에 대해 다음 3개의 값이 유효하다.
### `SCTP` {#protocol-sctp}
{{< feature-state for_k8s_version="v1.20" state="stable" >}}
SCTP 트래픽을 지원하는 네트워크 플러그인을 사용하는 경우, 대부분의 서비스에
SCTP를 사용할 수 있다. `type: LoadBalancer` 서비스의 경우 SCTP 지원 여부는
이 기능을 제공하는 클라우드 공급자에 따라 다르다. (대부분 지원하지 않음)
SCTP는 윈도우 노드에서는 지원되지 않는다.
#### 멀티홈(multihomed) SCTP 연결 지원 {#caveat-sctp-multihomed}
멀티홈 SCTP 연결 지원을 위해서는 CNI 플러그인이 파드에 복수개의 인터페이스 및 IP 주소를 할당하는 기능을 지원해야 한다.
멀티홈 SCTP 연결에서의 NAT는 상응하는 커널 모듈 내의 특수한 로직을 필요로 한다.
### `TCP` {#protocol-tcp}
모든 종류의 서비스에 TCP를 사용할 수 있으며, 이는 기본 네트워크 프로토콜이다.
### `UDP` {#protocol-udp}
대부분의 서비스에 UDP를 사용할 수 있다. `type: LoadBalancer` 서비스의 경우,
UDP 지원 여부는 이 기능을 제공하는 클라우드 공급자에 따라 다르다.
## 특수 케이스
### HTTP {#protocol-http-special}
클라우드 공급자가 이를 지원하는 경우,
LoadBalancer 모드의 서비스를 사용하여,
쿠버네티스 클러스터 외부에, HTTP / HTTPS 리버스 프록싱을 통해
해당 서비스의 백엔드 엔드포인트로 트래픽을 전달하는 로드밸런서를 구성할 수 있다.
일반적으로, 트래픽을 HTTP 수준에서 제어하려면
해당 서비스의 프로토콜을 `TCP`로 지정하고
로드밸런서를 구성하는
{{< glossary_tooltip text="어노테이션" term_id="annotation" >}}(보통
클라우드 공급자마다 다름)을 추가한다.
이 구성은 워크로드로의 HTTPS (HTTP over TLS) 지원 및 평문 HTTP 리버스 프록시도 포함할 수 있다.
{{< note >}}
서비스 대신 {{< glossary_tooltip term_id="ingress" text="인그레스" >}} 를 사용하여
HTTP/HTTPS 서비스를 노출할 수도 있다.
{{< /note >}}
특정 연결의
[애플리케이션 프로토콜](/ko/docs/concepts/services-networking/service/#애플리케이션-프로토콜)을
`http` 또는 `https`로 추가적으로 명시하고 싶을 수도 있다.
로드밸런서에서 워크로드로 가는 세션이 HTTP without TLS이면 `http`를 사용하고,
로드밸런서에서 워크로드로 가는 세션이 TLS 암호화를 사용하면 `https`를 사용한다.
### PROXY 프로토콜 {#protocol-proxy-special}
클라우드 공급자가 지원하는 경우에,
`type: LoadBalancer`로 설정된 서비스를 사용하여,
쿠버네티스 외부에 존재하면서 연결들을
[PROXY 프로토콜](https://www.haproxy.org/download/2.5/doc/proxy-protocol.txt)로 감싸 전달하는 로드밸런서를 구성할 수 있다.
이러한 로드 밸런서는 들어오는 연결을 설명하는 초기 일련의 옥텟(octets)을 전송하며,
이는 다음의 예시(PROXY 프로토콜 v1)와 유사하다.
```
PROXY TCP4 192.0.2.202 10.0.42.7 12345 7\r\n
```
프록시 프로토콜 프리앰블(preamble) 뒤에 오는 데이터는
클라이언트가 전송한 원본 데이터이다.
양쪽 중 한쪽에서 연결을 닫으면,
로드밸런서도 연결 종료를 트리거하며 남아있는 데이터를 수신 가능한 쪽으로 보낸다.
일반적으로는, 프로토콜을 `TCP`로 설정한 서비스를 정의한다.
또한, 클라우드 공급자별로 상이한 어노테이션을 설정하여
로드밸런서가 각 인커밍 연결을 PROXY 프로토콜로 감싸도록 구성할 수도 있다.
### TLS {#protocol-tls-special}
클라우드 공급자가 지원하는 경우에,
`type: LoadBalancer`로 설정된 서비스를 사용하여,
쿠버네티스 외부에 존재하는 리버스 프록시를 구축할 수 있으며,
이 때 클라이언트로부터 로드밸런서까지의 연결은 TLS 암호화되고 로드밸런서는 TLS 서버 피어가 된다.
로드밸런서로부터 워크로드까지의 연결은 TLS일 수도 있으며, 평문일 수도 있다.
사용 가능한 정확한 옵션의 범위는 클라우드 공급자 또는 커스텀 서비스 구현에 따라 다를 수 있다.
일반적으로는, 프로토콜을 `TCP`로 설정하고
어노테이션(보통 클라우드 공급자별로 상이함)을 설정하여
로드밸런서가 TLS 서버로 작동하도록 구성한다.
클라우드 공급자별로 상이한 메커니즘을 사용하여
TLS 아이덴티티(서버, 그리고 경우에 따라 워크로드로 연결하는 클라이언트도 가능)를 구성할 수도 있다.

View File

@ -0,0 +1,284 @@
---
title: 가상 IP 및 서비스 프록시
content_type: reference
weight: 50
---
<!-- overview -->
쿠버네티스 클러스터의 모든 {{< glossary_tooltip term_id="node" text="노드" >}}는
[`kube-proxy`](/ko/docs/reference/command-line-tools-reference/kube-proxy/)를
실행한다(`kube-proxy`를 대체하는 구성요소를 직접 배포한 경우가 아니라면).
`kube-proxy`
[`ExternalName`](/docs/concepts/services-networking/service/#externalname) 외의 `type`
{{< glossary_tooltip term_id="service" text="서비스">}}를 위한
_가상 IP_ 메커니즘의 구현을 담당한다.
항상 발생하는 질문은,
왜 쿠버네티스가 인바운드 트래픽을 백엔드로 전달하기 위해
프록시에 의존하는가 하는 점이다.
다른 접근법이 있는가? 예를 들어, 여러 A 값 (또는 IPv6의 경우 AAAA)을 가진 DNS 레코드를 구성하고,
라운드-로빈 이름 확인 방식을 취할 수 있는가?
There are a few reasons for using proxying for Services:
* 레코드 TTL을 고려하지 않고, 만료된 이름 검색 결과를 캐싱하는
DNS 구현에 대한 오래된 역사가 있다.
* 일부 앱은 DNS 검색을 한 번만 수행하고 결과를 무기한으로 캐시한다.
* 앱과 라이브러리가 적절히 재-확인을 했다고 하더라도,
DNS 레코드의 TTL이 낮거나 0이면
DNS에 부하가 높아 관리하기가 어려워질 수 있다.
본 페이지의 뒷 부분에서 다양한 kube-proxy 구현이 동작하는 방식에 대해 읽을 수 있다.
우선 알아두어야 할 것은, `kube-proxy`를 구동할 때,
커널 수준의 규칙이 수정(예를 들어, iptables 규칙이 생성될 수 있음)될 수 있고,
이는 때로는 리부트 전까지 정리되지 않을 수도 있다.
그래서, kube-proxy는 컴퓨터에서 저수준의, 특권을 가진(privileged) 네트워킹 프록시 서비스가 구동됨으로써 발생하는
결과를 이해하고 있는 관리자에 의해서만 구동되어야 한다.
비록 `kube-proxy` 실행 파일이 `cleanup` 기능을 지원하기는 하지만,
이 기능은 공식적인 기능이 아니기 때문에 구현된 그대로만 사용할 수 있다.
<a id="example"></a>
예를 들어, 3개의 레플리카로 실행되는 스테이트리스 이미지-처리 백엔드를 생각해보자.
이러한 레플리카는 대체 가능하다.
즉, 프론트엔드는 그것들이 사용하는 백엔드를 신경쓰지 않는다.
백엔드 세트를 구성하는 실제 파드는 변경될 수 있지만,
프론트엔드 클라이언트는 이를 인식할 필요가 없으며, 백엔드 세트 자체를 추적해야 할 필요도 없다.
<!-- body -->
## 프록시 모드들
kube-proxy는 여러 모드 중 하나로 기동될 수 있으며, 이는 환경 설정에 따라 결정됨에 유의한다.
- kube-proxy의 구성은 컨피그맵(ConfigMap)을 통해 이루어진다.
그리고 해당 kube-proxy를 위한 컨피그맵은 실효성있게
거의 대부분의 kube-proxy의 플래그의 행위를 더 이상 사용하지 않도록 한다.
- kube-proxy를 위한 해당 컨피그맵은 기동 중 구성의 재적용(live reloading)은 지원하지 않는다.
- kube-proxy를 위한 컨피그맵 파라미터는 기동 시에 검증이나 확인을 하지 않는다.
예를 들어, 운영 체계가 iptables 명령을 허용하지 않을 경우,
표준 커널 kube-proxy 구현체는 작동하지 않을 것이다.
### `iptables` 프록시 모드 {#proxy-mode-iptables}
이 모드에서는, kube-proxy는 쿠버네티스 컨트롤 플레인의
서비스, 엔드포인트슬라이스 오브젝트의 추가와 제거를 감시한다.
각 서비스에 대해, 서비스의 `clusterIP``port`에 대한 트래픽을 캡처하고
해당 트래픽을 서비스의 백엔드 세트 중 하나로 리다이렉트(redirect)하는
iptables 규칙을 설치한다.
각 엔드포인트 오브젝트에 대해, 백엔드 파드를 선택하는 iptables 규칙을 설치한다.
기본적으로, iptables 모드의 kube-proxy는 백엔드를 임의로 선택한다.
트래픽을 처리하기 위해 iptables를 사용하면 시스템 오버헤드가 줄어드는데,
유저스페이스와 커널 스페이스 사이를 전환할 필요없이 리눅스 넷필터(netfilter)가
트래픽을 처리하기 때문이다. 이 접근 방식은 더 신뢰할 수 있기도 하다.
kube-proxy가 iptables 모드에서 실행 중이고 선택된 첫 번째 파드가 응답하지 않으면, 연결이 실패한다.
이는 이전의 `userspace` 모드와 다르다.
이전의 `userspace` 시나리오에서는,
kube-proxy는 첫 번째 파드에 대한 연결이 실패했음을 감지하고 다른 백엔드 파드로 자동으로 재시도한다.
파드 [준비성 프로브(readiness probe)](/ko/docs/concepts/workloads/pods/pod-lifecycle/#컨테이너-프로브-probe)를 사용하여
백엔드 파드가 제대로 작동하는지 확인할 수 있으므로,
iptables 모드의 kube-proxy는 정상으로 테스트된 백엔드만 볼 수 있다.
이렇게 하면 트래픽이 kube-proxy를 통해 실패한 것으로 알려진 파드로 전송되는 것을 막을 수 있다.
{{< figure src="/images/docs/services-iptables-overview.svg" title="iptables 프록시에 대한 서비스 개요 다이어그램" class="diagram-medium" >}}
#### 예시 {#packet-processing-iptables}
다시 한번, [](#example)에서 설명한
이미지 처리 애플리케이션을 고려한다.
백엔드 서비스가 생성되면,
쿠버네티스 컨트롤 플레인은 가상 IP 주소(예 : 10.0.0.1)를 할당한다.
서비스 포트를 1234라고 가정하자.
클러스터의 모든 kube-proxy 인스턴스는
새 서비스의 생성을 관찰할 수 있다.
프록시가 새로운 서비스를 발견하면,
가상 IP 주소에서 서비스-별 규칙으로 리다이렉션되는 일련의 iptables 규칙을 설치한다.
서비스-별 규칙은 트래픽을 (목적지 NAT를 사용하여) 백엔드로 리다이렉션하는
엔드포인트-별 규칙에 연결한다.
클라이언트가 서비스의 가상 IP 주소에 연결하면 iptables 규칙이 시작한다.
(세션 어피니티(Affinity)에 따라 또는 무작위로) 백엔드가 선택되고,
패킷의 클라이언트 IP 주소를 덮어쓰지 않고 백엔드로 리다이렉션된다.
트래픽이 노드-포트 또는 로드 밸런서를 통해 들어오는 경우에도,
이와 동일한 기본 흐름이 실행되지만, 클라이언트 IP는 변경된다.
### IPVS 프록시 모드 {#proxy-mode-ipvs}
`ipvs` 모드에서, kube-proxy는 쿠버네티스 서비스와 엔드포인트슬라이스를 감시하고,
`netlink` 인터페이스를 호출하여 그에 따라 IPVS 규칙을 생성하고
IPVS 규칙을 쿠버네티스 서비스 및 엔드포인트슬라이스와 주기적으로 동기화한다.
이 제어 루프는 IPVS 상태가 원하는 상태와 일치하도록
보장한다.
서비스에 접근하면, IPVS는 트래픽을 백엔드 파드 중 하나로 보낸다.
IPVS 프록시 모드는 iptables 모드와 유사한 넷필터 후크 기능을
기반으로 하지만, 해시 테이블을 기본 데이터 구조로 사용하고
커널 스페이스에서 동작한다.
이는 IPVS 모드의 kube-proxy는 iptables 모드의 kube-proxy보다
지연 시간이 짧은 트래픽을 리다이렉션하고, 프록시 규칙을 동기화할 때 성능이
훨씬 향상됨을 의미한다. 다른 프록시 모드와 비교했을 때, IPVS 모드는
높은 네트워크 트래픽 처리량도 지원한다.
IPVS는 트래픽을 백엔드 파드로 밸런싱하기 위한 추가 옵션을 제공하며,
그 목록은 다음과 같다.
* `rr`: 라운드-로빈
* `lc`: 최소 연결 (가장 적은 수의 열려있는 연결)
* `dh`: 목적지 해싱
* `sh`: 소스 해싱
* `sed`: 최단 예상 지연 (shortest expected delay)
* `nq`: 큐 미사용 (never queue)
{{< note >}}
IPVS 모드에서 kube-proxy를 실행하려면, kube-proxy를 시작하기 전에 노드에서 IPVS를
사용 가능하도록 해야 한다.
kube-proxy가 IPVS 프록시 모드로 시작될 때, IPVS 커널 모듈이
사용 가능한지 확인한다. IPVS 커널 모듈이 감지되지 않으면, kube-proxy는
iptables 프록시 모드로 다시 실행된다.
{{< /note >}}
{{< figure src="/images/docs/services-ipvs-overview.svg" title="IPVS 프록시에 대한 서비스 개요 다이어그램" class="diagram-medium" >}}
## 세션 어피니티
이러한 프록시 모델에서,
클라이언트가 쿠버네티스/서비스/파드에 대해 전혀 모르더라도
서비스의 IP:포트로 향하는 트래픽은 적절한 백엔드로 프록시된다.
특정 클라이언트의 연결이 매번 동일한 파드로
전달되도록 하려면, 서비스의 `.spec.sessionAffinity``ClientIP`로 설정하여
클라이언트의 IP 주소를 기반으로 세션 어피니티를 선택할 수 있다.
(기본값은 `None`)
### 세션 고정(Session stickiness) 타임아웃
서비스의 `.spec.sessionAffinityConfig.clientIP.timeoutSeconds`를 적절히 설정하여
최대 세션 고정 시간을 설정할 수도 있다.
(기본값은 10800으로, 이는 3시간에 해당됨)
{{< note >}}
윈도우에서는, 서비스의 최대 세션 고정 시간(maximum session sticky time)을 설정하는 것이 지원되지 않는다.
{{< /note >}}
## 서비스에 IP 주소 할당
고정된 목적지로 실제로 라우팅되는 파드 IP 주소와 달리,
서비스 IP는 실제로는 단일 호스트에서 응답하지 않는다.
대신에, kube-proxy는 패킷 처리 로직(예: 리눅스의 iptables)을 사용하여,
필요에 따라 투명하게 리다이렉션되는 _가상_ IP 주소를 정의한다.
클라이언트가 VIP에 연결하면, 트래픽이 자동으로 적절한 엔드포인트로 전송된다.
환경 변수와 서비스 용 DNS는
실제로는 서비스의 가상 IP 주소 (및 포트)로 채워진다.
### 충돌 방지하기
쿠버네티스의 주요 철학 중 하나는,
사용자가 잘못한 것이 없는 경우에는 실패할 수 있는 상황에 노출되어서는 안된다는 것이다.
서비스 리소스 설계 시,
다른 사람의 포트 선택과 충돌할 경우에 대비해 자신의 포트 번호를 선택하지 않아도 된다.
만약 그러한 일이 발생한다면 그것은 격리 실패이다.
서비스에 대한 포트 번호를 사용자가 선택할 수 있도록 하려면,
두 개의 서비스가 충돌하지 않도록 해야 한다.
쿠버네티스는 API 서버에 설정되어 있는 `service-cluster-ip-range` CIDR 범위에서
각 서비스에 고유한 IP 주소를 할당하여 이를 달성한다.
각 서비스가 고유한 IP를 받도록 하기 위해, 각 서비스를 만들기 전에 내부 할당기가
{{< glossary_tooltip term_id="etcd" >}}에서
글로벌 할당 맵을 원자적으로(atomically) 업데이트한다.
서비스가 IP 주소 할당을 가져오려면 레지스트리에 맵 오브젝트가 있어야 하는데,
그렇지 않으면 IP 주소를 할당할 수 없다는 메시지와 함께 생성에 실패한다.
컨트롤 플레인에서, 백그라운드 컨트롤러는 해당 맵을 생성해야
한다(인-메모리 잠금을 사용하는 이전 버전의 쿠버네티스에서의 마이그레이션 지원을 위해 필요함).
쿠버네티스는 또한 컨트롤러를 사용하여 유효하지 않은
할당(예: 관리자 개입에 의한)을 체크하고
더 이상 어떠한 서비스도 사용하지 않는 할당된 IP 주소를 정리한다.
#### 서비스 가상 IP 주소의 IP 주소 범위 {#service-ip-static-sub-range}
{{< feature-state for_k8s_version="v1.25" state="beta" >}}
쿠버네티스는 `min(max(16, cidrSize / 16), 256)` 공식을 사용하여 얻어진
`service-cluster-ip-range`의 크기에 기반하여 `ClusterIP` 범위를 두 대역으로 나누며,
여기서 이 공식은 _16 이상 256 이하이며,
그 사이에 계단 함수가 있음_ 으로 설명할 수 있다.
쿠버네티스는 서비스에 대한 동적 IP 할당 시 상위 대역에서 우선적으로 선택하며,
이는 곧 만약 사용자가 `type: ClusterIP` 서비스에 특정 IP 주소를 할당하고 싶다면
**하위** 대역에서 골라야 함을 의미한다.
이렇게 함으로써 할당 시 충돌의 위험을 줄일 수 있다.
만약 `ServiceIPStaticSubrange`
[기능 게이트](/ko/docs/reference/command-line-tools-reference/feature-gates/)를 비활성화하면
쿠버네티스는 `type: ClusterIP` 서비스에 대해
수동 및 동적 할당 IP 주소를 위한 하나의 공유되는 풀을 사용한다.
## 트래픽 폴리시
`.spec.internalTrafficPolicy``.spec.externalTrafficPolicy` 필드를 설정하여
쿠버네티스가 트래픽을 어떻게 정상(healthy, “ready”) 백엔드로 라우팅할지를 제어할 수 있다.
### 내부 트래픽 폴리시
{{< feature-state for_k8s_version="v1.22" state="beta" >}}
`spec.internalTrafficPolicy` 필드를 설정하여 내부 소스에서 오는 트래픽이 어떻게 라우트될지를 제어할 수 있다.
이 필드는 `Cluster` 또는 `Local`로 설정할 수 있다.
필드를 `Cluster`로 설정하면 내부 트래픽을 준비 상태의 모든 엔드포인트로 라우트하며,
`Local`로 설정하면 준비 상태의 노드-로컬 엔드포인트로만 라우트한다.
만약 트래픽 정책이 `Local`로 설정되어 있는데 노드-로컬 엔드포인트가 하나도 없는 경우, kube-proxy는 트래픽을 드롭시킨다.
### 외부 트래픽 폴리시
`spec.externalTrafficPolicy` 필드를 설정하여 외부 소스에서 오는 트래픽이 어떻게 라우트될지를 제어할 수 있다.
이 필드는 `Cluster` 또는 `Local`로 설정할 수 있다.
필드를 `Cluster`로 설정하면 외부 트래픽을 준비 상태의 모든 엔드포인트로 라우트하며,
`Local`로 설정하면 준비 상태의 노드-로컬 엔드포인트로만 라우트한다.
만약 트래픽 정책이 `Local`로 설정되어 있는데 노드-로컬 엔드포인트가 하나도 없는 경우,
kube-proxy는 연관된 서비스로의 트래픽을 포워드하지 않는다.
### 종료 중인 엔드포인트로 가는 트래픽
{{< feature-state for_k8s_version="v1.26" state="beta" >}}
kube-proxy에 대해 `ProxyTerminatingEndpoints`
[기능 게이트](/ko/docs/reference/command-line-tools-reference/feature-gates/)가 활성화되어 있고
트래픽 폴리시가 `Local`이면,
해당 노드의 kube-proxy는 서비스에 대한 엔드포인트를 선택할 때 좀 더 복잡한 알고리즘을 사용한다.
이 기능이 활성화되어 있으면, kube-proxy는 노드가 로컬 엔드포인트를 갖고 있는지,
그리고 모든 로컬 엔드포인트가 '종료 중'으로 표시되어 있는지 여부를 확인한다.
만약 로컬 엔드포인트가 존재하고 **모든** 로컬 엔드포인트가 종료 중이면,
kube-proxy는 종료 중인 해당 엔드포인트로 트래픽을 전달한다.
이외의 경우, kube-proxy는 종료 중이 아닌 엔드포인트로 트래픽을 전달하는 편을 선호한다.
종료 중인 엔드포인트에 대한 이러한 포워딩 정책 덕분에, `externalTrafficPolicy: Local`을 사용하는 경우에
`NodePort``LoadBalancer` 서비스가 연결들을 자비롭게(gracefully) 종료시킬 수 있다.
디플로이먼트가 롤링 업데이트될 때, 로드밸런서 뒤에 있는 노드가 해당 디플로이먼트의 레플리카를 N개에서 0개 갖도록 변경될 수 있다.
일부 경우에, 외부 로드 밸런서가 헬스 체크 프로브 사이의 기간에 레플리카 0개를 갖는 노드로 트래픽을 전송할 수 있다.
종료 중인 엔드포인트로의 트래픽 라우팅 기능을 통해
파드를 스케일 다운 중인 노드가 해당 종료 중인 파드로의 트래픽을 자비롭게 수신 및 드레인할 수 있다.
파드 종료가 완료되면, 외부 로드 밸런서는 이미 노드의 헬스 체크가 실패했음을 확인하고
해당 노드를 백엔드 풀에서 완전히 제거했을 것이다.
## {{% heading "whatsnext" %}}
서비스에 대해 더 알아보려면,
[서비스와 애플리케이션 연결](/ko/docs/concepts/services-networking/connect-applications-service/)을 읽어 본다.
또한,
* [서비스](/ko/docs/concepts/services-networking/service/)에 대해 읽어 본다.
* 서비스 API에 대한 [API 레퍼런스](/docs/reference/kubernetes-api/service-resources/service-v1/)를 읽어 본다.