ReplicaSet과 Deployment
- 5.1 ReplicaSet
- 5.2 Deployment
파드를 만들 줄 알게 됐으니, 이제 그 파드를 여러 개 관리하고 업데이트하는 방법이야. ReplicaSet이 파드 복제를 보장하고, Deployment가 그 위에서 롤링 업데이트와 롤백을 처리해.
컨트롤러는 Kubernetes의 두뇌야. Kubernetes 오브젝트를 모니터링하고 그에 따라 응답하는 프로세스지. 여기서는 복제 컨트롤러(Replication Controller)와 레플리카 세트(ReplicaSet)에 대해 얘기할게.
레플리카가 왜 필요하냐면, 두 가지 이유가 있어. 첫째는 고가용성이야. 파드가 하나뿐인데 애플리케이션이 충돌하면 사용자가 접근을 못 하잖아. 복제 컨트롤러는 지정된 수의 파드가 항상 실행되도록 보장해. 파드가 1개든 100개든 상관없어. 하나의 파드만 있더라도 복제 컨트롤러를 쓰면, 기존 파드가 실패했을 때 자동으로 새 파드를 만들어줘. 둘째는 부하 분산이야. 사용자가 늘면 추가 파드를 배포해서 여러 파드에 부하를 나눌 수 있어. 첫 번째 노드에서 리소스가 부족해지면 클러스터의 다른 노드에도 파드를 배포할 수 있지. 복제 컨트롤러는 클러스터의 여러 노드에 걸쳐 동작하거든.
복제 컨트롤러(Replication Controller)와 레플리카 세트(ReplicaSet) 두 가지가 있는데, 복제 컨트롤러는 구형이고 레플리카 세트가 권장 방법이야. 둘 다 목적은 같지만 작동 방식에 약간 차이가 있어.
Replication Controller 정의 파일은 이래:
apiVersion: v1
kind: ReplicationController
metadata:
name: myapp-rc
labels:
app: myapp
spec:
template:
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx
replicas: 3
apiVersion은 v1이고, kind는 ReplicationController야. spec 아래 template 섹션에 파드 템플릿을 넣어. 이전에 만들었던 파드 정의 파일에서 apiVersion과 kind를 뺀 나머지(metadata, spec)를 template 아래에 넣으면 돼. replicas에 원하는 복제본 수를 지정하고. template과 replicas는 spec의 직계 자식이니까 같은 들여쓰기 수준이어야 해.
ReplicaSet 정의 파일은 거의 비슷한데 차이점이 있어:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myapp-replicaset
labels:
app: myapp
spec:
template:
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx
replicas: 3
selector:
matchLabels:
app: myapp
apiVersion이 apps/v1이야(복제 컨트롤러는 v1이었지). 이걸 틀리면 에러가 나. 그리고 가장 큰 차이점은 selector가 필수라는 거야. 복제 컨트롤러에서 selector는 선택사항이었고 생략하면 파드 정의의 레이블과 동일하다고 가정했어. 레플리카 세트에서는 matchLabels 형식으로 직접 지정해야 해.
selector가 왜 필요하냐면, 레플리카 세트는 자기가 생성하지 않은 파드도 관리할 수 있거든. 레플리카 세트가 만들어지기 전에 이미 생성된 파드가 있고, 그 파드의 레이블이 selector와 일치하면 레플리카 세트가 그 파드도 관리 대상으로 포함시켜. 레이블과 셀렉터의 이 개념은 Kubernetes 전체에서 다양한 곳에 사용돼.
레플리카 세트는 파드를 모니터링하는 프로세스야. 파드 중 하나가 실패하면 새 파드를 배포해야 하는데, 이때 template 정의가 필요해. 그래서 이미 파드가 다 있더라도 template 섹션은 반드시 넣어야 해.
스케일링하는 방법은 여러 가지야. 첫째, 정의 파일의 replicas 수를 변경하고 kubectl replace -f 명령을 실행하는 거야. 둘째, kubectl scale 명령을 쓰는 거야:
kubectl scale --replicas=6 -f replicaset-definition.yaml
kubectl scale --replicas=6 replicaset myapp-replicaset
다만 kubectl scale 명령은 파일 이름을 입력으로 줘도 파일 안의 replicas 값을 자동으로 바꿔주지는 않아.
주요 명령어 정리:
kubectl create -f replicaset-definition.yaml
kubectl get replicaset
kubectl delete replicaset myapp-replicaset
kubectl replace -f replicaset-definition.yaml
kubectl scale --replicas=6 replicaset myapp-replicaset
ReplicaSet이 파드의 복제본 수를 유지하는 역할이라면, 실제 프로덕션에서는 한 단계 위의 개념이 필요해. 프로덕션 환경에서 애플리케이션을 배포할 때 필요한 기능들을 생각해보자. 웹 서버를 여러 인스턴스로 운영해야 하고, 새 버전이 나오면 원활하게 업그레이드해야 하는데 모든 인스턴스를 한꺼번에 업그레이드하면 사용자에게 영향을 줄 수 있으니까 하나씩 차례로 업그레이드하고 싶어. 이걸 롤링 업데이트라고 해. 업그레이드 중에 문제가 생기면 롤백도 해야 하고, 여러 변경 사항을 한꺼번에 적용하기 위해 일시 중지했다가 다시 시작하는 기능도 필요해.
이런 기능들을 제공하는 게 바로 Deployment야. 계층 구조로 보면 파드 위에 레플리카 세트가 있고, 그 위에 Deployment가 있어. Deployment가 레플리카 세트를 자동으로 생성하고, 레플리카 세트가 파드를 생성하는 거지.
Deployment 정의 파일은 ReplicaSet 정의 파일과 거의 동일해. kind만 Deployment로 바꾸면 돼:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
labels:
app: myapp
spec:
template:
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx
replicas: 3
selector:
matchLabels:
app: myapp
파일이 준비되면:
kubectl create -f deployment-definition.yaml
이걸 실행하면 Deployment가 생성되고, Deployment가 자동으로 ReplicaSet을 만들고, ReplicaSet이 파드를 만들어:
kubectl get deployments
kubectl get replicaset
kubectl get pods
파드 이름을 보면 Deployment 이름과 ReplicaSet 이름이 접두사로 붙어있는 걸 확인할 수 있어.
생성된 모든 오브젝트를 한 번에 보려면:
kubectl get all
지금까지는 ReplicaSet과 Deployment 사이에 큰 차이가 없어 보이지만, 롤링 업데이트, 롤백, 일시 중지/재시작 같은 기능들은 이후 강의에서 자세히 다뤄.
정리
5장 읽고 기억할 거 세 가지:
- ReplicaSet = 파드 수 보장. 고가용성과 부하 분산을 위해 지정된 수의 파드가 항상 실행되도록 해. selector로 기존 파드까지 관리 범위에 포함시킬 수 있어
- Deployment > ReplicaSet > Pod 계층 구조. 실무에서는 ReplicaSet을 직접 만들 일이 거의 없어. Deployment를 만들면 나머지는 자동으로 생성돼
- Deployment의 진짜 가치는 롤링 업데이트와 롤백. 지금은 ReplicaSet과 거의 같아 보이지만, 버전 업그레이드와 장애 복구에서 차이가 드러나