Third Korean l10n work for release 1.18
- Translate cluster-administration/networking.md in Korean - Fix issue with concepts/storage/volumes.md - Translate /concepts/configuration/pod-overhead in Korean - Update to Outdated files in the dev-1.18-ko.3 branch. - Translate concepts/configuration/configmap.md in Korean - Translate contribute/review/reviewing-prs/ in Korean - Translate concepts/configuration/pod-priority-preemption.md in Korean - Translate tasks/configure-pod-container/configure-volume-storage in Korean - Translate contribute/new-content/new-content/ in Korean - Translate concepts/architecture/control-plane-node-communication.md in Korean - Restore the deleted master-node-communication.md file - Translate concepts/cluster-administration/addons.md in Korean - Translate contribute/new-content/overview/ in Korean - Translate tasks/tools/install-kubectl.md in Korean - Translate concepts/configuration/manage-resources-containers.md in Korean - Translate tasks/administer-cluster/kubeadm/kubeadm-upgrade/ in Korean - add new words to Korean glossary and fix minor - Translate contribute/style/_index.md in Korean - Translate concepts/cloud-administration/cloud-providers.md in Korean - Translate contribute/review/for-approvers.md in Korean Co-authored-by: Jerry Park <jaehwa@gmail.com> Co-authored-by: Seokho Son <shsongist@gmail.com> Co-authored-by: jmyung <jesang.myung@gmail.com> Co-authored-by: coolguyhong <podolsmith@naver.com> Co-authored-by: Yuk, Yongsu <ysyukr@gmail.com> Co-authored-by: bluefriday <bluefriday86@gmail.com> Co-authored-by: SangshikLee <neolss@gmail.com>
This commit is contained in:
committed by
Claudia J.Kang
parent
c74ce882ec
commit
ca62e21766
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: 노드에 파드 할당하기
|
||||
content_template: templates/concept
|
||||
weight: 30
|
||||
weight: 50
|
||||
---
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
---
|
||||
title: 컨피그맵(ConfigMap)
|
||||
content_template: templates/concept
|
||||
weight: 20
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
{{< glossary_definition term_id="configmap" prepend="컨피그맵은" length="all" >}}
|
||||
|
||||
{{< caution >}}
|
||||
컨피그맵은 보안 또는 암호화를 제공하지 않는다.
|
||||
저장하려는 데이터가 기밀인 경우, 컨피그맵
|
||||
대신 {{< glossary_tooltip text="시크릿(Secret)" term_id="secret" >}} 또는 추가(써드파티) 도구를
|
||||
사용하여 데이터를 비공개로 유지하자.
|
||||
{{< /caution >}}
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
## 사용 동기
|
||||
|
||||
애플리케이션 코드와 별도로 구성 데이터를 설정하려면 컨피그맵을 사용하자.
|
||||
|
||||
예를 들어, 자신의 컴퓨터(개발용)와 클라우드(실제 트래픽 처리)에서
|
||||
실행할 수 있는 애플리케이션을 개발한다고 가정해보자.
|
||||
`DATABASE_HOST` 라는
|
||||
환경 변수를 찾기 위해 코드를 작성한다. 로컬에서는 해당 변수를
|
||||
`localhost` 로 설정한다. 클라우드에서는, 데이터베이스
|
||||
컴포넌트를 클러스터에 노출하는 쿠버네티스 {{< glossary_tooltip text="서비스" term_id="service" >}}를 참조하도록
|
||||
설정한다.
|
||||
|
||||
이를 통해 클라우드에서 실행 중인 컨테이너 이미지를 가져와
|
||||
필요한 경우 정확히 동일한 코드를 로컬에서 디버깅할 수 있다.
|
||||
|
||||
## 컨피그맵 오브젝트
|
||||
|
||||
컨피그맵은 다른 오브젝트가 사용할 구성을 저장할 수 있는
|
||||
API [오브젝트](/ko/docs/concepts/overview/working-with-objects/kubernetes-objects/)이다.
|
||||
`spec` 이 있는 대부분의 쿠버네티스 오브젝트와 달리,
|
||||
컨피그맵에는 항목(키)과 해당 값을 저장하는 `data` 섹션이 있다.
|
||||
|
||||
컨피그맵의 이름은 유효한
|
||||
[DNS 서브도메인 이름](/ko/docs/concepts/overview/working-with-objects/names/#dns-서브도메인-이름)이어야 한다.
|
||||
|
||||
## 컨피그맵과 파드(Pod)
|
||||
|
||||
컨피그맵을 참조하는 파드 `spec` 을 작성하고 컨피그맵의 데이터를
|
||||
기반으로 해당 파드의 컨테이너를 구성할 수 있다. 파드와 컨피그맵은
|
||||
동일한 {{< glossary_tooltip text="네임스페이스" term_id="namespace" >}}에 있어야 한다.
|
||||
|
||||
다음은 단일 값을 가진 키와,
|
||||
값이 구성 형식의 일부처럼 보이는 키를 가진 컨피그맵의
|
||||
예시이다.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
Name: game-demo
|
||||
data:
|
||||
# 속성과 비슷한 키; 각 키는 간단한 값으로 매핑됨
|
||||
player_initial_lives: 3
|
||||
ui_properties_file_name: "user-interface.properties"
|
||||
#
|
||||
# 파일과 비슷한 키
|
||||
game.properties: |
|
||||
enemy.types=aliens,monsters
|
||||
player.maximum-lives=5
|
||||
user-interface.properties: |
|
||||
color.good=purple
|
||||
color.bad=yellow
|
||||
allow.textmode=true
|
||||
```
|
||||
|
||||
컨피그맵을 사용하여 파드 내부에 컨테이너를 구성할 수 있는
|
||||
네 가지 방법이 있다.
|
||||
|
||||
1. 컨테이너의 엔트리포인트에 대한 커맨드 라인 인수
|
||||
1. 컨테이너에 대한 환경 변수
|
||||
1. 애플리케이션이 읽을 수 있도록 읽기 전용 볼륨에 파일 추가
|
||||
1. 쿠버네티스 API를 사용하여 컨피그맵을 읽는 파드 내에서 실행할 코드 작성
|
||||
|
||||
이러한 방법들은 소비되는 데이터를 모델링하는
|
||||
방식에 따라 다르게 쓰인다.
|
||||
처음 세 가지 방법의 경우,
|
||||
{{< glossary_tooltip text="kubelet" term_id="kubelet" >}}은 파드의 컨테이너를 시작할 때
|
||||
시크릿의 데이터를 사용한다.
|
||||
|
||||
네 번째 방법은 시크릿과 데이터를 읽기 위해 코드를 작성해야 한다는 것을 의미한다.
|
||||
그러나, 쿠버네티스 API를 직접 사용하기 때문에, 애플리케이션은
|
||||
컨피그맵이 변경될 때마다 업데이트를 받기 위해 구독할 수 있고, 업데이트가
|
||||
있으면 반응한다. 쿠버네티스 API에 직접 접근하면, 이
|
||||
기술을 사용하여 다른 네임스페이스의 컨피그맵에 접근할 수도 있다.
|
||||
|
||||
다음은 `game-demo` 의 값을 사용하여 파드를 구성하는 파드 예시이다.
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: configmap-demo-pod
|
||||
spec:
|
||||
containers:
|
||||
- name: demo
|
||||
image: game.example/demo-game
|
||||
env:
|
||||
# 환경 변수 정의
|
||||
- name: PLAYER_INITIAL_LIVES # 참고로 여기서는 컨피그맵의 키 이름과
|
||||
# 대소문자가 다르다.
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: game-demo # 이 값의 컨피그맵.
|
||||
key: player_initial_lives # 가져올 키.
|
||||
- name: UI_PROPERTIES_FILE_NAME
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: game-demo
|
||||
key: ui_properties_file_name
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: "/config"
|
||||
readOnly: true
|
||||
volumes:
|
||||
# 파드 레벨에서 볼륨을 설정한 다음, 해당 파드 내의 컨테이너에 마운트한다.
|
||||
- name: config
|
||||
configMap:
|
||||
# 마운트하려는 컨피그맵의 이름을 제공한다.
|
||||
name: game-demo
|
||||
```
|
||||
|
||||
|
||||
컨피그맵은 단일 라인 속성(single line property) 값과 멀티 라인의 파일과 비슷한(multi-line file-like) 값을
|
||||
구분하지 않는다.
|
||||
더 중요한 것은 파드와 다른 오브젝트가 이러한 값을 소비하는 방식이다.
|
||||
이 예제에서, 볼륨을 정의하고 `demo` 컨테이너에
|
||||
`/config` 로 마운트하면 4개의 파일이 생성된다.
|
||||
|
||||
- `/config/player_initial_lives`
|
||||
- `/config/ui_properties_file_name`
|
||||
- `/config/game.properties`
|
||||
- `/config/user-interface.properties`
|
||||
|
||||
`/config` 에 `.properties` 확장자를 가진 파일만
|
||||
포함시키려면, 두 개의 다른 컨피그맵을 사용하고, 파드에
|
||||
대해서는 `spec` 의 두 컨피그맵을 참조한다. 첫 번째 컨피그맵은
|
||||
`player_initial_lives` 와 `ui_properties_file_name` 을 정의한다. 두 번째
|
||||
컨피그맵은 kubelet이 `/config` 에 넣는 파일을 정의한다.
|
||||
|
||||
{{< note >}}
|
||||
컨피그맵을 사용하는 가장 일반적인 방법은 동일한 네임스페이스의
|
||||
파드에서 실행되는 컨테이너에 대한 설정을 구성하는 것이다. 컨피그맵을
|
||||
별도로 사용할 수도 있다.
|
||||
|
||||
예를 들어,
|
||||
컨피그맵에 기반한 동작을 조정하는 {{< glossary_tooltip text="애드온" term_id="addons" >}}이나
|
||||
{{< glossary_tooltip text="오퍼레이터" term_id="operator-pattern" >}}를
|
||||
사용할 수도 있다.
|
||||
{{< /note >}}
|
||||
|
||||
|
||||
{{% /capture %}}
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* [시크릿](/docs/concepts/configuration/secret/)에 대해 읽어본다.
|
||||
* [컨피그맵을 사용하도록 파드 구성하기](/docs/tasks/configure-pod-container/configure-pod-configmap/)를 읽어본다.
|
||||
* 코드를 구성에서 분리하려는 동기를 이해하려면
|
||||
[Twelve-Factor 앱](https://12factor.net/ko/)을 읽어본다.
|
||||
|
||||
{{% /capture %}}
|
||||
@@ -0,0 +1,761 @@
|
||||
---
|
||||
title: 컨테이너 리소스 관리
|
||||
content_template: templates/concept
|
||||
weight: 40
|
||||
feature:
|
||||
title: 자동 빈 패킹(bin packing)
|
||||
description: >
|
||||
리소스 요구 사항과 기타 제약 조건에 따라 컨테이너를 자동으로 배치하지만, 가용성은 그대로 유지한다. 활용도를 높이고 더 많은 리소스를 절약하기 위해 중요한(critical) 워크로드와 최선의(best-effort) 워크로드를 혼합한다.
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
{{< glossary_tooltip text="파드" term_id="pod" >}}를 지정할 때,
|
||||
{{< glossary_tooltip text="컨테이너" term_id="container" >}}에 필요한 각 리소스의 양을 선택적으로 지정할 수 있다.
|
||||
지정할 가장 일반적인 리소스는 CPU와 메모리(RAM) 그리고 다른 것들이 있다.
|
||||
|
||||
파드에서 컨테이너에 대한 리소스 _요청(request)_ 을 지정하면, 스케줄러는 이 정보를
|
||||
사용하여 파드가 배치될 노드를 결정한다. 컨테이너에 대한 리소스 _제한(limit)_ 을
|
||||
지정하면, kubelet은 실행 중인 컨테이너가 설정한 제한보다 많은 리소스를
|
||||
사용할 수 없도록 해당 제한을 적용한다. 또한 kubelet은
|
||||
컨테이너가 사용할 수 있도록 해당 시스템 리소스의 최소 _요청_ 량을
|
||||
예약한다.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## 요청 및 제한
|
||||
|
||||
파드가 실행 중인 노드에 사용 가능한 리소스가 충분하면, 컨테이너가 해당
|
||||
리소스에 지정한 `request` 보다 더 많은 리소스를 사용할 수 있도록 허용된다.
|
||||
그러나, 컨테이너는 리소스 `limit` 보다 더 많은 리소스를 사용할 수는 없다.
|
||||
|
||||
예를 들어, 컨테이너에 대해 256MiB의 `memory` 요청을 설정하고, 해당 컨테이너가
|
||||
8GiB의 메모리를 가진 노드로 스케줄된 파드에 있고 다른 파드는 없는 경우, 컨테이너는 더 많은 RAM을
|
||||
사용할 수 있다.
|
||||
|
||||
해당 컨테이너에 대해 4GiB의 `memory` 제한을 설정하면, kubelet(그리고
|
||||
{{< glossary_tooltip text="컨테이너 런타임" term_id="container-runtime" >}})이 제한을 적용한다.
|
||||
런타임은 컨테이너가 구성된 리소스 제한을 초과하여 사용하지 못하게 한다. 예를 들어,
|
||||
컨테이너의 프로세스가 허용된 양보다 많은 메모리를 사용하려고 하면,
|
||||
시스템 커널은 메모리 부족(out of memory, OOM) 오류와 함께 할당을 시도한 프로세스를
|
||||
종료한다.
|
||||
|
||||
제한은 반응적(시스템이 위반을 감지한 후에 개입)으로
|
||||
또는 강제적(시스템이 컨테이너가 제한을 초과하지 않도록 방지)으로 구현할 수 있다. 런타임마다
|
||||
다른 방식으로 동일한 제약을 구현할 수 있다.
|
||||
|
||||
## 리소스 타입
|
||||
|
||||
*CPU* 와 *메모리* 는 각각 *리소스 타입* 이다. 리소스 타입에는 기본 단위가 있다.
|
||||
CPU는 컴퓨팅 처리를 나타내며 [쿠버네티스 CPU](#cpu의-의미) 단위로 지정된다.
|
||||
메모리는 바이트 단위로 지정된다.
|
||||
쿠버네티스 v1.14 이상을 사용하는 경우, _huge page_ 리소스를 지정할 수 있다.
|
||||
Huge page는 노드 커널이 기본 페이지 크기보다 훨씬 큰 메모리
|
||||
블록을 할당하는 리눅스 관련 기능이다.
|
||||
|
||||
예를 들어, 기본 페이지 크기가 4KiB인 시스템에서, `hugepages-2Mi: 80Mi` 제한을
|
||||
지정할 수 있다. 컨테이너가 40개 이상의 2MiB huge page(총 80MiB)를
|
||||
할당하려고 하면 해당 할당이 실패한다.
|
||||
|
||||
{{< note >}}
|
||||
`hugepages-*` 리소스를 오버커밋할 수 없다.
|
||||
이것은 `memory` 및 `cpu` 리소스와는 다르다.
|
||||
{{< /note >}}
|
||||
|
||||
CPU와 메모리를 통칭하여 *컴퓨트 리소스* 또는 그냥 *리소스* 라고 한다. 컴퓨트
|
||||
리소스는 요청, 할당 및 소비될 수 있는 측정 가능한
|
||||
수량이다. 이것은
|
||||
[API 리소스](/ko/docs/concepts/overview/kubernetes-api/)와는 다르다. 파드 및
|
||||
[서비스](/ko/docs/concepts/services-networking/service/)와 같은 API 리소스는
|
||||
쿠버네티스 API 서버를 통해 읽고 수정할 수
|
||||
있는 오브젝트이다.
|
||||
|
||||
## 파드와 컨테이너의 리소스 요청 및 제한
|
||||
|
||||
파드의 각 컨테이너는 다음 중 하나 이상을 지정할 수 있다.
|
||||
|
||||
* `spec.containers[].resources.limits.cpu`
|
||||
* `spec.containers[].resources.limits.memory`
|
||||
* `spec.containers[].resources.limits.hugepages-<size>`
|
||||
* `spec.containers[].resources.requests.cpu`
|
||||
* `spec.containers[].resources.requests.memory`
|
||||
* `spec.containers[].resources.requests.hugepages-<size>`
|
||||
|
||||
요청과 제한은 개별 컨테이너에서만 지정할 수 있지만,
|
||||
파드 리소스 요청 및 제한에 대해 이야기하는 것이 편리하다.
|
||||
특정 리소스 타입에 대한 *파드 리소스 요청/제한* 은 파드의 각 컨테이너에 대한
|
||||
해당 타입의 리소스 요청/제한의 합이다.
|
||||
|
||||
## 쿠버네티스의 리소스 단위
|
||||
|
||||
### CPU의 의미
|
||||
|
||||
CPU 리소스에 대한 제한 및 요청은 *cpu* 단위로 측정된다.
|
||||
쿠버네티스의 CPU 1개는 클라우드 공급자용 **vCPU/Core 1개** 와 베어메탈 인텔 프로세서에서의 **1개 하이퍼스레드** 에 해당한다.
|
||||
|
||||
분수의 요청이 허용된다.
|
||||
`0.5` 의 `spec.containers[].resources.requests.cpu` 요청을 가진
|
||||
컨테이너는 CPU 1개를 요구하는 컨테이너의 절반만큼 CPU를 보장한다. `0.1` 이라는 표현은
|
||||
"백 밀리cpu"로 읽을 수 있는 `100m` 표현과 동일하다. 어떤 사람들은
|
||||
"백 밀리코어"라고 말하는데, 같은 것을 의미하는 것으로 이해된다.
|
||||
`0.1` 과 같이 소수점이 있는 요청은 API에 의해 `100m` 로 변환되며,
|
||||
`1m` 도 허용되지 않게 정밀하다. 이러한 이유로, `100m` 형식이
|
||||
선호될 수 있다.
|
||||
|
||||
CPU는 항상 절대 수량으로 요청되며, 상대적 수량은 아니다.
|
||||
0.1은 단일 코어, 이중 코어 또는 48코어 시스템에서 동일한 양의 CPU이다.
|
||||
|
||||
### 메모리의 의미
|
||||
|
||||
`memory` 에 대한 제한 및 요청은 바이트 단위로 측정된다.
|
||||
E, P, T, G, M, K와 같은 접미사 중 하나를 사용하여 메모리를
|
||||
일반 정수 또는 고정 소수점 정수로 표현할 수 있다. Ei, Pi, Ti, Gi, Mi, Ki와
|
||||
같은 2의 거듭제곱을 사용할 수도 있다. 예를 들어, 다음은 대략 동일한 값을 나타낸다.
|
||||
|
||||
```shell
|
||||
128974848, 129e6, 129M, 123Mi
|
||||
```
|
||||
|
||||
다음은 예제이다.
|
||||
다음 파드에는 두 개의 컨테이너가 있다. 각 컨테이너에는 0.25 cpu와
|
||||
64MiB(2<sup>26</sup> 바이트)의 메모리 요청이 있다. 각 컨테이너는 0.5
|
||||
cpu와 128MiB 메모리로 제한된다. 파드에 0.5 cpu와 128 MiB
|
||||
메모리, 1 cpu와 256MiB 메모리 제한이 있다고 말할 수 있다.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
containers:
|
||||
- name: db
|
||||
image: mysql
|
||||
env:
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
value: "password"
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "500m"
|
||||
- name: wp
|
||||
image: wordpress
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "500m"
|
||||
```
|
||||
|
||||
## 리소스 요청이 포함된 파드를 스케줄링하는 방법
|
||||
|
||||
파드를 생성할 때, 쿠버네티스 스케줄러는 파드를 실행할 노드를
|
||||
선택한다. 각 노드는 파드에 제공할 수 있는 CPU와 메모리 양과 같은 각 리소스 타입에 대해
|
||||
최대 용량을 갖는다. 스케줄러는 각 리소스 타입마다
|
||||
스케줄된 컨테이너의 리소스 요청 합계가
|
||||
노드 용량보다 작도록 한다. 참고로 노드의 실제 메모리나
|
||||
CPU 리소스 사용량은 매우 적지만, 용량 확인에 실패한 경우
|
||||
스케줄러는 여전히 노드에 파드를 배치하지 않는다. 이는 리소스 사용량이
|
||||
나중에 증가할 때, 예를 들어, 일일 요청 비율이
|
||||
최대일 때 노드의 리소스 부족을 방지한다.
|
||||
|
||||
## 리소스 제한이 있는 파드가 실행되는 방법
|
||||
|
||||
kubelet은 파드의 컨테이너를 시작할 때, CPU와 메모리 제한을
|
||||
컨테이너 런타임으로 전달한다.
|
||||
|
||||
도커를 사용하는 경우에는 다음과 같다.
|
||||
|
||||
- `spec.containers[].resources.requests.cpu` 는 잠재적인 분수이며,
|
||||
1024를 곱한 값인 코어 값으로 변환된다. 이 숫자 또는 2보다
|
||||
큰 값은 `docker run` 명령에서
|
||||
[`--cpu-shares`](https://docs.docker.com/engine/reference/run/#cpu-share-constraint)
|
||||
플래그의 값으로 사용된다.
|
||||
|
||||
- 이 `spec.containers[].resources.limits.cpu` 값은 밀리코어 값으로 변환되고
|
||||
100을 곱한 값이다. 그 결과 값은 컨테이너가 100ms마다 사용할 수 있는 총 CPU
|
||||
시간이다. 이 간격 동안 컨테이너는 CPU 시간을 초과하여 사용할 수 없다.
|
||||
|
||||
{{< note >}}
|
||||
기본 쿼터 기간은 100ms이다. 최소 CPU 쿼터는 1ms이다.
|
||||
{{</ note >}}
|
||||
|
||||
- `spec.containers[].resources.limits.memory` 는 정수로 변환되어,
|
||||
`docker run` 명령에서
|
||||
[`--memory`](https://docs.docker.com/engine/reference/run/#/user-memory-constraints)
|
||||
플래그의 값으로 사용된다.
|
||||
|
||||
컨테이너가 메모리 제한을 초과하면, 컨테이너는 종료될 수 있다. 다시
|
||||
시작할 수 있으면, 다른 타입의 런타임 오류와 마찬가지로, kubelet이 다시
|
||||
시작한다.
|
||||
|
||||
컨테이너가 메모리 요청을 초과하면, 노드에 메모리가
|
||||
부족할 때마다 파드가 축출될 수 있다.
|
||||
|
||||
컨테이너가 오랫동안 CPU 제한을 초과하는 것은 허용되거나 허용되지
|
||||
않을 수 있다. 그러나, 과도한 CPU 사용으로 인해 종료되지는 않는다.
|
||||
|
||||
리소스 제한으로 인해 컨테이너를 스케줄할 수 없는지 또는
|
||||
종료 중인지 확인하려면,
|
||||
[문제 해결](#문제-해결) 섹션을 참조한다.
|
||||
|
||||
### 컴퓨트 및 메모리 리소스 사용량 모니터링
|
||||
|
||||
파드의 리소스 사용량은 파드 상태의 일부로 보고된다.
|
||||
|
||||
클러스터에서 선택적인 모니터링 도구를
|
||||
사용할 수 있다면, [메트릭 API](/ko/docs/tasks/debug-application-cluster/resource-metrics-pipeline/#메트릭-api)에서
|
||||
직접 또는 모니터링 도구에서 파드 리소스
|
||||
사용량을 검색할 수 있다.
|
||||
|
||||
## 로컬 임시(ephemeral) 스토리지
|
||||
|
||||
<!-- feature gate LocalStorageCapacityIsolation -->
|
||||
{{< feature-state for_k8s_version="v1.10" state="beta" >}}
|
||||
|
||||
노드에는 로컬에 연결된 쓰기 가능 장치 또는, 때로는 RAM에 의해
|
||||
지원되는 로컬 임시 스토리지가 있다.
|
||||
"임시"는 내구성에 대한 장기간의 보증이 없음을 의미한다.
|
||||
|
||||
파드는 스크래치 공간, 캐싱 및 로그에 대해 임시 로컬 스토리지를 사용한다.
|
||||
kubelet은 로컬 임시 스토리지를 사용하여 컨테이너에
|
||||
[`emptyDir`](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir)
|
||||
{{< glossary_tooltip term_id="volume" text="볼륨" >}}을 마운트하기 위해 파드에 스크래치 공간을 제공할 수 있다.
|
||||
|
||||
kubelet은 이러한 종류의 스토리지를 사용하여
|
||||
[노드-레벨 컨테이너 로그](/ko/docs/concepts/cluster-administration/logging/#노드-레벨에서의-로깅),
|
||||
컨테이너 이미지 및 실행 중인 컨테이너의 쓰기 가능 계층을 보유한다.
|
||||
|
||||
{{< caution >}}
|
||||
노드가 실패하면, 임시 스토리지의 데이터가 손실될 수 있다.
|
||||
애플리케이션은 로컬 임시 스토리지에서 성능에 대한 SLA(예: 디스크 IOPS)를
|
||||
기대할 수 없다.
|
||||
{{< /caution >}}
|
||||
|
||||
베타 기능에서, 쿠버네티스는 파드가 사용할 수 있는 임시 로컬 스토리지의 양을
|
||||
추적, 예약 및 제한할 수 있도록 해준다.
|
||||
|
||||
### 로컬 임시 스토리지 구성
|
||||
|
||||
쿠버네티스는 노드에서 로컬 임시 스토리지를 구성하는 두 가지 방법을 지원한다.
|
||||
{{< tabs name="local_storage_configurations" >}}
|
||||
{{% tab name="단일 파일시스템" %}}
|
||||
이 구성에서, 모든 종류의 임시 로컬 데이터(`emptyDir` 볼륨,
|
||||
쓰기 가능 계층, 컨테이너 이미지, 로그)를 하나의 파일시스템에 배치한다.
|
||||
kubelet을 구성하는 가장 효과적인 방법은 이 파일시스템을 쿠버네티스(kubelet) 데이터 전용으로
|
||||
하는 것이다.
|
||||
|
||||
kubelet은 또한
|
||||
[노드-레벨 컨테이너 로그](/ko/docs/concepts/cluster-administration/logging/#노드-레벨에서의-로깅)를
|
||||
작성하고 임시 로컬 스토리지와 유사하게 처리한다.
|
||||
|
||||
kubelet은 구성된 로그 디렉터리 내의 파일에 로그를 기록한다(기본적으로
|
||||
`/var/log`). 그리고 로컬에 저장된 다른 데이터에 대한 기본 디렉터리가 있다(기본적으로
|
||||
`/var/lib/kubelet`).
|
||||
|
||||
일반적으로, `/var/lib/kubelet` 와 `/var/log` 모두 시스템 루트 파일시스템에 위치하고,
|
||||
그리고 kubelet은 이런 레이아웃을 염두에 두고 설계되었다.
|
||||
|
||||
노드는 쿠버네티스에서 사용하지 않는 다른 많은 파일시스템을
|
||||
가질 수 있다.
|
||||
{{% /tab %}}
|
||||
{{% tab name="두 개의 파일시스템" %}}
|
||||
사용하고 있는 노드에 실행 중인 파드에서 발생하는 임시 데이터를
|
||||
위한 파일시스템을 가진다(로그와 `emptyDir` 볼륨). 이 파일시스템을
|
||||
다른 데이터(예를 들어, 쿠버네티스와 관련없는 시스템 로그)를 위해 사용할 수 있다. 이 파일시스템은
|
||||
루트 파일시스템일 수도 있다.
|
||||
|
||||
kubelet은 또한
|
||||
[노드-레벨 컨테이너 로그](/ko/docs/concepts/cluster-administration/logging/#노드-레벨에서의-로깅)를
|
||||
첫 번째 파일시스템에 기록하고, 임시 로컬 스토리지와 유사하게 처리한다.
|
||||
|
||||
또한 다른 논리 스토리지 장치가 지원하는 별도의 파일시스템을 사용한다.
|
||||
이 구성에서, 컨테이너 이미지 계층과 쓰기 가능한 계층을 배치하도록
|
||||
kubelet에 지시하는 디렉터리는 이 두 번째 파일시스템에 있다.
|
||||
|
||||
첫 번째 파일시스템에는 이미지 계층이나 쓰기 가능한 계층이 없다.
|
||||
|
||||
노드는 쿠버네티스에서 사용하지 않는 다른 많은 파일시스템을
|
||||
가질 수 있다.
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
kubelet은 사용 중인 로컬 스토리지 양을 측정할 수 있다. 이것은 다음을
|
||||
제공한다.
|
||||
|
||||
- `LocalStorageCapacityIsolation`
|
||||
[기능 게이트](/docs/reference/command-line-tools-reference/feature-gates/)(이
|
||||
기능이 기본적으로 설정되어 있음)를 활성화하고,
|
||||
- 로컬 임시 스토리지에 대한 지원되는 구성 중 하나를
|
||||
사용하여 노드를 설정한다.
|
||||
|
||||
다른 구성을 사용하는 경우, kubelet은 임시 로컬 스토리지에 대한 리소스
|
||||
제한을 적용하지 않는다.
|
||||
|
||||
{{< note >}}
|
||||
kubelet은 로컬 임시 스토리지가 아닌 컨테이너 메모리 사용으로
|
||||
`tmpfs` emptyDir 볼륨을 추적한다.
|
||||
{{< /note >}}
|
||||
|
||||
### 로컬 임시 스토리지에 대한 요청 및 제한 설정
|
||||
|
||||
_임시-스토리지_ 를 사용하여 로컬 임시 저장소를 관리할 수 있다. 파드의 각 컨테이너는 다음 중 하나 이상을 지정할 수 있다.
|
||||
|
||||
* `spec.containers[].resources.limits.ephemeral-storage`
|
||||
* `spec.containers[].resources.requests.ephemeral-storage`
|
||||
|
||||
`ephemeral-storage` 에 대한 제한 및 요청은 바이트 단위로 측정된다. E, P, T, G, M, K와
|
||||
같은 접미사 중 하나를 사용하여 스토리지를 일반 정수 또는 고정 소수점 정수로 표현할 수 있다.
|
||||
Ei, Pi, Ti, Gi, Mi, Ki와 같은 2의 거듭제곱을 사용할 수도 있다.
|
||||
예를 들어, 다음은 대략 동일한 값을 나타낸다.
|
||||
|
||||
```shell
|
||||
128974848, 129e6, 129M, 123Mi
|
||||
```
|
||||
|
||||
다음 예에서, 파드에 두 개의 컨테이너가 있다. 각 컨테이너에는 2GiB의 로컬 임시 스토리지 요청이 있다. 각 컨테이너에는 4GiB의 로컬 임시 스토리지 제한이 있다. 따라서, 파드는 4GiB의 로컬 임시 스토리지 요청과 8GiB 스토리지 제한을 가진다.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
containers:
|
||||
- name: db
|
||||
image: mysql
|
||||
env:
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
value: "password"
|
||||
resources:
|
||||
requests:
|
||||
ephemeral-storage: "2Gi"
|
||||
limits:
|
||||
ephemeral-storage: "4Gi"
|
||||
- name: wp
|
||||
image: wordpress
|
||||
resources:
|
||||
requests:
|
||||
ephemeral-storage: "2Gi"
|
||||
limits:
|
||||
ephemeral-storage: "4Gi"
|
||||
```
|
||||
|
||||
### 임시-스토리지 요청이 있는 파드의 스케줄링 방법
|
||||
|
||||
파드를 생성할 때, 쿠버네티스 스케줄러는 파드를 실행할 노드를
|
||||
선택한다. 각 노드에는 파드에 제공할 수 있는 최대 임시 스토리지 공간이 있다. 자세한 정보는, [노드 할당 가능](/docs/tasks/administer-cluster/reserve-compute-resources/#node-allocatable)을 참조한다.
|
||||
|
||||
스케줄러는 스케줄된 컨테이너의 리소스 요청 합계가 노드 용량보다 작도록 한다.
|
||||
|
||||
### 임시 스토리지 소비 관리 {#resource-emphemeralstorage-consumption}
|
||||
|
||||
kubelet이 로컬 임시 스토리지를 리소스로 관리하는 경우,
|
||||
kubelet은 다음에서 스토리지 사용을 측정한다.
|
||||
|
||||
- _tmpfs_ `emptyDir` 볼륨을 제외한 `emptyDir` 볼륨
|
||||
- 노드-레벨 로그가 있는 디렉터리
|
||||
- 쓰기 가능한 컨테이너 계층
|
||||
|
||||
허용하는 것보다 더 많은 임시 스토리지를 파드가 사용하는 경우, kubelet은
|
||||
파드 축출을 트리거하는 축출 신호를 설정한다.
|
||||
|
||||
컨테이너-레벨 격리의 경우, 컨테이너의 쓰기 가능한 계층과 로그
|
||||
사용량이 스토리지 제한을 초과하면, kubelet은 파드를 축출하도록 표시한다.
|
||||
|
||||
파드-레벨 격리에 대해 kubelet은 해당 파드의 컨테이너에 대한 제한을 합하여
|
||||
전체 파드 스토리지 제한을 해결한다. 이 경우, 모든
|
||||
컨테이너와 파드의 `emptyDir` 볼륨의 로컬 임시 스토리지 사용량 합계가
|
||||
전체 파드 스토리지 제한을 초과하면, kubelet은 파드를 축출 대상으로
|
||||
표시한다.
|
||||
|
||||
{{< caution >}}
|
||||
kubelet이 로컬 임시 스토리지를 측정하지 않는 경우,
|
||||
로컬 스토리지 제한을 초과하는 파드는 로컬 스토리지 리소스 제한을
|
||||
위반해도 축출되지 않는다.
|
||||
|
||||
그러나, 쓰기 가능한 컨테이너 계층, 노드-레벨 로그
|
||||
또는 `emptyDir` 볼륨의 파일 시스템 공간이 부족하면, 로컬
|
||||
스토리지가 부족하다고 노드 자체에 {{< glossary_tooltip text="테인트" term_id="taint" >}}되고
|
||||
이로인해 특별히 이 테인트를 허용하지 않는 모든 파드를 축출하도록 트리거한다.
|
||||
|
||||
임시 로컬 스토리지에 대해 지원되는 [구성](#로컬-임시-스토리지-구성)을
|
||||
참조한다.
|
||||
{{< /caution >}}
|
||||
|
||||
kubelet은 파드 스토리지 사용을 측정하는 다양한 방법을 지원한다.
|
||||
|
||||
{{< tabs name="resource-emphemeralstorage-measurement" >}}
|
||||
{{% tab name="주기적 스캐닝" %}}
|
||||
kubelet은 각 `emptyDir` 볼륨, 컨테이너 로그 디렉터리 및 쓰기 가능한 컨테이너 계층을
|
||||
스캔하는 정기적인 스케줄 검사를 수행한다.
|
||||
|
||||
스캔은 사용된 공간의 양을 측정한다.
|
||||
|
||||
{{< note >}}
|
||||
이 모드에서, kubelet은 삭제된 파일의 열린 파일 디스크립터를
|
||||
추적하지 않는다.
|
||||
|
||||
여러분(또는 컨테이너)이 `emptyDir` 볼륨 안에 파일을 생성하면,
|
||||
그 파일이 열리고, 파일이 열려있는 동안 파일을
|
||||
삭제하면, 삭제된 파일의 inode는 해당 파일을 닫을 때까지
|
||||
유지되지만 kubelet은 사용 중인 공간으로 분류하지 않는다.
|
||||
{{< /note >}}
|
||||
{{% /tab %}}
|
||||
{{% tab name="파일시스템 프로젝트 쿼터" %}}
|
||||
|
||||
{{< feature-state for_k8s_version="v1.15" state="alpha" >}}
|
||||
|
||||
프로젝트 쿼터는 파일시스템에서 스토리지 사용을 관리하기 위한
|
||||
운영체제 레벨의 기능이다. 쿠버네티스를 사용하면, 스토리지 사용을
|
||||
모니터링하기 위해 프로젝트 쿼터를 사용할 수 있다. 노드에서 'emptyDir' 볼륨을
|
||||
지원하는 파일시스템이 프로젝트 쿼터 지원을 제공하는지 확인한다.
|
||||
예를 들어, XFS와 ext4fs는 프로젝트 쿼터를 지원한다.
|
||||
|
||||
{{< note >}}
|
||||
프로젝트 쿼터를 통해 스토리지 사용을 모니터링할 수 있다. 이는 제한을 강제하지 않는다.
|
||||
{{< /note >}}
|
||||
|
||||
쿠버네티스는 `1048576` 부터 프로젝트 ID를 사용한다. 사용 중인 ID는
|
||||
`/etc/projects` 와 `/etc/projid` 에 등록되어 있다. 이 범위의 프로젝트 ID가
|
||||
시스템에서 다른 목적으로 사용되는 경우, 쿠버네티스가
|
||||
이를 사용하지 않도록 해당 프로젝트 ID를 `/etc/projects` 와 `/etc/projid` 에
|
||||
등록해야 한다.
|
||||
|
||||
쿼터는 디렉터리 검색보다 빠르고 정확하다. 디렉터리가
|
||||
프로젝트에 할당되면, 디렉터리 아래에 생성된
|
||||
모든 파일이 해당 프로젝트에 생성되며, 커널은 해당 프로젝트의
|
||||
파일에서 사용 중인 블록 수를 추적하기만 하면 된다.
|
||||
파일이 생성되고 삭제되었지만, 열린 파일 디스크립터가 있으면,
|
||||
계속 공간을 소비한다. 쿼터 추적은 공간을 정확하게 기록하는 반면
|
||||
디렉터리 스캔은 삭제된 파일이 사용한 스토리지를 간과한다.
|
||||
|
||||
프로젝트 쿼터를 사용하려면, 다음을 수행해야 한다.
|
||||
|
||||
* kubelet 구성에서 `LocalStorageCapacityIsolationFSQuotaMonitoring=true`
|
||||
[기능 게이트](/docs/reference/command-line-tools-reference/feature-gates/)를
|
||||
활성화한다.
|
||||
|
||||
* 루트 파일시스템(또는 선택적인 런타임 파일시스템)에
|
||||
프로젝트 쿼터가 활성화되어 있는지 확인한다. 모든 XFS 파일시스템은 프로젝트 쿼터를 지원한다.
|
||||
ext4 파일시스템의 경우, 파일시스템이 마운트되지 않은 상태에서 프로젝트 쿼터
|
||||
추적 기능을 활성화해야 한다.
|
||||
```bash
|
||||
# ext4인 /dev/block-device가 마운트되지 않은 경우
|
||||
sudo tune2fs -O project -Q prjquota /dev/block-device
|
||||
```
|
||||
|
||||
* 루트 파일시스템(또는 선택적인 런타임 파일시스템)은 프로젝트 쿼터를
|
||||
활성화한 상태에서 마운트해야 힌다. XFS와 ext4fs 모두에서,
|
||||
마운트 옵션의 이름은 `prjquota` 이다.
|
||||
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
## 확장된 리소스
|
||||
|
||||
확장된 리소스는 `kubernetes.io` 도메인 외부의 전체 주소(fully-qualified)
|
||||
리소스 이름이다. 쿠버네티스에 내장되지 않은 리소스를 클러스터 운영자가 알리고
|
||||
사용자는 사용할 수 있다.
|
||||
|
||||
확장된 리소스를 사용하려면 두 단계가 필요한다. 먼저, 클러스터
|
||||
운영자는 확장된 리소스를 알려야 한다. 둘째, 사용자는 파드의
|
||||
확장된 리소스를 요청해야 한다.
|
||||
|
||||
### 확장된 리소스 관리
|
||||
|
||||
#### 노드-레벨의 확장된 리소스
|
||||
|
||||
노드-레벨의 확장된 리소스는 노드에 연결된다.
|
||||
|
||||
##### 장치 플러그인 관리 리소스
|
||||
각 노드에서
|
||||
장치 플러그인 관리 리소스를 알리는 방법은
|
||||
[장치 플러그인](/ko/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/)을 참조한다.
|
||||
|
||||
##### 기타 리소스
|
||||
새로운 노드-레벨의 확장된 리소스를 알리기 위해, 클러스터 운영자는
|
||||
API 서버에 `PATCH` HTTP 요청을 제출하여 클러스터의
|
||||
노드에 대해 `status.capacity` 에서 사용할 수 있는 수량을 지정할 수 있다. 이 작업
|
||||
후에는, 노드의 `status.capacity` 에 새로운 리소스가 포함된다. 이
|
||||
`status.allocatable` 필드는 kubelet에 의해 비동기적으로 새로운
|
||||
리소스로 자동 업데이트된다. 참고로 스케줄러가 파드 적합성을 평가할 때 노드
|
||||
`status.allocatable` 값을 사용하므로, 노드 용량을
|
||||
새 리소스로 패치하는 것과 해당 노드에서 리소스를 스케줄하도록 요청하는 첫 번째 파드
|
||||
사이에 약간의 지연이 있을 수 있다.
|
||||
|
||||
**예제:**
|
||||
|
||||
다음은 `curl` 을 사용하여 마스터가 `k8s-master` 인 노드 `k8s-node-1` 에
|
||||
5개의 "example.com/foo" 리소스를 알리는 HTTP 요청을 구성하는 방법을
|
||||
보여주는 예이다.
|
||||
|
||||
```shell
|
||||
curl --header "Content-Type: application/json-patch+json" \
|
||||
--request PATCH \
|
||||
--data '[{"op": "add", "path": "/status/capacity/example.com~1foo", "value": "5"}]' \
|
||||
http://k8s-master:8080/api/v1/nodes/k8s-node-1/status
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
앞의 요청에서, `~1` 은 패치 경로에서 문자 `/` 의
|
||||
인코딩이다. JSON-Patch의 작업 경로 값은
|
||||
JSON-Pointer로 해석된다. 더 자세한 내용은,
|
||||
[IETF RFC 6901, 섹션 3](https://tools.ietf.org/html/rfc6901#section-3)을 참조한다.
|
||||
{{< /note >}}
|
||||
|
||||
#### 클러스터-레벨의 확장된 리소스
|
||||
|
||||
클러스터-레벨의 확장된 리소스는 노드에 연결되지 않는다. 이들은 일반적으로
|
||||
리소스 소비와 리소스 쿼터를 처리하는 스케줄러 익스텐더(extender)에 의해 관리된다.
|
||||
|
||||
[스케줄러 정책 구성](https://github.com/kubernetes/kubernetes/blob/release-1.10/pkg/scheduler/api/v1/types.go#L31)에서
|
||||
스케줄러 익스텐더가
|
||||
처리하는 확장된 리소스를 지정할 수 있다.
|
||||
|
||||
**예제:**
|
||||
|
||||
스케줄러 정책에 대한 다음의 구성은 클러스터-레벨의 확장된 리소스
|
||||
"example.com/foo"가 스케줄러 익스텐더에 의해 처리됨을
|
||||
나타낸다.
|
||||
|
||||
- 파드가 "example.com/foo"를 요청하는 경우에만 스케줄러가 파드를 스케줄러
|
||||
익스텐더로 보낸다.
|
||||
- 이 `ignoredByScheduler` 필드는 스케줄러가 `PodFitsResources` 속성에서
|
||||
"example.com/foo" 리소스를 확인하지 않도록 지정한다.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "Policy",
|
||||
"apiVersion": "v1",
|
||||
"extenders": [
|
||||
{
|
||||
"urlPrefix":"<extender-endpoint>",
|
||||
"bindVerb": "bind",
|
||||
"managedResources": [
|
||||
{
|
||||
"name": "example.com/foo",
|
||||
"ignoredByScheduler": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 확장된 리소스 소비
|
||||
|
||||
사용자는 CPU와 메모리 같은 파드 스펙의 확장된 리소스를 사용할 수 있다.
|
||||
스케줄러는 리소스 어카운팅(resource accounting)을 관리하여 사용 가능한 양보다
|
||||
많은 양의 리소스가 여러 파드에 동시에 할당되지 않도록 한다.
|
||||
|
||||
API 서버는 확장된 리소스의 수량을 정수로 제한한다.
|
||||
_유효한_ 수량의 예로는 `3`, `3000m` 그리고 `3Ki` 를 들 수 있다. _유효하지 않은_
|
||||
수량의 예는 `0.5` 와 `1500m` 이다.
|
||||
|
||||
{{< note >}}
|
||||
확장된 리소스는 불명확한 정수 리소스를 대체한다.
|
||||
사용자는 예약된 `kubernetes.io` 이외의 모든 도메인 이름 접두사를 사용할 수 있다.
|
||||
{{< /note >}}
|
||||
|
||||
파드에서 확장된 리소스를 사용하려면, 컨테이너 사양에서 `spec.containers[].resources.limits`
|
||||
맵에 리소스 이름을 키로 포함한다.
|
||||
|
||||
{{< note >}}
|
||||
확장된 리소스는 오버커밋할 수 없으므로, 컨테이너 사양에
|
||||
둘 다 있으면 요청과 제한이 동일해야 한다.
|
||||
{{< /note >}}
|
||||
|
||||
파드는 CPU, 메모리 및 확장된 리소스를 포함하여 모든 리소스 요청이
|
||||
충족되는 경우에만 예약된다. 리소스 요청을 충족할 수 없다면
|
||||
파드는 `PENDING` 상태를 유지한다.
|
||||
|
||||
**예제:**
|
||||
|
||||
아래의 파드는 2개의 CPU와 1개의 "example.com/foo"(확장된 리소스)를 요청한다.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: my-pod
|
||||
spec:
|
||||
containers:
|
||||
- name: my-container
|
||||
image: myimage
|
||||
resources:
|
||||
requests:
|
||||
cpu: 2
|
||||
example.com/foo: 1
|
||||
limits:
|
||||
example.com/foo: 1
|
||||
```
|
||||
|
||||
## 문제 해결
|
||||
|
||||
### 내 파드가 failedScheduling 이벤트 메시지로 보류 중이다
|
||||
|
||||
파드가 배치될 수 있는 노드를 스케줄러가 찾을 수 없으면, 노드를
|
||||
찾을 수 있을 때까지 파드는 스케줄되지 않은 상태로 유지한다. 스케줄러가 다음과 같이
|
||||
파드의 위치를 찾지 못하면 이벤트가 생성된다.
|
||||
|
||||
```shell
|
||||
kubectl describe pod frontend | grep -A 3 Events
|
||||
```
|
||||
```
|
||||
Events:
|
||||
FirstSeen LastSeen Count From Subobject PathReason Message
|
||||
36s 5s 6 {scheduler } FailedScheduling Failed for reason PodExceedsFreeCPU and possibly others
|
||||
```
|
||||
|
||||
위의 예에서, 노드의 CPU 리소스가 충분하지 않아 이름이
|
||||
"frontend"인 파드를 스케줄하지 못했다. 비슷한 메시지로
|
||||
메모리 부족(PodExceedsFreeMemory)으로 인한 장애도 알릴 수 있다. 일반적으로, 파드가
|
||||
이 타입의 메시지로 보류 중인 경우, 몇 가지 시도해 볼 것들이 있다.
|
||||
|
||||
- 클러스터에 더 많은 노드를 추가한다.
|
||||
- 불필요한 파드를 종료하여 보류 중인 파드를 위한 공간을 확보한다.
|
||||
- 파드가 모든 노드보다 크지 않은지 확인한다. 예를 들어, 모든
|
||||
노드의 용량이 `cpu: 1` 인 경우, `cpu: 1.1` 요청이 있는 파드는
|
||||
절대 스케줄되지 않는다.
|
||||
|
||||
`kubectl describe nodes` 명령으로 노드 용량과 할당된 양을
|
||||
확인할 수 있다. 예를 들면, 다음과 같다.
|
||||
|
||||
```shell
|
||||
kubectl describe nodes e2e-test-node-pool-4lw4
|
||||
```
|
||||
```
|
||||
Name: e2e-test-node-pool-4lw4
|
||||
[ ... 명확하게 하기 위해 라인들을 제거함 ...]
|
||||
Capacity:
|
||||
cpu: 2
|
||||
memory: 7679792Ki
|
||||
pods: 110
|
||||
Allocatable:
|
||||
cpu: 1800m
|
||||
memory: 7474992Ki
|
||||
pods: 110
|
||||
[ ... 명확하게 하기 위해 라인들을 제거함 ...]
|
||||
Non-terminated Pods: (5 in total)
|
||||
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
|
||||
--------- ---- ------------ ---------- --------------- -------------
|
||||
kube-system fluentd-gcp-v1.38-28bv1 100m (5%) 0 (0%) 200Mi (2%) 200Mi (2%)
|
||||
kube-system kube-dns-3297075139-61lj3 260m (13%) 0 (0%) 100Mi (1%) 170Mi (2%)
|
||||
kube-system kube-proxy-e2e-test-... 100m (5%) 0 (0%) 0 (0%) 0 (0%)
|
||||
kube-system monitoring-influxdb-grafana-v4-z1m12 200m (10%) 200m (10%) 600Mi (8%) 600Mi (8%)
|
||||
kube-system node-problem-detector-v0.1-fj7m3 20m (1%) 200m (10%) 20Mi (0%) 100Mi (1%)
|
||||
Allocated resources:
|
||||
(Total limits may be over 100 percent, i.e., overcommitted.)
|
||||
CPU Requests CPU Limits Memory Requests Memory Limits
|
||||
------------ ---------- --------------- -------------
|
||||
680m (34%) 400m (20%) 920Mi (12%) 1070Mi (14%)
|
||||
```
|
||||
|
||||
위의 출력에서, 파드가 1120m 이상의 CPU 또는 6.23Gi의 메모리를
|
||||
요청하는 것은 노드에 맞지 않음을 알 수 있다.
|
||||
|
||||
`Pods` 섹션을 살펴보면, 파드가 노드에서 공간을 차지하는 것을
|
||||
볼 수 있다.
|
||||
|
||||
시스템 데몬이 사용 가능한 리소스의 일부를 사용하기 때문에, 파드에
|
||||
사용 가능한 리소스의 양이 노드 용량보다 적다. `allocatable` 필드
|
||||
[NodeStatus](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#nodestatus-v1-core)는
|
||||
파드가 사용할 수 있는 리소스의 양을 제공한다. 자세한 정보는
|
||||
[노드 할당 가능 리소스](https://git.k8s.io/community/contributors/design-proposals/node/node-allocatable.md)를 참조한다.
|
||||
|
||||
[리소스 쿼터](/ko/docs/concepts/policy/resource-quotas/) 기능은
|
||||
소비될 수 있는 리소스의 총량을 제한하도록 구성할 수 있다. 네임스페이스와
|
||||
함께 사용하면, 한 팀이 모든 리소스를 사용하는 경우를 방지할 수 있다.
|
||||
|
||||
### 내 컨테이너가 종료되었다
|
||||
|
||||
리소스가 부족하여 컨테이너가 종료될 수 있다. 리소스
|
||||
제한에 도달하여 컨테이너가 종료되고 있는지 확인하려면,
|
||||
관심있는 파드에 대해 `kubectl describe pod` 를 호출한다.
|
||||
|
||||
```shell
|
||||
kubectl describe pod simmemleak-hra99
|
||||
```
|
||||
```
|
||||
Name: simmemleak-hra99
|
||||
Namespace: default
|
||||
Image(s): saadali/simmemleak
|
||||
Node: kubernetes-node-tf0f/10.240.216.66
|
||||
Labels: name=simmemleak
|
||||
Status: Running
|
||||
Reason:
|
||||
Message:
|
||||
IP: 10.244.2.75
|
||||
Replication Controllers: simmemleak (1/1 replicas created)
|
||||
Containers:
|
||||
simmemleak:
|
||||
Image: saadali/simmemleak
|
||||
Limits:
|
||||
cpu: 100m
|
||||
memory: 50Mi
|
||||
State: Running
|
||||
Started: Tue, 07 Jul 2015 12:54:41 -0700
|
||||
Last Termination State: Terminated
|
||||
Exit Code: 1
|
||||
Started: Fri, 07 Jul 2015 12:54:30 -0700
|
||||
Finished: Fri, 07 Jul 2015 12:54:33 -0700
|
||||
Ready: False
|
||||
Restart Count: 5
|
||||
Conditions:
|
||||
Type Status
|
||||
Ready False
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Reason Message
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {scheduler } scheduled Successfully assigned simmemleak-hra99 to kubernetes-node-tf0f
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD pulled Pod container image "k8s.gcr.io/pause:0.8.0" already present on machine
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD created Created with docker id 6a41280f516d
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD started Started with docker id 6a41280f516d
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} spec.containers{simmemleak} created Created with docker id 87348f12526a
|
||||
```
|
||||
|
||||
앞의 예제에서, `Restart Count: 5` 표시는 파드의 `simmemleak`
|
||||
컨테이너가 종료되고 5번 다시 시작되었음을 나타낸다.
|
||||
|
||||
이전에 종료된 컨테이너의 상태를 가져오기 위해 `-o go-template=...` 옵션을 사용해서
|
||||
`kubectl get pod` 를 호출할 수 있다.
|
||||
|
||||
```shell
|
||||
kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}' simmemleak-hra99
|
||||
```
|
||||
```
|
||||
Container Name: simmemleak
|
||||
LastState: map[terminated:map[exitCode:137 reason:OOM Killed startedAt:2015-07-07T20:58:43Z finishedAt:2015-07-07T20:58:43Z containerID:docker://0e4095bba1feccdfe7ef9fb6ebffe972b4b14285d5acdec6f0d3ae8a22fad8b2]]
|
||||
```
|
||||
|
||||
컨테이너가 `reason:OOM Killed`(`OOM` 은 메모리 부족(Out Of Memory)의 약자) 때문에 종료된 것을 알 수 있다.
|
||||
|
||||
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* [컨테이너와 파드에 메모리 리소스를 할당](/ko/docs/tasks/configure-pod-container/assign-memory-resource/)하는 핸즈온 경험을 해보자.
|
||||
|
||||
* [컨테이너와 파드에 CPU 리소스를 할당](/docs/tasks/configure-pod-container/assign-cpu-resource/)하는 핸즈온 경험을 해보자.
|
||||
|
||||
* 요청과 제한의 차이점에 대한 자세한 내용은,
|
||||
[리소스 QoS](https://git.k8s.io/community/contributors/design-proposals/node/resource-qos.md)를 참조한다.
|
||||
|
||||
* [컨테이너](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#container-v1-core) API 레퍼런스 읽어보기
|
||||
|
||||
* [ResourceRequirements](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#resourcerequirements-v1-core) API 레퍼런스 읽어보기
|
||||
|
||||
* XFS의 [프로젝트 쿼터](http://xfs.org/docs/xfsdocs-xml-dev/XFS_User_Guide/tmp/en-US/html/xfs-quotas.html)에 대해 읽어보기
|
||||
|
||||
{{% /capture %}}
|
||||
@@ -0,0 +1,193 @@
|
||||
---
|
||||
title: 파드 오버헤드
|
||||
content_template: templates/concept
|
||||
weight: 20
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
{{< feature-state for_k8s_version="v1.18" state="beta" >}}
|
||||
|
||||
노드 위에서 파드를 구동할 때, 파드는 그 자체적으로 많은 시스템 리소스를 사용한다.
|
||||
이러한 리소스는 파드 내의 컨테이너들을 구동하기 위한 리소스 이외에 추가적으로 필요한 것이다.
|
||||
_파드 오버헤드_ 는 컨테이너 리소스 요청과 상한 위에서 파드의 인프라에 의해
|
||||
소비되는 리소스를 계산하는 기능이다.
|
||||
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
쿠버네티스에서 파드의 오버헤드는 파드의
|
||||
[런타임클래스](/ko/docs/concepts/containers/runtime-class/) 와 관련된 오버헤드에 따라
|
||||
[어드미션](/docs/reference/access-authn-authz/extensible-admission-controllers/#what-are-admission-webhooks)
|
||||
이 수행될 때 지정된다.
|
||||
|
||||
파드 오버헤드가 활성화 되면, 파드를 노드에 스케줄링 할 때 컨테이너 리소스 요청의 합에
|
||||
파드의 오버헤드를 추가해서 스케줄링을 고려한다. 마찬가지로, Kubelet은 파드의 cgroups 크기를 변경하거나
|
||||
파드의 축출 등급을 부여할 때에도 파드의 오버헤드를 포함하여 고려한다.
|
||||
|
||||
## 파드 오버헤드 활성화하기 {#set-up}
|
||||
|
||||
기능 활성화를 위해 클러스터에서
|
||||
`PodOverhead` [기능 게이트](/docs/reference/command-line-tools-reference/feature-gates/) 가 활성화 되어 있고 (1.18 버전에서는 기본적으로 활성화),
|
||||
`overhead` 필드를 정의하는 `RuntimeClass` 가 사용되고 있는지 확인해야 한다.
|
||||
|
||||
## 사용 예제
|
||||
|
||||
파드 오버헤드 기능을 사용하기 위하여, `overhead` 필드를 정의하는 런타임클래스가 필요하다.
|
||||
예를 들어, 가상 머신 및 게스트 OS에 대하여 파드 당 120 MiB를 사용하는
|
||||
가상화 컨테이너 런타임의 런타임클래스의 경우 다음과 같이 정의 할 수 있다.
|
||||
|
||||
```yaml
|
||||
---
|
||||
kind: RuntimeClass
|
||||
apiVersion: node.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: kata-fc
|
||||
handler: kata-fc
|
||||
overhead:
|
||||
podFixed:
|
||||
memory: "120Mi"
|
||||
cpu: "250m"
|
||||
```
|
||||
|
||||
`kata-fc` 런타임클래스 핸들러를 지정하는 워크로드는 리소스 쿼터 계산,
|
||||
노드 스케줄링 및 파드 cgroup 크기 조정을 위하여 메모리와 CPU 오버헤드를 고려한다.
|
||||
|
||||
주어진 예제 워크로드 test-pod의 구동을 고려해보자.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: test-pod
|
||||
spec:
|
||||
runtimeClassName: kata-fc
|
||||
containers:
|
||||
- name: busybox-ctr
|
||||
image: busybox
|
||||
stdin: true
|
||||
tty: true
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 100Mi
|
||||
- name: nginx-ctr
|
||||
image: nginx
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1500m
|
||||
memory: 100Mi
|
||||
```
|
||||
|
||||
어드미션 수행 시에, [어드미션 컨트롤러](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/)는
|
||||
런타임클래스에 기술된 `overhead` 를 포함하기 위하여 워크로드의 PodSpec 항목을 갱신한다. 만약 PodSpec이 이미 해당 필드에 정의되어 있으면,
|
||||
파드는 거부된다. 주어진 예제에서, 오직 런타임클래스의 이름만이 정의되어 있기 때문에, 어드미션 컨트롤러는 파드가
|
||||
`overhead` 를 포함하도록 변경한다.
|
||||
|
||||
런타임클래스의 어드미션 수행 후에, 파드의 스펙이 갱신된 것을 확인할 수 있다.
|
||||
|
||||
```bash
|
||||
kubectl get pod test-pod -o jsonpath='{.spec.overhead}'
|
||||
```
|
||||
|
||||
명령 실행 결과는 다음과 같다.
|
||||
```
|
||||
map[cpu:250m memory:120Mi]
|
||||
```
|
||||
|
||||
만약 리소스쿼터 항목이 정의되어 있다면, 컨테이너의 리소스 요청의 합에는
|
||||
`overhead` 필드도 추가된다.
|
||||
|
||||
kube-scheduler 는 어떤 노드에 파드가 기동 되어야 할지를 정할 때, 파드의 `overhead` 와
|
||||
해당 파드에 대한 컨테이너의 리소스 요청의 합을 고려한다. 이 예제에서, 스케줄러는
|
||||
리소스 요청과 파드의 오버헤드를 더하고, 2.25 CPU와 320 MiB 메모리가 사용 가능한 노드를 찾는다.
|
||||
|
||||
일단 파드가 특정 노드에 스케줄링 되면, 해당 노드에 있는 kubelet 은 파드에 대한 새로운 {{< glossary_tooltip text="cgroup" term_id="cgroup" >}}을 생성한다.
|
||||
기본 컨테이너 런타임이 만들어내는 컨테이너들은 이 파드 안에 존재한다.
|
||||
|
||||
만약 각 컨테이너에 대하여 QoS가 보장되었거나 향상이 가능하도록 QoS 의 리소스 상한 제한이 걸려있으면,
|
||||
kubelet 은 해당 리소스(CPU의 경우 cpu.cfs_quota_us, 메모리의 경우 memory.limit_in_bytes)와 연관된 파드의
|
||||
cgroup 의 상한선을 설정한다. 이 상한선은 컨테이너 리소스 상한과 PodSpec에
|
||||
정의된 `overhead` 의 합에 기반한다.
|
||||
|
||||
CPU의 경우, 만약 파드가 보장형 또는 버스트형 QoS로 설정되었으면, kubelet은 PodSpec에 정의된 `overhead` 에 컨테이너의
|
||||
리소스 요청의 합을 더한 값을 `cpu.shares` 로 설정한다.
|
||||
|
||||
다음의 예제를 참고하여, 워크로드에 대하여 컨테이너의 리소스 요청을 확인하자.
|
||||
```bash
|
||||
kubectl get pod test-pod -o jsonpath='{.spec.containers[*].resources.limits}'
|
||||
```
|
||||
|
||||
컨테이너 리소스 요청의 합은 각각 CPU 2000m 와 메모리 200MiB 이다.
|
||||
```
|
||||
map[cpu: 500m memory:100Mi] map[cpu:1500m memory:100Mi]
|
||||
```
|
||||
|
||||
노드에서 측정된 내용과 비교하여 확인해보자.
|
||||
|
||||
```bash
|
||||
kubectl describe node | grep test-pod -B2
|
||||
```
|
||||
|
||||
CPU 2250m와 메모리 320MiB 가 리소스로 요청되었으며, 이 결과는 파드의 오버헤드를 포함한다.
|
||||
```
|
||||
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE
|
||||
--------- ---- ------------ ---------- --------------- ------------- ---
|
||||
default test-pod 2250m (56%) 2250m (56%) 320Mi (1%) 320Mi (1%) 36m
|
||||
```
|
||||
|
||||
## 파드 cgroup 상한 확인하기
|
||||
|
||||
워크로드가 실행 중인 노드에서 파드의 메모리 cgroup들을 확인 해보자. 다음의 예제에서, [`crictl`](https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/crictl.md)은 노드에서 사용되며,
|
||||
CRI-호환 컨테이너 런타임을 위해서 노드에서 사용할 수 있는 CLI 를 제공한다.
|
||||
파드의 오버헤드 동작을 보여주는 좋은 예이며,
|
||||
사용자가 노드에서 직접 cgroup들을 확인하지 않아도 된다.
|
||||
|
||||
먼저 특정 노드에서 파드의 식별자를 확인해 보자.
|
||||
|
||||
```bash
|
||||
# 파드가 스케줄 된 노드에서 이것을 실행
|
||||
POD_ID="$(sudo crictl pods --name test-pod -q)"
|
||||
```
|
||||
|
||||
여기에서, 파드의 cgroup 경로를 확인할 수 있다.
|
||||
```bash
|
||||
# 파드가 스케줄 된 노드에서 이것을 실행
|
||||
sudo crictl inspectp -o=json $POD_ID | grep cgroupsPath
|
||||
```
|
||||
|
||||
명령의 결과로 나온 cgroup 경로는 파드의 `pause` 컨테이너를 포함한다. 파드 레벨의 cgroup은 하나의 디렉터리이다.
|
||||
```
|
||||
"cgroupsPath": "/kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2/7ccf55aee35dd16aca4189c952d83487297f3cd760f1bbf09620e206e7d0c27a"
|
||||
```
|
||||
|
||||
아래의 특정한 경우에, 파드 cgroup 경로는 `kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2` 이다. 메모리의 파드 레벨 cgroup 설정을 확인하자.
|
||||
```bash
|
||||
# 파드가 스케줄 된 노드에서 이것을 실행.
|
||||
# 또한 사용자의 파드에 할당된 cgroup 이름에 맞춰 해당 이름을 수정.
|
||||
cat /sys/fs/cgroup/memory/kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2/memory.limit_in_bytes
|
||||
```
|
||||
|
||||
예상대로 320 MiB 이다.
|
||||
```
|
||||
335544320
|
||||
```
|
||||
|
||||
### 관찰성
|
||||
`kube_pod_overhead` 항목은 [kube-state-metrics](https://github.com/kubernetes/kube-state-metrics)
|
||||
에서 사용할 수 있어, 파드 오버헤드가 사용되는 시기를 식별하고,
|
||||
정의된 오버헤드로 실행되는 워크로드의 안정성을 관찰할 수 있다.
|
||||
이 기능은 kube-state-metrics 의 1.9 릴리스에서는 사용할 수 없지만, 다음 릴리스에서는 가능할 예정이다.
|
||||
그 전까지는 소스로부터 kube-state-metric 을 빌드해야 한다.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* [런타임클래스](/ko/docs/concepts/containers/runtime-class/)
|
||||
* [파드오버헤드 디자인](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/20190226-pod-overhead.md)
|
||||
|
||||
{{% /capture %}}
|
||||
@@ -0,0 +1,417 @@
|
||||
---
|
||||
title: 파드 우선순위(priority)와 선점(preemption)
|
||||
content_template: templates/concept
|
||||
weight: 70
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
{{< feature-state for_k8s_version="v1.14" state="stable" >}}
|
||||
|
||||
[파드](/ko/docs/concepts/workloads/pods/pod/)는 _우선순위_ 를 가질 수 있다. 우선순위는
|
||||
다른 파드에 대한 상대적인 파드의 중요성을 나타낸다. 파드를 스케줄링할 수 없는 경우,
|
||||
스케줄러는 우선순위가 낮은 파드를 선점(축출)하여 보류 중인 파드를
|
||||
스케줄링할 수 있게 한다.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
|
||||
{{< warning >}}
|
||||
모든 사용자를 신뢰할 수 없는 클러스터에서, 악의적인 사용자가 우선순위가
|
||||
가장 높은 파드를 생성하여 다른 파드가 축출되거나 스케줄링되지
|
||||
않을 수 있다.
|
||||
관리자는 리소스쿼터를 사용하여 사용자가 우선순위가 높은 파드를 생성하지
|
||||
못하게 할 수 있다.
|
||||
|
||||
자세한 내용은 [기본적으로 프라이어리티 클래스(Priority Class) 소비 제한](/ko/docs/concepts/policy/resource-quotas/#기본적으로-우선-순위-클래스-소비-제한)을
|
||||
참고한다.
|
||||
{{< /warning >}}
|
||||
|
||||
## 우선순위와 선점을 사용하는 방법
|
||||
|
||||
우선순위와 선점을 사용하려면 다음을 참고한다.
|
||||
|
||||
1. 하나 이상의 [프라이어리티클래스](#프라이어리티클래스)를 추가한다.
|
||||
|
||||
1. 추가된 프라이어리티클래스 중 하나에 [`priorityClassName`](#파드-우선순위)이 설정된
|
||||
파드를 생성한다. 물론 파드를 직접 생성할 필요는 없다.
|
||||
일반적으로 디플로이먼트와 같은 컬렉션 오브젝트의 파드 템플릿에 `priorityClassName`
|
||||
을 추가한다.
|
||||
|
||||
이 단계에 대한 자세한 내용은 계속 읽어보자.
|
||||
|
||||
{{< note >}}
|
||||
쿠버네티스는 이미 `system-cluster-critical` 과 `system-node-critical`,
|
||||
두 개의 프라이어리티클래스를 제공한다.
|
||||
이들은 일반적인 클래스이며 [중요한(critical) 컴포넌트가 항상 먼저 스케줄링이 되도록 하는 데](/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/) 사용된다.
|
||||
{{< /note >}}
|
||||
|
||||
기능을 사용해 본 후 사용하지 않기로 했다면, PodPriority
|
||||
커맨드-라인 플래그를 제거하거나 `false` 로 설정한 후, API 서버와
|
||||
스케줄러를 다시 시작해야 한다. 기능이 비활성화된 후, 기존 파드는
|
||||
우선순위 필드를 유지하지만, 선점은 비활성화되며, 우선순위 필드는
|
||||
무시된다. 이 기능이 비활성화되면, 새로운 파드에서 `priorityClassName` 을 설정할 수
|
||||
없다.
|
||||
|
||||
## 선점을 비활성화하는 방법
|
||||
|
||||
{{< caution >}}
|
||||
중요 파드는 클러스터에 리소스 압박(resource pressure)이 가해지면
|
||||
스케줄러 선점에 따라 스케줄링된다. 이런 이유로, 선점을 비활성화하지
|
||||
않는 것을 권장한다.
|
||||
{{< /caution >}}
|
||||
|
||||
{{< note >}}
|
||||
쿠버네티스 1.15 이상에서, `NonPreemptingPriority` 기능이 활성화된 경우,
|
||||
프라이어리티클래스는 옵션을 `preemptionPolicy: Never` 로 설정할 수 있다.
|
||||
이렇게 하면 해당 프라이어리티클래스의 파드가 다른 파드를 축출할 수 없다.
|
||||
{{< /note >}}
|
||||
|
||||
선점은 기본값이 `false`로 설정된 `disablePreemption` kube-scheduler
|
||||
플래그에 의해 제어된다.
|
||||
위의 주의에도 불구하고 선점을 비활성화하려는 경우,
|
||||
`disablePreemption` 을 `true` 로 설정할 수 있다.
|
||||
|
||||
이 옵션은 컴포넌트 구성에서만 사용할 수 있으며
|
||||
이전 스타일의 커맨드 라인 옵션에서는 사용할 수 없다. 다음은 선점을 비활성화하는 샘플 컴포넌트
|
||||
구성이다.
|
||||
|
||||
```yaml
|
||||
apiVersion: kubescheduler.config.k8s.io/v1alpha1
|
||||
kind: KubeSchedulerConfiguration
|
||||
algorithmSource:
|
||||
provider: DefaultProvider
|
||||
|
||||
...
|
||||
|
||||
disablePreemption: true
|
||||
```
|
||||
|
||||
## 프라이어리티클래스
|
||||
|
||||
프라이어리티클래스는 프라이어리티 클래스 이름에서 우선순위의 정수 값으로의 매핑을
|
||||
정의하는 네임스페이스가 아닌(non-namespaced) 오브젝트이다. 이름은
|
||||
프라이어리티클래스 오브젝트의 메타데이터의 `name` 필드에 지정된다. 값은
|
||||
필수 `value` 필드에 지정되어 있다. 값이 클수록, 우선순위가
|
||||
높다.
|
||||
프라이어리티클래스 오브젝트의 이름은 유효한
|
||||
[DNS 서브 도메인 이름](/ko/docs/concepts/overview/working-with-objects/names/#dns-서브도메인-이름)이어야 하며,
|
||||
`system-` 접두사를 붙일 수 없다.
|
||||
|
||||
프라이어리티클래스 오브젝트는 10억 이하의 32비트 정수 값을 가질
|
||||
수 있다. 일반적으로 선점하거나 축출해서는 안되는 중요한 시스템 파드에는 더 큰 숫자가
|
||||
예약되어 있다. 클러스터 관리자는 원하는 각 매핑에 대해 프라이어리티클래스 오브젝트를
|
||||
하나씩 생성해야 한다.
|
||||
|
||||
프라이어리티클래스에는 `globalDefault` 와 `description` 두 개의 선택적인 필드도 있다.
|
||||
`globalDefault` 필드는 이 프라이어리티클래스의 값을 `priorityClassName` 이 없는
|
||||
파드에 사용해야 함을 나타낸다. 시스템에서 `globalDefault` 가 `true` 로 설정된
|
||||
프라이어리티클래스는 하나만 존재할 수 있다. `globalDefault` 가 설정된
|
||||
프라이어리티클래스가 없을 경우, `priorityClassName` 이 없는 파드의
|
||||
우선순위는 0이다.
|
||||
|
||||
`description` 필드는 임의의 문자열이다. 이 필드는 이 프라이어리티클래스를 언제
|
||||
사용해야 하는지를 클러스터 사용자에게 알려주기 위한 것이다.
|
||||
|
||||
### PodPriority와 기존 클러스터에 대한 참고 사항
|
||||
|
||||
- 기존 클러스터를 업그레이드하고 이 기능을 활성화하면, 기존 파드의
|
||||
우선순위는 사실상 0이다.
|
||||
|
||||
- `globalDefault` 가 `true` 로 설정된 프라이어리티클래스를 추가해도 기존 파드의
|
||||
우선순위는 변경되지 않는다. 이러한 프라이어리티클래스의 값은
|
||||
프라이어리티클래스를 추가한 후 생성된 파드에만 사용된다.
|
||||
|
||||
- 프라이어리티클래스를 삭제하면, 삭제된 프라이어리티클래스의 이름을 사용하는
|
||||
기존 파드는 변경되지 않고 남아있지만, 삭제된 프라이어리티클래스의 이름을
|
||||
사용하는 파드는 더 이상 생성할 수 없다.
|
||||
|
||||
### 프라이어리티클래스 예제
|
||||
|
||||
```yaml
|
||||
apiVersion: scheduling.k8s.io/v1
|
||||
kind: PriorityClass
|
||||
metadata:
|
||||
name: high-priority
|
||||
value: 1000000
|
||||
globalDefault: false
|
||||
description: "이 프라이어리티 클래스는 XYZ 서비스 파드에만 사용해야 한다."
|
||||
```
|
||||
|
||||
## 비-선점 프라이어리티클래스 {#non-preempting-priority-class}
|
||||
|
||||
{{< feature-state for_k8s_version="v1.15" state="alpha" >}}
|
||||
|
||||
`PreemptionPolicy: Never` 를 가진 파드는 낮은 우선순위 파드의 스케줄링 대기열의
|
||||
앞쪽에 배치되지만,
|
||||
그 파드는 다른 파드를 축출할 수 없다.
|
||||
스케줄링 대기 중인 비-선점 파드는 충분한 리소스가 확보되고
|
||||
스케줄링될 수 있을 때까지
|
||||
스케줄링 대기열에 대기한다.
|
||||
다른 파드와 마찬가지로,
|
||||
비-선점 파드는
|
||||
스케줄러 백오프(back-off)에 종속된다.
|
||||
이는 스케줄러가 이러한 파드를 스케줄링하려고 시도하고 스케줄링할 수 없는 경우,
|
||||
더 적은 횟수로 재시도하여,
|
||||
우선순위가 낮은 다른 파드를 미리 스케줄링할 수 있음을 의미한다.
|
||||
|
||||
비-선점 파드는 다른 우선순위가 높은 파드에 의해
|
||||
축출될 수 있다.
|
||||
|
||||
`PreemptionPolicy` 는 기본값으로 `PreemptLowerPriority` 로 설정되어,
|
||||
해당 프라이어리티클래스의 파드가 우선순위가 낮은 파드를 축출할 수
|
||||
있다(기존의 기본 동작과 동일).
|
||||
`PreemptionPolicy` 가 `Never` 로 설정된 경우,
|
||||
해당 프라이어리티클래스의 파드는 비-선점될 것이다.
|
||||
|
||||
`PreemptionPolicy` 필드를 사용하려면 `NonPreemptingPriority`
|
||||
[기능 게이트](/docs/reference/command-line-tools-reference/feature-gates/)가
|
||||
활성화되어야 한다.
|
||||
|
||||
예제 유스케이스는 데이터 과학 관련 워크로드이다.
|
||||
사용자는 다른 워크로드보다 우선순위가 높은 잡(job)을 제출할 수 있지만,
|
||||
실행 중인 파드를 축출하여 기존의 작업을 삭제하지는 않을 것이다.
|
||||
클러스터 리소스가 "자연스럽게" 충분히 사용할 수 있게 되면,
|
||||
`PreemptionPolicy: Never` 의 우선순위가 높은 잡이
|
||||
다른 대기 중인 파드보다 먼저 스케줄링된다.
|
||||
|
||||
### 비-선점 프라이어리티클래스 예제
|
||||
|
||||
```yaml
|
||||
apiVersion: scheduling.k8s.io/v1
|
||||
kind: PriorityClass
|
||||
metadata:
|
||||
name: high-priority-nonpreempting
|
||||
value: 1000000
|
||||
preemptionPolicy: Never
|
||||
globalDefault: false
|
||||
description: "이 프라이어리티 클래스는 다른 파드를 축출하지 않는다."
|
||||
```
|
||||
|
||||
## 파드 우선순위
|
||||
|
||||
프라이어리티클래스가 하나 이상 있으면, 그것의 명세에서 이들 프라이어리티클래스 이름 중 하나를
|
||||
지정하는 파드를 생성할 수 있다. 우선순위 어드미션
|
||||
컨트롤러는 `priorityClassName` 필드를 사용하고 우선순위의 정수 값을
|
||||
채운다. 프라이어리티 클래스를 찾을 수 없으면, 파드가 거부된다.
|
||||
|
||||
다음의 YAML은 이전 예제에서 생성된 프라이어리티클래스를
|
||||
사용하는 파드 구성의 예이다. 우선순위 어드미션 컨트롤러는
|
||||
명세를 확인하고 파드의 우선순위를 1000000으로
|
||||
해석한다.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
env: test
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
imagePullPolicy: IfNotPresent
|
||||
priorityClassName: high-priority
|
||||
```
|
||||
|
||||
### 스케줄링 순서에 대한 파드 우선순위의 영향
|
||||
|
||||
파드 우선순위가 활성화되면, 스케줄러가 우선순위에 따라 보류 중인
|
||||
파드를 주문하고 보류 중인 파드는 스케줄링 대기열에서
|
||||
우선순위가 낮은 다른 보류 중인 파드보다 우선한다. 결과적으로, 스케줄링
|
||||
요구 사항이 충족되는 경우 우선순위가 더 낮은 파드보다 우선순위가 높은 파드가
|
||||
더 빨리 스케줄링될 수 있다. 이러한 파드를 스케줄링할 수 없는 경우,
|
||||
스케줄러는 계속 진행하고 우선순위가 낮은 다른 파드를 스케줄링하려고 한다.
|
||||
|
||||
## 선점
|
||||
|
||||
파드가 생성되면, 대기열로 이동하여 스케줄링을 기다린다.
|
||||
스케줄러가 대기열에서 파드를 선택하여 노드에 스케줄링하려고 한다.
|
||||
파드의 지정된 모든 요구 사항을 충족하는 노드가 없으면,
|
||||
보류 중인 파드에 대해 선점 로직이 트리거된다. 보류 중인 파드를 P라 하자.
|
||||
선점 로직은 P보다 우선순위가 낮은 하나 이상의 파드를 제거하면
|
||||
해당 노드에서 P를 스케줄링할 수 있는 노드를 찾는다. 이러한
|
||||
노드가 발견되면, 하나 이상의 우선순위가 낮은 파드가 노드에서 축출된다.
|
||||
파드가 축출된 후, P는 노드에 스케줄링될 수 있다.
|
||||
|
||||
### 사용자 노출 정보
|
||||
|
||||
파드 P가 노드 N에서 하나 이상의 파드를 축출할 경우, 파드 P의 상태 `nominatedNodeName`
|
||||
필드는 노드 N의 이름으로 설정된다. 이 필드는 스케줄러가 파드 P에
|
||||
예약된 리소스를 추적하는 데 도움이 되고 사용자에게 클러스터의 선점에 대한
|
||||
정보를 제공한다.
|
||||
|
||||
파드 P는 반드시 "지정된 노드"로 스케줄링되지는 않는다.
|
||||
피해자 파드가 축출된 후, 그것은 정상적(graceful)으로 종료되는 기간을 갖는다.
|
||||
스케줄러가 종료될 피해자 파드를 기다리는 동안 다른 노드를 사용할 수
|
||||
있게 되면, 스케줄러는 파드 P를 스케줄링하기 위해 다른 노드를 사용한다. 그 결과,
|
||||
파드 스펙의 `nominatedNodeName` 과 `nodeName` 은 항상 동일하지 않다. 또한,
|
||||
스케줄러가 노드 N에서 파드를 축출했지만, 파드 P보다 우선순위가 높은 파드가
|
||||
도착하면, 스케줄러가 노드 N에 새로운 우선순위가 높은 파드를 제공할 수 있다. 이러한
|
||||
경우, 스케줄러는 파드 P의 `nominatedNodeName` 을 지운다. 이렇게하면, 스케줄러는
|
||||
파드 P가 다른 노드에서 파드를 축출할 수 있도록 한다.
|
||||
|
||||
### 선점의 한계
|
||||
|
||||
#### 선점 피해자의 정상적인 종료
|
||||
|
||||
파드가 축출되면, 축출된 피해자 파드는
|
||||
[정상적인 종료 기간](/ko/docs/concepts/workloads/pods/pod/#파드의-종료)을 가진다.
|
||||
피해자 파드는 작업을 종료하고 빠져나가는 데(exit) 많은 시간을 가진다. 그렇지 않으면,
|
||||
파드는 강제종료(kill) 된다. 이 정상적인 종료 기간은 스케줄러가 파드를 축출하는
|
||||
지점과 보류 중인 파드(P)를 노드(N)에서 스케줄링할 수 있는 시점 사이의
|
||||
시간 간격을 만든다. 그 동안, 스케줄러는 보류 중인 다른 파드를
|
||||
계속 스케줄링한다. 피해자 파드가 빠져나가거나 종료되면, 스케줄러는 보류 대기열에서
|
||||
파드를 스케줄하려고 한다. 따라서, 일반적으로 스케줄러가 피해자 파드를 축출하는 시점과
|
||||
파드 P가 스케줄링된 시점 사이에 시간 간격이 있다.
|
||||
이러한 차이를 최소화하기 위해, 우선순위가 낮은 파드의 정상적인 종료 기간을 0 또는
|
||||
작은 수로 설정할 수 있다.
|
||||
|
||||
#### PodDisruptionBudget을 지원하지만, 보장하지 않음
|
||||
|
||||
[Pod Disruption Budget(PDB)](/ko/docs/concepts/workloads/pods/disruptions/)은
|
||||
애플리케이션 소유자가 자발적 중단에서 동시에 다운된 복제된
|
||||
애플리케이션의 파드 수를 제한할 수 있다. 쿠버네티스는 파드를
|
||||
선점할 때 PDB를 지원하지만, PDB를 따르는 것이 최선의 노력이다. 스케줄러는
|
||||
선점에 의해 PDB를 위반하지 않은 피해자 파드를 찾으려고 하지만, 그러한 피해자 파드가
|
||||
발견되지 않으면, 선점은 여전히 발생하며, PDB를 위반하더라도 우선순위가
|
||||
낮은 파드는 제거된다.
|
||||
|
||||
#### 우선순위가 낮은 파드에 대한 파드-간 어피니티
|
||||
|
||||
이 질문에 대한 답변이 '예'인 경우에만 노드가 선점 대상으로 간주된다.
|
||||
"대기 중인 파드보다 우선순위가 낮은 모든 파드가 노드에서
|
||||
제거되면, 보류 중인 파드를 노드에 스케줄링할 수 있습니까?"
|
||||
|
||||
{{< note >}}
|
||||
선점으로 우선순위가 낮은 모든 파드를 반드시 제거할 필요는
|
||||
없다. 우선순위가 낮은 모든 파드보다 적은 수를 제거하여 보류 중인 파드를
|
||||
스케줄링할 수 있는 경우, 우선순위가 낮은 파드의 일부만 제거된다.
|
||||
그럼에도 불구하고, 앞의 질문에 대한 대답은 '예'여야 한다. 답변이 '아니오'인 경우,
|
||||
노드가 선점 대상으로 간주되지 않는다.
|
||||
{{< /note >}}
|
||||
|
||||
보류 중인 파드가 노드에 있는 하나 이상의 우선순위가 낮은 파드에 대한 파드-간 어피니티를
|
||||
가진 경우에, 우선순위가 낮은 파드가 없을 때 파드-간 어피니티 규칙을
|
||||
충족할 수 없다. 이 경우, 스케줄러는 노드의 파드를 축출하지
|
||||
않는다. 대신, 다른 노드를 찾는다. 스케줄러가
|
||||
적합한 노드를 찾거나 찾지 못할 수 있다. 보류 중인 파드를 스케줄링할 수 있다는
|
||||
보장은 없다.
|
||||
|
||||
이 문제에 대한 권장 솔루션은 우선순위가 같거나 높은 파드에 대해서만 파드-간 어피니티를
|
||||
생성하는 것이다.
|
||||
|
||||
#### 교차 노드 선점
|
||||
|
||||
보류 중인 파드 P가 노드 N에 스케줄링될 수 있도록 노드 N이 선점 대상으로 고려되고
|
||||
있다고 가정한다. 다른 노드의 파드가 축출된 경우에만 P가 N에서 실행 가능해질 수
|
||||
있다. 예를 들면 다음과 같다.
|
||||
|
||||
* 파드 P는 노드 N에 대해 고려된다.
|
||||
* 파드 Q는 노드 N과 동일한 영역의 다른 노드에서 실행 중이다.
|
||||
* 파드 P는 파드 Q(`topologyKey:
|
||||
failure-domain.beta.kubernetes.io/zone`)와 영역(zone) 전체의 안티-어피니티를 갖는다.
|
||||
* 영역에서 파드 P와 다른 파드 간의 안티-어피니티에 대한 다른 경우는
|
||||
없다.
|
||||
* 노드 N에서 파드 P를 스케줄링하기 위해, 파드 Q를 축출할 수 있지만, 스케줄러는
|
||||
교차-노드 선점을 수행하지 않는다. 따라서, 파드 P가 노드 N에서
|
||||
스케줄링할 수 없는 것으로 간주된다.
|
||||
|
||||
파드 Q가 노드에서 제거되면, 파드 안티-어피니티 위반이
|
||||
사라지고, 파드 P는 노드 N에서 스케줄링될 수 있다.
|
||||
|
||||
수요가 충분하고 합리적인 성능의 알고리즘을 찾을 경우
|
||||
향후 버전에서 교차 노드 선점의 추가를 고려할 수 있다.
|
||||
|
||||
## 문제 해결
|
||||
|
||||
파드 우선순위와 선점은 원하지 않는 부작용을 가질 수 있다. 다음은
|
||||
잠재적 문제의 예시와 이를 해결하는 방법이다.
|
||||
|
||||
### 파드가 불필요하게 선점(축출)됨
|
||||
|
||||
선점은 우선순위가 높은 보류 중인 파드를 위한 공간을 만들기 위해 리소스 압박을 받고 있는
|
||||
클러스터에서 기존 파드를 제거한다. 실수로 특정 파드에 높은 우선순위를
|
||||
부여하면, 의도하지 않은 높은 우선순위 파드가 클러스터에서
|
||||
선점을 유발할 수 있다. 파드 우선순위는 파드 명세에서
|
||||
`priorityClassName` 필드를 설정하여 지정한다. 그런 다음
|
||||
우선순위의 정수 값이 분석되어 `podSpec` 의 `priority` 필드에 채워진다.
|
||||
|
||||
문제를 해결하기 위해, 해당 파드가 우선순위가 낮은 클래스를 사용하도록 `priorityClassName` 을
|
||||
변경하거나, 해당 필드를 비워둘 수 있다. 빈
|
||||
`priorityClassName` 은 기본값이 0으로 해석된다.
|
||||
|
||||
파드가 축출되면, 축출된 파드에 대한 이벤트가 기록된다.
|
||||
선점은 클러스터가 파드에 대한 리소스를 충분히 가지지 못한 경우에만
|
||||
발생한다. 이러한 경우, 선점은 보류 중인 파드(선점자)의 우선순위가
|
||||
피해자 파드보다 높은 경우에만 발생한다. 보류 중인 파드가 없거나,
|
||||
보류 중인 파드의 우선순위가 피해자 파드와 같거나 낮은 경우
|
||||
선점이 발생하지 않아야 한다. 그러한 시나리오에서 선점이 발생하면, 이슈를 올리기 바란다.
|
||||
|
||||
### 파드가 축출되었지만, 선점자는 스케줄링되지 않음
|
||||
|
||||
파드가 축출되면, 요청된 정상적인 종료
|
||||
기간(기본적으로 30초)이 주어진다. 이 기간 내에 대상 파드가
|
||||
종료되지 않으면, 강제 종료된다. 모든 피해자 파드가 사라지면,
|
||||
선점자 파드를 스케줄링할 수 있다.
|
||||
|
||||
선점자 파드가 피해자 파드가 없어지기를 기다리는 동안, 동일한 노드에
|
||||
적합한 우선순위가 높은 파드가 생성될 수 있다. 이 경우, 스케줄러는
|
||||
선점자 대신 우선순위가 높은 파드를 스케줄링한다.
|
||||
|
||||
이것은 예상된 동작이다. 우선순위가 높은 파드는 우선순위가 낮은 파드를
|
||||
대체해야 한다. [클러스터 오토스케일링](/ko/docs/tasks/administer-cluster/cluster-management/#클러스터-오토스케일링)과
|
||||
같은 다른 컨트롤러 작업은,
|
||||
결국 보류 중인 파드를 스케줄링할 수 있는 용량을 제공할 수 있다.
|
||||
|
||||
### 우선순위가 높은 파드는 우선순위가 낮은 파드보다 우선함
|
||||
|
||||
스케줄러가 보류 중인 파드를 실행할 수 있는 노드를 찾으려고 한다. 노드를 찾지
|
||||
못하면, 스케줄러는 임의의 노드에서 우선순위가 낮은 파드를 제거하여
|
||||
보류 중인 파드를 위한 공간을 만든다.
|
||||
우선순위가 낮은 파드가 있는 노드가 보류 중인 파드를 실행할 수 없는 경우, 스케줄러는
|
||||
선점을 위해 우선순위가 높은 다른 노드(다른 노드의 파드와 비교)를
|
||||
선택할 수 있다. 피해자 파드는 여전히 선점자 파드보다 우선순위가
|
||||
낮아야 한다.
|
||||
|
||||
선점할 수 있는 여러 노드가 있는 경우, 스케줄러는
|
||||
우선순위가 가장 낮은 파드 세트를 가진 노드를 선택하려고 한다. 그러나,
|
||||
이러한 파드가 위반될 PodDisruptionBudget을 가지고 있고 축출된 경우
|
||||
스케줄러는 우선순위가 높은 파드를 가진 다른 노드를 선택할 수 있다.
|
||||
|
||||
선점을 위해 여러 개의 노드가 존재하고 위의 시나리오 중 어느 것도 적용되지 않는 경우,
|
||||
스케줄러는 우선순위가 가장 낮은 노드를 선택한다.
|
||||
|
||||
## 파드 우선순위와 서비스 품질 간의 상호 작용 {#interactions-of-pod-priority-and-qos}
|
||||
|
||||
파드 우선순위와 {{< glossary_tooltip text="QoS 클래스" term_id="qos-class" >}}는
|
||||
상호 작용이 거의 없고 QoS 클래스를 기반으로 파드 우선순위를 설정하는 데 대한
|
||||
기본 제한이 없는 두 개의 직교(orthogonal) 기능이다. 스케줄러의
|
||||
선점 로직은 선점 대상을 선택할 때 QoS를 고려하지 않는다.
|
||||
선점은 파드 우선순위를 고려하고 우선순위가 가장 낮은 대상 세트를
|
||||
선택하려고 한다. 우선순위가 가장 높은 파드는 스케줄러가
|
||||
선점자 파드를 스케줄링할 수 없거나 우선순위가 가장 낮은 파드가
|
||||
`PodDisruptionBudget` 으로 보호되는 경우에만, 우선순위가 가장 낮은 파드를
|
||||
축출 대상으로 고려한다.
|
||||
|
||||
QoS와 파드 우선순위를 모두 고려하는 유일한 컴포넌트는
|
||||
[kubelet 리소스 부족 축출](/docs/tasks/administer-cluster/out-of-resource/)이다.
|
||||
kubelet은 부족한 리소스의 사용이 요청을 초과하는지 여부에 따라, 그런 다음 우선순위에 따라,
|
||||
파드의 스케줄링 요청에 대한 부족한 컴퓨팅 리소스의 소비에 의해
|
||||
먼저 축출 대상 파드의 순위를 매긴다.
|
||||
더 자세한 내용은
|
||||
[엔드유저 파드 축출](/docs/tasks/administer-cluster/out-of-resource/#evicting-end-user-pods)을
|
||||
참조한다.
|
||||
|
||||
kubelet 리소스 부족 축출은 사용량이 요청을 초과하지 않는 경우
|
||||
파드를 축출하지 않는다. 우선순위가 낮은 파드가 요청을
|
||||
초과하지 않으면, 축출되지 않는다. 요청을 초과하는 우선순위가
|
||||
더 높은 다른 파드가 축출될 수 있다.
|
||||
|
||||
{{% /capture %}}
|
||||
{{% capture whatsnext %}}
|
||||
* 프라이어리티클래스와 관련하여 리소스쿼터 사용에 대해 [기본적으로 프라이어리티 클래스 소비 제한](/ko/docs/concepts/policy/resource-quotas/#기본적으로-우선-순위-클래스-소비-제한)을 읽어보자.
|
||||
{{% /capture %}}
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: 확장된 리소스를 위한 리소스 빈 패킹(bin packing)
|
||||
content_template: templates/concept
|
||||
weight: 10
|
||||
weight: 50
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
@@ -198,7 +198,7 @@ tolerations:
|
||||
|
||||
## 테인트 기반 축출
|
||||
|
||||
{{< feature-state for_k8s_version="1.18" state="stable" >}}
|
||||
{{< feature-state for_k8s_version="v1.18" state="stable" >}}
|
||||
|
||||
앞에서 우리는 노드에서 이미 실행 중인 파드에 영향을 주는 `NoExecute` 테인트 이펙트를
|
||||
다음과 같이 언급했다.
|
||||
|
||||
Reference in New Issue
Block a user