[ko] Update outdated files in dev-1.26-ko.1 M67
parent
5ae3aaab5b
commit
5c6199cb0c
|
@ -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는 조금씩 다르게 작동하는 세 가지 프록시 모드—유저스페이스, iptables and IPVS—를
|
||||
지원한다.
|
||||
|
||||
#### 유저스페이스 (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/) 살펴보기
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: 네트워킹 레퍼런스
|
||||
content_type: reference
|
||||
weight: 85
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
이 섹션에서는
|
||||
쿠버네티스 네트워킹의 레퍼런스 상세를 제공한다.
|
||||
|
||||
<!-- body -->
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: 포트와 프로토콜
|
||||
content_type: reference
|
||||
weight: 50
|
||||
weight: 40
|
||||
---
|
||||
|
||||
물리적 네트워크 방화벽이 있는 온프레미스 데이터 센터 또는
|
|
@ -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 아이덴티티(서버, 그리고 경우에 따라 워크로드로 연결하는 클라이언트도 가능)를 구성할 수도 있다.
|
|
@ -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/)를 읽어 본다.
|
Loading…
Reference in New Issue