Deployment 뜯어보기 / 배포 방식

타미·2023년 4월 16일
0

Hello Kubernetes

목록 보기
5/5
post-thumbnail

Deployment란?

  • kubernetes controller 종류 중 하나
    • replica set
    • deployment
    • daemon set
    • job
      ...
  • replica set (실행해야 하는 pod의 개수를 관리) + 배포 전략 설정 + rollback

기본 포맷

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app # deployment의 이름
  labels:
    app: nginx-app # deployment의 label
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-app
  template:
    metadata:
      labels:
        app: nginx-app
    spec:
      containers:
      - name: nginx-app
        image: nginx
        ports:
        - containerPort: 80

Deployment 적용 결과

위 yaml 파일을 실행했을 때의 결과 (kubectl apply -f deployment.yaml)

> kubectl get deployment              
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
nginx-app   1/1     1            1           21s
--
> kubectl get rs                      
NAME                  DESIRED   CURRENT   READY   AGE
nginx-app-f9d85f7f6   1         1         1       25s
--
> kubectl get pod
NAME                        READY   STATUS    RESTARTS   AGE
nginx-app-f9d85f7f6-hkxg2   1/1     Running   0          29s
  • deployment를 생성하면 replica set이 생성된다.
    • 이 replica set이 pod의 개수를 관리한다.
  • replica set, pod의 이름은 deployment 이름에 hash 값이 붙어 만들어진다.
    • rs 이름: nginx-app-f9d85f7f6
    • pod 이름: nginx-app-f9d85f7f6-hkxg2

yaml 파일 뜯어보기

Label, Selector

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
  labels:
    app: nginx-app # deployment의 label
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-app # deployment가 관리하는 label
  template:
    metadata:
      labels:
        app: nginx-app # replica set, pod에 부여되는 label
    spec:
      containers:
      - name: nginx-app
        image: nginx
        ports:
        - containerPort: 80

label은 object에 부여되는 key, value 값이다. 속성을 식별하는 역할을 한다.

  • 쿠버네티스 리소스에는 label로 key, value 값을 부여할 수 있다.
  • deployment는 replica set, pod에 부여된 label 값을 기반으로 리소스를 식별한다.
  • deployment의 label과 deployment가 관리하는 label이 일치할 필요는 없다.
  • 하지만 deployment가 관리할 label(selector.matchLabels)와 rs, pod에 부여되는 label의 값(template.metadata)은 같아야 한다. 다르면 실행이 안된다.
    • The Deployment "nginx-app2" is invalid: spec.template.metadata.labels: Invalid value: map[string]string{"app":"mylabel2"}: selector does not match template labels
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
  labels:
    app: nginx-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-app2 # 수정
  template:
    metadata:
      labels:
        app: nginx-app2 # 수정
    spec:
      containers:
      - name: nginx-app
        image: nginx
        ports:
        - containerPort: 80
> kubectl get rs --show-labels
NAME                   DESIRED   CURRENT   READY   AGE   LABELS
nginx-app-76dc4c94c4   1         1         1       14s   app=mylabel,pod-template-hash=76dc4c94c4
>  kubectl get pods --show-labels
NAME                         READY   STATUS    RESTARTS   AGE    LABELS
nginx-app-76dc4c94c4-wjkjz   1/1     Running   0          101s   app=mylabel,pod-template-hash=76dc4c94c4
  • metadata.labels에 있는 label 값이 rs, pods에 부여된 것을 확인할 수 있다.
  • pod-tempalte-hash는 kubernetes에서 부여하는 label로 pod를 직접 생성한 것이 아니라, deployment와 같이 다른 리소스에 의해 생성될 때 생기는 label이다.
  • 유의할 점은 label 값은 변경할 수 없다는 것이다. (immutable)
    • label은 리소스를 식별하는 유일한 기준이기 때문에 쿠버네티스에서 변경을 금지하고 있다.
    • app2: nginx-app2라는 label을 새로 추가하는 것은 가능하다.

Container Name

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app 
  labels:
    app: nginx-app 
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-app
  template:
    metadata:
      labels:
        app: nginx-app
    spec:
      containers:
      - name: nginx-app # container name
        image: nginx
        ports:
        - containerPort: 80

Container의 이름으로 Pod의 이름과는 다르다. Cotainer 이름을 nginx-app2로 바꿨을 때 다음과 같다.

> kubectl describe pod nginx-app-745f746788-mx8q2
Name:             nginx-app-745f746788-mx8q2
...
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  2m9s  default-scheduler  Successfully assigned default/nginx-app-745f746788-mx8q2 to minikube
  Normal  Pulling    2m8s  kubelet            Pulling image "nginx"
  Normal  Pulled     2m6s  kubelet            Successfully pulled image "nginx" in 2.178144199s
  Normal  Created    2m6s  kubelet            Created container nginx-app2
  Normal  Started    2m6s  kubelet            Started container nginx-app2

컨테이너의 이름은 무슨 의미가 있을까?

  • 하나의 파드에 여러 개의 컨테이너가 있을 때 식별
    • 파드 안에 있는 하나의 이미지만 업데이트/롤백 할 수 있다.
      • ex. kubectl rollout restart deployment/my-deployment -c my-container
    • 파드 안에 있는 로그 정보를 디버그를 컨테이너 단위로 할 수 있다.
      • ex. kubectl logs <pod-name> -c <container-name>
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
  labels:
    app: nginx-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-app
  template:
    metadata:
      labels:
        app: nginx-app
    spec:
      containers:
      - name: nginx-app # 컨테이너 1
        image: nginx
        ports:
        - containerPort: 80
      - name: nginx-app2 # 컨테이너 2
        image: arisu1000/simple-container-app:latest
        ports:
          - containerPort: 81

위 파일을 적용하면 하나의 파드 안에 2개의 image (nginx, simple-container-app)이 들어간다.

> kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
nginx-app-5f6f64fc6f-zx5mk   2/2     Running   0          118m

> kubectl describe pod nginx-app-5f6f64fc6f-zx5mk 

...
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  20s   default-scheduler  Successfully assigned default/nginx-app-5f6f64fc6f-zx5mk to minikube
  Normal  Pulling    20s   kubelet            Pulling image "nginx"
  Normal  Pulled     17s   kubelet            Successfully pulled image "nginx" in 2.13241259s
  Normal  Created    17s   kubelet            Created container nginx-app
  Normal  Started    17s   kubelet            Started container nginx-app
  Normal  Pulling    17s   kubelet            Pulling image "arisu1000/simple-container-app:latest"
  Normal  Pulled     15s   kubelet            Successfully pulled image "arisu1000/simple-container-app:latest" in 2.101710998s
  Normal  Created    15s   kubelet            Created container nginx-app2
  Normal  Started    15s   kubelet            Started container nginx-app2

Container Port

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
  labels:
    app: nginx-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-app
  template:
    metadata:
      labels:
        app: nginx-app
    spec:
      containers:
      - name: nginx-app
        image: nginx
        ports:
        - containerPort: 80 # here

파드 안에 있는 nginx 이미지에 접근하기 위해서 80번 포트를 사용

배포 전략

  • 배포 전략
    • Recreate
      • 모든 파드 삭제 -> 모든 파드 생성
      • 일시적으로 서비스 중단 발생
        • 수정된 deployment에 문제가 있어 새로운 파드가 이상해도, 이전 replica set으로 동작 X
    • Rolling Update
      • 파드를 하나씩 제거, 하나씩 생성
      • 서비스 중단 x
    • Canary
      • 일부는 새로운 버전 배포 / 일부 트래픽은 이전 버전 사용하며 점진적 배포
      • old deployment, new deployment를 생성한 후, service를 활용하여 일부 트래픽을 new deployment로 흘려보내며, 정상적인 것으로 모니터링이 되면 new deployment로 모든 트래픽을 보낸다.
      • deployment만을 활용해서 canary 배포를 할 수는 없다. 프로세스 자동화를 위한 여러 도구가 별도로 있다.
    • Blue/Green
      • old deployment (blue), new deployment (green)을 동시에 배포
      • new deployment 테스트 완료되면 old version을 지우는 방식
      • service selector.matchLabels에 version을 연동 (old version label - 테스트 - new version label로 수정)
      • old, new deployment 모두 리소스를 사용해서 2배로 리소스를 사용하게 된다.

https://blog.yevgnenll.me/k8s/deployment-declaration-update-application

Rolling Update

deployment의 기본 업데이트 전략은 Rolling Update

maxUnavilable

  • 롤링 업데이트 중 동시에 삭제할 수 있는 파드의 최대 갯수
  • 기본 값은 replicas의 25% 이다.
  • replicas: 4의 경우 1개 파드 삭제, replicas: 8의 경우 2개 파드 동시 삭제
  • 퍼센트 및 직접 지정이 가능하다.
  • 이 값을 높게 설정하면 동시에 교체되는 파드가 늘어나므로 롤링 업데이트 시간이 줄어든다.
    하지만 롤링업데이트 중에 남아 있는 파드에 요청 수가 몰릴 수 있다.
    따라서 1로 설정해 파드를 하나씩 교체하는 것이 안전할 수 있다.

출처) https://gracefullight.dev/2019/12/27/kubernetes-rolling-update/

maxSurge

  • 롤링 업데이트 중 동시에 생성하는 파드 갯수
  • 기본 값은 replicas의 25% 이다.
  • replicas: 4면서 maxSurge: 4면 롤링 업데이트 시작 시 새 버전의 파드가 4개 추가로 생성된다.
  • 이 값을 높게 설정하면 필요한 파드를 빨리 생성하므로 파드 교체 시간이 단축된다.
    하지만 필요한 시스템 자원이 급증할 수 있다.

출처) https://gracefullight.dev/2019/12/27/kubernetes-rolling-update/

deployment의 image를 변경했을 때 결과

  • nginx -> nginx:1.9.8
  • kubectl apply -f 로 갱신
  • 기존 replica set은 남아있으면서, 새로운 replica set이 생성
    • 기존 replica set - revision : 1
    • 새로운 replica set - revision : 2
    • kubectl rollout history를 통해 revision 기록을 볼 수 있다.
  > kubectl rollout history deployment/nginx-deployment
  deployment.apps/nginx-deployment 
  REVISION  CHANGE-CAUSE
  1         <none>
  2         <none>
  • pod1 새로 생성 -> 기존 한 개 삭제 / pod2 생성 -> 기존 한 개 삭제 ...
    • 내부적으로 replicaset의 개수를 늘리고, 줄이는 방식으로 pod의 개수를 조절한다.
> kubectl get rs,pod -o wide
NAME                                          DESIRED   CURRENT   READY   AGE     CONTAINERS         IMAGES        SELECTOR
replicaset.apps/nginx-deployment-556d4bf7cb   3         3         2       19s     nginx-deployment   nginx:1.9.8   app=nginx-deployment,pod-template-hash=556d4bf7cb
replicaset.apps/nginx-deployment-dfcbd5fd6    1         1         1       3m25s   nginx-deployment   nginx         app=nginx-deployment,pod-template-hash=dfcbd5fd6

NAME                                    READY   STATUS              RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
pod/nginx-deployment-556d4bf7cb-6bt7g   1/1     Running             0          8s      172.17.0.5   minikube   <none>           <none>
pod/nginx-deployment-556d4bf7cb-8xsjn   1/1     Running             0          19s     172.17.0.4   minikube   <none>           <none>
pod/nginx-deployment-556d4bf7cb-b2n2j   0/1     ContainerCreating   0          4s      <none>       minikube   <none>           <none>
pod/nginx-deployment-dfcbd5fd6-8v4gj    1/1     Running             0          3m25s   172.17.0.8   minikube   <none>           <none>
---
> kubectl get rs,pod -o wide
NAME                                          DESIRED   CURRENT   READY   AGE     CONTAINERS         IMAGES        SELECTOR
replicaset.apps/nginx-deployment-556d4bf7cb   3         3         3       20s     nginx-deployment   nginx:1.9.8   app=nginx-deployment,pod-template-hash=556d4bf7cb
replicaset.apps/nginx-deployment-dfcbd5fd6    0         0         0       3m26s   nginx-deployment   nginx         app=nginx-deployment,pod-template-hash=dfcbd5fd6

NAME                                    READY   STATUS        RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
pod/nginx-deployment-556d4bf7cb-6bt7g   1/1     Running       0          9s      172.17.0.5   minikube   <none>           <none>
pod/nginx-deployment-556d4bf7cb-8xsjn   1/1     Running       0          20s     172.17.0.4   minikube   <none>           <none>
pod/nginx-deployment-556d4bf7cb-b2n2j   1/1     Running       0          5s      172.17.0.2   minikube   <none>           <none>
pod/nginx-deployment-dfcbd5fd6-8v4gj    1/1     Terminating   0          3m26s   172.17.0.8   minikube   <none>           <none>
---
> kubectl get rs,pod -o wide
NAME                                          DESIRED   CURRENT   READY   AGE     CONTAINERS         IMAGES        SELECTOR
replicaset.apps/nginx-deployment-556d4bf7cb   3         3         3       22s     nginx-deployment   nginx:1.9.8   app=nginx-deployment,pod-template-hash=556d4bf7cb
replicaset.apps/nginx-deployment-dfcbd5fd6    0         0         0       3m28s   nginx-deployment   nginx         app=nginx-deployment,pod-template-hash=dfcbd5fd6

NAME                                    READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
pod/nginx-deployment-556d4bf7cb-6bt7g   1/1     Running   0          11s   172.17.0.5   minikube   <none>           <none>
pod/nginx-deployment-556d4bf7cb-8xsjn   1/1     Running   0          22s   172.17.0.4   minikube   <none>           <none>
pod/nginx-deployment-556d4bf7cb-b2n2j   1/1     Running   0          7s    172.17.0.2   minikube   <none>           <none>

이전 replica set으로 롤백하기

kubectl rollout undo deployment/app --to-revision=1

> kubectl rollout history deployment/nginx-deployment             
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
2         <none>
3         <none>
  • 1 REVISION와 같은 Replicaset 이지만, REVISION은 3
  • 기존 Replicaset 재활용한다.
    • 기존 Replicaset의 replica 0 -> 원하는 파드의 개수로 늘린다.
  • 대신 REVISION 1은 없어진다.
    • history에 없는 REVISION으로는 rollback 할 수 없다.
> kubectl rollout undo deployment/nginx-deployment --to-revision=1
error: unable to find specified revision 1 in history

변경될 replica set이 정상이 아니면, 기존 replicaset으로 동작

  • nginx -> nginx:111.1.0 (존재하지 않는 이미지)
  • rolling update를 하다가, 문제가 있을 경우 new replicaset을 배포하려다가 만 상태
    • deployment를 describe해보면, new replicaset의 정보를 담고 있다. (이미지 이름)
    • 하지만 동작은 old replicaset으로 하고 있는 상태
> kubectl get deployment -o wide
NAME               READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS         IMAGES           SELECTOR
nginx-deployment   3/3     1            3           36m   nginx-deployment   nginx:111.11.0   app=nginx-deployment
  • NAME lists the names of the Deployments in the namespace.
  • READY displays how many replicas of the application are available to your users. It follows the pattern ready/desired.
  • UP-TO-DATE displays the number of replicas that have been updated to achieve the desired state.
    • replica 숫자와 일치하면 정상적으로 update된 것
  • AVAILABLE displays how many replicas of the application are available to your users.
    • 위 예시에서는 이전 replica set이 AVAILABLE에 해당하고 있다.
  • AGE displays the amount of time that the application has been running.
profile
IT's 호기심 천국

0개의 댓글