Merge pull request #33911 from jihoon-seo/220523_ko_Update_outdated_dev-1.24-ko.1_M32-M33
[ko] Update outdated files in `dev-1.24-ko.1` (M32-M33)pull/34385/head
commit
4efa91f00c
|
@ -1,18 +1,122 @@
|
|||
---
|
||||
title: API를 이용한 축출(Eviction)
|
||||
title: API를 이용한 축출(API-initiated Eviction)
|
||||
content_type: concept
|
||||
weight: 70
|
||||
---
|
||||
|
||||
{{< glossary_definition term_id="api-eviction" length="short" >}} </br>
|
||||
|
||||
`kubectl drain` 명령과 같은 kube-apiserver의 클라이언트를 사용하여,
|
||||
축출 API를 직접 호출해 축출 요청을 할 수 있다.
|
||||
그러면 API 서버가 파드를 종료하는 `Eviction` 오브젝트가 생성된다.
|
||||
축출 API를 직접 호출하거나, 또는 `kubectl drain` 명령과 같이
|
||||
{{<glossary_tooltip term_id="kube-apiserver" text="API 서버">}}의 클라이언트를 사용하여 프로그램적인 방법으로 축출 요청을 할 수 있다.
|
||||
이는 `Eviction` 오브젝트를 만들며, API 서버로 하여금 파드를 종료하도록 만든다.
|
||||
|
||||
API를 이용한 축출은 구성된 [`PodDisruptionBudgets`](/docs/tasks/run-application/configure-pdb/) 및 [`terminationGracePeriodSeconds`](/ko/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination)를 준수한다.
|
||||
API를 이용한 축출은 사용자가 설정한 [`PodDisruptionBudgets`](/docs/tasks/run-application/configure-pdb/) 및
|
||||
[`terminationGracePeriodSeconds`](/ko/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination) 값을 준수한다.
|
||||
|
||||
API를 사용하여 `Eviction` 오브젝트를 만드는 것은
|
||||
정책 기반의 파드 [`DELETE` 동작](/docs/reference/kubernetes-api/workload-resources/pod-v1/#delete-delete-a-pod)을 수행하는 것과
|
||||
비슷한 효과를 낸다.
|
||||
|
||||
## 축출 API 호출하기
|
||||
|
||||
[각 언어 별 쿠버네티스 클라이언트](/ko/docs/tasks/administer-cluster/access-cluster-api/#api에-프로그래밍-방식으로-접근)를 사용하여
|
||||
쿠버네티스 API를 호출하고 `Eviction` 오브젝트를 생성할 수 있다.
|
||||
이를 실행하려면, 아래의 예시를 참고하여 POST 호출을 수행한다.
|
||||
|
||||
{{< tabs name="Eviction_example" >}}
|
||||
{{% tab name="policy/v1" %}}
|
||||
{{< note >}}
|
||||
`policy/v1` 축출은 v1.22 이상에서 사용 가능하다. 이전 버전에서는 `policy/v1beta1`를 사용한다.
|
||||
{{< /note >}}
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "policy/v1",
|
||||
"kind": "Eviction",
|
||||
"metadata": {
|
||||
"name": "quux",
|
||||
"namespace": "default"
|
||||
}
|
||||
}
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab name="policy/v1beta1" %}}
|
||||
{{< note >}}
|
||||
v1.22에서 사용 중단 및 `policy/v1`으로 대체되었다.
|
||||
{{< /note >}}
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "policy/v1beta1",
|
||||
"kind": "Eviction",
|
||||
"metadata": {
|
||||
"name": "quux",
|
||||
"namespace": "default"
|
||||
}
|
||||
}
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
또는 다음 예시와 같이 `curl` 또는 `wget`으로 API에 접근하여
|
||||
축출 동작을 시도할 수도 있다.
|
||||
|
||||
```bash
|
||||
curl -v -H 'Content-type: application/json' https://your-cluster-api-endpoint.example/api/v1/namespaces/default/pods/quux/eviction -d @eviction.json
|
||||
```
|
||||
|
||||
## API를 이용한 축출의 동작
|
||||
|
||||
API를 사용하여 축출을 요청하면,
|
||||
API 서버는 인가 확인(admission checks)를 수행하고 다음 중 하나로 응답한다.
|
||||
|
||||
* `200 OK`: 축출 요청이 허용되었고, `Eviction` 서브리소스가 생성되었고,
|
||||
(마치 파드 URL에 `DELETE` 요청을 보낸 것처럼) 파드가 삭제되었다.
|
||||
* `429 Too Many Requests`: 현재 설정된
|
||||
{{<glossary_tooltip term_id="pod-disruption-budget" text="PodDisruptionBudget">}} 때문에
|
||||
축출이 현재 허용되지 않는다.
|
||||
또는 API 요청 속도 제한(rate limiting) 때문에 이 응답을 받았을 수도 있다.
|
||||
* `500 Internal Server Error`: 잘못된 환경 설정(예:
|
||||
여러 PodDisruptionBudget이 하나의 동일한 파드를 참조함)으로 인해 축출이 허용되지 않는다.
|
||||
|
||||
축출하려는 파드가
|
||||
PodDisruptionBudget이 설정된 워크로드에 속하지 않는다면,
|
||||
API 서버는 항상 `200 OK`를 반환하고 축출을 허용한다.
|
||||
|
||||
API 서버가 축출을 허용하면, 파드는 다음과 같이 삭제된다.
|
||||
|
||||
1. API 서버 내 `Pod` 리소스의 삭제 타임스탬프(deletion timestamp)가 업데이트되며,
|
||||
이 타임스탬프에 명시된 시각이 경과하면 API 서버는 해당 `Pod` 리소스를 종료 대상으로 간주한다.
|
||||
또한 설정된 그레이스 시간(grace period)이 `Pod` 리소스에 기록된다.
|
||||
1. 로컬 파드가 실행되고 있는 노드의 {{<glossary_tooltip term_id="kubelet" text="kubelet">}}이
|
||||
`Pod`가 종료 대상으로 표시된 것을 감지하고
|
||||
로컬 파드의 그레이스풀 셧다운을 시작한다.
|
||||
1. kubelet이 파드를 종료하는 와중에, 컨트롤 플레인은
|
||||
{{<glossary_tooltip term_id="endpoint" text="엔드포인트">}} 및
|
||||
{{<glossary_tooltip term_id="endpoint-slice" text="엔드포인트슬라이스">}} 오브젝트에서 파드를 삭제한다.
|
||||
이 결과, 컨트롤러는 파드를 더 이상 유효한 오브젝트로 간주하지 않는다.
|
||||
1. 파드의 그레이스 시간이 만료되면,
|
||||
kubelet이 로컬 파드를 강제로 종료한다.
|
||||
1. kubelet이 API 서버에 `Pod` 리소스를 삭제하도록 지시한다.
|
||||
1. API 서버가 `Pod` 리소스를 삭제한다.
|
||||
|
||||
## 문제가 있어 중단된 축출 트러블슈팅하기
|
||||
|
||||
일부 경우에, 애플리케이션이 잘못된 상태로 돌입하여,
|
||||
직접 개입하기 전에는 축출 API가 `429` 또는 `500` 응답만 반환할 수 있다.
|
||||
이러한 현상은, 예를 들면 레플리카셋이 애플리케이션을 서비스할 파드를 생성했지만
|
||||
새 파드가 `Ready`로 바뀌지 못하는 경우에 발생할 수 있다.
|
||||
또는 마지막으로 축출된 파드가 긴 종료 그레이스 시간을 가진 경우에 이러한 현상을 목격할 수도 있다.
|
||||
|
||||
문제가 있어 중단된 축출을 발견했다면, 다음 해결책 중 하나를 시도해 본다.
|
||||
|
||||
* 이 문제를 발생시키는 자동 동작(automated operation)을 중단하거나 일시 중지한다.
|
||||
해당 동작을 재시작하기 전에, 문제가 있어 중단된 애플리케이션을 조사한다.
|
||||
* 잠시 기다린 뒤, 축출 API를 사용하는 것 대신
|
||||
클러스터 컨트롤 플레인에서 파드를 직접 삭제한다.
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
- [노드-압박 축출](/ko/docs/concepts/scheduling-eviction/node-pressure-eviction/)에 대해 더 배우기
|
||||
- [파드 우선순위와 선점](/ko/docs/concepts/scheduling-eviction/pod-priority-preemption/)에 대해 더 배우기
|
||||
* [Pod Disruption Budget](/docs/tasks/run-application/configure-pdb/)을 사용하여 애플리케이션을 보호하는 방법에 대해 알아본다.
|
||||
* [노드-압박 축출](/ko/docs/concepts/scheduling-eviction/node-pressure-eviction/)에 대해 알아본다.
|
||||
* [파드 우선순위와 선점](/ko/docs/concepts/scheduling-eviction/pod-priority-preemption/)에 대해 알아본다.
|
||||
|
|
|
@ -15,159 +15,182 @@ weight: 20
|
|||
{{< glossary_tooltip text="파드" term_id="pod" >}}를 제한할 수 있다.
|
||||
이를 수행하는 방법에는 여러 가지가 있으며 권장되는 접근 방식은 모두
|
||||
[레이블 셀렉터](/ko/docs/concepts/overview/working-with-objects/labels/)를 사용하여 선택을 용이하게 한다.
|
||||
보통 스케줄러가 자동으로 합리적인 배치(예: 자원이 부족한 노드에 파드를 배치하지 않도록
|
||||
노드 간에 파드를 분배하는 등)를 수행하기에 이러한 제약 조건은 필요하지 않지만
|
||||
간혹 파드가 배포될 노드를 제어해야 하는 경우가 있다.
|
||||
예를 들어 SSD가 장착된 머신에 파드가 배포되도록 하거나 또는 많은 통신을 하는 두 개의 서로 다른 서비스의 파드를
|
||||
동일한 가용성 영역(availability zone)에 배치할 수 있다.
|
||||
|
||||
보통은 스케줄러가 자동으로 합리적인 배치(예: 자원이 부족한 노드에 파드를 배치하지 않도록
|
||||
노드 간에 파드를 분배)를 수행하기에 이러한 제약 조건은 필요하지 않다.
|
||||
그러나, 예를 들어 SSD가 장착된 머신에 파드가 배포되도록 하거나 또는
|
||||
많은 통신을 하는 두 개의 서로 다른 서비스의 파드를 동일한 가용성 영역(availability zone)에 배치하는 경우와 같이,
|
||||
파드가 어느 노드에 배포될지를 제어해야 하는 경우도 있다.
|
||||
|
||||
<!-- body -->
|
||||
|
||||
## 노드 셀렉터(nodeSelector)
|
||||
쿠버네티스가 특정 파드를 어느 노드에 스케줄링할지 고르는
|
||||
다음의 방법 중 하나를 골라 사용할 수 있다.
|
||||
|
||||
`nodeSelector` 는 가장 간단하고 권장되는 노드 선택 제약 조건의 형태이다.
|
||||
`nodeSelector` 는 PodSpec의 필드이다. 이는 키-값 쌍의 매핑으로 지정한다. 파드가 노드에서 동작할 수 있으려면,
|
||||
노드는 키-값의 쌍으로 표시되는 레이블을 각자 가지고 있어야 한다(이는 추가 레이블을 가지고 있을 수 있다).
|
||||
일반적으로 하나의 키-값 쌍이 사용된다.
|
||||
* [노드 레이블](#built-in-node-labels)에 매칭되는 [nodeSelector](#nodeselector) 필드
|
||||
* [어피니티 / 안티 어피니티](#affinity-and-anti-affinity)
|
||||
* [nodeName](#nodename) 필드
|
||||
|
||||
`nodeSelector` 를 어떻게 사용하는지 예시를 통해 알아보도록 하자.
|
||||
## 노드 레이블 {#built-in-node-labels}
|
||||
|
||||
### 0 단계: 사전 준비
|
||||
다른 쿠버네티스 오브젝트와 마찬가지로, 노드도 [레이블](/ko/docs/concepts/overview/working-with-objects/labels/)을 가진다.
|
||||
[레이블을 수동으로 추가](/ko/docs/tasks/configure-pod-container/assign-pods-nodes/#노드에-레이블-추가)할 수 있다.
|
||||
또한 쿠버네티스도 클러스터의 모든 노드에 표준화된 레이블 집합을 적용한다.
|
||||
[잘 알려진 레이블, 어노테이션, 테인트](/ko/docs/reference/labels-annotations-taints/)에서 널리 사용되는 노드 레이블의 목록을 확인한다.
|
||||
|
||||
이 예시는 쿠버네티스 파드에 대한 기본적인 이해를 하고 있고 [쿠버네티스 클러스터가 설정](/ko/docs/setup/)되어 있다고 가정한다.
|
||||
{{<note>}}
|
||||
이러한 레이블에 대한 값은 클라우드 제공자별로 다르며 정확하지 않을 수 있다.
|
||||
예를 들어, `kubernetes.io/hostname`에 대한 값은 특정 환경에서는 노드 이름과 동일할 수 있지만
|
||||
다른 환경에서는 다른 값일 수도 있다.
|
||||
{{</note>}}
|
||||
|
||||
### 1 단계: 노드에 레이블 붙이기
|
||||
### 노드 격리/제한 {#node-isolation-restriction}
|
||||
|
||||
`kubectl get nodes` 를 실행해서 클러스터 노드 이름을 가져온다. 이 중에 레이블을 추가하기 원하는 것 하나를 선택한 다음에 `kubectl label nodes <노드 이름> <레이블 키>=<레이블 값>` 을 실행해서 선택한 노드에 레이블을 추가한다. 예를 들어 노드의 이름이 'kubernetes-foo-node-1.c.a-robinson.internal' 이고, 원하는 레이블이 'disktype=ssd' 라면, `kubectl label nodes kubernetes-foo-node-1.c.a-robinson.internal disktype=ssd` 를 실행한다.
|
||||
노드에 레이블을 추가하여
|
||||
파드를 특정 노드 또는 노드 그룹에 스케줄링되도록 지정할 수 있다.
|
||||
이 기능을 사용하여 특정 파드가 특정 격리/보안/규제 속성을 만족하는 노드에서만
|
||||
실행되도록 할 수 있다.
|
||||
|
||||
`kubectl get nodes --show-labels` 를 다시 실행해서 노드가 현재 가진 레이블을 확인하여, 이 작업을 검증할 수 있다. 또한 `kubectl describe node "노드 이름"` 을 사용해서 노드에 주어진 레이블의 전체 목록을 확인할 수 있다.
|
||||
노드 격리를 위해 레이블을 사용할 때, {{<glossary_tooltip text="kubelet" term_id="kubelet">}}이 변경할 수 없는 레이블 키를 선택한다.
|
||||
그렇지 않으면 kubelet이 해당 레이블을 변경하여 노드가 사용 불가능(compromised) 상태로 빠지고
|
||||
스케줄러가 이 노드에 워크로드를 스케줄링하는 일이 발생할 수 있다.
|
||||
|
||||
### 2 단계: 파드 설정에 nodeSelector 필드 추가하기
|
||||
[`NodeRestriction` 어드미션 플러그인](/docs/reference/access-authn-authz/admission-controllers/#noderestriction)은
|
||||
kubelet이 `node-restriction.kubernetes.io/` 접두사를 갖는 레이블을
|
||||
설정하거나 변경하지 못하도록 한다.
|
||||
|
||||
실행하고자 하는 파드의 설정 파일을 가져오고, 이처럼 nodeSelector 섹션을 추가한다. 예를 들어 이것이 파드 설정이라면,
|
||||
노드 격리를 위해 레이블 접두사를 사용하려면,
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
env: test
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
```
|
||||
1. [노드 인가자(authorizer)](/docs/reference/access-authn-authz/node/)를 사용하고 있는지, 그리고 `NodeRestriction` 어드미션 플러그인을 **활성화** 했는지 확인한다.
|
||||
1. 노드에 `node-restriction.kubernetes.io/` 접두사를 갖는 레이블을 추가하고, [노드 셀렉터](#nodeselector)에서 해당 레이블을 사용한다.
|
||||
예: `example.com.node-restriction.kubernetes.io/fips=true` 또는 `example.com.node-restriction.kubernetes.io/pci-dss=true`
|
||||
|
||||
이 다음에 nodeSelector 를 다음과 같이 추가한다.
|
||||
## 노드셀렉터(nodeSelector) {#nodeselector}
|
||||
|
||||
{{< codenew file="pods/pod-nginx.yaml" >}}
|
||||
`nodeSelector`는 노드 선택 제약사항의 가장 간단하면서도 추천하는 형태이다.
|
||||
파드 스펙에 `nodeSelector` 필드를 추가하고,
|
||||
타겟으로 삼고 싶은 노드가 갖고 있는 [노드 레이블](#built-in-node-labels)을 명시한다.
|
||||
쿠버네티스는 사용자가 명시한 레이블을 갖고 있는 노드에만
|
||||
파드를 스케줄링한다.
|
||||
|
||||
그런 다음에 `kubectl apply -f https://k8s.io/examples/pods/pod-nginx.yaml` 을
|
||||
실행하면, 레이블이 붙여진 노드에 파드가 스케줄된다.
|
||||
`kubectl get pods -o wide` 를 실행해서 파드가 할당된
|
||||
"NODE" 를 보면 작동하는지 검증할 수 있다.
|
||||
[노드에 파드 할당](/ko/docs/tasks/configure-pod-container/assign-pods-nodes)에서
|
||||
더 많은 정보를 확인한다.
|
||||
|
||||
## 넘어가기 전에: 내장 노드 레이블들 {#built-in-node-labels}
|
||||
## 어피니티(affinity)와 안티-어피니티(anti-affinity) {#affinity-and-anti-affinity}
|
||||
|
||||
[붙인](#1-단계-노드에-레이블-붙이기) 레이블뿐만 아니라, 노드에는
|
||||
표준 레이블 셋이 미리 채워져 있다. 이들 목록은 [잘 알려진 레이블, 어노테이션 및 테인트](/ko/docs/reference/labels-annotations-taints/)를 참고한다.
|
||||
`nodeSelector` 는 파드를 특정 레이블이 있는 노드로 제한하는 가장 간단한 방법이다.
|
||||
어피니티/안티-어피니티 기능은 표현할 수 있는 제약 종류를 크게 확장한다.
|
||||
주요 개선 사항은 다음과 같다.
|
||||
|
||||
{{< note >}}
|
||||
이 레이블들의 값은 클라우드 공급자에 따라 다르고 신뢰성이 보장되지 않는다.
|
||||
예를 들어 `kubernetes.io/hostname` 은 어떤 환경에서는 노드 이름과 같지만,
|
||||
다른 환경에서는 다른 값일 수 있다.
|
||||
{{< /note >}}
|
||||
* 어피니티/안티-어피니티 언어가 더 표현적이다.
|
||||
`nodeSelector`로는 명시한 레이블이 있는 노드만 선택할 수 있다.
|
||||
어피니티/안티-어피니티는 선택 로직에 대한 좀 더 많은 제어권을 제공한다.
|
||||
* 규칙이 "소프트(soft)" 또는 "선호사항(preference)" 임을 나타낼 수 있으며,
|
||||
이 덕분에 스케줄러는 매치되는 노드를 찾지 못한 경우에도 파드를 스케줄링할 수 있다.
|
||||
* 다른 노드 (또는 다른 토폴로지 도메인)에서 실행 중인
|
||||
다른 파드의 레이블을 사용하여 파드를 제한할 수 있으며,
|
||||
이를 통해 어떤 파드들이 노드에 함께 위치할 수 있는지에 대한 규칙을 정의할 수 있다.
|
||||
|
||||
## 노드 격리(isolation)/제한(restriction)
|
||||
어피니티 기능은 다음의 두 가지 종류로 구성된다.
|
||||
|
||||
노드 오브젝트에 레이블을 추가하면 파드가 특정 노드 또는 노드 그룹을 목표 대상으로 할 수 있게 된다.
|
||||
이는 특정 파드가 어떤 격리, 보안, 또는 규제 속성이 있는 노드에서만 실행되도록 사용할 수 있다.
|
||||
이 목적으로 레이블을 사용하는 경우, 노드에서 kubelet 프로세스로 수정할 수 없는 레이블 키를 선택하는 것을 권장한다.
|
||||
이렇게 하면 손상된 노드가 해당 kubelet 자격 증명을 사용해서 해당 레이블을 자체 노드 오브젝트에 설정하고,
|
||||
스케줄러가 손상된 노드로 워크로드를 스케줄 하는 것을 방지할 수 있다.
|
||||
* *노드 어피니티* 기능은 `nodeSelector` 필드와 비슷하지만
|
||||
더 표현적이고 소프트(soft) 규칙을 지정할 수 있게 해 준다.
|
||||
* *파드 간 어피니티/안티-어피니티* 는 다른 파드의 레이블을 이용하여
|
||||
해당 파드를 제한할 수 있게 해 준다.
|
||||
|
||||
`NodeRestriction` 어드미션 플러그인은 kubelet이 `node-restriction.kubernetes.io/` 접두사로 레이블을 설정 또는 수정하지 못하게 한다.
|
||||
노드 격리에 해당 레이블 접두사를 사용하려면 다음과 같이 한다.
|
||||
### 노드 어피니티 {#node-affinity}
|
||||
|
||||
1. [노드 권한부여자](/docs/reference/access-authn-authz/node/)를 사용하고 있고, [NodeRestriction 어드미션 플러그인](/docs/reference/access-authn-authz/admission-controllers/#noderestriction)을 _활성화_ 해야 한다.
|
||||
2. 노드 오브젝트의 `node-restriction.kubernetes.io/` 접두사 아래에 레이블을 추가하고, 해당 레이블을 노드 셀렉터에서 사용한다.
|
||||
예를 들어, `example.com.node-restriction.kubernetes.io/fips=true` 또는 `example.com.node-restriction.kubernetes.io/pci-dss=true` 이다.
|
||||
노드 어피니티는 개념적으로 `nodeSelector` 와 비슷하며,
|
||||
노드의 레이블을 기반으로 파드가 스케줄링될 수 있는 노드를 제한할 수 있다.
|
||||
노드 어피니티에는 다음의 두 종류가 있다.
|
||||
|
||||
## 어피니티(affinity)와 안티-어피니티(anti-affinity)
|
||||
* `requiredDuringSchedulingIgnoredDuringExecution`:
|
||||
규칙이 만족되지 않으면 스케줄러가 파드를 스케줄링할 수 없다.
|
||||
이 기능은 `nodeSelector`와 유사하지만, 좀 더 표현적인 문법을 제공한다.
|
||||
* `preferredDuringSchedulingIgnoredDuringExecution`:
|
||||
스케줄러는 조건을 만족하는 노드를 찾으려고 노력한다.
|
||||
해당되는 노드가 없더라도, 스케줄러는 여전히 파드를 스케줄링한다.
|
||||
|
||||
`nodeSelector` 는 파드를 특정 레이블이 있는 노드로 제한하는 매우 간단한 방법을 제공한다.
|
||||
어피니티/안티-어피니티 기능은 표현할 수 있는 제약 종류를 크게 확장한다. 주요 개선 사항은 다음과 같다.
|
||||
{{<note>}}
|
||||
앞의 두 유형에서, `IgnoredDuringExecution`는
|
||||
쿠버네티스가 파드를 스케줄링한 뒤에 노드 레이블이 변경되어도 파드는 계속 해당 노드에서 실행됨을 의미한다.
|
||||
{{</note>}}
|
||||
|
||||
1. 어피니티/안티-어피니티 언어가 더 표현적이다. 언어는 논리 연산자인 AND 연산으로 작성된
|
||||
정확한 매칭 항목 이외에 더 많은 매칭 규칙을 제공한다.
|
||||
2. 규칙이 엄격한 요구 사항이 아니라 "유연한(soft)"/"선호(preference)" 규칙을 나타낼 수 있기에 스케줄러가 규칙을 만족할 수 없더라도,
|
||||
파드가 계속 스케줄되도록 한다.
|
||||
3. 노드 자체에 레이블을 붙이기보다는 노드(또는 다른 토폴로지 도메인)에서 실행 중인 다른 파드의 레이블을 제한할 수 있다.
|
||||
이를 통해 어떤 파드가 함께 위치할 수 있는지와 없는지에 대한 규칙을 적용할 수 있다.
|
||||
파드 스펙의 `.spec.affinity.nodeAffinity` 필드에
|
||||
노드 어피니티를 명시할 수 있다.
|
||||
|
||||
어피니티 기능은 "노드 어피니티" 와 "파드 간 어피니티/안티-어피니티" 두 종류의 어피니티로 구성된다.
|
||||
노드 어피니티는 기존 `nodeSelector` 와 비슷하지만(그러나 위에서 나열된 첫째와 두 번째 이점이 있다.),
|
||||
파드 간 어피니티/안티-어피니티는 위에서 나열된 세번째 항목에 설명된 대로
|
||||
노드 레이블이 아닌 파드 레이블에 대해 제한되고 위에서 나열된 첫 번째와 두 번째 속성을 가진다.
|
||||
|
||||
### 노드 어피니티
|
||||
|
||||
노드 어피니티는 개념적으로 `nodeSelector` 와 비슷하다 -- 이는 노드의 레이블을 기반으로 파드를
|
||||
스케줄할 수 있는 노드를 제한할 수 있다.
|
||||
|
||||
여기에 현재 `requiredDuringSchedulingIgnoredDuringExecution` 와 `preferredDuringSchedulingIgnoredDuringExecution` 로 부르는
|
||||
두 가지 종류의 노드 어피니티가 있다. 전자는 파드가 노드에 스케줄되도록 *반드시*
|
||||
규칙을 만족해야 하는 것(`nodeSelector` 와 비슷하나 보다 표현적인 구문을 사용해서)을 지정하고,
|
||||
후자는 스케줄러가 시도하려고는 하지만, 보증하지 않는 *선호(preferences)* 를 지정한다는 점에서
|
||||
이를 각각 "엄격함(hard)" 과 "유연함(soft)" 으로 생각할 수 있다.
|
||||
이름의 "IgnoredDuringExecution" 부분은 `nodeSelector` 작동 방식과 유사하게 노드의
|
||||
레이블이 런타임 중에 변경되어 파드의 어피니티 규칙이 더 이상 충족되지 않으면 파드가 그 노드에서
|
||||
동작한다는 의미이다. 향후에는 파드의 노드 어피니티 요구 사항을 충족하지 않는 노드에서 파드를 제거한다는
|
||||
점을 제외하고는 `requiredDuringSchedulingIgnoredDuringExecution` 와 동일한 `requiredDuringSchedulingRequiredDuringExecution` 를 제공할 계획이다.
|
||||
|
||||
따라서 `requiredDuringSchedulingIgnoredDuringExecution` 의 예로는 "인텔 CPU가 있는 노드에서만 파드 실행"이
|
||||
될 수 있고, `preferredDuringSchedulingIgnoredDuringExecution` 의 예로는 "장애 조치 영역 XYZ에 파드 집합을 실행하려고
|
||||
하지만, 불가능하다면 다른 곳에서 일부를 실행하도록 허용"이 있을 것이다.
|
||||
|
||||
노드 어피니티는 PodSpec의 `affinity` 필드의 `nodeAffinity` 필드에서 지정된다.
|
||||
|
||||
여기에 노드 어피니티를 사용하는 파드 예시가 있다.
|
||||
예를 들어, 다음과 같은 파드 스펙이 있다고 하자.
|
||||
|
||||
{{< codenew file="pods/pod-with-node-affinity.yaml" >}}
|
||||
|
||||
이 노드 어피니티 규칙은 키가 `kubernetes.io/e2e-az-name` 이고 값이 `e2e-az1` 또는 `e2e-az2` 인
|
||||
레이블이 있는 노드에만 파드를 배치할 수 있다고 말한다. 또한, 이 기준을 충족하는 노드들
|
||||
중에서 키가 `another-node-label-key` 이고 값이 `another-node-label-value` 인 레이블이 있는 노드를
|
||||
선호하도록 한다.
|
||||
이 예시에서는 다음의 규칙이 적용된다.
|
||||
|
||||
예시에서 연산자 `In` 이 사용되고 있는 것을 볼 수 있다. 새로운 노드 어피니티 구문은 다음의 연산자들을 지원한다. `In`, `NotIn`, `Exists`, `DoesNotExist`, `Gt`, `Lt`.
|
||||
`NotIn` 과 `DoesNotExist` 를 사용해서 안티-어피니티를 수행하거나,
|
||||
특정 노드에서 파드를 쫓아내는 [노드 테인트(taint)](/ko/docs/concepts/scheduling-eviction/taint-and-toleration/)를 설정할 수 있다.
|
||||
* 노드는 키가 `kubernetes.io/os`이고 값이 `linux`인 레이블을
|
||||
갖고 *있어야 한다* .
|
||||
* 키가 `another-node-label-key`이고 값이 `another-node-label-value`인 레이블을
|
||||
갖고 있는 노드를 *선호한다* .
|
||||
|
||||
`nodeSelector` 와 `nodeAffinity` 를 모두 지정한다면 파드가 후보 노드에 스케줄되기 위해서는
|
||||
*둘 다* 반드시 만족해야 한다.
|
||||
`operator` 필드를 사용하여
|
||||
쿠버네티스가 규칙을 해석할 때 사용할 논리 연산자를 지정할 수 있다.
|
||||
`In`, `NotIn`, `Exists`, `DoesNotExist`, `Gt` 및 `Lt` 연산자를 사용할 수 있다.
|
||||
|
||||
`nodeAffinity` 유형과 연관된 `nodeSelectorTerms` 를 지정하면, `nodeSelectorTerms` 중 **하나라도** 만족시키는 노드에 파드가 스케줄된다.
|
||||
`NotIn` 및 `DoesNotExist` 연산자를 사용하여 노드 안티-어피니티 규칙을 정의할 수 있다.
|
||||
또는, 특정 노드에서 파드를 쫓아내는
|
||||
[노드 테인트(taint)](/ko/docs/concepts/scheduling-eviction/taint-and-toleration/)를 설정할 수 있다.
|
||||
|
||||
`nodeSelectorTerms` 와 연관된 여러 `matchExpressions` 를 지정하면, 파드는 `matchExpressions` 를 **모두** 만족하는 노드에만 스케줄된다.
|
||||
{{<note>}}
|
||||
`nodeSelector`와 `nodeAffinity`를 모두 사용하는 경우,
|
||||
파드가 노드에 스케줄링되려면 두 조건 *모두* 만족되어야 한다.
|
||||
|
||||
파드가 스케줄된 노드의 레이블을 지우거나 변경해도 파드는 제거되지 않는다. 다시 말해서 어피니티 선택은 파드를 스케줄링 하는 시점에만 작동한다.
|
||||
`nodeAffinity`에 연결된 `nodeSelectorTerms`를 여러 개 명시한 경우,
|
||||
명시된 `nodeSelectorTerms` 중 하나를 만족하는 노드에도
|
||||
파드가 스케줄링될 수 있다.
|
||||
|
||||
`preferredDuringSchedulingIgnoredDuringExecution` 의 `weight` 필드의 범위는 1-100이다. 모든 스케줄링 요구 사항 (리소스 요청, RequiredDuringScheduling 어피니티 표현식 등)을 만족하는 각 노드들에 대해 스케줄러는 이 필드의 요소들을 반복해서 합계를 계산하고 노드가 MatchExpressions 에 일치하는 경우 합계에 "가중치(weight)"를 추가한다. 이후에 이 점수는 노드에 대한 다른 우선순위 함수의 점수와 합쳐진다. 전체 점수가 가장 높은 노드를 가장 선호한다.
|
||||
단일 `nodeSelectorTerms`와 연결된 `matchExpressions`를 여러 개 명시한 경우,
|
||||
모든 `matchExpressions`를 만족하는 노드에만
|
||||
파드가 스케줄링될 수 있다.
|
||||
{{</note>}}
|
||||
|
||||
#### 스케줄링 프로파일당 노드 어피니티
|
||||
[노드 어피니티를 사용해 노드에 파드 할당](/ko/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/)에서
|
||||
더 많은 정보를 확인한다.
|
||||
|
||||
#### 노드 어피니티 가중치(weight) {#node-affinity-weight}
|
||||
|
||||
각 `preferredDuringSchedulingIgnoredDuringExecution` 어피니티 타입 인스턴스에 대해
|
||||
1-100 범위의 `weight`를 명시할 수 있다.
|
||||
스케줄러가 다른 모든 파드 스케줄링 요구 사항을 만족하는 노드를 찾으면,
|
||||
스케줄러는 노드가 만족한 모든 선호하는(preferred) 규칙에 대해
|
||||
합계 계산을 위한 `weight` 값을 각각 추가한다.
|
||||
|
||||
최종 합계는 해당 노드에 대한 다른 우선 순위 함수 점수에 더해진다.
|
||||
스케줄러가 파드에 대한 스케줄링 판단을 할 때,
|
||||
총 점수가 가장 높은 노드가 우선 순위를 갖는다.
|
||||
|
||||
예를 들어, 다음과 같은 파드 스펙이 있다고 하자.
|
||||
|
||||
{{< codenew file="pods/pod-with-affinity-anti-affinity.yaml" >}}
|
||||
|
||||
`requiredDuringSchedulingIgnoredDuringExecution` 규칙을 만족하는 노드가 2개 있고,
|
||||
하나에는 `label-1:key-1` 레이블이 있고 다른 하나에는 `label-2:key-2` 레이블이 있으면,
|
||||
스케줄러는 각 노드의 `weight`를 확인한 뒤
|
||||
해당 노드에 대한 다른 점수에 가중치를 더하고,
|
||||
최종 점수가 가장 높은 노드에 해당 파드를 스케줄링한다.
|
||||
|
||||
{{<note>}}
|
||||
이 예시에서 쿠버네티스가 정상적으로 파드를 스케줄링하려면,
|
||||
보유하고 있는 노드에 `kubernetes.io/os=linux` 레이블이 있어야 한다.
|
||||
{{</note>}}
|
||||
|
||||
#### 스케줄링 프로파일당 노드 어피니티 {#node-affinity-per-scheduling-profile}
|
||||
|
||||
{{< feature-state for_k8s_version="v1.20" state="beta" >}}
|
||||
|
||||
여러 [스케줄링 프로파일](/ko/docs/reference/scheduling/config/#여러-프로파일)을 구성할 때
|
||||
노드 어피니티가 있는 프로파일을 연결할 수 있는데, 이는 프로파일이 특정 노드 집합에만 적용되는 경우 유용하다.
|
||||
이렇게 하려면 [스케줄러 구성](/ko/docs/reference/scheduling/config/)에 있는
|
||||
[`NodeAffinity` 플러그인](/ko/docs/reference/scheduling/config/#스케줄링-플러그인-1)의 인수에 `addedAffinity`를 추가한다. 예를 들면
|
||||
이렇게 하려면 다음과 같이 [스케줄러 구성](/ko/docs/reference/scheduling/config/)에 있는
|
||||
[`NodeAffinity` 플러그인](/ko/docs/reference/scheduling/config/#스케줄링-플러그인-1)의 `args` 필드에 `addedAffinity`를 추가한다.
|
||||
|
||||
```yaml
|
||||
apiVersion: kubescheduler.config.k8s.io/v1beta1
|
||||
apiVersion: kubescheduler.config.k8s.io/v1beta3
|
||||
kind: KubeSchedulerConfiguration
|
||||
|
||||
profiles:
|
||||
|
@ -188,29 +211,41 @@ profiles:
|
|||
|
||||
`addedAffinity`는 `.spec.schedulerName`을 `foo-scheduler`로 설정하는 모든 파드에 적용되며
|
||||
PodSpec에 지정된 NodeAffinity도 적용된다.
|
||||
즉, 파드를 매칭시키려면, 노드가 `addedAffinity`와 파드의 `.spec.NodeAffinity`를 충족해야 한다.
|
||||
즉, 파드를 매칭시키려면, 노드가 `addedAffinity`와
|
||||
파드의 `.spec.NodeAffinity`를 충족해야 한다.
|
||||
|
||||
`addedAffinity`는 엔드 유저에게 표시되지 않으므로, 예상치 못한 동작이 일어날 수 있다. 프로파일의
|
||||
스케줄러 이름과 명확한 상관 관계가 있는 노드 레이블을 사용하는 것이 좋다.
|
||||
`addedAffinity`는 엔드 유저에게 표시되지 않으므로,
|
||||
예상치 못한 동작이 일어날 수 있다.
|
||||
스케줄러 프로파일 이름과 명확한 상관 관계가 있는 노드 레이블을 사용한다.
|
||||
|
||||
{{< note >}}
|
||||
[데몬셋용 파드를 생성](/ko/docs/concepts/workloads/controllers/daemonset/#기본-스케줄러로-스케줄)하는 데몬셋 컨트롤러는
|
||||
스케줄링 프로파일을 인식하지 못한다.
|
||||
따라서 `addedAffinity`없이 `default-scheduler`와 같은 스케줄러 프로파일을 유지하는 것이 좋다. 그런 다음 데몬셋의 파드 템플릿이 스케줄러 이름을 사용해야 한다.
|
||||
그렇지 않으면, 데몬셋 컨트롤러에 의해 생성된 일부 파드가 스케줄되지 않은 상태로 유지될 수 있다.
|
||||
[데몬셋 파드를 생성](/ko/docs/concepts/workloads/controllers/daemonset/#기본-스케줄러로-스케줄)하는 데몬셋 컨트롤러는
|
||||
스케줄링 프로파일을 지원하지 않는다.
|
||||
데몬셋 컨트롤러가 파드를 생성할 때, 기본 쿠버네티스 스케줄러는 해당 파드를 배치하고
|
||||
데몬셋 컨트롤러의 모든 `nodeAffinity` 규칙을 준수한다.
|
||||
{{< /note >}}
|
||||
|
||||
### 파드간 어피니티와 안티-어피니티
|
||||
### 파드간 어피니티와 안티-어피니티 {#inter-pod-affinity-and-anti-affinity}
|
||||
|
||||
파드간 어피니티와 안티-어피니티를 사용하면 노드의 레이블을 기반으로 하지 않고, *노드에서 이미 실행 중인 파드 레이블을 기반으로*
|
||||
파드가 스케줄될 수 있는 노드를 제한할 수 있다. 규칙은 "X가 규칙 Y를 충족하는 하나 이상의 파드를 이미 실행중인 경우
|
||||
이 파드는 X에서 실행해야 한다(또는 안티-어피니티가 없는 경우에는 동작하면 안된다)"는 형태이다. Y는
|
||||
선택적으로 연관된 네임스페이스 목록을 가진 LabelSelector로 표현된다. 노드와는 다르게 파드는 네임스페이스이기에
|
||||
(그리고 따라서 파드의 레이블은 암암리에 네임스페이스이다) 파드 레이블위의 레이블 셀렉터는 반드시
|
||||
셀렉터가 적용될 네임스페이스를 지정해야만 한다. 개념적으로 X는 노드, 랙,
|
||||
클라우드 공급자 영역, 클라우드 공급자 지역 등과 같은 토폴로지 도메인이다. 시스템이 이런 토폴로지
|
||||
도메인을 나타내는 데 사용하는 노드 레이블 키인 `topologyKey` 를 사용하여 이를 표현한다.
|
||||
예: [넘어가기 전에: 빌트인 노드 레이블](#built-in-node-labels) 섹션 위에 나열된 레이블 키를 본다.
|
||||
파드간 어피니티와 안티-어피니티를 사용하여,
|
||||
노드 레이블 대신, 각 노드에 이미 실행 중인 다른 **파드** 의 레이블을 기반으로
|
||||
파드가 스케줄링될 노드를 제한할 수 있다.
|
||||
|
||||
파드간 어피니티와 안티-어피니티 규칙은
|
||||
"X가 규칙 Y를 충족하는 하나 이상의 파드를 이미 실행중인 경우 이 파드는 X에서 실행해야 한다(또는
|
||||
안티-어피니티의 경우에는 "실행하면 안 된다")"의 형태이며,
|
||||
여기서 X는 노드, 랙, 클라우드 제공자 존 또는 리전 등이며
|
||||
Y는 쿠버네티스가 충족할 규칙이다.
|
||||
|
||||
이러한 규칙(Y)은 [레이블 셀렉터](/ko/docs/concepts/overview/working-with-objects/labels/#레이블-셀렉터) 형태로 작성하며,
|
||||
연관된 네임스페이스 목록을 선택적으로 명시할 수도 있다.
|
||||
쿠버네티스에서 파드는 네임스페이스에 속하는(namespaced) 오브젝트이므로,
|
||||
파드 레이블도 암묵적으로 특정 네임스페이스에 속하게 된다.
|
||||
파드 레이블에 대한 모든 레이블 셀렉터는 쿠버네티스가 해당 레이블을 어떤 네임스페이스에서 탐색할지를 명시해야 한다.
|
||||
|
||||
`topologyKey`를 사용하여 토폴로지 도메인(X)를 나타낼 수 있으며,
|
||||
이는 시스템이 도메인을 표시하기 위해 사용하는 노드 레이블의 키이다.
|
||||
이에 대한 예시는 [잘 알려진 레이블, 어노테이션, 테인트](/ko/docs/reference/labels-annotations-taints/)를 참고한다.
|
||||
|
||||
{{< note >}}
|
||||
파드간 어피니티와 안티-어피니티에는 상당한 양의 프로세싱이 필요하기에
|
||||
|
@ -219,80 +254,100 @@ PodSpec에 지정된 NodeAffinity도 적용된다.
|
|||
{{< /note >}}
|
||||
|
||||
{{< note >}}
|
||||
파드 안티-어피니티에서는 노드에 일관된 레이블을 지정해야 한다. 즉, 클러스터의 모든 노드는 `topologyKey` 와 매칭되는 적절한 레이블을 가지고 있어야 한다. 일부 또는 모든 노드에 지정된 `topologyKey` 레이블이 없는 경우에는 의도하지 않은 동작이 발생할 수 있다.
|
||||
파드 안티-어피니티에서는 노드에 일관된 레이블을 지정해야 한다.
|
||||
즉, 클러스터의 모든 노드는 `topologyKey` 와 매칭되는 적절한 레이블을 가지고 있어야 한다.
|
||||
일부 또는 모든 노드에 지정된 `topologyKey` 레이블이 없는 경우에는
|
||||
의도하지 않은 동작이 발생할 수 있다.
|
||||
{{< /note >}}
|
||||
|
||||
노드 어피니티와 마찬가지로 현재 파드 어피니티와 안티-어피니티로 부르는 "엄격함" 대 "유연함"의 요구사항을 나타내는 `requiredDuringSchedulingIgnoredDuringExecution` 와
|
||||
`preferredDuringSchedulingIgnoredDuringExecution` 두 가지 종류가 있다.
|
||||
앞의 노드 어피니티 섹션의 설명을 본다.
|
||||
`requiredDuringSchedulingIgnoredDuringExecution` 어피니티의 예시는
|
||||
"서로 많은 통신을 하기 때문에 서비스 A와 서비스 B를 같은 영역에 함께 위치시키는 것"이고,
|
||||
`preferredDuringSchedulingIgnoredDuringExecution` 안티-어피니티의 예시는 "서비스를 여러 영역에 걸쳐서 분배하는 것"이다
|
||||
(엄격한 요구사항은 영역보다 파드가 더 많을 수 있기 때문에 엄격한 요구사항은 의미가 없다).
|
||||
#### 파드간 어피니티 및 안티-어피니티 종류 {#types-of-inter-pod-affinity-and-anti-affinity}
|
||||
|
||||
파드간 어피니티는 PodSpec에서 `affinity` 필드 중 `podAffinity` 필드로 지정한다.
|
||||
그리고 파드간 안티-어피니티는 PodSpec에서 `affinity` 필드 중 `podAntiAffinity` 필드로 지정한다.
|
||||
노드 어피니티와 마찬가지로
|
||||
파드 어피니티 및 안티-어피니티에는 다음의 2 종류가 있다.
|
||||
|
||||
#### 파드 어피니티를 사용하는 파드의 예시
|
||||
* `requiredDuringSchedulingIgnoredDuringExecution`
|
||||
* `preferredDuringSchedulingIgnoredDuringExecution`
|
||||
|
||||
예를 들어, `requiredDuringSchedulingIgnoredDuringExecution` 어피니티를 사용하여
|
||||
서로 통신을 많이 하는 두 서비스의 파드를
|
||||
동일 클라우드 제공자 존에 배치하도록 스케줄러에게 지시할 수 있다.
|
||||
비슷하게, `preferredDuringSchedulingIgnoredDuringExecution` 안티-어피니티를 사용하여
|
||||
서비스의 파드를
|
||||
여러 클라우드 제공자 존에 퍼뜨릴 수 있다.
|
||||
|
||||
파드간 어피니티를 사용하려면, 파드 스펙에 `affinity.podAffinity` 필드를 사용한다.
|
||||
파드간 안티-어피니티를 사용하려면,
|
||||
파드 스펙에 `affinity.podAntiAffinity` 필드를 사용한다.
|
||||
|
||||
#### 파드 어피니티 예시 {#an-example-of-a-pod-that-uses-pod-affinity}
|
||||
|
||||
다음과 같은 파드 스펙을 가정한다.
|
||||
|
||||
{{< codenew file="pods/pod-with-pod-affinity.yaml" >}}
|
||||
|
||||
이 파드의 어피니티는 하나의 파드 어피니티 규칙과 하나의 파드 안티-어피니티 규칙을 정의한다.
|
||||
이 예시에서 `podAffinity` 는 `requiredDuringSchedulingIgnoredDuringExecution` 이고 `podAntiAffinity` 는
|
||||
`preferredDuringSchedulingIgnoredDuringExecution` 이다. 파드 어피니티 규칙에 의하면 키 "security" 와 값
|
||||
"S1"인 레이블이 있는 하나 이상의 이미 실행 중인 파드와 동일한 영역에 있는 경우에만 파드를 노드에 스케줄할 수 있다.
|
||||
(보다 정확하게는, 클러스터에 키 "security"와 값 "S1"인 레이블을 가지고 있는 실행 중인 파드가 있는 키
|
||||
`topology.kubernetes.io/zone` 와 값 V인 노드가 최소 하나 이상 있고,
|
||||
노드 N이 키 `topology.kubernetes.io/zone` 와
|
||||
일부 값이 V인 레이블을 가진다면 파드는 노드 N에서 실행할 수 있다.)
|
||||
파드 안티-어피니티 규칙에 의하면 파드는 키 "security"와 값 "S2"인 레이블을 가진 파드와
|
||||
동일한 영역의 노드에 스케줄되지 않는다.
|
||||
[디자인 문서](https://git.k8s.io/community/contributors/design-proposals/scheduling/podaffinity.md)를 통해
|
||||
`requiredDuringSchedulingIgnoredDuringExecution` 와 `preferredDuringSchedulingIgnoredDuringExecution` 의
|
||||
파드 어피니티와 안티-어피니티에 대한 많은 예시를 맛볼 수 있다.
|
||||
이 예시는 하나의 파드 어피니티 규칙과
|
||||
하나의 파드 안티-어피니티 규칙을 정의한다.
|
||||
파드 어피니티 규칙은 "하드" `requiredDuringSchedulingIgnoredDuringExecution`을,
|
||||
안티-어피니티 규칙은 "소프트" `preferredDuringSchedulingIgnoredDuringExecution`을 사용한다.
|
||||
|
||||
파드 어피니티와 안티-어피니티의 적합한 연산자는 `In`, `NotIn`, `Exists`, `DoesNotExist` 이다.
|
||||
위의 어피니티 규칙은 `security=S1` 레이블이 있는 하나 이상의 기존 파드의 존와 동일한 존에 있는 노드에만
|
||||
파드를 스케줄링하도록 스케줄러에 지시한다.
|
||||
더 정확히 말하면, 만약 `security=S1` 파드 레이블이 있는 하나 이상의 기존 파드를 실행하고 있는 노드가
|
||||
`zone=V`에 하나 이상 존재한다면,
|
||||
스케줄러는 파드를 `topology.kubernetes.io/zone=V` 레이블이 있는 노드에 배치해야 한다.
|
||||
|
||||
원칙적으로, `topologyKey` 는 적법한 어느 레이블-키도 될 수 있다.
|
||||
하지만, 성능과 보안상의 이유로 topologyKey에는 몇 가지 제약조건이 있다.
|
||||
위의 안티-어피니티 규칙은 `security=S2` 레이블이 있는 하나 이상의 기존 파드의 존와 동일한 존에 있는 노드에는
|
||||
가급적 파드를 스케줄링하지 않도록 스케줄러에 지시한다.
|
||||
더 정확히 말하면, 만약 `security=S2` 파드 레이블이 있는 파드가 실행되고 있는 `zone=R`에
|
||||
다른 노드도 존재한다면,
|
||||
스케줄러는 `topology.kubernetes.io/zone=R` 레이블이 있는 노드에는 가급적 해당 파드를 스케줄링하지 않야아 한다.
|
||||
|
||||
1. 파드 어피니티에서 `requiredDuringSchedulingIgnoredDuringExecution` 와 `preferredDuringSchedulingIgnoredDuringExecution` 는
|
||||
`topologyKey` 의 빈 값을 허용하지 않는다.
|
||||
2. 파드 안티-어피니티에서도 `requiredDuringSchedulingIgnoredDuringExecution` 와 `preferredDuringSchedulingIgnoredDuringExecution` 는
|
||||
`topologyKey` 의 빈 값을 허용하지 않는다.
|
||||
3. `requiredDuringSchedulingIgnoredDuringExecution` 파드 안티-어피니티에서 `topologyKey` 를 `kubernetes.io/hostname` 로 제한하기 위해 어드미션 컨트롤러 `LimitPodHardAntiAffinityTopology` 가 도입되었다. 사용자 지정 토폴로지를 사용할 수 있도록 하려면, 어드미션 컨트롤러를 수정하거나 아니면 이를 비활성화해야 한다.
|
||||
4. 위의 경우를 제외하고, `topologyKey` 는 적법한 어느 레이블-키도 가능하다.
|
||||
[디자인 문서](https://git.k8s.io/community/contributors/design-proposals/scheduling/podaffinity.md)에서
|
||||
파드 어피니티와 안티-어피니티에 대한
|
||||
많은 예시를 볼 수 있다.
|
||||
|
||||
`labelSelector` 와 `topologyKey` 외에도 `labelSelector` 와 일치해야 하는 네임스페이스 목록 `namespaces` 를
|
||||
선택적으로 지정할 수 있다(이것은 `labelSelector` 와 `topologyKey` 와 같은 수준의 정의이다).
|
||||
생략되어 있거나 비어있을 경우 어피니티/안티-어피니티 정의가 있는 파드의 네임스페이스가 기본 값이다.
|
||||
파드 어피니티와 안티-어피니티의 `operator` 필드에
|
||||
`In`, `NotIn`, `Exists` 및 `DoesNotExist` 값을 사용할 수 있다.
|
||||
|
||||
파드를 노드에 스케줄하려면 `requiredDuringSchedulingIgnoredDuringExecution` 어피니티와 안티-어피니티와
|
||||
연관된 `matchExpressions` 가 모두 충족되어야 한다.
|
||||
원칙적으로, `topologyKey` 에는 성능과 보안상의 이유로 다음의 예외를 제외하면
|
||||
어느 레이블 키도 사용할 수 있다.
|
||||
|
||||
#### 네임스페이스 셀렉터
|
||||
{{< feature-state for_k8s_version="v1.22" state="beta" >}}
|
||||
* 파드 어피니티 및 안티-어피니티에 대해, 빈 `topologyKey` 필드는
|
||||
`requiredDuringSchedulingIgnoredDuringExecution` 및 `preferredDuringSchedulingIgnoredDuringExecution` 내에 허용되지 않는다.
|
||||
* `requiredDuringSchedulingIgnoredDuringExecution` 파드 안티-어피니티 규칙에 대해,
|
||||
`LimitPodHardAntiAffinityTopology` 어드미션 컨트롤러는
|
||||
`topologyKey`를 `kubernetes.io/hostname`으로 제한한다.
|
||||
커스텀 토폴로지를 허용하고 싶다면 어드미션 컨트롤러를 수정하거나 비활성화할 수 있다.
|
||||
|
||||
사용자는 네임스페이스 집합에 대한 레이블 쿼리인 `namespaceSelector` 를 사용하여 일치하는 네임스페이스를 선택할 수도 있다.
|
||||
어피니티 용어는 `namespaceSelector` 에서 선택한 네임스페이스와 `namespaces` 필드에 나열된 네임스페이스의 결합에 적용된다.
|
||||
빈 `namespaceSelector` ({})는 모든 네임스페이스와 일치하는 반면, null 또는 빈 `namespaces` 목록과
|
||||
null `namespaceSelector` 는 "이 파드의 네임스페이스"를 의미한다.
|
||||
`labelSelector`와 `topologyKey`에 더하여 선택적으로,
|
||||
`labelSelector`가 비교해야 하는 네임스페이스의 목록을
|
||||
`labelSelector` 및 `topologyKey` 필드와 동일한 계위의 `namespaces` 필드에 명시할 수 있다.
|
||||
생략하거나 비워 두면,
|
||||
해당 어피니티/안티-어피니티 정의가 있는 파드의 네임스페이스를 기본값으로 사용한다.
|
||||
|
||||
이 기능은 베타이며 기본으로 활성화되어 있다. kube-apiserver 및 kube-scheduler 모두에서
|
||||
[기능 게이트](/ko/docs/reference/command-line-tools-reference/feature-gates/)
|
||||
`PodAffinityNamespaceSelector` 를 사용하여 비활성화할 수 있다.
|
||||
#### 네임스페이스 셀렉터 {#namespace-selector}
|
||||
{{< feature-state for_k8s_version="v1.24" state="stable" >}}
|
||||
|
||||
#### 더 실용적인 유스케이스
|
||||
네임스페이스 집합에 대한 레이블 쿼리인 `namespaceSelector` 를 사용하여 일치하는 네임스페이스를 선택할 수도 있다.
|
||||
`namespaceSelector` 또는 `namespaces` 필드에 의해 선택된 네임스페이스 모두에 적용된다.
|
||||
빈 `namespaceSelector` ({})는 모든 네임스페이스와 일치하는 반면,
|
||||
null 또는 빈 `namespaces` 목록과 null `namespaceSelector` 는 규칙이 적용된 파드의 네임스페이스에 매치된다.
|
||||
|
||||
파드간 어피니티와 안티-어피니티는 레플리카셋, 스테이트풀셋, 디플로이먼트 등과 같은
|
||||
상위 레벨 모음과 함께 사용할 때 더욱 유용할 수 있다. 워크로드 집합이 동일한 노드와 같이
|
||||
#### 더 실제적인 유스케이스 {#more-practical-use-cases}
|
||||
|
||||
파드간 어피니티와 안티-어피니티는 레플리카셋, 스테이트풀셋, 디플로이먼트 등과 같은
|
||||
상위 레벨 모음과 함께 사용할 때 더욱 유용할 수 있다.
|
||||
이러한 규칙을 사용하여, 워크로드 집합이 예를 들면 '동일한 노드'와 같이
|
||||
동일하게 정의된 토폴로지와 같은 위치에 배치되도록 쉽게 구성할 수 있다.
|
||||
|
||||
##### 항상 같은 노드에 위치시키기
|
||||
redis와 같은 인-메모리 캐시를 사용하는 웹 애플리케이션을 실행하는 세 개의 노드로 구성된 클러스터를 가정한다.
|
||||
이 때 웹 서버를 가능한 한 캐시와 같은 위치에서 실행되도록 하기 위해
|
||||
파드간 어피니티/안티-어피니티를 사용할 수 있다.
|
||||
|
||||
세 개의 노드가 있는 클러스터에서 웹 애플리케이션에는 redis와 같은 인-메모리 캐시가 있다. 웹 서버가 가능한 캐시와 함께 위치하기를 원한다.
|
||||
|
||||
다음은 세 개의 레플리카와 셀렉터 레이블이 `app=store` 가 있는 간단한 redis 디플로이먼트의 yaml 스니펫이다. 디플로이먼트에는 스케줄러가 단일 노드에서 레플리카를 함께 배치하지 않도록 `PodAntiAffinity` 가 구성되어 있다.
|
||||
다음의 redis 캐시 디플로이먼트 예시에서, 레플리카는 `app=store` 레이블을 갖는다.
|
||||
`podAntiAffinity` 규칙은 스케줄러로 하여금
|
||||
`app=store` 레이블이 있는 레플리카를 한 노드에 여러 개 배치하지 못하도록 한다.
|
||||
이렇게 하여 캐시 파드를 각 노드에 분산하여 생성한다.
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
|
@ -324,7 +379,10 @@ spec:
|
|||
image: redis:3.2-alpine
|
||||
```
|
||||
|
||||
아래 yaml 스니펫의 웹서버 디플로이먼트는 `podAntiAffinity` 와 `podAffinity` 설정을 가지고 있다. 이렇게 하면 스케줄러에 모든 레플리카는 셀렉터 레이블이 `app=store` 인 파드와 함께 위치해야 한다. 또한 각 웹 서버 레플리카가 단일 노드의 같은 위치에 있지 않도록 한다.
|
||||
웹 서버를 위한 다음의 디플로이먼트는 `app=web-store` 레이블을 갖는 레플리카를 생성한다.
|
||||
파드 어피니티 규칙은 스케줄러로 하여금 `app=store` 레이블이 있는 파드를 실행 중인 노드에 각 레플리카를 배치하도록 한다.
|
||||
파드 안티-어피니티 규칙은 스케줄러로 하여금 `app=web-store` 레이블이 있는 서버 파드를
|
||||
한 노드에 여러 개 배치하지 못하도록 한다.
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
|
@ -365,44 +423,25 @@ spec:
|
|||
image: nginx:1.16-alpine
|
||||
```
|
||||
|
||||
만약 위의 두 디플로이먼트를 생성하면 세 개의 노드가 있는 클러스터는 다음과 같아야 한다.
|
||||
위의 두 디플로이먼트를 생성하면 다음과 같은 클러스터 형상이 나타나는데,
|
||||
세 노드에 각 웹 서버가 캐시와 함께 있는 형상이다.
|
||||
|
||||
| node-1 | node-2 | node-3 |
|
||||
|:--------------------:|:-------------------:|:------------------:|
|
||||
| *webserver-1* | *webserver-2* | *webserver-3* |
|
||||
| *cache-1* | *cache-2* | *cache-3* |
|
||||
|
||||
여기서 볼 수 있듯이 `web-server` 의 세 레플리카들이 기대했던 것처럼 자동으로 캐시와 함께 위치하게 된다.
|
||||
[ZooKeeper 튜토리얼](/ko/docs/tutorials/stateful-application/zookeeper/#노드-실패-방지)에서
|
||||
위 예시와 동일한 기술을 사용해
|
||||
고 가용성을 위한 안티-어피니티로 구성된 스테이트풀셋의 예시를 확인한다.
|
||||
|
||||
```
|
||||
kubectl get pods -o wide
|
||||
```
|
||||
출력은 다음과 유사할 것이다.
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
redis-cache-1450370735-6dzlj 1/1 Running 0 8m 10.192.4.2 kube-node-3
|
||||
redis-cache-1450370735-j2j96 1/1 Running 0 8m 10.192.2.2 kube-node-1
|
||||
redis-cache-1450370735-z73mh 1/1 Running 0 8m 10.192.3.1 kube-node-2
|
||||
web-server-1287567482-5d4dz 1/1 Running 0 7m 10.192.2.3 kube-node-1
|
||||
web-server-1287567482-6f7v5 1/1 Running 0 7m 10.192.4.3 kube-node-3
|
||||
web-server-1287567482-s330j 1/1 Running 0 7m 10.192.3.2 kube-node-2
|
||||
```
|
||||
## nodeName {#nodename}
|
||||
|
||||
##### 절대 동일한 노드에 위치시키지 않게 하기
|
||||
|
||||
위의 예시에서 `topologyKey:"kubernetes.io/hostname"` 과 함께 `PodAntiAffinity` 규칙을 사용해서
|
||||
두 개의 인스터스가 동일한 호스트에 있지 않도록 redis 클러스터를 배포한다.
|
||||
같은 기술을 사용해서 고 가용성을 위해 안티-어피니티로 구성된 스테이트풀셋의 예시는
|
||||
[ZooKeeper 튜토리얼](/ko/docs/tutorials/stateful-application/zookeeper/#노드-실패-방지)을 본다.
|
||||
|
||||
## nodeName
|
||||
|
||||
`nodeName` 은 가장 간단한 형태의 노트 선택 제약 조건이지만,
|
||||
한계로 인해 일반적으로는 사용하지 않는다.
|
||||
`nodeName` 은 PodSpec의 필드이다. 만약 비어있지 않으면, 스케줄러는
|
||||
파드를 무시하고 명명된 노드에서 실행 중인 kubelet이
|
||||
파드를 실행하려고 한다. 따라서 만약 PodSpec에 `nodeName` 가
|
||||
제공된 경우, 노드 선택을 위해 위의 방법보다 우선한다.
|
||||
`nodeName`은 어피니티 또는 `nodeSelector`보다 더 직접적인 형태의 노드 선택 방법이다.
|
||||
`nodeName`은 파드 스펙의 필드 중 하나이다.
|
||||
`nodeName` 필드가 비어 있지 않으면, 스케줄러는 파드를 무시하고,
|
||||
명명된 노드의 kubelet이 해당 파드를 자기 노드에 배치하려고 시도한다.
|
||||
`nodeName`은 `nodeSelector` 또는 어피니티/안티-어피니티 규칙이 무시된다.
|
||||
|
||||
`nodeName` 을 사용해서 노드를 선택할 때의 몇 가지 제한은 다음과 같다.
|
||||
|
||||
|
@ -414,7 +453,7 @@ web-server-1287567482-s330j 1/1 Running 0 7m 10.192.3
|
|||
- 클라우드 환경의 노드 이름은 항상 예측 가능하거나
|
||||
안정적인 것은 아니다.
|
||||
|
||||
여기에 `nodeName` 필드를 사용하는 파드 설정 파일 예시가 있다.
|
||||
다음은 `nodeName` 필드를 사용하는 파드 스펙 예시이다.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
|
@ -428,19 +467,14 @@ spec:
|
|||
nodeName: kube-01
|
||||
```
|
||||
|
||||
위 파드는 kube-01 노드에서 실행될 것이다.
|
||||
|
||||
|
||||
위 파드는 `kube-01` 노드에서만 실행될 것이다.
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
|
||||
[테인트](/ko/docs/concepts/scheduling-eviction/taint-and-toleration/)는 노드가 특정 파드들을 *쫓아낼* 수 있다.
|
||||
|
||||
[노드 어피니티](https://git.k8s.io/community/contributors/design-proposals/scheduling/nodeaffinity.md)와
|
||||
[파드간 어피니티/안티-어피니티](https://git.k8s.io/community/contributors/design-proposals/scheduling/podaffinity.md)에 대한 디자인 문서에는
|
||||
이러한 기능에 대한 추가 배경 정보가 있다.
|
||||
|
||||
파드가 노드에 할당되면 kubelet은 파드를 실행하고 노드의 로컬 리소스를 할당한다.
|
||||
[토폴로지 매니저](/docs/tasks/administer-cluster/topology-manager/)는
|
||||
노드 수준의 리소스 할당 결정에 참여할 수 있다.
|
||||
* [테인트 및 톨러레이션](/ko/docs/concepts/scheduling-eviction/taint-and-toleration/)에 대해 더 읽어본다.
|
||||
* [노드 어피니티](https://git.k8s.io/community/contributors/design-proposals/scheduling/nodeaffinity.md)와
|
||||
[파드간 어피니티/안티-어피니티](https://git.k8s.io/community/contributors/design-proposals/scheduling/podaffinity.md)에 대한 디자인 문서를 읽어본다.
|
||||
* [토폴로지 매니저](/docs/tasks/administer-cluster/topology-manager/)가
|
||||
노드 수준 리소스 할당 결정에 어떻게 관여하는지 알아본다.
|
||||
* [노드셀렉터(nodeSelector)](/ko/docs/tasks/configure-pod-container/assign-pods-nodes/)를 어떻게 사용하는지 알아본다.
|
||||
* [어피니티/안티-어피니티](/ko/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/)를 어떻게 사용하는지 알아본다.
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: with-affinity-anti-affinity
|
||||
spec:
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: kubernetes.io/os
|
||||
operator: In
|
||||
values:
|
||||
- linux
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 1
|
||||
preference:
|
||||
matchExpressions:
|
||||
- key: label-1
|
||||
operator: In
|
||||
values:
|
||||
- key-1
|
||||
- weight: 50
|
||||
preference:
|
||||
matchExpressions:
|
||||
- key: label-2
|
||||
operator: In
|
||||
values:
|
||||
- key-2
|
||||
containers:
|
||||
- name: with-node-affinity
|
||||
image: k8s.gcr.io/pause:2.0
|
Loading…
Reference in New Issue