레플리카셋
쿠버네티스 공식문서를 확인하며 레플리카셋에 대해서 기억해야 하는 부분을 기록한다.
- 레플리카셋의 목적은 레플리카 파드 집합의 실행을 안정적으로 유지하는 것이다.
- 레플리카셋은 보통 명시된 동일 파드 개수에 대한 가용성을 보증하는데 사용한다.
레플리카셋의 작동 방식
- 레플리카셋을 정의하는 필드는 획득 가능한 파드를 식별하는 방법이 명시된 셀렉터, 유지해야 하는 파드 개수를 명시하는 레플리카의 개수 유지를 위해 생성하는 신규 파드에 대한 데이터를 명시하는 파드 템플릿을 포함한다.
- 레플리카셋은 필드에 지정된 설정을 충족하기 위해 필요한 만큼 파드를 만들고 삭제한다. 이 때 파드를 생성하기 위해 명시된 파드 템플릿을 사용한다.
- 레플리카셋은 파드의
metadata.ownerReferences
필드를 통해 파드에 연결되며, 현재 오브젝트가 소유한 리소스를 명시한다. - 레플리카셋이 가지고 있는 모든 파드의 ownerReferences 필드는 해당 파드를 소유한 레플리카셋을 식별하기 위한 소유자 정보를 가지고, 링크를 통해 레플리카셋은 자신이 유지하는 파드의 상태를 확인하고 관리한다.
- 레플리카셋은 셀렉터를 이용해서 필요한 새 파드를 식별한다. 만약 파드에 OwnerReference가 없거나, OwnerReference가 컨트롤러가 아니가 레플리카셋의 셀렉터와 일치한다면 레플리카셋이 즉각 파드를 가지게 될 것이다.
[정리]
레플리카셋의 목적은 레플리카 파드 집합의 실행을 안정적으로 유지하는 것이며 의도된 파드 개수에 대한 가용성을 보증하는데 사용된다. 레플리카셋을 정의하기 위해 파드 템플릿을 포함해야 하며 파드 템플릿에 명시된 파드의 수를 유지하기 위해 작동된다. 파드는 자신을 소유한 레플리카셋을 정보를 가지고 있으며 레플리카셋은 이 정보를 확인하고 해당 파드를 관리한다.
레플리카셋을 사용하는 시기
- 레플리카셋은 지정된 수의 파드 레플리카가 항상 실행되도록 보장하지만 디플로이먼트는 레플리카셋을 관리하고 다른 유용한 기능과 함께 파드에 대한 선언적 업데이트를 제공하는 상위 개념이다.
- 우리는 사용자 지정 오케스트레이션이 필요하거나 업데이트가 전혀 필요하지 않은 경우라면 레플리카셋을 직접적으로 사용하기 보다는 디플로이먼트를 사용하는 것을 권장한다.
- 이것은 레플리카셋 오브젝트를 직접 조작할 필요가 없다는 것을 의미한다. 직접 조작하는 것 대신 디플로이먼트를 이용하고 사양 부분에서 애플리케이션을 정의하면 된다.
[정리]
레플리카셋은 파드 레플리카가 항상 실행되는 것을 보장하지만 다른 기능을 추가로 제공하는 디플로이먼트가 상위 개념이기 때문에 디플로이먼트를 사용하는 것이 권장된다.
예시
아래의 yaml 구성 파일을 사용하여 직접 레플리카셋을 구성해본다.
apiVersion: apps/v1 kind: ReplicaSet metadata: name: frontend labels: app: guestbook tier: frontend spec: # 케이스에 따라 레플리카를 수정한다. replicas: 3 selector: matchLabels: tier: frontend template: metadata: labels: tier: frontend spec: containers: - name: php-redis image: gcr.io/google_samples/gb-frontend:v3
kubectl apply -f [https://kubernetes.io/examples/controllers/frontend.yaml
커맨드를](https://kubernetes.io/examples/controllers/frontend.yaml커맨드를) 사용하여 레플리카셋을 생성한다.kubectl get rs
커맨드를 사용하여 정상적으로 레플리카셋이 생성되었는지 확인할 수 있으며 정상적으로 생성되었다면 아래의 출력과 같이 총 세개의 레플리카가 생성되었을 것이다.NAME DESIRED CURRENT READY AGE frontend 3 3 3 6s
kubectl describe rs/frontend
커맨드를 사용해서 레플리카셋의 상태를 확인해보면 아래와 같이 출력되는 것을 확인할 수 있다.Name: frontend Namespace: default Selector: tier=frontend Labels: app=guestbook tier=frontend Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"labels":{"app":"guestbook","tier":"frontend"},"name":"frontend",... Replicas: 3 current / 3 desired Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed Pod Template: Labels: tier=frontend Containers: php-redis: Image: gcr.io/google_samples/gb-frontend:v3 Port: <none> Host Port: <none> Environment: <none> Mounts: <none> Volumes: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 117s replicaset-controller Created pod: frontend-wtsmm Normal SuccessfulCreate 116s replicaset-controller Created pod: frontend-b2zdv Normal SuccessfulCreate 116s replicaset-controller Created pod: frontend-vcmts
각 파드의 상태를 확인하려면
kubectl get pods
커맨드를 실행하면 된다.NAME READY STATUS RESTARTS AGE frontend-b2zdv 1/1 Running 0 6m36s frontend-vcmts 1/1 Running 0 6m36s frontend-wtsmm 1/1 Running 0 6m36s
kubectl get pods frontend-b2zdv -o yaml
커맨드를 실행하면 yaml의 정보를 확인할 수 있다. 메타데이터의 ownerReferences 필드에 설정되어 있는 프론트엔드 레플리카셋의 정보가 아래와 유사하게 출력되는 것을 볼 수 있다.apiVersion: v1 kind: Pod metadata: creationTimestamp: "2020-02-12T07:06:16Z" generateName: frontend- labels: tier: frontend name: frontend-b2zdv namespace: default ownerReferences: - apiVersion: apps/v1 blockOwnerDeletion: true controller: true kind: ReplicaSet name: frontend uid: f391f6db-bb9b-4c09-ae74-6a1f77f3d5cf ...
템플릿을 사용하지 않는 파드의 획득
단독(bare) 파드를 생성하는 것에는 문제가 없지만, 단독 파드가 레플리카셋의 셀렉터와 일치하는 레이블을 가지지 않도록 하는 것을 강력하게 권장한다.
강력하게 권장하는 이유는 레플리카셋이 소유하는 파드가 템플릿에 명시된 파드에만 국한되지 않고, 이전 섹션에서 명시된 방식에 의해서도 다른 파드의 획득이 가능하기 때문이다.
위에서 살펴본 프론트엔드 레플리카셋 예제와 아래에 명시되어 있는 파드를 가져와 참조한다.
apiVersion: v1 kind: Pod metadata: name: pod1 labels: tier: frontend spec: containers: - name: hello1 image: gcr.io/google-samples/hello-app:2.0 --- apiVersion: v1 kind: Pod metadata: name: pod2 labels: tier: frontend spec: containers: - name: hello2 image: gcr.io/google-samples/hello-app:1.0
기존 파드는 소유자 관련 정보에 컨트롤러(또는 오브젝트)를 가지지 않기 때문에 프론트엔드 레플리카셋의 셀렉터와 일치하면 즉시 레플리카셋에 소유된다.
프론트엔드 레플리카셋이 배치되고 초기 파드 레플리카가 셋업된 이후에, 레플리카 수 요구 사항을 충족시키기 위해서 신규 파드를 생성한다고 가정하고
kubectl apply -f [https://kubernetes.io/examples/pods/pod-rs.yaml](https://kubernetes.io/examples/pods/pod-rs.yaml)
커맨드를 실행하여 신규 파드를 생성한다.새로운 파드는 레플리카셋에 의해 인식되며 레플리카셋이 필요한 수량을 초과하면 즉시 종료된다. 실제로 파드의 상태를 확인하기 위해
kubectl get pods
커맨드를 실행해보면 새로운 파드가 이미 종료되었거나 종료가 진행 중인 것을 확인할 수 있다.
NAME READY STATUS RESTARTS AGE
frontend-b2zdv 1/1 Running 0 10m
frontend-vcmts 1/1 Running 0 10m
frontend-wtsmm 1/1 Running 0 10m
pod1 0/1 Terminating 0 1s
pod2 0/1 Terminating 0 1s
아래와 같이 커맨드를 순서대로 실행하여 파드를 먼저 생성한 이후 레플리카셋을 생성해 본다.
# 파드를 먼저 생성하고 $ kubectl apply -f https://kubernetes.io/examples/pods/pod-rs.yaml # 레플리카셋을 생성한다. $ kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml
레플리카셋이 해당 파드를 소유한 것을 볼 수 있으며 새 파드 및 기존 파드의 수가 레플리카셋이 필요로 하는 수와 일치할 때까지 사양에 따라 신규 파드만 생성한다. 파드의 상태를 확인해 보면 레플리카셋이 템플릿을 사용하지 않는 파드를 소유한 것을 확인할 수 있다.
NAME READY STATUS RESTARTS AGE frontend-hmmj2 1/1 Running 0 9s pod1 1/1 Running 0 36s pod2 1/1 Running 0 36s
[정리]
레플리카셋이 쇼유하는 파드가 템플릿 뿐만 아니라 다른 방식으로도 파드 획득이 가능하기 때문에 단독 파드를 사용자가 직접 생성하는 것은 문제가 없지만 레플리카셋의 셀렉터에 일치하지 않도록 하는 것이 중요하다.
소유자 정보가 없는 파드는 레플리카셋의 셀렉터와 일치하게 되는 즉시 레플리카셋의 소유가 된다. 이렇게 새로운 파드는 레플리카셋에 의해 인식되면 레플리카셋이 필요한 수량을 초과하게 되는 경우 즉시 종료된다.
레플리카셋 매니페스트 작성하기
- 레플리카셋은 모든 쿠버네티스 API 오브젝트와 마찬가지로
apiVersion
,kind
,metadata
필드가 필요하고.kind
필드의 값은 항상 레플리카셋이다.
파드 템플릿
.spec.selector
필드는 레이블 셀렉터이며 소유될 가능성이 있는 파드를 식별하는데 사용되고 위에서 살펴본 예제에서의 셀렉터는 아래와 같다.matchLabels: tier: frontend
레플리카셋에서
.spec.template.metadata.labels
는spec.selector
와 일치해야 하며 그렇지 않으면 API에 의해 거부된다.2개의 레플리카셋이 동일한
.spec.selector
필드를 지정한 반면, 다른.spec.template.metadata.labels
와.spec.template.spec
필드를 명시하는 경우, 각 레플리카셋은 다른 레플리카셋이 생성한 파드를 무시한다.
레플리카
spec.replicas
를 설정해서 동시에 동작하는 파드의 수를 지정할 수 있고 레플리카셋은 파드의 수가 일치할 수 있도록 생성 및 삭제한다.
[정리]
레플리카셋은 apiVersion
, kind
, metadata
필드를 필수값으로 한다. selector
를 통해 소유될 가능성이 있는 파드를 식별하고, replicas
를 통해 동작하는 파드의 수를 지정해서 관리하게 할 수 있다.
레플리카셋 작업
레플리카셋과 해당 파드 삭제
- 레플리카셋 및 모든 파드를 삭제하려면
kubectl delete
를 사용한다. 레플리카셋이 삭제되는 경우 가비지 수집기는 기본적으로 종속되어 있는 모든 파드를 자동으로 삭제한다. - REST API 또는
client-go
라이브러리를 이용할 때는 -d 옵션으로propagationPolicy
를Background
또는Foreground
로 설정해야 한다.
레플리카셋만 삭제하기
kubectl delete
에--cascade-orphan
옵션을 사용하여 연관 파드에 영향을 주지 않고 레플리카셋을 삭제할 수 있다. REST API 또는client-go
라이브러리를 이용할 때는propagationPolicy
에Orphan
을 설정해야 한다.- 원본이 삭제되면 새 레플리카셋을 생성해서 대체할 수 있다. 기존
.selector
와 신규.selector
가 같다면 새 레플리카셋은 기존 파드를 선택하지만 신규 레플리카셋은 기존 파드를 신규 레플리카셋의 새롭고 다른 파드 템플릿에 일치시키는 작업을 수행하지 않는다. - 컨트롤 방식으로 파드를 새로운 사양으로 업데이트 하기 위해서는 디플로이먼트를 이용하면 된다. 레플리카셋이 롤링 업데이트를 직접적으로 지원하지 않기 때문이다.
레플리카셋의 스케일링
- 레플리카셋을 손쉽게 스케일링하는 방법은 단순히
.spec.replicas
필드를 업데이트하면 된다. - 레플리카셋 컨트롤러는 일치하는 레이블 셀렉터가 있는 파드가 의도한 수 만큼 가용하고 운영 가능하도록 보장한다.
- 스케일 다운할 때, 레플리카셋 컨트롤러는 스케일 다운할 파드의 우선순위를 정하기 위해 아래의 기준으로 가용 파드를 정렬하여 삭제할 파드를 결정한다.
- Pending 상태(스케줄링할 수 없는)인 파드가 먼저 스케일 다운된다.
[controller.kubernetes.io/pod-deletion-cost](http://controller.kubernetes.io/pod-deletion-cost)
애너테이션이 설정되어 있는 파드에 대해서는, 낮은 값을 갖는 파드가 먼저 스케일 다운된다.- 더 많은 레플리카가 있는 노드의 파드가 더 적은 레플리카가 있는 노드의 파드보다 먼저 스케일 다운된다.
- 파드 생성 시간이 다르면, 더 최근에 생성된 파드가 이전에 생성된 파드보다 먼저 스케일 다운된다.(
LogarithmicScaleDown
기능 게이트가 활성화되어 있으면 생성 시간이 정수 로그 스케일로 버킷화된다.)
- 만약 모든 기준에 대해 동등하다면, 스케일 다운할 파드가 임의로 선택된다.
파드 삭제 비용
[controller.kubernetes.io/pod-deletion-cost](http://controller.kubernetes.io/pod-deletion-const)
애너테이션을 이용하여, 레플리카셋을 스케일 다운할 때 어떤 파드부터 먼저 삭제할지에 대한 우선순위를 설정할 수 있다.- 이 애너테이션은 파드에 설정되어야 하며, [-2147483647, 2147483647] 범위를 갖는다. 이 애너테이션은 하나의 레플리카셋에 있는 다른 파드와의 상대적 삭제 비용을 나타내고, 삭제 비용이 낮은 파드는 삭제 비용이 높은 파드보다 삭제의 우선순위가 높다.
- 파드에 대해 이 값을 명시하지 않으면 기본값은 0이고 음수로 설정할 수 있지만, 값이 유효하지 않다면 API 서버에서 거부한다.
- 삭제 비용은 베타 상태이며 기본적으로 활성화되어 있다. kube-apiserver와 kube-controller-manager에 대해
PodDeletionCost
기능 게이트를 이용하여 비활성화할 수 있다. - best-effort 방식으로 동작하기 때문에 파드의 삭제 순서를 보장하지 않는다.
- 값을 자주 변경하는 것은 apiserver에서 많은 양의 파드 업데이트를 동반하기 때문에 추천되지 않는다.
사용 예시
- 한 애플리케이션 내의 여러 파드는 각각 사용률이 다를 수 있으며 스케일 다운할 때, 애플리케이션은 사용률이 낮은 파드를 먼저 삭제하고 싶을 수 있다.
- 파드를 자주 업데이트하는 것을 피하기 위해, 애플리케이션은
[controller.kubernetes.io/pod-deletion-cost](http://controller.kubernetes.io/pod-deletion-cost)
값을 스케일 다운하기 전에 1회만 업데이트해야 한다. - 이러한 방식은 Spark 애플리케이션의 드라이버 파드처럼 애플리케이션이 스스로 다운스케일링을 수행하는 경우에 유효하다.
[정리]
레플리카셋이 삭제되는 경우 관리되던 레플리카들은 가비지 수집기에 의해 자동으로 정리된다. 물론 레플리카들이 정리되지 않게 하기위한 방법은 있다. 레플리카셋은 롤링 업데이트를 직접적으로 지원하지 않기 때문에 새로운 사양으로 업데이트 하기 위해서는 디플로이먼트를 사용하면 된다.
레플리카셋은 .replicas
필드의 값에 명시된 수에 맞게 파드를 가용하고 운영 가능하도록 보장한다. 스케일 다운하는 경우 레플리카가 삭제되는 기준이 있으며 모든 기준이 동일하다면 임의로 삭제된다.
pod-deletion-cost
애너테이션을 통해 레플리카셋을 스케일 다운할 때 어떤 파드부터 먼저 삭제할지 우선순위를 정할 수 있다. 하지만 해당 값으로 인해 많은 양의 파드 업데이트를 동반하기 때문에 잦은 변경은 추천되지 않는다.
레플리카셋을 Horizontal Pod Autoscaler 대상으로 설정
레플리카셋은 Horizontal Pod Autoscalers(HPA)의 대상이 될 수 있으며 레플리카셋은 HPA에 의해 오토스케일링 될 수 있음을 의미한다.
아래는 레플리카셋을 대상으로 하는 HPA 예시이다.
apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: frontend-scaler spec: scaleTargetRef: kind: ReplicaSet name: frontend minReplicas: 3 maxReplicas: 10 targetCPUUtilizationPercentage: 50
해당 매니페스트를
hpa-rs.yaml
로 저장한 다음 쿠버네티스 클러스터에 적용하면 CPU 사용량에 따라 파드가 복제되는 오토스케일 레플리카셋 HPA가 생성된다.kubectl apply -f https://k8s.io/examples/controllers/hpa-rs.yaml
kubectl autoscale
커맨드를 사용해서도 동일한 작업을 진행할 수 있다.kubectl autoscale rs frontend --max=10 --min=3 --cpu-percent=50
레플리카셋의 대안
디플로이먼트
- 디플로이먼트는 레플리카셋을 원하는 사용자에게 쿠버네티스에서 권장하는 방식이다.
- 디플로이먼트는 레플리카셋을 소유하거나 업데이트하고, 파드의 선언적인 업데이트와 서버측 롤링 업데이트를 할 수 있는 오브젝트다.
- 레플리카셋은 단독으로 사용할 수 있지만, 오늘날에는 주로 디플로이먼트로 파드의 생성과 삭제 그리고 업데이트를 오케스트레이션하는 메커니즘으로 사용한다.
- 디플로이먼트를 이용해서 배포할 때 생성되는 레플리카셋을 관리하는 것에 대해 걱정하지 않아도 된다.
기본 파드
- 사용자가 직접 파드를 생성하는 경우와는 다르게, 레플리카셋은 노드 장애 또는 노드의 커널 업데이트와 같은 관리 목적의 중단 등 어떤 이유로든 종료되거나 삭제된 파드를 교체한다.
- 이런 이유로 애플리케이션이 단일 파드가 필요하더라도 레플리카셋을 이용하는 것을 권장된다.
- 레플리카셋을 프로세스 관리자와 비교해서 생각해본다면, 레플리카셋은 단일 노드에서의 개별 프로세스들이 아닌 다수의 노드에 걸쳐있는 다수의 파드를 관리하는 것이다.
- 레플리카셋은 로컬 컨테이너의 재시작을 노드에 있는 Kubelet과 같은 에이전트에게 위임한다.
잡
- 스스로 종료되는 것이 예상되는 파드의 경우 레플리카셋 대신
잡
을 이용한다.
데몬셋
- 머신 모니터링 또는 머신 로깅과 같은 머신-레벨의 기능을 제공하는 파드를 위해서는 레플리카셋 대신
데몬셋
을 사용한다. - 파드의 수명은 머신의 수명과 연관되어 있고, 머신에서 다른 파드가 시작하기 전에 실행되어야 하며, 머신의 재부팅/종료가 준비되었을 때, 해당 파드를 종료하는 것이 안전한다.
레플리케이션 컨트롤러
- 레플리카셋은 레플리케이션 컨트롤러를 계승하였다.
- 두 개의 용도는 동일하고, 유사하게 동작하며, 레플리케이션 컨트롤러가 레이블 사용자 가이드에 설명된 설정-기반 셀렉터의 요건을 지원하지 않는 점을 제외하면 유사하다.
- 레플리카셋이 레플리케이션 컨트롤러보다 선호된다.
[정리]
레플리카셋보다는 더 많은 기능을 제공하는 디플로이먼트를 사용하는 것이 권장된다.
기본 파드를 단일로 사용하는 것 보다는 레플리카셋으로 관리하는 것이 추천된다.
스스로 종료될 것이 예상될 때는 레플리카셋 대신 잡을 이용한다.
머신 모니터링이나 머신-레벨의 기능을 제공하는 파드는 레플리카셋 대신 데몬셋을 사용하는 것이 권장된다.
레플리케이션 컨트롤러는 레플리카셋과 대부분의 기능이 유사하며 특별한 경우가 아니라면 레플리카셋을 사용하는 것이 권장된다.
참고 자료
'Infrastructure > Kubernetes' 카테고리의 다른 글
[워크로드 리소스] 데몬셋 (0) | 2022.10.20 |
---|---|
[워크로드 리소스] 스테이트풀셋 (0) | 2022.10.20 |
[워크로드 리소스] 디플로이먼트 스케일리와 롤아웃 (0) | 2022.10.18 |
[워크로드 리소스] 디플로이먼트 업데이트와 롤백 (0) | 2022.10.18 |
[Pod] 다운워드(Downward) API (0) | 2022.10.18 |