Notice
Recent Posts
Recent Comments
Link
Gom3rye
Kubernetes- DaemonSet, StatefulSet, Job 본문
728x90
반응형
Workload API
Deployment
업데이트 전략
- Deployment의 배포 전략은 주로 애플리케이션이 변경될 때 사용한다.
- 이전 버전의 애플리케이션에서 업데이트가 필요한 경우에 주로 사용되며 방법으로는 RollingUpdate, Recreate가 있다.
- Recreate
- 재생성 업데이트는 모든 이전 버전의 Pod를 모두 한 번에 종료하고 새 버전의 Pod로 일괄적으로 교체하는 방식
- 빠르게 업데이트 할 수 있지만 새로운 버전의 Pod에 문제가 발생하면 대처가 늦어질 수 있다. (일괄적으로 교체가 되니까)
- spec.strategy에 type를 recreate로 설정하면 된다.
- Rolling과의 차이→ 하나 만들고 안정적으로 돌면 하나 죽이는 것
- 업데이트할 때 rolling이 조금 더 안정적이다. (기본도 rolling)
- 실습
# sample-deployment-recreate.yaml apiVersion: apps/v1 kind: Deployment metadata: name: sample-deployment-recreate # 이름 spec: selector: matchLabels: app: sample-app replicas: 3 strategy: type: Recreate template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx # 이미지 생성 kubectl apply -f sample-deployment-recreate.yaml # 이미지 변경 kubectl set image deployment sample-deployment-recreate nginx-container=nginx:1.16 # 레플리카셋 확인 kubectl get replicaset --watch # 그 전 replicaset이 0이 되어버린다. - RollingUpdate
- 새 버전의 애플리케이션을 배포할 때 새 버전의 애플리케이션은 하나씩 늘려가고 기존 버전의 애플리케이션은 하나씩 줄여가는 방식
- 쿠버네티스의 기본 배포 방식
- 새로운 버전의 pod에 문제가 발생하면 다시 이전 버전의 pod로 대체할 수 있어서 상당히 안정적인 배포 방식이지만 업데이트가 느리게 진행된다는 단점이 있다.
- maxSurge
- Rolling Update를 할 때 최대로 생성할 수 있는 Pod의 개수
- maxSurge를 높게 설정하면 배포를 빠르게 할 수 있다.
- %로 설정할 수 있고 개수로도 설정 가능하다.
- 설정하지 않을 경우 기본값은 25%
- 왠만하면 maxUnabailable 보다 maxSurge를 쓰는게 낫다. (maxUnavailable은 파드의 수가 일시적으로 replica 개수보다 작아지고 서비스 부하가 생기니까/ 반면 maxSurge를 설정하면 일시적으로 파드의 개수가 레플리카의 개수보다 많아진다.)
- maxSurge는 생성되고 삭제, maxUnavailable은 삭제되고 생성 순서이다.
- maxUnavailable
- Rolling Update를 할 때 최대로 삭제할 수 있는 Pod의 개수
- 높게 설정하면 배포를 빠르게 할 수 있다.
- 한 번에 많은 pod를 삭제할 경우 트래픽이 남아있는 소수의 pod로 집중될 수 있기 때문에 적절히 설정할 필요가 있다.
- %로 설정해도 되고 개수로 지정 가능하다.
- 설정하지 않을 경우 기본값은 25% (maxSurge, maxUnavailable 둘 중에 하나만 설정하는 것)
- 실습
# sample-deployment-rollingupdate.yaml apiVersion: apps/v1 kind: Deployment metadata: name: sample-deployment-rollingupdate # 이름 spec: selector: matchLabels: app: sample-app replicas: 3 strategy: type: RollingUpdate template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx # 이미지 생성 kubectl apply -f sample-deployment-rollingupdate.yaml # 이미지 변경 kubectl set image deployment sample-deployment-rollingupdate nginx-container=nginx:1.16 # 레플리카셋 확인 kubectl get replicaset --watch # 하나씩 줄어들고 늘어나는 걸 확인할 수 있다. - Blue/Green Update
- 애플리케이션이 이전 버전(blue)과 새로운 버전(green)을 동시에 운영
- 서비스 목적으로 새로운 버전이나 이전 버전을 이용하고 다른 버전은 테스트 버전으로 사용할 수 있다.
- 새로운 버전의 pod에 문제가 발생했을 때 빠르게 대응할 수 있으며 안정적으로 배포할 수 있다.
- 많은 pod가 필요하므로 자원의 소모가 심하다.
- 이전 버전의 yaml과 새로운 버전의 yaml파일 2개로 운영하는데 새로운 버전은 일반적으로 이미지 경로와 lable의 버전만 수정한다.
- Canary Update
- Blue/Green과 유사한 방식의 업데이트 전략인데 초기에는 새로운 버전에 트래픽을 흘려보내고 업데이트를 진행하면서 새로운 버전에 트래픽을 늘려나가는 방식
- 모든 테스트가 끝나면 이전 버전을 종료한다.
- 문제점과 해결 방안
- UI/UX가 변경되어 100명의 유저가 사용하는 서비스에서 20명을 대상으로 Canary 업데이트를 진행하고 싶은 경우 가장 일반적인 방식 중 하나는 로드 밸런서를 통해서 서비스의 엔드포인트를 유저들에게 노출하는 것인데 로드밸런서는 서버의 과부하가 일어나지 않도록 가장 최적의 방식으로 트래픽을 분산하는데 한 명의 유저가 서비스를 사용할 때 로드밸런서에 의해 자동으로 여러 서버에 접속할 수 있다.
- 어떤 유저가 웹 페이지를 새로고침했을 때 로드 밸런싱이 일어나 Canary 업데이트가 있는 서버에서 기존 서버로 바뀌었다고 가정하면 갑자기 신버전 UI/UX에서 구버전으로 변경되게 되는데 서비스를 사용하기 불편할 뿐 아니라 UI/UX에서 사용자 반응성이나 이용 시간 등 일련의 과정을 거쳐야 하는 테스트를 진행하기 힘들 수 있다.
- 스티키 세션을 사용해서 사용자가 한 번 특정한 서버에 접속되어 있으면 그 서버에만 계속 접속되도록 만들 수 있다.
- 상세 업데이트 파라미터
- minReadySeconds: 파드가 Ready 상태가 된 다음부터 디플로이먼트 리소스에서 파드 기동이 완료되었다고 판단하기까지의 최소 시간
- revisionHistoryLimit
- 수정할 버전의 기록을 제한
- 디플로이먼트가 유지할 레플리카셋의 개수
- 롤백이 가능한 이력의 수
- progressDeadlineSeconds
- Recreate/RollingUpdate를 할 때 처리 타임 아웃 시간
- 타임아웃 시간이 경과할 때까지 업데이트가 진행되지 않으면 자동으로 롤백한다.
# sample-deployment-params.yaml apiVersion: apps/v1 kind: Deployment metadata: name: sample-deployment-params # 이름 spec: minReadySeconds: 120 revisionHistoryLimit: 2 progressDeadlineSeconds: 240 selector: matchLabels: app: sample-app replicas: 3 template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx - deployment scaling
- kubectl apply -f 나 kubectl scale 명령을 이용해 스케일링 가능
kubectl scale deployment sample-deployment --replicas=5 - 매니페스트를 사용하지 않고 생성
kubectl create deployment 이름 --image 이미지
kubectl create deployment sample-deployment-by-cli --image nginx
DaemonSet
- ReplicaSet의 특수한 형태
- DaemonSet은 모든 노드에 파드를 생성한다. (모든 노드마다 특정 파드를 하나씩 자동으로 실행시키는 리소스)
- ReplicaSet은 특정 개수의 파드를 유지할 때 사용하는 것이라면 DaemonSet은 모든 노드에 Pod를 배포할 때 사용한다.
- DaemonSet은 레플리카 수를 지정할 수 없고 하나의 노드에 두 개의 파드를 배치할 수도 없다.
- 파드를 배치하고 싶지 않은 노드가 있을 경우 nodeselector나 노드 어피니티를 사용한 스케쥴링으로 예외 처리한다.
- 쿠버네티스 노드를 늘렸을 때도 데몬셋의 파드는 자동으로 늘어난 노드에서 기동하기 때문에 데몬셋은 각 파드가 출력하는 로그를 호스트 단위로 수집하는 Fluntd나 파드 리소스 사용 현황 및 노드 상태를 모니터링 하는 Datadog, Prometheus등이 daemonset을 활용한다. (로그 수집이나 모니터링 용)
- 실습
# sample-daemonsets.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: prometheus-daemonset # 이름
spec:
selector:
matchLabels:
tier: monitoring
name: prometheus-exporter
template:
metadata:
labels:
tier: monitoring
name: prometheus-exporter
spec:
containers:
- name: prometheus
image: prom/node-exporter
ports:
- containerPort: 80
# 배포
kubectl apply -f sample-daemonsets.yaml
데몬셋 업데이트 전략
OnDelete & RollingUpdate
- OnDelete : 파드가 새로 만들어 질 때 바뀌어라
- 데몬셋 매니페스트를 수정해서 이미지 등을 변경했더라도 기존 파드는 업데이트 되지 않는다.
- 디플로이먼트와 달리 데몬셋은 모니터링이나 로그 전송과 같은 용도로 많이 사용하기 때문에 업데이트는 다음 번에 다시 생성할 때나 수동으로 임의의 시점에 하게 되어 있으며 type 이외에 지정할 수 있는 항목이 없다.
- OnDelete로 설정하고 아무것도 하지 않을 경우 노드의 유지보수를 이유로 파드가 정지되거나 예기치 못하게 파드가 정지되는 등 다양한 이유로 파드가 정지되어 다시 생성되기 전까지는 업데이트가 되지 않기 때문에 운영상의 이유로 정지되면 안되는 파드이거나 업데이트가 급하게 필요 없는 경우 OnDelete 설정으로 사용해도 되지만 이전 버전이 계속 장기간 사용된다는 점에 주의해야 한다.
- 원하는 시점에 파드를 업데이트하는 경우에는 데몬셋과 연결된 파드를 kubectl delete pod 명령어로 수동으로 정지시키고 자동화된 복구 기능으로 새로운 파드를 생성해야 한다.
- 실습
# sample-daemonset-ondelete.yaml apiVersion: apps/v1 kind: DaemonSet metadata: name: prometheus-daemonset-ondelete # 이름 spec: updateStrategy: type: OnDelete selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx # 배포 kubectl apply -f sample-daemonset-ondelete.yaml # 이미지 업데이트 # 그냥 deployment를 수정하고 get pods 해보면 바뀌어 있다. (rollingupdate가 기본이어서) # But daemonset ondelete는 이미지를 바꿔도 get pods 해보면 이미지 안 바뀌어 있고 # 지우고 다시 get pods 해보면 이미지가 바뀐 것을 확인할 수 있다. # -> 업데이트 유보해놓은 것과 비슷 # 로그 수집 중 파드가 일시 정지 되면 기존에 했던 것들이 없어지면 안됨 # 따라서 업데이트 하고 싶으면 너가 수동으로 직접 해라. - RollingUpdate
- DaemonSet도 디플로이먼트와 마찬가지로 RollingUpdate를 사용한 업데이트가 가능하다.
- 데몬셋에서는 하나의 노드에 동일한 파드를 여러 개 생성할 수 없으므로 디플로이먼트와 달리 동시에 생성할 수 있는 파드의 수(maxSurge)를 설정할 수 없고 정지 가능한 최대 파드 수(maxUnavilable)만 지정하여 RollingUpdate를 수행한다.
- 실습
# sample-daemonset-rollingupdate.yaml apiVersion: apps/v1 kind: DaemonSet metadata: name: prometheus-daemonset-rollingupdate # 이름 spec: updateStrategy: type: RollingUpdate selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: nginx-container image: nginx:1.16 # 배포 kubectl apply -f sample-daemonset-rollingupdate.yaml # 이미지 업데이트하고 바로 확인해보면 변경된 이미지가 있어야 한다. kubectl get pods kubectl describe pod 파드이름
StatefulSet
- 레플리카셋의 특수한 형태
- 데이터베이스 등과 같은 stateful한 워크로드에 사용하기 위한 리소스
- ReplicaSet과 차이점
- 생성되는 파드명의 접미사는 숫자 인덱스가 부여된 것이다.
- 파드명이 변경되지 않는다.
- 데이터를 영구적으로 저장하기 위한 구조이다.
- spec.volumeClaimTemplates를 지정할 수 있는데 이 설정으로 StatefulSet으로 생성되는 각 파드에 영구 볼륨 클레임을 설정할 수 있고 영구 볼륨 클레임을 사용하면 클러스터 외부의 네트워크를 통해 제공되는 영구 볼륨을 파드에 연결할 수 있기 때문에 파드를 재기동할 때는 다른 노드로 이동할 때 동일한 데이터를 보유한 상태로 컨테이너가 다시 생성되고 영구 볼륨은 하나의 파드가 소유할 수 있고 영구 볼륨 종류에 따라 여러 파드에서 공유할 수 도 있다.
- 실습
# sample-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: sample-statefulset # 이름
spec:
serviceName: sample-statefulset
replicas: 3
selector:
matchLabels:
app: sample-app
template:
metadata:
labels:
app: sample-app
spec:
containers:
- name: nginx-container
image: nginx
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi # 저장해야 하니 스토리지 설정
# 리소스 생성
kubectl apply -f sample-statefulset.yaml
# pod 확인
kubectl get pods
# 이전까지는 set 이름 뒤에 해시코드가 붙었는데 statefulset은 일련번호를 붙여서 만든다.
# 저장소 확인
kubectl get persistentvolumeclaims
# 저장소 정보 확인
kubectl get persistentvolumes
# 스케일링 수행
kubectl scale statefulset sample-statefulset --replicas=5
# 병렬 생성
# spec.podManagementPolicy 가 OrderedReady로 되어 있는데 Parallel로 수정하면 병렬로 생성하는 것이 가능하다.
spec:
podManagementPolicy: Parallel
serviceName: sample-statefulset 로 추가해주면 된다.
- 계속 pending 상황이라면
# 하이퍼바이저+kubeadm설치한 환경에서 statefulset pod들이 pending상태인 경우 -> minikube에서는 같이 제공되는 스토리지 프로비저너가 기본으로 설치되어있지 않기 때문. 설치하고 디폴트로 지정해준 뒤 재시도하면 해결됨!
kubectl apply -f <https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml>
kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
kubectl delete -f sample-statefulset.yaml
kubectl apply -f sample-statefulset.yaml
StatefulSet 업데이트 전략
OnDelete
- StatefulSet 매니페스트를 수정해서 이미지를 변경했더라도 기존 파드는 업데이트 되지 않는다.
- 영속성 영역을 가진 데이터베이스나 클러스터 등에서 많이 사용되기 때문에 수동으로 업데이트 하고자 하는 경우 OnDelete를 사용해서 다음에 재기동할 때 업데이트를 진행하도록 한다.
- 실습
# sample-statefulset-ondelete.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: sample-statefulset-ondelete # 이름
spec:
updateStrategy:
type: OnDelete
serviceName: sample-statefulset-ondelete
replicas: 3
selector:
matchLabels:
app: sample-app
template:
metadata:
labels:
app: sample-app
spec:
containers:
- name: nginx-container
image: nginx
# 리소스 생성
kubectl apply -f sample-statefulset-ondelete.yaml
# pod 확인
kubectl get pods
# 매니페스트 파일의 image를 수정 (nginx:1.16으로)
# 리소스 업데이트
# pod의 이미지 확인 (describe pod ~)
# -> 이미지가 여전히 nginx 인 것을 확인할 수 있다.
RollingUpdate (가 좀 다른 구조가 된다.)
- 디플로이먼트와 마찬가지로 RollingUpdate를 사용한 스테이트풀셋 사용이 가능하지만 스테이트풀셋에는 영속성 데이터가 있으므로 디플로이먼트와 다르게 추가 파드를 생성해서 롤링 업데이트를 할 수 없고 동시에 정지 가능한 파드 수(maxUnavailable)를 지정하여 롤링 업데이트를 할 수도 없으므로 파드마다 Ready 상태인지 확인하고 업데이트한다.
- spec.podManagementPolicy가 Parallel로 설정되어 있는 경우도 병렬로 처리되지 않고 파드 하나씩 업데이트한다.
- 스테이트풀셋의 RollingUpdate에서는 partition이라는 특정 값을 설정할 수 있는데 partition을 설정하면 전체 파드 중 어떤 파드까지 업데이트 할 지 지정할 수 있고 이 설정을 사용하면 전체에 영향을 주지 않고 부분적으로 업데이트를 적용하고 확인할 수 있어 안전한 업데이트를 할 수 있다.
- OnDelete와 달리 수동으로 재기동을 해도 partition 값보다 작은 인덱스를 가진 파드는 업데이트 되지 않는다. (특정한 개수만 업데이트 할 수 있다.)
- 실습
# sample-statefulset-rollingupdate.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: sample-statefulset-rollingupdate # 이름
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 3 # 3개까지는 업데이트 적용 안 받기
serviceName: sample-statefulset-rollingupdate
replicas: 5
selector:
matchLabels:
app: sample-app
template:
metadata:
labels:
app: sample-app
spec:
containers:
- name: nginx-container
image: nginx
# 리소스 생성
kubectl apply -f sample-statefulset-rollingupdate.yaml
# pod 확인
kubectl get pods # 5개 파드 모두 정상 구동
kubectl get pods --watch
# 각각의 pod를 확인해보면 인덱스 3, 4번은 업데이트가 이루어져서 image가 nginx:1.16 이지만 나머지는 nginx로 바뀌지 않았다.
# partition: 3, replicas: 5 의 결과로 2개만 업데이트 된 것!

영구 볼륨 데이터 저장 확인
# 이전에 만들었던 sample-statefulset 리소스 생성
kubectl apply -f sample-statefulset.yaml
# 마운트 확인
kubectl exec -it sample-statefulset-0 -- df -h
# 파일 생성
# 파일 존재 여부 확인
kubectl exec -it sample-statefulset-0 -- ls /usr/share/nginx/html/sample.html
# 이런 파일이 없다고 나온다.
# 따라서 파일 생성
kubectl exec -it sample-statefulset-0 -- touch /usr/share/nginx/html/sample.html
# 파드를 삭제
kubectl delete pod sample-statefulset-0
# 파일 존재 여부 확인
kubectl exec -it sample-statefulset-0 -- ls /usr/share/nginx/html/sample.html
# statefulset은 파드가 삭제되었다 다시 만들어지더라도 이전 상태를 유지한다.
# 파드가 복구되면 이름은 동일한데 ip가 변경된다.
# sample-statefulset-0 ip 10.244.0.61 -> 10.244.0.62
삭제
- statefulset은 생성되면 파드에 영구 볼륨 클레임을 설정할 수 있어 영구 볼륨도 동시에 확보할 수 있다.
- 영구 볼륨은 스테이트풀셋이 삭제되어도 동시에 해제되지 않는다.
- 스테이트풀셋이 영구 볼륨을 해제하기 전에 볼륨에서 데이터를 백업할 수 있도록 시간을 주기 때문이다.
- 스테이트풀셋을 삭제하고 스테이트풀셋이 영구 볼륨 클레임으로 확보한 영구 볼륨을 해제하지 않고 다시 스테이트풀셋을 생성하면 영ㅇ구 볼륨 데이터를 그대로 가지고 파드가 기동되는데 스케일인을 수행해서 레플리카 수를 줄인 경우에도 마찬가지이다.
- 실습
# statefulset 삭제
kubectl delete statefulset sample-statefulset
# statefulset 생성
kubectl apply -f sample-statefulset.yaml
# 정말 데이터가 남아있는지 확인하기
kubectl exec -it sample-statefulset-0 -- ls /usr/share/nginx/html/sample.html
# /usr/share/nginx/html/sample.html
# 파일이 남아 있다 -> 영구 볼륨을 해제하지 않으면 다음에 다시 만들 때 그 데이터를 그대로 가지고 있다.
# 영구 볼륨 확인 (다 지웠다 생각했는데 여기에 있으면 안 지워진거니까)
kubectl get persistentvolumeclaims
# 삭제
kubectl delete statefulset sample-statefulset
kubectl delete persistentvolumeclaims www-sample-statefulset-{0..2}
Job
- 컨테이너를 사용하여 한 번만 실행되는 리소스
- N개로 병렬로 실행하면서 지정한 횟수의 컨테이너 실행을 보장하는 리소스
- CronJob은 주기적으로 어떤 액션을 발생시키는 잡으로 어떤 액션을 얼마나 자주 발생시킬지는 매니페스트에서 지정한다.
- 특정 시기에 주기적으로 발생시켜야 하는 크론잡은 애플리케이션이나 데이터를 백업해야 할 때 주로 사용된다.
- 잡과 레플리카셋 간의 차이점
- 기동 중인 파드가 정지되는 것을 전제로 만들어졌는지에 따라 차이 발생
- 레플리카셋 등에서 파드의 정지는 예상치 못한 에러지만 잡의 경우는 파드의 정지가 정상 종료되는 작업에 적합하다.
- 레플리카셋 등에서는 정상 종료 횟수 등을 셀 수 없기 때문에 배치 처리인 경우에는 잡을 사용한다. (사용하는 용도가 좀 다르다.)
- 잡 생성
# 파이를 2천자리까지 계산해서 출력하는 잡을 생성해서 실행
# sample-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl:5.34.0
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4
# 리소스 생성
kubectl apply -f sample-job.yaml
# print한 결과는 logs로 확인
kubectl get pods
kubectl logs pi-z7mq6
→ 어떤 일을 딱 한 번만 실행시키고 싶을 때 쓰는 게 Job. 대부분 command에 필요한 명령어 들어가야 할 것
728x90
반응형
'현대 오토에버 클라우드 스쿨' 카테고리의 다른 글
| Kubernetes Service의 type (1) | 2025.07.07 |
|---|---|
| Kubernetes- Job, CronJob, Service (2) | 2025.07.04 |
| Kubernetes- Deployment (1) | 2025.07.02 |
| Kubernetes- Prune, 로그 확인 (3) | 2025.07.01 |
| Kubernetes- Pod (2) | 2025.06.30 |