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:
Jerry Park
2020-04-11 15:21:34 +09:00
committed by Claudia J.Kang
parent c74ce882ec
commit ca62e21766
67 changed files with 4827 additions and 313 deletions
@@ -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` 테인트 이펙트를
다음과 같이 언급했다.