이 섹션의 다중 페이지 출력 화면임. 여기를 클릭하여 프린트.
정책
- 1: 리밋 레인지(Limit Range)
- 2: 리소스 쿼터
- 3: 프로세스 ID 제한 및 예약
- 4: 노드 리소스 매니저
1 - 리밋 레인지(Limit Range)
기본적으로 컨테이너는 쿠버네티스 클러스터에서 무제한 컴퓨팅 리소스로 실행된다. 쿠버네티스의 리소스 쿼터를 사용하면 클러스터 관리자(또는 클러스터 오퍼레이터 라고 함)는 네임스페이스별로 리소스(CPU 시간, 메모리 및 퍼시스턴트 스토리지) 사용과 생성을 제한할 수 있다. 네임스페이스 내에서 파드는 네임스페이스의 리소스 쿼터에 정의된 만큼의 CPU와 메모리를 사용할 수 있다. 클러스터 운영자 또는 네임스페이스 수준 관리자는 단일 오브젝트가 네임스페이스 내에서 사용 가능한 모든 리소스를 독점하지 못하도록 하는 것에 대해 우려할 수도 있다.
리밋레인지는 네임스페이스의 각 적용 가능한 오브젝트 종류(예: 파드 또는 퍼시스턴트볼륨클레임)에 대해 지정할 수 있는 리소스 할당(제한 및 요청)을 제한하는 정책이다.
리밋레인지 는 다음과 같은 제약 조건을 제공한다.
- 네임스페이스에서 파드 또는 컨테이너별 최소 및 최대 컴퓨팅 리소스 사용량을 지정한다.
- 네임스페이스에서 퍼시스턴트볼륨클레임별 최소 및 최대 스토리지 요청을 지정한다.
- 네임스페이스에서 리소스에 대한 요청과 제한 사이의 비율을 지정한다.
- 네임스페이스에서 컴퓨팅 리소스에 대한 기본 요청/제한을 설정하고 런타임에 있는 컨테이너에 자동으로 설정한다.
해당 네임스페이스에 리밋레인지 오브젝트가 있는 경우 특정 네임스페이스에 리밋레인지가 지정된다.
리밋레인지 오브젝트의 이름은 유효한 DNS 서브도메인 이름이어야 한다.
리소스 제한 및 요청에 대한 제약
- 관리자는 네임스페이스에 리밋레인지를 생성한다.
- 사용자는 해당 네임스페이스에서 파드 또는 퍼시스턴트볼륨클레임과 같은 오브젝트를 생성하거나 생성하려고 시도한다.
- 첫째,
LimitRange
어드미션 컨트롤러는 컴퓨팅 리소스 요구사항을 설정하지 않은 모든 파드(및 해당 컨테이너)에 대해 기본 요청 및 제한 값을 적용한다. - 둘째,
LimitRange
는 사용량을 추적하여 네임스페이스에 존재하는LimitRange
에 정의된 리소스 최소, 최대 및 비율을 초과하지 않는지 확인한다. - 리밋레인지 제약 조건을 위반하는 리소스(파드, 컨테이너, 퍼시스턴트볼륨클레임)를 생성하거나 업데이트하려고 하는 경우 HTTP 상태 코드
403 FORBIDDEN
및 위반된 제약 조건을 설명하는 메시지와 함께 API 서버에 대한 요청이 실패한다. cpu
,memory
와 같은 컴퓨팅 리소스의 네임스페이스에서 리밋레인지를 추가한 경우 사용자는 해당 값에 대한 요청 또는 제한을 지정해야 한다. 그렇지 않으면 시스템에서 파드 생성이 거부될 수 있다.LimitRange
유효성 검사는 실행 중인 파드가 아닌 파드 어드미션 단계에서만 수행된다. 리밋레인지가 추가되거나 수정되면, 해당 네임스페이스에 이미 존재하는 파드는 변경되지 않고 계속 유지된다.- 네임스페이스에 두 개 이상의
LimitRange
오브젝트가 존재하는 경우, 어떤 기본값이 적용될지는 결정적이지 않다.
파드에 대한 리밋레인지 및 어드미션 확인
LimitRange
는 적용하는 기본값의 일관성을 확인하지 않는다. 즉, LimitRange
에 의해 설정된 limit 의 기본값이 클라이언트가 API 서버에 제출하는 스펙에서 컨테이너에 지정된 request 값보다 작을 수 있다. 이 경우, 최종 파드는 스케줄링할 수 없다.
예를 들어, 이 매니페스트에 LimitRange
를 정의한다.
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-resource-constraint
spec:
limits:
- default: # 이 섹션에서는 기본 한도를 정의한다
cpu: 500m
defaultRequest: # 이 섹션에서는 기본 요청을 정의한다
cpu: 500m
max: # max와 min은 제한 범위를 정의한다
cpu: "1"
min:
cpu: 100m
이 때 CPU 리소스 요청을 700m
로 선언하지만 제한은 선언하지 않는 파드를 포함한다.
apiVersion: v1
kind: Pod
metadata:
name: example-conflict-with-limitrange-cpu
spec:
containers:
- name: demo
image: registry.k8s.io/pause:2.0
resources:
requests:
cpu: 700m
그러면 해당 파드는 스케줄링되지 않고 다음과 유사한 오류와 함께 실패한다.
Pod "example-conflict-with-limitrange-cpu" is invalid: spec.containers[0].resources.requests: Invalid value: "700m": must be less than or equal to cpu limit
request
와 limit
를 모두 설정하면, 동일한 LimitRange
가 적용되어 있어도 새 파드는 성공적으로 스케줄링된다.
apiVersion: v1
kind: Pod
metadata:
name: example-no-conflict-with-limitrange-cpu
spec:
containers:
- name: demo
image: registry.k8s.io/pause:2.0
resources:
requests:
cpu: 700m
limits:
cpu: 700m
리소스 제약 예시
LimitRange
를 사용하여 생성할 수 있는 정책의 예는 다음과 같다.
- 용량이 8GiB RAM과 16 코어인 2 노드 클러스터에서 네임스페이스의 파드를 제한하여 CPU의 최대 제한이 500m인 CPU 100m를 요청하고 메모리의 최대 제한이 600M인 메모리 200Mi를 요청하라.
- 스펙에 CPU 및 메모리 요청없이 시작된 컨테이너에 대해 기본 CPU 제한 및 요청을 150m로, 메모리 기본 요청을 300Mi로 정의하라.
네임스페이스의 총 제한이 파드/컨테이너의 제한 합보다 작은 경우 리소스에 대한 경합이 있을 수 있다. 이 경우 컨테이너 또는 파드가 생성되지 않는다.
경합이나 리밋레인지 변경은 이미 생성된 리소스에 영향을 미치지 않는다.
다음 내용
제한의 사용에 대한 예시는 다음을 참조한다.
- 네임스페이스당 최소 및 최대 CPU 제약 조건을 설정하는 방법.
- 네임스페이스당 최소 및 최대 메모리 제약 조건을 설정하는 방법.
- 네임스페이스당 기본 CPU 요청과 제한을 설정하는 방법.
- 네임스페이스당 기본 메모리 요청과 제한을 설정하는 방법.
- 네임스페이스당 최소 및 최대 스토리지 사용량을 설정하는 방법.
- 네임스페이스당 할당량을 설정하는 자세한 예시.
컨텍스트 및 기록 정보는 LimitRanger 디자인 문서를 참조한다.
2 - 리소스 쿼터
여러 사용자나 팀이 정해진 수의 노드로 클러스터를 공유할 때 한 팀이 공정하게 분배된 리소스보다 많은 리소스를 사용할 수 있다는 우려가 있다.
리소스 쿼터는 관리자가 이 문제를 해결하기 위한 도구이다.
ResourceQuota
오브젝트로 정의된 리소스 쿼터는 네임스페이스별 총 리소스 사용을 제한하는
제약 조건을 제공한다. 유형별로 네임스페이스에서 만들 수 있는 오브젝트 수와
해당 네임스페이스의 리소스가 사용할 수 있는 총 컴퓨트 리소스의 양을
제한할 수 있다.
리소스 쿼터는 다음과 같이 작동한다.
-
다른 팀은 다른 네임스페이스에서 작업한다. 이것은 RBAC으로 설정할 수 있다.
-
관리자는 각 네임스페이스에 대해 하나의 리소스쿼터를 생성한다.
-
사용자는 네임스페이스에서 리소스(파드, 서비스 등)를 생성하고 쿼터 시스템은 사용량을 추적하여 리소스쿼터에 정의된 하드(hard) 리소스 제한을 초과하지 않도록 한다.
-
리소스를 생성하거나 업데이트할 때 쿼터 제약 조건을 위반하면 위반된 제약 조건을 설명하는 메시지와 함께 HTTP 상태 코드
403 FORBIDDEN
으로 요청이 실패한다. -
cpu
,memory
와 같은 컴퓨트 리소스에 대해 네임스페이스에서 쿼터가 활성화된 경우 사용자는 해당값에 대한 요청 또는 제한을 지정해야 한다. 그렇지 않으면 쿼터 시스템이 파드 생성을 거부할 수 있다. 힌트: 컴퓨트 리소스 요구 사항이 없는 파드를 기본값으로 설정하려면LimitRanger
어드미션 컨트롤러를 사용하자.이 문제를 회피하는 방법에 대한 예제는 연습을 참고하길 바란다.
- 리소스쿼터는
cpu
및memory
리소스의 경우, 해당 네임스페이스의 모든 (신규) 파드가 해당 리소스에 대한 제한을 설정하도록 강제한다. 네임스페이스에서cpu
또는memory
에 대해 리소스 할당량을 적용하는 경우, 사용자와 다른 클라이언트는 반드시 제출하는 모든 새 파드에 대해 해당 리소스에requests
또는limits
중 하나를 지정해야 한다. 그렇지 않으면 컨트롤 플레인이 해당 파드에 대한 어드미션을 거부할 수 있다. - 다른 리소스의 경우: 리소스쿼터는 작동하며 해당 리소스에 대한 제한이나 요청을 설정하지 않고 네임스페이스의 파드를 무시한다. 즉, 리소스 쿼터가 이 네임스페이스의 임시 스토리지를 제한하는 경우 임시 스토리지를 제한/요청하지 않고 새 파드를 생성할 수 있다. 리밋 레인지(Limit Range)를 사용하여 이러한 리소스에 대한 기본 요청을 자동으로 설정할 수 있다.
리소스쿼터 오브젝트의 이름은 유효한 DNS 서브도메인 이름이어야 한다.
네임스페이스와 쿼터를 사용하여 만들 수 있는 정책의 예는 다음과 같다.
- 용량이 32GiB RAM, 16 코어인 클러스터에서 A 팀이 20GiB 및 10 코어를 사용하고 B 팀은 10GiB 및 4 코어를 사용하게 하고 2GiB 및 2 코어를 향후 할당을 위해 보유하도록 한다.
- "testing" 네임스페이스를 1 코어 및 1GiB RAM을 사용하도록 제한한다. "production" 네임스페이스에는 원하는 양을 사용하도록 한다.
클러스터의 총 용량이 네임스페이스의 쿼터 합보다 작은 경우 리소스에 대한 경합이 있을 수 있다. 이것은 선착순으로 처리된다.
경합이나 쿼터 변경은 이미 생성된 리소스에 영향을 미치지 않는다.
리소스 쿼터 활성화
많은 쿠버네티스 배포판에 기본적으로 리소스 쿼터 지원이 활성화되어 있다.
API 서버
--enable-admission-plugins=
플래그의 인수 중 하나로
ResourceQuota
가 있는 경우 활성화된다.
해당 네임스페이스에 리소스쿼터가 있는 경우 특정 네임스페이스에 리소스 쿼터가 적용된다.
컴퓨트 리소스 쿼터
지정된 네임스페이스에서 요청할 수 있는 총 컴퓨트 리소스 합을 제한할 수 있다.
다음과 같은 리소스 유형이 지원된다.
리소스 이름 | 설명 |
---|---|
limits.cpu |
터미널이 아닌 상태의 모든 파드에서 CPU 제한의 합은 이 값을 초과할 수 없음. |
limits.memory |
터미널이 아닌 상태의 모든 파드에서 메모리 제한의 합은 이 값을 초과할 수 없음. |
requests.cpu |
터미널이 아닌 상태의 모든 파드에서 CPU 요청의 합은 이 값을 초과할 수 없음. |
requests.memory |
터미널이 아닌 상태의 모든 파드에서 메모리 요청의 합은 이 값을 초과할 수 없음. |
hugepages-<size> |
터미널 상태가 아닌 모든 파드에 걸쳐서, 지정된 사이즈의 휴즈 페이지 요청은 이 값을 초과하지 못함. |
cpu |
requests.cpu 와 같음. |
memory |
requests.memory 와 같음. |
확장된 리소스에 대한 리소스 쿼터
위에서 언급한 리소스 외에도 릴리스 1.10에서는 확장된 리소스에 대한 쿼터 지원이 추가되었다.
확장된 리소스에는 오버커밋(overcommit)이 허용되지 않으므로 하나의 쿼터에서
동일한 확장된 리소스에 대한 requests
와 limits
을 모두 지정하는 것은 의미가 없다. 따라서 확장된
리소스의 경우 지금은 접두사 requests.
이 있는 쿼터 항목만 허용된다.
예를 들어, 리소스 이름이 nvidia.com/gpu
이고 네임스페이스에서 요청된 총 GPU 수를 4개로 제한하려는 경우,
GPU 리소스를 다음과 같이 쿼터를 정의할 수 있다.
requests.nvidia.com/gpu: 4
자세한 내용은 쿼터 보기 및 설정을 참고하길 바란다.
스토리지 리소스 쿼터
지정된 네임스페이스에서 요청할 수 있는 총 스토리지 리소스 합을 제한할 수 있다.
또한 연관된 스토리지 클래스를 기반으로 스토리지 리소스 사용을 제한할 수 있다.
리소스 이름 | 설명 |
---|---|
requests.storage |
모든 퍼시스턴트 볼륨 클레임에서 스토리지 요청의 합은 이 값을 초과할 수 없음 |
persistentvolumeclaims |
네임스페이스에 존재할 수 있는 총 퍼시스턴트 볼륨 클레임 수 |
<storage-class-name>.storageclass.storage.k8s.io/requests.storage |
storage-class-name과 관련된 모든 퍼시스턴트 볼륨 클레임에서 스토리지 요청의 합은 이 값을 초과할 수 없음 |
<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims |
<storage-class-name> 과 관련된 모든 퍼시스턴트 볼륨 클레임에서 네임스페이스에 존재할 수 있는 총 퍼시스턴트 볼륨 클레임 수 |
예를 들어, 운영자가 bronze
스토리지 클래스와 별도로 gold
스토리지 클래스를 사용하여 스토리지에 쿼터를 지정하려는 경우 운영자는 다음과 같이
쿼터를 정의할 수 있다.
gold.storageclass.storage.k8s.io/requests.storage: 500Gi
bronze.storageclass.storage.k8s.io/requests.storage: 100Gi
릴리스 1.8에서는 로컬 임시 스토리지에 대한 쿼터 지원이 알파 기능으로 추가되었다.
리소스 이름 | 설명 |
---|---|
requests.ephemeral-storage |
네임스페이스의 모든 파드에서 로컬 임시 스토리지 요청의 합은 이 값을 초과할 수 없음. |
limits.ephemeral-storage |
네임스페이스의 모든 파드에서 로컬 임시 스토리지 제한의 합은 이 값을 초과할 수 없음. |
ephemeral-storage |
requests.ephemeral-storage 와 같음. |
오브젝트 수 쿼터
다음 구문을 사용하여 모든 표준 네임스페이스 처리된(namespaced) 리소스 유형에 대한 특정 리소스 전체 수에 대하여 쿼터를 지정할 수 있다.
- 코어 그룹이 아닌(non-core) 리소스를 위한
count/<resource>.<group>
- 코어 그룹의 리소스를 위한
count/<resource>
다음은 사용자가 오브젝트 수 쿼터 아래에 배치하려는 리소스 셋의 예이다.
count/persistentvolumeclaims
count/services
count/secrets
count/configmaps
count/replicationcontrollers
count/deployments.apps
count/replicasets.apps
count/statefulsets.apps
count/jobs.batch
count/cronjobs.batch
사용자 정의 리소스를 위해 동일한 구문을 사용할 수 있다.
예를 들어 example.com
API 그룹에서 widgets
사용자 정의 리소스에 대한 쿼터를 생성하려면 count/widgets.example.com
을 사용한다.
count/*
리소스 쿼터를 사용할 때 서버 스토리지 영역에 있다면 오브젝트는 쿼터에 대해 과금된다.
이러한 유형의 쿼터는 스토리지 리소스 고갈을 방지하는 데 유용하다. 예를 들어,
크기가 큰 서버에서 시크릿 수에 쿼터를 지정할 수 있다. 클러스터에 시크릿이 너무 많으면 실제로 서버와
컨트롤러가 시작되지 않을 수 있다. 잘못 구성된 크론 잡으로부터의 보호를 위해
잡의 쿼터를 설정할 수 있다. 네임스페이스 내에서 너무 많은 잡을 생성하는 크론 잡은 서비스 거부를 유발할 수 있다.
또한 제한된 리소스 셋에 대해서 일반 오브젝트 수(generic object count) 쿼터를 적용하는 것도 가능하다. 다음 유형이 지원된다.
리소스 이름 | 설명 |
---|---|
configmaps |
네임스페이스에 존재할 수 있는 총 컨피그맵 수 |
persistentvolumeclaims |
네임스페이스에 존재할 수 있는 총 퍼시스턴트 볼륨 클레임 수 |
pods |
네임스페이스에 존재할 수 있는 터미널이 아닌 상태의 파드의 총 수. .status.phase in (Failed, Succeeded) 가 true인 경우 파드는 터미널 상태임 |
replicationcontrollers |
네임스페이스에 존재할 수 있는 총 레플리케이션컨트롤러 수 |
resourcequotas |
네임스페이스에 존재할 수 있는 총 리소스쿼터 수 |
services |
네임스페이스에 존재할 수 있는 총 서비스 수 |
services.loadbalancers |
네임스페이스에 존재할 수 있는 LoadBalancer 유형의 총 서비스 수 |
services.nodeports |
네임스페이스에 존재할 수 있는 NodePort 유형의 총 서비스 수 |
secrets |
네임스페이스에 존재할 수 있는 총 시크릿 수 |
예를 들어, pods
쿼터는 터미널이 아닌 단일 네임스페이스에서 생성된 pods
수를
계산하고 최댓값을 적용한다. 사용자가 작은 파드를 많이 생성하여 클러스터의 파드 IP
공급이 고갈되는 경우를 피하기 위해 네임스페이스에
pods
쿼터를 설정할 수 있다.
쿼터 범위
각 쿼터에는 연결된 scopes
셋이 있을 수 있다. 쿼터는 열거된 범위의 교차 부분과 일치하는 경우에만
리소스 사용량을 측정한다.
범위가 쿼터에 추가되면 해당 범위와 관련된 리소스를 지원하는 리소스 수가 제한된다. 허용된 셋 이외의 쿼터에 지정된 리소스는 유효성 검사 오류가 발생한다.
범위 | 설명 |
---|---|
Terminating |
.spec.activeDeadlineSeconds >= 0 에 일치하는 파드 |
NotTerminating |
.spec.activeDeadlineSeconds is nil 에 일치하는 파드 |
BestEffort |
최상의 서비스 품질을 제공하는 파드 |
NotBestEffort |
서비스 품질이 나쁜 파드 |
PriorityClass |
지정된 프라이어리티클래스를 참조하여 일치하는 파드. |
CrossNamespacePodAffinity |
크로스-네임스페이스 파드 [(안티)어피니티 용어]가 있는 파드 |
BestEffort
범위는 다음의 리소스를 추적하도록 쿼터를 제한한다.
pods
Terminating
, NotTerminating
, NotBestEffort
및 PriorityClass
범위는 쿼터를 제한하여 다음의 리소스를 추적한다.
pods
cpu
memory
requests.cpu
requests.memory
limits.cpu
limits.memory
Terminating
과 NotTerminating
범위를 동일한 쿼터 내에 모두
명시하지는 못하며, 마찬가지로 BestEffort
와
NotBestEffort
범위도 동일한 쿼터 내에서 모두 명시하지는 못한다.
scopeSelector
는 operator
필드에 다음의 값을 지원한다.
In
NotIn
Exists
DoesNotExist
scopeSelector
를 정의할 때, scopeName
으로 다음의 값 중 하나를 사용하는
경우, operator
는 Exists
이어야 한다.
Terminating
NotTerminating
BestEffort
NotBestEffort
만약 operator
가 In
또는 NotIn
인 경우, values
필드는 적어도 하나의 값은
가져야 한다. 예를 들면 다음과 같다.
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values:
- middle
만약 operator
가 Exists
또는 DoesNotExist
이라면, values
필드는 명시되면
안된다.
PriorityClass별 리소스 쿼터
Kubernetes v1.17 [stable]
특정 우선 순위로 파드를 생성할 수 있다.
쿼터 스펙의 scopeSelector
필드를 사용하여 파드의 우선 순위에 따라 파드의 시스템 리소스 사용을
제어할 수 있다.
쿼터 스펙의 scopeSelector
가 파드를 선택한 경우에만 쿼터가 일치하고 사용된다.
scopeSelector
필드를 사용하여 우선 순위 클래스의 쿼터 범위를 지정하면,
쿼터 오브젝트는 다음의 리소스만 추적하도록 제한된다.
pods
cpu
memory
ephemeral-storage
limits.cpu
limits.memory
limits.ephemeral-storage
requests.cpu
requests.memory
requests.ephemeral-storage
이 예에서는 쿼터 오브젝트를 생성하여 특정 우선 순위의 파드와 일치시킨다. 예제는 다음과 같이 작동한다.
- 클러스터의 파드는 "low(낮음)", "medium(중간)", "high(높음)"의 세 가지 우선 순위 클래스 중 하나를 가진다.
- 각 우선 순위마다 하나의 쿼터 오브젝트가 생성된다.
다음 YAML을 quota.yml
파일에 저장한다.
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-high
spec:
hard:
cpu: "1000"
memory: 200Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["high"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-medium
spec:
hard:
cpu: "10"
memory: 20Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["medium"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-low
spec:
hard:
cpu: "5"
memory: 10Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["low"]
kubectl create
를 사용하여 YAML을 적용한다.
kubectl create -f ./quota.yml
resourcequota/pods-high created
resourcequota/pods-medium created
resourcequota/pods-low created
kubectl describe quota
를 사용하여 Used
쿼터가 0
인지 확인하자.
kubectl describe quota
Name: pods-high
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 1k
memory 0 200Gi
pods 0 10
Name: pods-low
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 5
memory 0 10Gi
pods 0 10
Name: pods-medium
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 10
memory 0 20Gi
pods 0 10
우선 순위가 "high"인 파드를 생성한다. 다음 YAML을
high-priority-pod.yml
파일에 저장한다.
apiVersion: v1
kind: Pod
metadata:
name: high-priority
spec:
containers:
- name: high-priority
image: ubuntu
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]
resources:
requests:
memory: "10Gi"
cpu: "500m"
limits:
memory: "10Gi"
cpu: "500m"
priorityClassName: high
kubectl create
로 적용하자.
kubectl create -f ./high-priority-pod.yml
"high" 우선 순위 쿼터가 적용된 pods-high
에 대한 "Used" 통계가 변경되었고
다른 두 쿼터는 변경되지 않았는지 확인한다.
kubectl describe quota
Name: pods-high
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 500m 1k
memory 10Gi 200Gi
pods 1 10
Name: pods-low
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 5
memory 0 10Gi
pods 0 10
Name: pods-medium
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 10
memory 0 20Gi
pods 0 10
네임스페이스 간 파드 어피니티 쿼터
Kubernetes v1.24 [stable]
오퍼레이터는 네임스페이스를 교차하는 어피니티가 있는 파드를 가질 수 있는 네임스페이스를
제한하기 위해 CrossNamespacePodAffinity
쿼터 범위를 사용할 수 있다. 특히, 파드 어피니티 용어의
namespaces
또는 namespaceSelector
필드를 설정할 수 있는 파드를 제어한다.
안티-어피니티 제약 조건이 있는 파드는 장애 도메인에서 다른 모든 네임스페이스의 파드가 예약되지 않도록 차단할 수 있으므로 사용자가 네임스페이스 간 어피니티 용어를 사용하지 못하도록 하는 것이 바람직할 수 있다.
이 범위 오퍼레이터를 사용하면 CrossNamespaceAffinity
범위와 하드(hard) 제한이 0인
네임스페이스에 리소스 쿼터 오브젝트를 생성하여 특정 네임스페이스(아래 예에서 foo-ns
)가 네임스페이스 간 파드 어피니티를
사용하는 파드를 사용하지 못하도록 방지할 수 있다.
apiVersion: v1
kind: ResourceQuota
metadata:
name: disable-cross-namespace-affinity
namespace: foo-ns
spec:
hard:
pods: "0"
scopeSelector:
matchExpressions:
- scopeName: CrossNamespaceAffinity
오퍼레이터가 기본적으로 namespaces
및 namespaceSelector
사용을 허용하지 않고,
특정 네임스페이스에만 허용하려는 경우, kube-apiserver 플래그 --admission-control-config-file를
다음의 구성 파일의 경로로 설정하여 CrossNamespaceAffinity
를
제한된 리소스로 구성할 수 있다.
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: "ResourceQuota"
configuration:
apiVersion: apiserver.config.k8s.io/v1
kind: ResourceQuotaConfiguration
limitedResources:
- resource: pods
matchScopes:
- scopeName: CrossNamespaceAffinity
위의 구성을 사용하면, 파드는 생성된 네임스페이스에 CrossNamespaceAffinity
범위가 있는 리소스 쿼터 오브젝트가 있고,
해당 필드를 사용하는 파드 수보다 크거나 같은 하드 제한이 있는 경우에만
파드 어피니티에서 namespaces
및 namespaceSelector
를 사용할 수 있다.
요청과 제한의 비교
컴퓨트 리소스를 할당할 때 각 컨테이너는 CPU 또는 메모리에 대한 요청과 제한값을 지정할 수 있다. 쿼터는 값에 대한 쿼터를 지정하도록 구성할 수 있다.
쿼터에 requests.cpu
나 requests.memory
에 지정된 값이 있으면 들어오는 모든
컨테이너가 해당 리소스에 대한 명시적인 요청을 지정해야 한다. 쿼터에 limits.cpu
나
limits.memory
에 지정된 값이 있으면 들어오는 모든 컨테이너가 해당 리소스에 대한 명시적인 제한을 지정해야 한다.
쿼터 보기 및 설정
Kubectl은 쿼터 생성, 업데이트 및 보기를 지원한다.
kubectl create namespace myspace
cat <<EOF > compute-resources.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
requests.nvidia.com/gpu: 4
EOF
kubectl create -f ./compute-resources.yaml --namespace=myspace
cat <<EOF > object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
configmaps: "10"
persistentvolumeclaims: "4"
pods: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
EOF
kubectl create -f ./object-counts.yaml --namespace=myspace
kubectl get quota --namespace=myspace
NAME AGE
compute-resources 30s
object-counts 32s
kubectl describe quota compute-resources --namespace=myspace
Name: compute-resources
Namespace: myspace
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
requests.cpu 0 1
requests.memory 0 1Gi
requests.nvidia.com/gpu 0 4
kubectl describe quota object-counts --namespace=myspace
Name: object-counts
Namespace: myspace
Resource Used Hard
-------- ---- ----
configmaps 0 10
persistentvolumeclaims 0 4
pods 0 4
replicationcontrollers 0 20
secrets 1 10
services 0 10
services.loadbalancers 0 2
Kubectl은 count/<resource>.<group>
구문을 사용하여 모든 표준 네임스페이스 리소스에 대한
오브젝트 수 쿼터를 지원한다.
kubectl create namespace myspace
kubectl create quota test --hard=count/deployments.apps=2,count/replicasets.apps=4,count/pods=3,count/secrets=4 --namespace=myspace
kubectl create deployment nginx --image=nginx --namespace=myspace --replicas=2
kubectl describe quota --namespace=myspace
Name: test
Namespace: myspace
Resource Used Hard
-------- ---- ----
count/deployments.apps 1 2
count/pods 2 3
count/replicasets.apps 1 4
count/secrets 1 4
쿼터 및 클러스터 용량
리소스쿼터는 클러스터 용량과 무관하다. 그것들은 절대 단위로 표현된다. 따라서 클러스터에 노드를 추가해도 각 네임스페이스에 더 많은 리소스를 사용할 수 있는 기능이 자동으로 부여되지는 않는다.
가끔 다음과 같은 보다 복잡한 정책이 필요할 수 있다.
- 여러 팀으로 전체 클러스터 리소스를 비례적으로 나눈다.
- 각 테넌트가 필요에 따라 리소스 사용량을 늘릴 수 있지만, 실수로 리소스가 고갈되는 것을 막기 위한 충분한 제한이 있다.
- 하나의 네임스페이스에서 요구를 감지하고 노드를 추가하며 쿼터를 늘린다.
이러한 정책은 쿼터 사용을 감시하고 다른 신호에 따라 각 네임스페이스의 쿼터 하드 제한을
조정하는 "컨트롤러"를 작성하여 ResourceQuotas
를 구성 요소로
사용하여 구현할 수 있다.
리소스 쿼터는 통합된 클러스터 리소스를 분할하지만 노드에 대한 제한은 없다. 여러 네임스페이스의 파드가 동일한 노드에서 실행될 수 있다.
기본적으로 우선 순위 클래스 소비 제한
파드가 특정 우선 순위, 예를 들어 일치하는 쿼터 오브젝트가 존재하는 경우에만 "cluster-services"가 네임스페이스에 허용되어야 한다.
이 메커니즘을 통해 운영자는 특정 우선 순위가 높은 클래스의 사용을 제한된 수의 네임스페이스로 제한할 수 있으며 모든 네임스페이스가 기본적으로 이러한 우선 순위 클래스를 사용할 수 있는 것은 아니다.
이를 적용하려면 kube-apiserver 플래그 --admission-control-config-file
을
사용하여 다음 구성 파일의 경로를 전달해야 한다.
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: "ResourceQuota"
configuration:
apiVersion: apiserver.config.k8s.io/v1
kind: ResourceQuotaConfiguration
limitedResources:
- resource: pods
matchScopes:
- scopeName: PriorityClass
operator: In
values: ["cluster-services"]
그리고, kube-system
네임스페이스에 리소스 쿼터 오브젝트를 생성한다.
apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-cluster-services
spec:
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["cluster-services"]
kubectl apply -f https://k8s.io/examples/policy/priority-class-resourcequota.yaml -n kube-system
resourcequota/pods-cluster-services created
이 경우, 파드 생성은 다음의 조건을 만족해야 허용될 것이다.
- 파드의
priorityClassName
가 명시되지 않음. - 파드의
priorityClassName
가cluster-services
이외의 다른 값으로 명시됨. - 파드의
priorityClassName
가cluster-services
로 설정되고, 파드가kube-system
네임스페이스에 생성되었으며 리소스 쿼터 검증을 통과함.
파드 생성 요청은 priorityClassName
가 cluster-services
로 명시되고
kube-system
이외의 다른 네임스페이스에 생성되는 경우, 거절된다.
다음 내용
- 자세한 내용은 리소스쿼터 디자인 문서를 참고한다.
- 리소스 쿼터를 사용하는 방법에 대한 자세한 예를 참고한다.
- 우선 순위 클래스에 대한 쿼터 지원 디자인 문서를 읽는다.
- 제한된 자원을 참고한다.
3 - 프로세스 ID 제한 및 예약
Kubernetes v1.20 [stable]
쿠버네티스에서 파드가 사용할 수 있는 프로세스 ID(PID)의 수를 제한할 수 있다. 또한 (파드가 아닌) 운영체제와 데몬이 사용할 용도로 각 노드에 대해 할당 가능한 PID의 수를 미리 예약할 수 있다.
프로세스 ID(PID)는 노드에서 기본이 되는 리소스이다. 다른 종류의 리소스 상한(limit)을 초과하지 않고도, 태스크의 상한을 초과하게 되는 상황은 일상적이며 사소해 보일 수 있다. 그러나, 이러한 상황은 호스트 머신의 불안정성을 야기할 수 있다.
클러스터 관리자는 클러스터에서 실행 중인 파드가 호스트 데몬(예를 들어, kubelet 또는 kube-proxy 그리고 잠재적 컨테이너 런타임)이 실행되는 것을 방해하는 PID 소진이 발생하지 않도록 하는 메커니즘이 필요하다. 추가적으로, PID가 동일한 노드의 다른 워크로드에 미치는 영향을 제한하려면 파드 간에 PID를 제한하는 것이 중요하다.
/proc/sys/kernel/pid_max
의 값을 높이는 것을 고려하길 바란다.
지정된 파드가 사용할 수 있는 PID 수를 제한하도록 kubelet을 구성할 수 있다. 예를 들어, 노드의 호스트 OS가 최대 '262144' PID를 사용하도록 설정되어 있고 '250' 미만의 파드를 호스팅할 것으로 예상되는 경우, 각 파드에 '1000' PID의 양을 할당하여 해당 노드의 가용 PID의 수를 전부 소비해버리지 않도록 방지할 수 있다. 관리자는 몇 가지 추가 위험을 감수하여 CPU 또는 메모리와 유사한 PID를 오버 커밋할 수 있다. 어느 쪽이든 간에, 하나의 파드가 전체 시스템을 중단시키지는 않을 것이다. 이러한 종류의 리소스 제한은 단순 포크 폭탄(fork bomb)이 전체 클러스터의 작동에 영향을 미치는 것을 방지하는 데 도움이 된다.
관리자는 파드별 PID 제한을 통해 각 파드를 서로에게서 보호할 수 있지만, 해당 호스트에 배정된 모든 파드가 노드 전체에 영향을 미치지 못함을 보장하진 않는다. 또한 파드별 제한은 노드 에이전트 자체를 PID 고갈로부터 보호하지 않는다.
또한 파드에 대한 할당과는 별도로, 노드 오버헤드를 위해 일정량의 PID를 예약할 수 있다. 이는 파드와 해당 컨테이너 외부의 운영 체제 및 기타 장비에서 사용하기 위해 CPU, 메모리 또는 기타 리소스를 예약하는 방식과 유사하다.
PID 제한은 컴퓨팅 리소스 요청 및 제한에서 중요한 개념이다. 하지만 다른 방식으로 명시한다. 파드의 '.spec'에 파드 리소스 제한을 정의하는 대신, kubelet 설정에서 제한을 구성한다. 파드에서 정의하는 PID 제한은 현재 지원되지 않는다.
노드 PID 제한
쿠버네티스를 사용하면 시스템 사용을 위해 여러 프로세스 ID를 예약할 수 있다.
예약을 구성하려면 --system-reserved
및 --kube-reserved
명령줄 옵션에서
pid=<number>
매개변수를 kubelet에 사용하면 된다.
지정한 값은 지정된 수의 프로세스 ID가
시스템 전체와 Kubernetes 시스템 데몬에 각각 예약됨을
선언한다.
파드 PID 제한
쿠버네티스를 사용하면 파드에서 실행되는 프로세스 수를 제한할 수 있다.
이 제한을 특정 파드에 대한 리소스 제한으로 구성하는 대신 노드 수준에서 지정한다.
각각의 노드는 다른 PID 제한을 가질 수 있다.
제한을 구성하려면 kubelet에 커맨드라인 매개변수 --pod-max-pids
를
지정하거나, kubelet 구성 파일에서
PodPidsLimit
을 설정하면 된다.
PID 기반 축출(eviction)
파드가 오작동하고 비정상적인 양의 리소스를 사용할 때 파드를 종료하게끔 kubelet을 구성할 수 있다.
이 기능을 축출(eviction)이라고 한다. 다양한
축출 신호에 대한 리소스 부족 처리를 구성할
수 있다.
pid.available
축출 신호를 사용하여 파드에서 사용하는 PID 수에 대한 임계값을 구성한다.
소프트(soft) 및 하드(hard) 축출 정책을 설정할 수 있다.
그러나 하드 축출 정책을 사용하더라도 PID 수가 매우 빠르게 증가하면,
노드 PID 제한에 도달하여 노드가 여전히 불안정한 상태가 될 수 있다.
축출 신호 값은 주기적으로 계산되는 것이며 제한을 강제하지는 않는다.
PID 제한 - 각 파드와 각 노드는 하드 제한을 설정한다. 제한에 도달하게 되면, 새로운 PID를 가져오려고 할 때 워크로드에 오류가 발생할 것이다. 워크로드가 이러한 장애에 대응하는 방식과 파드에 대한 활성 및 준비성 프로브가 어떻게 구성되었는지에 따라, 파드가 재배포(rescheduling)될 수도 있고 그렇지 않을 수도 있다. 그러나 제한이 올바르게 설정되었다면, 하나의 파드가 오작동할 때 다른 파드 워크로드 및 시스템 프로세스에 PID가 부족하지 않도록 보장할 수 있다.
다음 내용
- 자세한 내용은 PID 제한 개선 문서를 참고한다.
- 역사적인 맥락을 원한다면, Kubernetes 1.14의 안정성 향상을 위한 프로세스 ID 제한을 참고한다.
- 컨테이너에 대한 리소스 관리를 읽는다.
- 리소스 부족 처리 구성을 배운다.