Deployments란?
Deployment는 Pod와 Replicaset에 대한 선언과 업데이트를 관리해주는 모듈이다.
Kubernetes의 최소 유닛인 Pod에 대한 기준 스펙을 정의한 Object이다.
Kubernetes는 각 Object를 독립적으로 생산하는 것보다 Deployment를 통해서 생성하는 것을 권장한다.
Replicaset은 실행되는 파드 개수에 대한 가용성을 보증하며, 지정한 파드 개수만큼 항상 실행될 수 있도록 관리하는 것이다. 5개의 파드를 항상 실행하게 설정해놓으면 파드 1개가 삭제된다 하더라도 다시 파드 1개가 실행되어 5개를 유지한다.
즉 Deployment가 Replicasets을 생성하고 Replicasets이 Pod를 만든다.
Deployment를 선언하면 Replicasets부터 Pod까지 만들어 지는 것이다.
yaml 파일 생성하기
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Object는 Deployment이며 Deployment의 이름은 nginx-deployment이다. 레이블은 object에 첨부된 키와 값의 상이다. 이는 오브젝트의 특성을 식별하는 데 사용되어 사용자에게는 중요하지만 코어 시스템에는 직접적인 의미는 없다.
위 Yaml의 Deployment의 Spec을 살펴보자.
먼저 replicas이다. 이는 유지하고자 하는 Pod의 갯수로 3으로 지정했다면 정상적인 Pod의 개수가 3개가 되도록 한다.
그 다음은 Selector이다. Selector는 관리하고자 하는 Pod를 선택하기 위한 조건을 정의하는 것이다.
matchLabels를 사용해서 app: nginx 라는 label을 가진 pod를 선택하는 조건을 만들었다.
template은 관리되고자 하는 Pod를 지정하는 필드이다. template 역시 pod를 정의할 때처럼 metadata와 spec을 정의해주면 된다.
관리하는 Pod의 갯수가 유지하려는 Pod의 개수보다 부족할 때 여기서 정의된 Pod를 생성하여 개수를 유지시킨다.
그러므로 Pod의 metadata에 정의된 label은 반드시 Deployment의 selector와 매치되어야 한다.
먼저 deployment.yaml 이라는 형식으로 파일을 만들고 위의 내용을 그대로 붙여넣어 준다.
그렇다면 deployment.apps가 생성되었다는 것을 확인할 수 있다.
kubectl apply -f deployment.yaml
현재 우리가 name으로 지정해 두었던 nginx-deployment가 생성 된 것을 확인할 수 있고 총 3개가 띄워져 3개 모두 사용 가능한 것을 알 수 있다. Selector 역시 위에서 설정했던 app:nginx 임을 확인할 수 있다.
kubectl get deployments.apps -o wide
파드를 검색해 본 결과 3개가 모두 잘 띄워져 있는 것을 확인할 수 있다.
여기에 있는 10.36 이나 10.44 IP는 CNI(여기서는 위브넷) IP이다.
kubectl get pods -o wide
Update
Deployment와 Replicaset의 가장 큰 차이점은 Update이다. Deployment는 Update가 가능하다.
Update가 진행되면 Deployment는 update된 새로운 Replicaset을 생성하여 새로운 Pod를 생성하고 기존 Replicaset에서 생성된 Pod는 모두 제거된다.
Update 방식은 총 4가지이지만 Deployment에서 제공되는 Update 기능은 Recreate와 Rolling Update 이다.
만약 Blue/Green, Canary 방식을 사용하고 싶다면 Replicas를 관리하는 Deploy Controller를 이용해야 한다.
아무런 설정을 하지 않는다면 기본값으로 Rolling Update가 들어가게 된다.
Recreate
관리중인 모든 Pod를 없앤 후 새로운 Pod를 배포하는 방식이다. 이는 불가피한 DownTime이 발생한다.
아래 그림을 살펴보면 먼저 v1 두개를 삭제 한 후 빈 공간에 v2를 채워 넣는 식으로 모든 pod가 종료되기 때문에 DownTime이 발생한다.
strategy 항목을 추가한 후 type을 Recreate로 변경시킨 후 코드를 저장한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
strategy:
type: Recreate
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
먼저 watch 명령어를 사용해 update가 진행될 동안 Deployment의 상태변화를 관찰해보자
watch "kubectl get deployments nginx-deployment"
그 후 이런식으로 master에 대한 terminal을 하나 더 띄운 후 update를 진행 해 보았다.
nginx의 버전을 1.14.2에서 1.21.6 버전으로 변경해서 적용해 보았다.
kubectl set image deployment/nginx-deployment nginx=nginx:1.21.6
그러자 잠시 후 deployment가 사용 가능한게 0이 되더니 일정 시간이 지난 후 Available이 3개로 변한 것을 확인할 수 있었다.
또한 update 시 rollout status 라는 명령어를 사용하면 이렇게 배포하는 과정을 살펴 볼 수 있다.
kubectl rollout status deployment/nginx-deployment
Rolling Update
이 방식은 기존 Pod중 일부를 제거한 후 새로 Update 된 Pod를 일부 배포하는 과정을 반복해서 진행하는 방식으로 점진적인 배포과정 때문에 배포 완료까지 시간이 걸리지만 DownTime이 존재하지 않고 무중단 Update가 가능하다.
Rolling Update에는 추가 설정이 가능하다.
- maxSurge
- Update시 최대 얼마만큼의 Pod를 더 생성할 수 있을지 정하는 설정이다. int 값(개수) 또는 string값(%)으로 사용이 가능하다. 만약 replicas 개수가 10인 상황에서 maxSurger가 5인 경우 update시 기존 Pod + 신규 Pod의 개수가 최대 15까지 유지하며 Update가 진행되며, maxSurger가 20%인 경우 최대 12개가 유지되며 Update를 진행함
- maxUnavailable
- Update시 최대 얼마만큼의 Pod가 Unavailable 상태여도 되는지 지정하는 설정이다. 쉽게 말하면 Update 시 동시에 삭제할 수 있는 Pod의 최대 개수 설정을 의미한다. 이 역시 int 값(개수) 또는 String 값(%)으로 설정이 가능하다. 만약 replicas가 10개인 상황에서 maxUnavailable을 2로 설정하면 update시 10개의 Pod를 기준으로 2개까지 unavailable 상태가 가능하며 8개는 항상 정상동작 하는 상태가 유지 될 것이다.
replicas를 4로 수정한 후 strategy type을 Rolling update로 변경했다. 그리고 maxSurge에 2 maxUnavailable에 2를 주었다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 4
selector:
matchLabels:
app: nginx
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2
maxUnavailable: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
먼저 설정을 변경해 주었기 때문에 deployments를 삭제하고 다시 적용 해 주었다.
kubectl delete deployments.app nginx-deployment
kubectl apply -f deployment.yaml
그 후 이미지 버전을 변경시켜 업데이트를 진행 해 주었다.
kubectl set image deployment/nginx-deployment nginx=nginx:1.21.6
먼저 rollout 명령어를 통해 살펴보니 2개가 먼저 종료가 된 후 2개의 update replica가 사용 가능해지고 총 4개가 완료가 된다. 하지만 이것만 봐서는 판단이 어려웠다.
Watch 명령어를 사용해서 관찰 해 보았다. 먼저 4개중 2개의 Pod만이 Available 상태임을 확인할 수 있고 잠시 뒤 4개
모두 Available임을 확인할 수 있다.
그리고 업데이트가 진행되는 동안 실시간으로 확인해 본 Pod List를 확인해 본 결과
내가 아까 지정했던 maxSurge의 개수는 2로 replicas + 2 총 6개의 Pod가 뜬 것을 확인할 수 있다.
또한 두번째로 지정했던 maxUnavailable의 개수는 2로 총 2개를 중지 시킬 수 있었으므로 2개가 먼저 Terminating 되는 것을 볼 수 있다.
즉 4개의 새로운 Pod가 생성중이고 2개의 Pod를 먼저 중지 시켜 총 6개를 유지하고 2개씩 2개씩 변경시켜 주는 것을 확인 할 수 있었다.
Blue/Green
Blue/Green은 기존에 띄워져 있는 Pod 개수와 동일한 개수만큼의 신규 Pod를 모두 띄운 다음 신규 Pod가 이상이 없이 정상적으로 작동하는지 확인 후 들어오는 트래픽을 LoadBalancer 설정을 변경하여 한번에 신규 Pod로 옮기는 방법이다.
즉 서버 세트를 구, 신버전으로 2세트 준비한 이후 이를 한꺼번에 교체하는 방법이다.
Blue의 의미는 구버전 즉 운영중인 애플리케이션이다.
Green의 의미는 새버전 새로운 애플리케이션이다.
Blue/Green은 Deployment에서 지원하는 기능은 아니지만 yaml 파일을 수정한다면 사용할 수 있다.
먼저 nginx11이라는 deployment.yaml 파일을 먼저 만들어 주었다. 이 파일이 Blue 파일이라고 생각하면 된다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx11
spec:
replicas: 3
selector:
matchLabels:
app: deploy-nginx11
template:
metadata:
labels:
app: deploy-nginx11
spec:
containers:
- name: deploy-nginx11
image: nginx:1.11
그 후 nginx12라는 deployment.yaml 파일을 만들어 주었다. 이 파일이 Green이 될 파일이다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx12
spec:
replicas: 3
selector:
matchLabels:
app: deploy-nginx12
template:
metadata:
labels:
app: deploy-nginx12
spec:
containers:
- name: deploy-nginx12
image: nginx:1.12
그 후 각 파일들의 index.html의 내용을 변경한다.(nginx 버전으로 변경)
# nginx v1.11 의 index.html 내용 변경
for pod in $(kubectl get pod -l app=deploy-nginx11 |awk 'NR>1 {print $1}'); do kubectl exec $pod -- /bin/sh -c "hostname > /usr/share/nginx/html/index.html; echo 'nginx:v1.11 END' >> /usr/share/nginx/html/index.html"; done
# nginx v1.12 의 index.html 내용 변경
for pod in $(kubectl get pod -l app=deploy-nginx12 |awk 'NR>1 {print $1}'); do kubectl exec $pod -- /bin/sh -c "hostname > /usr/share/nginx/html/index.html; echo 'nginx:v1.12 END' >> /usr/share/nginx/html/index.html"; done
그 후 Pod의 IP로 curl 접속을 시도해 보니 nginx11 버전의 pod들의 index.html의 내용은 nginx11로
nginx12 버전의 pod들의 index.html 내용은 nginx12로 변경이 된 것을 확인할 수 있다.
# nginx v1.11 의 Pod IP로 curl 접속 시도
for podIP in $(kubectl get pod -o wide -l app=deploy-nginx11 |awk 'NR>1 {print $6}'); do curl -s $podIP; done
# nginx v1.12 의 Pod IP로 curl 접속 시도
for podIP in $(kubectl get pod -o wide -l app=deploy-nginx12 |awk 'NR>1 {print $6}'); do curl -s $podIP; done
그 후 svc-nginx.yaml 파일을 만들어 주었다. 이 파일은 Service yaml 파일로 deploy-nginx11 버전을 서비스로 올린다는
의미이다.
apiVersion: v1
kind: Service
metadata:
name: svc-nginx
spec:
ports:
- name: svc-nginx
port: 9000
targetPort: 80
selector:
app: deploy-nginx11
curl 명령어를 사용해 보니 현재 nginx 11 버전이 돌아가는 것을 확인할 수 있다.
그 후 Blue/Green 업데이트를 실행해 주었다.
kubectl get svc svc-nginx -o yaml | sed -e "s/app: deploy-nginx11/app: deploy-nginx12/" | kubectl apply -f -
curl을 확인해 보니 nginx:v1.12로 변경 된 것을 확인할 수 있다.
하지만 Pod들은 여전히 11버전, 12 버전 모두 잘 돌아가는 것을 확인할 수 있다.
그 후 버전을 롤백한 후 다시 curl 명령어를 날려보니 다시 11 버전으로 돌아간 것을 확인할 수 있었다.
다시 버전을 변경한 이후 nginx11을 모두 삭제하였다.
그 후 curl 명령어를 날렸다 1.12 버전으로 잘 돌아오는 것을 확인할 수 있었다.
kubectl get svc svc-nginx -o yaml | sed -e "s/app: deploy-nginx12/app: deploy-nginx11/" | kubectl apply -f -
kubectl scale deployment deploy-nginx11 --replicas=0
11버전을 지운 후 Service를 다시 nginx11 버전으로 돌린 후 curl 명령어로 접속하자 접근이 거부되었다고 나온다.
그 후 다시 12 버전으로 돌린 후 curl 명령어를 날리니 제대로 nginx:v1.12로 나오는 것을 확인할 수 있다.
Canary
카나리아 방식은 신규 버전을 배포할 때 한꺼번에 앱의 전체를 교체하는 것이 아닌 기존 버전을 유지한 채로 일부 버전만 신규 버전으로 올려 신규 버전에 버그나 이상은 없는지, 사용자 반응은 어떤지를 확인하는데 유용하게 사용되는 방법이다. 새로운 버전의 애플리케이션을 PROD 환경으로 보내 어떻게 동작하는지 모니터링하는 도구로 주로 사용한다.
이 역시 Deployment가 지원하는 기능은 아니기 때문에 labels을 이용해서 Canary 배포를 해야 한다.
먼저 deployment-v1.yaml 이라는 yaml 파일을 생성한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8s-testapp
labels:
app: myapp
version: stable
spec:
replicas: 2
selector:
matchLabels:
app: myapp
version: stable
template:
metadata:
labels:
app: myapp
version: stable
spec:
containers:
- name: testapp
image: arisu1000/simple-container-app:v0.1
ports:
- containerPort: 8080
그 후 deployment-v2.yaml 이라는 yaml 파일을 생성한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8s-testapp-canary
labels:
app: myapp
version: canary
spec:
replicas: 1
selector:
matchLabels:
app: myapp
version: canary
template:
metadata:
labels:
app: myapp
version: canary
spec:
containers:
- name: testapp
image: arisu1000/simple-container-app:v0.2
ports:
- containerPort: 8080
그리고 두개의 Deployment.yaml 파일을 실행시킨다.
이 두개의 yaml 파일은 각자의 버전을 표시한다 v1에서는 v0.1을 v2에서는 v0.2를 보여준다.
v1은 app=myapp, version=stable 이라는 라벨을 가지고
v2는 app=myapp, version=canary 라는 라벨을 가진다.
같은 앱이지만 라벨을 이용해서 stable과 canary 버전을 구분하는 것이다.
그 후 pod를 외부로 노출시킬 myapp-svc.yaml을 생성한다.
apiVersion: v1
kind: Service
metadata:
labels:
app: myapp
name: myapp-svc
namespace: default
spec:
ports:
- nodePort: 30880
port: 8080
protocol: TCP
targetPort: 8080
selector:
app: myapp
type: NodePort
그 후 서비스를 적용한 이후 localhost:30880 명령어를 통해서 살펴보면 v1과 v2의 앱버전이 같이 출력 되는 것을 확인할 수 있다. 여러개의 deployment를 하나의 접속 주소로 묶어 서비스하고 있다는 걸 알 수 있다.
여기서 replicas를 조정하여 아예 v0.2의 서비스를 막을수도 있고 replicas를 증가시켜 v0.2의 빈도를 더욱 높일수도 있다.
롤백
Deployment는 롤백 기능을 지원한다.
개발을 하다보면 새로운 애플리케이션을 배포했다 문제가 생길 시 다시 이전 버전으로 롤백을 하는 경험을 가진다.
먼저 위에서 했던 내용을 그대로 진행해 현재 Deployment가 Update 된 Pod를 관리하는 상태로 만들어 주었다.
이 그림을 보면 replicaset이 하나는 4개가 사용이 가능하고 하나는 0개가 사용 가능한 것을 확인할 수 있다.
이는 nginx 버전을 1.14.2 에서 1.21.6으로 변경했기 때문에 1.14.2의 rs는 현재 0개고 1.21.6의 rs는 현재 4개인 것을 볼 수 있다.
kubectl get rs
rollout history 명령어를 통해서 현재 nginx-deployment 라는 deployment가 총 2개의 이력이 있음을 확인할 수 있다.
kubectl rollout history deployment/nginx-deployment
--revision 옵션을 통해 특정 버전의 정보를 확인할 수 있다. 현재는 revision2가 배포되어 있다는 것을 알 수 있다.
kubectl rollout history deployment/nginx-deployment --revision=2
--to-revision 명령어를 통해서 특정 REVISION으로 롤백을 완료하였다.
kubectl rollout history deployment/nginx-deployment --revision=1
롤백 완료 후 모습이다. 다시 예전처럼 nginx 버전이 1.14.2 임을 확인할 수 있다.
출처
Kubernetes Deployment(디플로이먼트) (velog.io)
쿠버네티스 - Blue Green 배포 (클러스터 서비스 활용) · GitHub
쿠버네티스 라벨을 이용한 카나리(canary) 배포 :: 아리수 (tistory.com)
'[Kubernetes]' 카테고리의 다른 글
sample devops end to end project v1- devops project | ci/cd declarative pipeline using devops tools (0) | 2023.07.22 |
---|---|
[마이크로 서비스] 사용하지 않는 경우!! (0) | 2023.07.11 |
[k8s] YAML 기본 문법 및 k8s yaml 작성방법 (0) | 2022.11.23 |
[k8s] kubernetes의 Service가 무엇인가? (0) | 2022.11.22 |
[k8s] Helm을 통해 Prometheus, Grafana 적용하기 (0) | 2022.11.22 |
[k8s] 파드란 무엇인가, 파드 만들기(명령어로 생성 및 yaml로 생성) (0) | 2022.11.21 |
[K8s] 쿠버네티스란 무엇인가? (0) | 2022.11.16 |
[k8s] 프로메테우스란 무엇인가? (개념 및 아키텍쳐) (0) | 2022.11.15 |
댓글