디플로이먼트
공식 문서: https://kubernetes.io/ko/docs/concepts/workloads/controllers/deployment/
디플로이먼트(Deployment) 는 파드와 레플리카셋(ReplicaSet)에 대한 선언적 업데이트를 제공한다.
디플로이먼트에서 의도하는 상태 를 설명하고, 디플로이먼트 컨트롤러(Controller)는 현재 상태에서 의도하는 상태로 비율을 조정하며 변경한다. 새 레플리카셋을 생성하는 디플로이먼트를 정의하거나 기존 디플로이먼트를 제거하고, 모든 리소스를 새 디플로이먼트에 적용할 수 있다.
Use Case
다음은 디플로이먼트의 일반적인 사례이다.
- 레플리카셋을 롤아웃 할 디플로이먼트 생성. 레플리카셋은 백그라운드에서 파드를 생성한다. 롤아웃 상태를 체크해서 성공 여부를 확인한다.
- 디플로이먼트의 PodTemplateSpec을 업데이트해서 파드의 새로운 상태를 선언한다. 새 레플리카셋이 생성되면, 디플로이먼트는 파드를 기존 레플리카셋에서 새로운 레플리카셋으로 속도를 제어하며 이동하는 것을 관리한다. 각각의 새로운 레플리카셋은 디플로이먼트의 수정 버전에 따라 업데이트한다.
- 만약 디플로이먼트의 현재 상태가 안정적이지 않은 경우 디플로이먼트의 이전 버전으로 롤백한다. 각 롤백은 디플로이먼트의 수정 버전에 따라 업데이트한다.
- 더 많은 로드를 위해 디플로이먼트의 스케일 업.
- 디플로이먼트 롤아웃 일시 중지로 PodTemplateSpec에 여러 수정 사항을 적용하고, 재개하여 새로운 롤아웃을 시작한다.
- 롤아웃이 막혀있는지를 나타내는 디플로이먼트 상태를 이용.
- 더 이상 필요 없는 이전 레플리카셋 정리.
애플리케이션 배포 전략
어플리케이션 배포 전략: https://thenewstack.io/deployment-strategies/
Recreate
Pros
- 배포 설정하기가 아주 쉽다.
- 애플리케이션 상태가 완전히 갱신된다.
Cons
- 다운 타임이 발생한다. 그렇기 때문에 계획된 다운 타임을 사용하여 특정 시간에 서비스를 사용하지 못하게 하고 앱을 업데이트 한다.
Ramped(롤링 업데이트)
레플리카셋이 공존하고있는 상태로 하나씩 순차적으로 업데이트하는 방식이다.
Pros
- 배포 설정하기가 아주 쉽다.
- 업데이트가 인스턴스 간에 천천히 릴리스된다.
- 데이터 재조정을 처리할 수 있는 상태 저장 애플리케이션에 편리하다.
- 무중단 시스템이다.
Cons
- 롤아웃/롤백에 시간이 걸린다.
- API 가 변경되는 경우 API 를 지원하는 데 문제가 발생한다.
- 트래픽을 컨트롤할 방법이 없다.
Blue/Green
recreate 와 비슷하지만 업데이트할 버전의 리소스를 미리 만들어놓은 후에 버전 업그레이드를 한다.
Pros
- 롤아웃/롤백을 즉각적으로 할 수 있다.
- 버전 관리 문제를 피할 수 있고, 전체 애플리케이션 상태가 한 번에 변경된다.
Cons
- 리소스를 더 많이 사용하여 비용이 많이 든다.
- 프로덕션에 배포하기 전에 전체 플랫폼에 대한 적절한 테스트를 수행해야 한다.
- stateful 애플리케이션을 처리하는 것이 어렵다.
Canary
일부 트래픽을 업데이트하려는 버전으로 보내고 테스팅을 하며 문제가 있으면 해결하고 문제가 없으면 트래픽을 더 늘리는 방식이다.
Pros
- 일부 사용자를 위해 출시된 버전입니다.
- 오류나 성능 모니터링 하기에 매우 좋다.
- 롤백이 매우 빠르다.
Cons
- 롤아웃이 매우 느리다.
A/B testing
A/B 테스트 배포는 특정 종류를 테스팅할 때 사용한다. 브라우저 쿠키, 쿼리 파라미터, 지리적 위 등을 사용하여 다른 버전으로 라우팅되게 한다. 예를 들어, 모바일 사용자와 데스크톱 사용자가 사용하는 배포 버전을 다르게 하여 테스팅하는 방식이 될 수 있다.
Pros
- 여러 버전이 병렬로 실행된다.
- 트래픽 분산을 완벽하게 제어한다.
Cons
- intelligent 로드 밸런서가 필요하다.
- 주어진 세션에 대한 오류를 해결하기 어렵기 때문에 분산 추적이 필수이다.
Shadow
로드 밸런서가 클라이언트로부터 받은 트래픽을 현재 버전과 업데이트 하려는 버전으로 모두 전송된다.
Pros
- 프로덕션 레벨에서 받은 트래픽으로 업그레이드 버전의 성능을 테스트 할 수 있다.
- 사용자에게 영향이 없다.
- 애플리케이션의 안정성과 성능이 요구 사항을 충족할 때까지 롤아웃이 없다.
Cons
- 두 배의 리소스가 필요하므로 비용이 많이 든다.
- 실제 사용자 테스트가 아니기 때문에 오해의 소지가 있다.
- 설정이 복잡하다.
- 특정 경우에 모의 서비스가 필요하다.
디플로이먼트 Rollout
apiVersion: v1
kind: Service
metadata:
name: myweb-svc-lb
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: 8080
apiVersion: apps/v1
kind: Deployment
metadata:
name: myweb-deploy
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb:v1.0
ports:
- containerPort: 8080
Deployment → RS → Pod
kubectl rollout status deploy myweb-deploy
kubectl rollout history deploy myweb-deploy
kubectl set image deployments myweb-deploy myweb=ghcr.io/c1t1d0s7/go-myweb:v2.0 --record
디플로이먼트 전략
.spec.strategy 는 이전 파드를 새로운 파드로 대체하는 전략을 명시한다. .spec.strategy.type 은 "재생성" 또는 "롤링업데이트"가 될 수 있다. "롤링업데이트"가 기본값이다.
디플로이먼트 롤링 업데이트
디플로이먼트는 .spec.strategy.type==RollingUpdate 이면 파드를 롤링 업데이트 방식으로 업데이트 한다. maxUnavailable 와 maxSurge 를 명시해서 롤링 업데이트 프로세스를 제어할 수 있다.
최대 불가(Max Unavailable)
.spec.strategy.rollingUpdate.maxUnavailable 은 업데이트 프로세스 중에 사용할 수 없는 최대 파드의 수를 지정하는 선택적 필드이다. 이 값은 절대 숫자(예: 5) 또는 의도한 파드 비율(예: 10%)이 될 수 있다. 절대 값은 내림해서 백분율로 계산한다. 만약 .spec.strategy.rollingUpdate.maxSurge 가 0이면 값이 0이 될 수 없다. 기본 값은 25% 이다.
예를 들어 이 값을 30%로 설정하면 롤링업데이트 시작시 즉각 이전 레플리카셋의 크기를 의도한 파드 중 70%를 스케일 다운할 수 있다. 새 파드가 준비되면 기존 레플리카셋을 스케일 다운할 수 있으며, 업데이트 중에 항상 사용 가능한 전체 파드의 수는 의도한 파드의 수의 70% 이상이 되도록 새 레플리카셋을 스케일 업할 수 있다.
최대 서지(Max Surge)
.spec.strategy.rollingUpdate.maxSurge 는 의도한 파드의 수에 대해 생성할 수 있는 최대 파드의 수를 지정하는 선택적 필드이다. 이 값은 절대 숫자(예: 5) 또는 의도한 파드 비율(예: 10%)이 될 수 있다. MaxUnavailable 값이 0이면 이 값은 0이 될 수 없다. 절대 값은 올림해서 백분율로 계산한다. 기본 값은 25% 이다.
예를 들어 이 값을 30%로 설정하면 롤링업데이트 시작시 새 레플리카셋의 크기를 즉시 조정해서 기존 및 새 파드의 전체 갯수를 의도한 파드의 130%를 넘지 않도록 한다. 기존 파드가 죽으면 새로운 래플리카셋은 스케일 업할 수 있으며, 업데이트하는 동안 항상 실행하는 총 파드의 수는 최대 의도한 파드의 수의 130%가 되도록 보장한다.
즉, 최대 서지 값이 많으면 많을수록 기존의 파드를 삭제하지 않고 서지 값만큼 Rollout 이 가능하다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: myweb-deploy
annotations:
kubernetes.io/change-cause: "Go Myweb version from 2 to 4"
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailabe: 1
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb:v4.0
ports:
- containerPort: 8080
진행 기한 시간(초)
.spec.progressDeadlineSeconds 는 디플로어먼트가 표면적으로 type: Progressing, status: "False"의 상태 그리고 리소스가 reason: ProgressDeadlineExceeded 상태로 진행 실패를 보고하기 전에 디플로이먼트가 진행되는 것을 대기시키는 시간(초)를 명시하는 선택적 필드이다. 디플로이먼트 컨트롤러는 디플로이먼트를 계속 재시도 한다. 기본값은 600(초)이다. 미래에 자동화된 롤백이 구현된다면 디플로이먼트 컨트롤러는 상태를 관찰하고, 그 즉시 디플로이먼트를 롤백할 것이다.
만약 명시된다면 이 필드는 .spec.minReadySeconds 보다 커야 한다.
최소 대기 시간(초)
.spec.minReadySeconds 는 새롭게 생성된 파드의 컨테이너가 어떤 것과도 충돌하지 않고 사 용할 수 있도록 준비되어야 하는 최소 시간(초)을 지정하는 선택적 필드이다. 이 기본 값은 0이다(파드는 준비되는 즉시 사용할 수 있는 것으로 간주됨). 파드가 준비되었다고 간주되는 시기에 대한 자세한 내용은 컨테이너 프로브를 참조한다.
프로브를 사용한다면 굳이 세팅할 필요는 없다.
수정 버전 기록 제한
디플로이먼트의 수정 버전 기록은 자신이 컨트롤하는 레플리카셋에 저장된다.
.spec.revisionHistoryLimit 은 롤백을 허용하기 위해 보존할 이전 레플리카셋의 수를 지정하는 선택적 필드이다. 이 이전 레플리카셋은 etcd 의 리소스를 소비하고, kubectl get rs 의 결과를 가득차게 만든다. 각 디플로이먼트의 구성은 디플로이먼트의 레플리카셋에 저장된다. 이전 레플리카셋이 삭제되면 해당 디플로이먼트 수정 버전으로 롤백할 수 있는 기능이 사라진다. 기본적으로 10개의 기존 레플리카셋이 유지되지만 이상적인 값은 새로운 디플로이먼트의 빈도와 안정성에 따라 달라진다.
더욱 구체적으로 이 필드를 0으로 설정하면 레플리카가 0이 되며 이전 레플리카셋이 정리된다. 이 경우, 새로운 디플로이먼트 롤아웃을 취소할 수 없다. 새로운 디플로이먼트 롤아웃은 수정 버전 이력이 정리되기 때문이다.
일시 정지
.spec.paused 는 디플로이먼트를 일시 중지나 재개하기 위한 선택적 부울 필드이다. 일시 중지 된 디플로이먼트와 일시 중지 되지 않은 디플로이먼트 사이의 유일한 차이점은 일시 중지된 디플로이먼트는 PodTemplateSpec에 대한 변경 사항이 일시중지 된 경우 새 롤아웃을 트리거 하지 않는다. 디플로이먼트는 생성시 기본적으로 일시 중지되지 않는다.