용찬호. 「 시작하세요! 도커/쿠버네티스」. 위키북스 를 읽으며, 학습한 내용을 정리하는 글입니다.
→ 본문의 내용은 모두 책의 내용에 대한 직/간접적 인용임을 밝힙니다.
→ 포드 자체에 자원 사용량을 명시적으로 설정하기
apiVersion: v1
kind: Pod
metadata:
name: resource-limit-pod
labels:
name: resource-limit-pod
spec:
containers:
- name: nginx
image: nginx:latest
resources:
limits:
memory: "256Mi"
cpu: "1000m"
→ docker run --memory 256m
과 같다.
→ cpu: 1000m
은 1개의 CPU, 즉 1000밀리코어를 의미
docker run --cpus 1
과 같다. cf. 자원의 오버커밋(OverCommit)이란?
→ 이런 경우에, 한 컨테이너가 500MB를 사용 중일 때, 다른 컨테이너가 750MB를 사용하려 한다면,
→ 메모리 충돌 및 비정상적 에러 발생!
→ 각 컨테이너가 사용을 보장받을 수 있는 경계선을 함께 정해야 한다.
[ Request 지정하여 최소 보장 자원 정하기 ]
apiVersion: v1
kind: Pod
metadata:
name: resource-limit-with-request-pod
labels:
name: resource-limit-with-request-pod
spec:
containers:
- name: nginx
image: nginx:latest
resources:
limits:
memory: "256Mi"
cpu: "1000m"
requests:
memory: "128Mi"
cpu: "500m"
→ requests에서 128Mi를, limits에서 256Mi를 설정했으므로
'최소한 128Mi의 메모리 사용은 보장되지만, 유휴 메모리 자원이 있다면 최대 256Mi까지 사용할 수 있다'는 뜻!
** requests
는 컨테이너가 보장받아야 하는 최소한의 자원이므로,
노드의 총 크기보다 더 많은 양의 requests
를 할당할 수는 없다.
→ 포드를 할당할 때 사용되는 자원 할당 기준은 limit이 아닌 requests
...
resources:
limits:
memory: "256Mi"
cpu: "1000m" # 최대 1개의 CPU만큼 사용 가능
requests:
memory: "128Mi"
cpu: "500m" # 최소한 0.5개의 CPU만큼의 사용을 보장
resources.requests.cpu 1000m은 포드의 컨테이너는 최대 1개 CPU를 사용함을 의미
= 아래 명령어와 같다!
→ docker run --cpus 1
→ docker run --cpu-period 100000 --cpu-runtime 100000
+) CPU의 Requests는 --cpu-shares
옵션과 같다.
[ 자원의 경합(Contention) 상황 ]
CPU 사용량에 경합이 발생하면 일시적으로 컨테이너 내부의 프로세스에 CPU 스로틀이 걸릴 뿐, 컨테이너 자체엔 문제가 없다.
메모리의 사용량에 경합이 발생하는 건 문제!
그렇다면, "노드에 메모리 자원이 부족해지면 어떤 포드나 프로세스가 먼저 종료돼야 하는가"가 중요!
→ 쿠버네티스는 포드의 컨테이너에 설정된 Limit과 Request의 값에 따라 우선순위를 계산
→ 내부적으로 포드의 우선순위를 구분하기 위해 3가지 종류의 QoS(Quality of Service) 클래스를 포드에 설정!
[ 1. Guaranteed 클래스 ]
[ 2. BestEffort 클래스 ]
[ 3. Burstable 클래스 ]
기본적으로 포드의 우선순위는 Guaranteed가 가장 높고, Burstable과 BestEffort가 그 뒤이다.
하지만, Burstable과 BestEffort 클래스의 포드는 현재 메모리를 얼마나 사용하고 있는지에 따라 우선순위가 역전될 수 있음!
→ 포드가 메모리를 많이 사용하면 할수록 우선순위가 낮아진다.
쿠버네티스를 여러 사람 또는 개발팀이 함께 사용하고 있다면, 각 네임스페이스에서 할당할 수 있는 자원의 최대 한도 또는 범위를 설정해야 함.
→ 이를 위해 ResourceQuote와 LimitRanger라는 오브젝트를 이용해 자원 사용량 관리를 가능케 하는 기능을 제공
ResourceQuota는 네임스페이스에 종속되는 오브젝트이기에, 네임스페이스별로 생성해야 한다.
apiVersion: v1
kind: ResourceQuota
metadata:
name: resource-quota-example
namespace: default
spec:
hard:
requests.cpu: "1000m"
requests.memory: "500Mi"
limits.cpu: "1500m"
limits.memory: "1000Mi"
1500m
: 위 예시에서는 500m의 limits.cpu를 가지는 3개의 포드까지는 생성할 수 있으나, 그 뒤로는 limits.cpu를 가지는 포드를 더 생성할 수 없음.[ cf. 디플로이먼트 ]
apiVersion: apps/v1
kind: Deployment
...
resources:
limits:
memory: "3000Mi"
cpu: "1000m"
requests:
memory: "128Mi"
cpu: "500m"
포드를 생성하는 주체는 디플로이먼트가 아니라 레플리카셋
[ 11.1.5.2 LimitRange로 자원 사용량 제한 ]
apiVersion: v1
kind: LimitRange
metadata:
name: mem-limit-range
spec:
limits:
- default: # 자동으로 설정될 기본 Limit 값
memory: 256Mi
cpu: 200m
defaultRequest: # 자동으로 설정될 기본 Request 값
memory: 128Mi
cpu: 100m
max: # 자원 할당량의 최댓값
memory: 1Gi
cpu: 1000m
min: # 자원 할당량의 최솟값
memory: 16Mi
cpu: 50m
type: Container # 각 컨테이너에 대해서 적용
cf. 유명한 서비스 메쉬 솔루션인 Istio는 어드미션 컨트롤러를 통해 포드에 프록시 사이드카 컨테이너를 주입하는 방법을 사용
→ 대부분은 스케줄링 조건을 포드의 YAML 파일에 설정함으로써 노드 필터링 단계에 적용할 수 있도록 구성
특정 노드에 얼룩(Taint)를 지정함으로써 해당 노드에 포드가 할당되는 것을 막는 기능
해당 Taints에 대응하는 Tolerations를 포드에 설정하면 Taints가 설정된 노드에도 포드를 할당할 수 있다.
쿠버네티스는 기본적으로 다양한 Taint를 노드에 설정한다!
[ cordon ]
kubectl cordon <노드 이름>
→ 해당 노드에 더 이상 포드가 스케줄링되지 않는다.
→ 해당 노드에서 이미 실행 중인 포드가 종료되지는 않음!
[ drain ]
[ PodDistributionBudget ]
kubectl drain
명령어 등으로 인해 포드에 퇴거(Eviction)이 발생할 때, 특정 개수 또는 비율만큼의 포드는 반드시 정상적인 상태를 유지하기 위해서 사용[ 디플로이먼트를 통한 롤링 업데이트 설정 ]
일시적으로 사용자의 요청을 처리하지 못해도 괜찮은 애플리케이션이라면 쿠버네티스에서 제공하는 Recreate 사용 가능
이 방식은 일시적으로 요청을 처리할 수 없으므로, 쿠버네티스는 포드를 조금씩 삭제하고 생성하는 롤링 업데이트 기능을 제공
RollingUpdate
로 지정...
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2
maxUnavailable: 2
maxUnavailable
: 롤링 업데이트 도중 사용 불가능한 상태가 되는 포드의 최대 개수를 설정maxSurge
: 롤링 업데이트 도중 전체 포드의 개수가 디플로이먼트의 replicas 값보다 얼마나 많이 존재할 수 있는지 설정[ 블루 그린 배포 사용하기 ]
[ 11.3.2.1 포드의 상태와 생애 주기 ]
Pending
: 포드를 생성하는 요청이 API 서버에 의해 승인됐지만, 어떠한 이유로 인해 실제로 생성되지 않은 상태Running
: 포드에 포함된 컨테이너들이 모두 생성돼 포드가 정상적으로 실행된 상태Desired
)로 간주하는 상태Completed
: 포드가 정상적으로 실행돼 종료됐음을 의미. 포드 컨테이너의 init 프로세스가 종료 코드로서 0을 반환한 경우Error
: 포드가 정상적으로 실행되지 않은 상태로 종료됐음을 의미. 포드 컨테이너의 init 프로세스가 0이 아닌 종료 코드를 반환했을 때 해당 Terminating
: 포드가 삭제 또는 퇴거(Eviction)되기 위해 삭제 상태에 머물러 있는 경우[ 명령형(Imperative) Vs. 선언적(Declarative) ]
< 명령형 >
docker run
처럼 특정 명령을 처리하는 주체와 통신해 그 작업을 수행하고 결괏값을 돌려받는 방식kubectl create -f
또한 명령형 방식의 대표적인 예< 선언형 >
kubectl apply
명령어가 대표적인 예시이다.kubectl apply -f
뒤에 따라오는 YAML 파일은 '최종적으로 도달해야 하는 상태'를 의미하며, 쿠버네티스는 현재 상태가 해당 YAML 파일과 일치하도록 특정 동작을 수행한다. [ 커스텀 리소스를 사용하기 위한 단계 ]
1. 현재 상태를 커스텀 리소스에 대한 바람직한 상태로 변화시킬 수 있는 컨트롤러를 구현하고, 컨트롤러를 실행합니다.
2. 커스텀 리소스의 상세 정보를 정의하는 CRD(Custom Resource Definition) 리소스를 생성합니다.
3. CRD에 정의된 데이터에 맞춰 커스텀 리소스를 생성합니다.
4. 1번에서 실행한 컨트롤러는 커스텀 리소스의 생성을 감지하고, 커스텀 리소스가 원하는 바람직한 상태가 되도록 적절한 작업을 수행합니다.
apiVersion: batch/v1
kind: Job
metadata:
name: job-hello-world
spec:
template:
spec:
restartPolicy: Never
containers:
- image: busybox
args: ["sh", "-c", "echo Hello, World && exit 0"]
name: job-hello-world
[ 크론잡(CronJobs)으로 잡을 주기적으로 실행하기 ]
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: cronjob-example
spec:
schedule: "*/1 * * * *" # Job의 실행 주기
jobTemplate: # 실행될 Job의 설정 내용(spec)
spec:
template:
spec:
restartPolicy: Never
containers:
- name: cronjob-example
image: busybox
args: ["sh", "-c", "date"]