티스토리 뷰
<출처>
https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/
이번 튜토리얼에서는 StatefulSets 을 갖는 어플리케이션을 관리하기 위한 입문서를 제공한다. StatefulSets Pod들에 대한 생성, 삭제, 스케일 그리고 업데이트에 대한 방법을 설명한다.
StatefulSets 개념 간략 정리
먼저 stateful의 정의가 필요하여 구글링 해보니,
"Stateful means the computer or program keeps track of the state of interaction, usually by setting values in a storage field designated for that purpose."
컴퓨터 또는 프로그램이 스토리지 필드에 값을 설정하여, 상호작용에 대한 상태를 지속적으로 기록하는 것을 의미한다고 한다. 이런 개념을 참고하여 계속 진행해보자.
StatefulSet은 stateful한 애플리케이션들을 관리하기 위해 이용되는 작업부하(workload) API 객체다.
주의: StatefulSets은 1.9 GA에서 안정적이다.
일련의 Pods 세트에 대한 배포와 스케일링을 관리하고, 이들 Pod들의 순서와 유일성에 대해 보증해준다.
StatefulSet은 Deployment와 같이, 동일 컨테이너 스펙을 근거로 Pod들을 관리하면서, (한편으로는) Deployment와 달리, 그 Pod들 각각에 대해 끈끈한 동일성(sticky identity)을 유지시켜 준다. 이러한 Pod들은 동일 스펙으로부터 생성되지만, 교체는 불가하다. 그래서 각각의 Pod는 어떠한 재 스케쥴링이 이루어지더라도 유지하려는 지속성있는 동일성을 갖는다.
하나의 StatefulSet은 여타 다른 컨트롤러와 동일한 패턴 하에 운영된다. 여러분은 StatefulSet 객체에 여러분이 의도하는 상태를 정의하고, StatefulSet 컨트롤러는 현재 상태로부터 그 (의도하는) 상태에 도달하기 위해 필요한 어떤 업데이트든 하게될 것이다.
Objectives
StatefulSets 은 stateful 어플리케이션들과 분산시스템들이 함께 이용되도록 의도 되어졌다. 그러나, K8S 에서 stateful 어플리케이션들과 분산시스템들을 관리한다는 것은 광범위하고도 복잡스런 주제이다. StatefulSet 의 기본 특징을 설명하기 위해, 그리고 후자와 전자의 주제가 뒤섞이지 않도록, StatefulSet을 이용하여 간단한 웹 어플리케이션을 배포해 볼 것이다.
이 튜토리얼을 통해, 여러분은 다음에 대해 익숙해지게 될 것이다.
- StatefulSet 생성 방법
- StatefulSet 이 Pod들을 다루는 방법
- StatefulSet 삭제 방법
- StatefulSet 스케일 방법
- StatefulSet 의 Pod들을 업데이트 하는 방법
Before you begin
본 튜토리얼을 시작하기 전에, 여러분은 다음 K8S 개념들에 대해 익숙해야만 한다.
- Pods
- Cluster DNS
- Headless Services
- PersistentVolumes
- PersistentVolume Provisioning
- StatefulSets
- kubectl CLI
본 튜토리얼은 여러분의 클러스터가 동적으로 PersistentVolumes을 제공하도록 구성 되어져 있다고 가정한다. 여러분의 클러스터가 그렇게 처리하도록 구성되어 있지 않다면, 여러분은 이 튜토리얼을 시작하기 전에 1GB 볼륨 2개를 손수 준비해야만 한다.
실습 준비와 관련하여
이번 실습은 구글 클라우드 엔진 환경에서 진행되고 정리되었다. 최초 Minikube 를 통해 진행하는 과정에서 실행결과가 원문과 다르게 나오는 부분(DNS 쿼리결과 등)이 있었고, 검증 차원에서 다시 구글 클라우드 환경에서 진행해 봤는데, 결과는 동일하였다.
여러분이 클라우드 환경에 대한 구성 준비가 안되었다면, Minikube 를 통한 진행도 문제없을 듯 하다. 하지만 이후 진행될 실습 중에서 Minikube 로 진행이 어려운 것들이 등장하기 시작작하니, 이에 대한 준비를 위해서 또는 다양한 환경에 대해 직접 체험을 위해서, 구글 클라우드 클러스터 환경에서 진행해 볼 것을 권장한다.
구글 클러스터 환경 구성 관련해서는 본 튜토리얼에서 다루는 범위에서 벗어나므로 따로 다루지 않을 것이며, 구글 클러스터 생성은 이미 된 것으로 가정하고 진행하겠다.
생성된 클러스터에서 연결을 클릭한다.
혹시 로컬 터미널이 따로 준비 안되어 있거나 클라우드 쉘을 선호하는 경우, "Cloud Shell에서 실행" 을 선택하여 진행한다. 필자는 로컬 터미널 기준으로 진행하였다.
복사한 것을 터미널에 붙여넣고 확인 차원에서 Node 상태를 확인 해본다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | [root@docker-registry ~]# gcloud container clusters get-credentials zerobig-cluster-1 --zone asia-east1-c --project zerobig-k8s-tutorial Fetching cluster endpoint and auth data. kubeconfig entry generated for zerobig-cluster-1. Updates are available for some Cloud SDK components. To install them, please run: $ gcloud components update [root@docker-registry ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION gke-zerobig-cluster-1-default-pool-d22ac19b-4c42 Ready <none> 41m v1.9.7-gke.6 gke-zerobig-cluster-1-default-pool-d22ac19b-7gc1 Ready <none> 41m v1.9.7-gke.6 gke-zerobig-cluster-1-default-pool-d22ac19b-fc6x Ready <none> 41m v1.9.7-gke.6 | cs |
Creating a StatefulSet
하기 예제를 이용하여 StatefulSet 을 생성하는 것으로 시작한다. StatefulSets 개념 편에서 제시된 예제와 유사하다. "web", StatefulSet 내 Pod 들의 IP 주소를 발행하기 위해, "nginx", Headless Service를 생성한다.
(yaml 파일을 생성할 디렉토리를 만들고 그 안에 하기 yaml 파일을 생성한다.)
1 2 | [root@docker-registry ~]# mkdir -p application/web/ [root@docker-registry ~]# vi application/web/web.yaml | cs |
application/web/web.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: "nginx" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: k8s.gcr.io/nginx-slim:0.8 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 1Gi | cs |
위 예제 파일을 다운받아 "web.yaml" 이라는 이름으로 저장한다. (참고로 필자는 k8s/application/web 라는 디렉토리 생성 후 그 밑에 파일을 생성하였다.)
여러분은 두 개의 터미널 창이 필요하게 된다. 첫번 째 창에서 StatefulSet 내 Pod 들의 생성을 지켜보기 위해 "kubectl get"을 수행한다.
1 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx | cs |
두번 째 터미널에서, "web.yaml"에 정의한 Headless Service 와 StatefulSet 을 생성하기 위해 kubectl create 를 이용한다.
1 2 3 4 | [root@docker-registry ~]# cd application/web/ [root@docker-registry web]# kubectl create -f web.yaml service/nginx created statefulset.apps/web created | cs |
1 2 3 4 5 6 | [root@docker-registry web]# kubectl get service nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx ClusterIP None <none> 80/TCP 1m [root@docker-registry web]# kubectl get statefulset web NAME DESIRED CURRENT AGE web 2 2 1m | cs |
Ordered Pod Creation
N 개의 복제본들을 갖는 StatefulSet은, Pod 들이 배포되어질 때, {0..N-1} 의 순서로 순차적으로 생성되어 진다. 첫번 째 터미널 창에서 "kubectl get" 명령의 출력결과를 검토해본다. 결과적으로, 출력은 다음 예시와 같을 것이다.
1 2 3 4 5 6 7 8 9 10 11 12 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 0/1 Pending 0 0s web-0 0/1 Pending 0 0s web-0 0/1 Pending 0 7s web-0 0/1 ContainerCreating 0 7s web-0 1/1 Running 0 31s web-1 0/1 Pending 0 1s web-1 0/1 Pending 0 1s web-1 0/1 Pending 0 8s web-1 0/1 ContainerCreating 0 8s web-1 1/1 Running 0 32s | cs |
"web-1" Pod는"web-0" Pod가 동작 준비(Running and Ready) 상태에 이를 때까지 개시되지 않는다는 점을 주목하자.
Pods in StatefulSet
StatefulSet에서 Pod들은 고유의 순서를 나타내는 인덱스(ordinal index)와 복원력있는(stable) 네트워크 ID를 갖는다.
1 2 3 4 | [root@docker-registry web]# kubectl get pods -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 5m web-1 1/1 Running 0 4m | cs |
StatefulSets 개념에서 언급한 바와 같이, Pod들은 끈끈한(sticky), 유일 ID를 갖는다. 이 ID는 고유한 순서 인덱스를 근거로 한하는데 StatefulSet 컨트롤러에 의해 각 Pod에게 할당되어진다. Pod들의 이름은 "<statefulset name>-<ordinal index>" 의 형식를 취하게 된다. "web" StatefulSet 이 2개의 복제본을 갖으므로, 두 개의 Pod 즉, web-0 와 web-1 을 생성한다.
Using Stable Network Identities
각 Pod는 자신의 순서 인덱스를 근거로 하는 안정적인 호스트네임을 갖는다. 각 Pod에서 "hostname" 명령을 실행하기 위해 kubectl exec
을 이용한다.
1 2 3 | [root@docker-registry web]# for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done web-0 web-1 | cs |
"dnsutils" 패키지로부터 "nslookup" 명령을 제공해주는 컨테이너를 실행하기 위해 kubectl run
을 이용한다. Pod의 호스트네임에 대해 nslookup을 이용하여, 클러스터 내에서의 DNS 주소를 확인해 볼 수 있다.
1 2 3 4 5 6 7 8 9 10 11 | [root@docker-registry web]# kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh If you don't see a command prompt, try pressing enter. / # nslookup web-0.nginx Server: 10.55.240.10 Address: 10.55.240.10:53 ** server can't find web-0.nginx: NXDOMAIN *** Can't find web-0.nginx: No answer / # | cs |
(Minikube에서도 동일하게 DNS 쿼리 결과가 나타나지 않았다. 참고로 원문의 결과는 다음과 같다고 한다.)
headless service 의 CNAME은 SRV 레코드들을 가르킨다 (각 Pod 마다 하나씩 구동 준비된 상태다). SRV 레코드들은 A 레코드를 가르키며 Pod의 IP 주소들을 포함하고 있다.
하나의 터미널에서, StatefulSet의 Pod들을 지켜보자.
1 2 3 4 | [root@docker-registry ~]# kubectl get pod -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 9m web-1 1/1 Running 0 9m | cs |
두번 째 창에서, StatefulSet 내 Pod 룰 삭제하기 위해 kubectl delete
를 사용한다.
1 2 3 | [root@docker-registry web]# kubectl delete pod -l app=nginx pod "web-0" deleted pod "web-1" deleted | cs |
StatefulSet Pod 들을 재시작시키고, 두 Pod가 구동준비 상태로 전이되는 것을 기다린다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | [root@docker-registry ~]# kubectl get pod -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 9m web-1 1/1 Running 0 9m web-0 1/1 Terminating 0 9m web-1 1/1 Terminating 0 9m web-0 0/1 Terminating 0 9m web-1 0/1 Terminating 0 9m web-1 0/1 Terminating 0 9m web-1 0/1 Terminating 0 9m web-0 0/1 Terminating 0 9m web-0 0/1 Terminating 0 9m web-0 0/1 Pending 0 0s web-0 0/1 Pending 0 0s web-0 0/1 ContainerCreating 0 0s web-0 1/1 Running 0 18s web-1 0/1 Pending 0 0s web-1 0/1 Pending 0 0s web-1 0/1 ContainerCreating 0 0s web-1 1/1 Running 0 10s | cs |
Pod의 호스트네임과 클러스터 내의 DNS 엔트리를 확인하기 위해 "kubectl exec" 와 "kubectl run" 을 수행한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | [root@docker-registry web]# for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done web-0 web-1 [root@docker-registry web]# kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh If you don't see a command prompt, try pressing enter. / # nslookup web-0.nginx Server: 10.55.240.10 Address: 10.55.240.10:53 ** server can't find web-0.nginx: NXDOMAIN *** Can't find web-0.nginx: No answer / # | cs |
Pod의 순서, 호스트네임, SRV 레코드들, 그리고 A 레코드 이름은 변경되지 않았지만, Pod와 연관된 IP 주소는 변경 되었을 것이다. 이는 IP 주소로 StatefulSet 내의 Pod에게 접속하기 위해 다른 어플리케이션을 구성하지 않아도 된다는 점이 왜 중요한지를 나타낸다.
여러분이 활동 중인 StatefulSet 맴버를 찾아 접속해야 하는 경우, Headless 서비스 ("nginx.default.svc.cluster.local")의 CNAME을 쿼리해야 한다. CNAME 과 연관된 SRV 레코드들은 StatefulSet 내 오직 동작 준비상태의 Pod만을 포함하게 될 것이다.
여러분의 어플리케이션이 이미 liveness 와 readiness에 대해 테스트하는 접속 로직을 구현된 경우라면, 여러분은 Pod("web-0.nginx.default.svc.cluster.local, web-1.nginx.default.svc.cluster.local")의 SRV 레코드를 이용할 수 있다. SRV 레코드는 안정적이기 때문에, 그것이 동작 준비 상태로 전이될 때 여러분의 어플리케이션이 Pod 의 주소를 찾아낼 수 있을 것이다.
Writing to Stable Storage
"web-0" 와 "web-1" 에 대한 PersistentVolumeClaims 을 확인해 보자.
1 2 3 4 | [root@docker-registry web]# kubectl get pvc -l app=nginx NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE www-web-0 Bound pvc-e52bf0f3-a9e7-11e8-9180-42010af00143 1Gi RWO standard 34m www-web-1 Bound pvc-f77ddbff-a9e7-11e8-9180-42010af00143 1Gi RWO standard 33m | cs |
StatefulSet 컨트롤러는 두 개의 PersistentVolumes에 속해진 두 개의 PersistentVolumeClaims을 생성한다. 이 튜토리얼에서 사용한 클러스터는 동적으로 PersistentVolumes이 준비되도록 구성되어 있으므로, PersistentVolume이 동적으로 생성되어 묶여졌다.
NGINX 웹서버는, 기본적으로, "/usr/share/nginx/html/index.html" 에 위치한 index 파일을 서비스로 제공할 것이다. StatefulSets "spec" 내 "volumeMounts" 필드는 "/usr/share/nginx/html" 디렉토리 뒤에 PersistentVolume이 위치하도록 보장해준다.
Pod의 호스트네임을 "index.html" 파일에 기록하고 NGINX 웹서버가 호스트네임을 제공하는지 검증해 보자.
1 2 3 4 | [root@docker-registry web]# for i in 0 1; do kubectl exec web-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; done [root@docker-registry web]# for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done web-0 web-1 | cs |
주의: 위 curl 명령에 대해 403 사용권한 없음이 나타난다면, curl 명령을 다시 수행해보기 전에, 다음 명령으로 "volumeMounts" (bug when using hostPath volumes 와 같은 사유로) 에 의해 마운트된 디렉토리의 퍼미션을 수정해야 할 것이다.
1 [root@docker-registry web]# for i in 0 1; do kubectl exec web-$i -- chmod 755 /usr/share/nginx/html; donecs
하나의 터미널에서, StatefulSet 들의 Pod를 지켜본다.
1 2 3 4 | [root@docker-registry ~]# kubectl get pod -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 28m web-1 1/1 Running 0 27m | cs |
다른 터미널에서, StatefulSet의 Pod를 지운다.
1 2 3 | [root@docker-registry web]# kubectl delete pod -l app=nginx pod "web-0" deleted pod "web-1" deleted | cs |
첫번 째 터미널에서 "kubectl get" 명령의 출력을 검사해보고, 모든 Pod가 동작 준비로 전이될 때가지 기다린다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | [root@docker-registry ~]# kubectl get pod -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 28m web-1 1/1 Running 0 27m web-0 1/1 Terminating 0 28m web-1 1/1 Terminating 0 28m web-1 0/1 Terminating 0 28m web-0 0/1 Terminating 0 28m web-0 0/1 Terminating 0 28m web-0 0/1 Terminating 0 28m web-0 0/1 Pending 0 0s web-0 0/1 Pending 0 0s web-0 0/1 ContainerCreating 0 0s web-0 1/1 Running 0 7s web-1 0/1 Terminating 0 28m web-1 0/1 Terminating 0 28m web-1 0/1 Pending 0 0s web-1 0/1 Pending 0 0s web-1 0/1 ContainerCreating 0 0s web-1 1/1 Running 0 11s | cs |
웹 서버가 계속해서 호스트네임을 제공하는지 검증한다.
1 2 3 | [root@docker-registry web]# for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done web-0 web-1 | cs |
"web-0"과 "web-1"이 다시 스케쥴되었지만, "volumeMounts"에 다시 마운트 되어진 PersistentVolumeClaims과 연관된 PersistentVolumes 덕택으로 웹서버는 계속하여 호스트네임을 제공하고 있다. node "web-0" 와 "web-1" 어디에 스케쥴이 이루어지더라도, 그것들의 PersistentVolumes은 적절한 마운트 포인트에 마운트 되어질 것이다.
Scaling a StatefulSet
StatefulSet을 스케일링 하는 것은 복제본의 수를 늘리거나 줄이는 것을 의미한다. 이것은 "replicas" 필드를 업데이트하는 것으로 이루어진다. 여러분은 StatefulSet 을 스케일하기 위해 kubectl scale
또는 kubectl patch
를 이용할 수 있다.
Scaling Up
하나의 터미널 창에서, StatefulSet 들의 Pod를 지켜본다.
1 2 3 4 | [root@docker-registry ~]# kubectl get pod -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 1m web-1 1/1 Running 0 1m | cs |
다른 터미널 창에서, 복제본의 수를 5로 스케일 하기 위해 kubectl scale 을 이용한다.
1 2 | [root@docker-registry web]# kubectl scale sts web --replicas=5 statefulset.apps/web scaled | cs |
첫번 째 터미널에서 kubectl get
명령의 결과를 조사해 보고 3개의 추가된 Pod가 동작 준비 상태로 전이될 때까지 대기한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [root@docker-registry ~]# kubectl get pod -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 1m web-1 1/1 Running 0 1m web-2 0/1 Pending 0 0s web-2 0/1 Pending 0 0s web-2 0/1 Pending 0 7s web-2 0/1 ContainerCreating 0 7s web-2 1/1 Running 0 18s web-3 0/1 Pending 0 0s web-3 0/1 Pending 0 0s web-3 0/1 Pending 0 7s web-3 0/1 ContainerCreating 0 7s web-3 1/1 Running 0 17s web-4 0/1 Pending 0 1s web-4 0/1 Pending 0 1s web-4 0/1 Pending 0 8s web-4 0/1 ContainerCreating 0 8s web-4 1/1 Running 0 32s | cs |
StatefulSet controller는 복제본의 수를 스케일 해줬다. StatefulSet creation과 같이, StatefulSet controller는 Pod 의 순서 인덱스에 맞게 순차적으로 각 Pod를 생성하였다. 그리고 후속되는 Pod는 개시하기 전에 각 Pod의 전임 Pod 가 동작 준비 상태가 되도록 기다렸다.
Scaling Down
하나의 터미널 창에서, StatefulSet의 Pod를 지켜본다.
1 2 3 4 5 6 7 | [root@docker-registry ~]# kubectl get pod -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 3m web-1 1/1 Running 0 3m web-2 1/1 Running 0 1m web-3 1/1 Running 0 1m web-4 1/1 Running 0 50s | cs |
"web-4"
와 "web-3"
이 종료 상태로 전이되는 것을 기다린다.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | [root@docker-registry ~]# kubectl get pod -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 3m web-1 1/1 Running 0 3m web-2 1/1 Running 0 1m web-3 1/1 Running 0 1m web-4 1/1 Running 0 50s web-4 1/1 Terminating 0 1m web-4 0/1 Terminating 0 1m web-4 0/1 Terminating 0 1m web-4 0/1 Terminating 0 1m web-3 1/1 Terminating 0 1m web-3 0/1 Terminating 0 1m web-3 0/1 Terminating 0 1m web-3 0/1 Terminating 0 1m | cs |
Ordered Pod Termination
컨트롤러는 순서 인덱스에 대한 역순으로, 한번에 하나의 Pod 를 삭제했고 다음 Pod를 삭제하기 전에 각 Pod의 완전한 중지가 이루어 질때가지 대기했다.
StatefulSet의 PersistentVolumeClaims을 확인해 보자.
1 2 3 4 5 6 7 | [root@docker-registry web]# kubectl get pvc -l app=nginx NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE www-web-0 Bound pvc-e52bf0f3-a9e7-11e8-9180-42010af00143 1Gi RWO standard 44m www-web-1 Bound pvc-f77ddbff-a9e7-11e8-9180-42010af00143 1Gi RWO standard 44m www-web-2 Bound pvc-a03c59ca-a9ed-11e8-9180-42010af00143 1Gi RWO standard 3m www-web-3 Bound pvc-ab07cb9a-a9ed-11e8-9180-42010af00143 1Gi RWO standard 3m www-web-4 Bound pvc-b5579be1-a9ed-11e8-9180-42010af00143 1Gi RWO standard 3m | cs |
여전히 다섯 개의 PersistentVolumeClaims와 다섯 개의 PersistentVolumes들이 존재한다. Pod의 stable storage 를 살펴보면, StatefulSet의 Pod들이 삭제될 때 삭제되지 않았던 StatefulSet의 Pod들에게 PersistentVolumes에 마운트 되어진 것을 볼 수 있다. 이것은 Pod 삭제가 StatefulSet에 대한 스케일링 다운(규모 축소)으로부터 기인됨이 여전히 사실임을 말해준다.
Updating StatefulSets
K8S 1.7 이상에서, StatefulSet 컨트롤러는 자동화 업데이트를 지원한다. StatefulSet API 객체의 "spec.updateStrategy" 필드에 의해 이용되는 전략이 결정되어 진다. 이 기능은 컨트롤러 이미지, 자원 요청 그리고/또는 StatefulSet 내 Pod들에 대한 제한, 레이블, 그리고 주석들을 업그레이드 하는데 이용될 수 있다. 두 개의 유효한 업데이트 전략들이 있는데, "RollingUpdate" 와 "OnDelete" 이 그것이다.
"RollingUpdate" 업데이트 전략은 StatefulSets 이 기본값이다.
Rolling Update
"RollingUpdate" 업데이트 전략은 StatefulSet에 대한 보장을 중시하면서, 순서 인덱스의 역순으로 StatefulSet 내의 모든 Pod를 업데이트할 것이다.
"RollingUpdate" 업데이트 전략을 적용하기 위해 "web"
StatefulSet를 패치하자.
1 2 | [root@docker-registry web]# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}' statefulset.apps/web not patched | cs |
터니널 창 하나에서, 다시 컨테이너 이미지를 변경하기 위해 "web"
StatefulSet을 패치 한다.
1 2 | [root@docker-registry web]# kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.8"}]' statefulset.apps/web patched | cs |
또 다른 창에서, StatefulSet의 Pod를 지켜보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | [root@docker-registry ~]# kubectl get pod -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 22m web-1 1/1 Running 0 22m web-2 0/1 ContainerCreating 0 8s web-2 1/1 Running 0 19s web-1 1/1 Terminating 0 22m web-1 0/1 Terminating 0 22m web-1 0/1 Terminating 0 22m web-1 0/1 Terminating 0 22m web-1 0/1 Pending 0 0s web-1 0/1 Pending 0 1s web-1 0/1 ContainerCreating 0 1s web-1 1/1 Running 0 20s web-0 1/1 Terminating 0 23m web-0 0/1 Terminating 0 23m web-0 0/1 Terminating 0 23m web-0 0/1 Terminating 0 23m web-0 0/1 Pending 0 0s web-0 0/1 Pending 0 0s web-0 0/1 ContainerCreating 0 0s web-0 1/1 Running 0 10s | cs |
StatefulSet 내 Pod는 순서 인덱스의 역순으로 업데이트 된다. StatefulSet 컨테이너는 각 Pod를 종료시키고 다음 Pod를 업데이트하기 이전에 Pod가 동작 준비상태로 전이되는 것을 기다린다. 비록 StatefulSet controller는 뒤 순서의 Pod가 동작 준비 상태가 될 때까지 다음 Pod 업데이트를 진행시키지 않겠지만, 현재 버전을 업데이트 하는 동안 실패가 발생한 어떤 Pod에 대해서라도 복구처리 해줄 것임을 주목하자. 이미 업데이트 처리된 Pod는 업데이트 된 버전으로 복구되어질 것이며, 아직 업데이트 처리되지 않은 Pod는 이전 버전으로 복구되어질 것이다. 이런식으로, 컨트롤러는 애플리케이션의 건강상태를 유지해주고 간헐적 실패들이 존재하는 상황에서도 업데이트가 지속될 수 있도록 시도할 것이다.
Pod들의 컨테이너 이미지를 확인해 보자.
1 2 3 4 | [root@docker-registry web]# for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done gcr.io/google_containers/nginx-slim:0.8 gcr.io/google_containers/nginx-slim:0.8 gcr.io/google_containers/nginx-slim:0.8 | cs |
StatefulSet의 모든 Pod는 이제 이전 컨테이너 이미지로 동작 중이다.
팁 여러분은 롤링 업데이트의 상태를 확인하기 위해 "kubectl rollout status sts/<name>" 도 이용할 수 있다
Staging an Update
"RollingUpdate" 업데이트 전략의 "partition" 파라미터를 이용하여 StatefulSet 에 업데이트를 공개할 수 있다.
공개된 업데이트는 StatefulSet의 ".spec.template"에 대해 변화를 허용하면서 현재 버전의 StatefulSet 내 모든 Pod를 유지시켜 줄 것이다.
"PupdateStrategy" 필드에 파티션을 추가하기 위해 web StatefulSet을 패치하자.
1 2 | [root@docker-registry web]# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}' statefulset.apps/web patched | cs |
컨테이너의 이미지를 변경하기 위해 다시 StatefulSet을 패치하자.
1 2 | [root@docker-registry web]# kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]' statefulset.apps/web patched | cs |
StatefulSet 내 Pod 하나를 삭제한다.
1 2 | [root@docker-registry web]# kubectl delete po web-2 pod "web-2" deleted | cs |
Pod 가 동작 준비 상태에 이르길 기다린다.
1 2 3 4 5 6 7 8 9 10 11 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 5m web-1 1/1 Running 0 5m web-2 0/1 Terminating 0 6m web-2 0/1 Terminating 0 6m web-2 0/1 Terminating 0 6m web-2 0/1 Pending 0 0s web-2 0/1 Pending 0 0s web-2 0/1 ContainerCreating 0 0s web-2 1/1 Running 0 10s | cs |
Pod의 컨테이너를 확인해 본다.
1 2 | [root@docker-registry web]# kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}' gcr.io/google_containers/nginx-slim:0.8 | cs |
다음을 주의하자. 비록 업데이트 전략이 "RollingUpdate" 라 할지라도, StatefulSet controller는 원래 컨테이너를 갖는 Pod를 복원시켰다. 이는 Pod의 순서가 "updateStrategy" 에 의해 정의한 "partition" 보다 더 적기 때문이다.
Rolling Out a Canary
여러분은 위에서 지정했던 "partition"을 감소시켜 수정하는 테스트를 위해 canary 를 배포할 수 있다.
partition을 감소시키기 위해 StatefulSet 을 패치한다.
1 2 | [root@docker-registry web]# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}' statefulset.apps/web patched | cs |
"web-2" 가 동작 준비상태가 되기를 기다린다.
1 2 3 4 5 6 7 8 9 10 11 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 7m web-1 1/1 Running 0 8m web-2 0/1 Terminating 0 2m web-2 0/1 Terminating 0 2m web-2 0/1 Terminating 0 2m web-2 0/1 Pending 0 0s web-2 0/1 Pending 0 0s web-2 0/1 ContainerCreating 0 0s web-2 1/1 Running 0 13s | cs |
Pod의 컨테이너를 확인해 본다.
1 2 | [root@docker-registry web]# kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}' k8s.gcr.io/nginx-slim:0.7 | cs |
"partition"을 변경할 때, StatefulSet 컨트롤러는 Pod의 순서값이 "partition" 의 값 이상이었기 때문에 자동으로 "web-2" 를 업데이트 시켰다.
"web-1" 를 삭제한다.
1 2 | [root@docker-registry web]# kubectl delete po web-1 pod "web-1" deleted | cs |
"web-1" 이 동작 준비 상태가 되기를 기다린다.
1 2 3 4 5 6 7 8 9 10 11 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 10m web-1 0/1 Terminating 0 10m web-2 1/1 Running 0 2m web-1 0/1 Terminating 0 10m web-1 0/1 Terminating 0 10m web-1 0/1 Pending 0 0s web-1 0/1 Pending 0 0s web-1 0/1 ContainerCreating 0 0s web-1 1/1 Running 0 10s | cs |
"web-1" Pod의 컨테이너를 확인해 본다.
1 2 | [root@docker-registry web]# kubectl get po web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}' gcr.io/google_containers/nginx-slim:0.8 | cs |
"web-1" 은 Pod의 순서값이 partition 보다 작았으므로 원래 설정으로 복원되었다. 임의의 partition이 지정되어 질때, 그 partition 이상의 순서값을 갖는 모든 Pod들은 StatefulSet의 ".spec.template" 이 업데이트 될때, 업데이트가 이루어질 것이다. 만약 어떤 Pod가 그 partition 보다 작은 값을 갖고 있다면, 삭제되거나 종료되버고, 원래의 구성으로 복원될 것이다.
Phased Roll Outs
여러분은 canary를 배포했던 방법과 유사한 방식으로 분할된 롤링 업데이트를 이용하여 단계별 배포(가령, 선형적, 기하학적, 기하급수적 배포)를 이행할 수 있다. 단계별 배포를 이행하기 위해, 업데이트를 정지시키려는 컨트롤러에서 "partition" 에 순서를 설정한다.
현재 partition은 2다, 0으로 설정한다.
1 2 | [root@docker-registry web]# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}' statefulset.apps/web patched | cs |
StatefulSet 내 Pod가 동작 준비 상태가 되기를 기다린다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 11m web-1 0/1 Terminating 0 1m web-2 1/1 Running 0 3m web-1 0/1 Terminating 0 1m web-1 0/1 Terminating 0 1m web-1 0/1 Pending 0 0s web-1 0/1 Pending 0 0s web-1 0/1 ContainerCreating 0 0s web-1 1/1 Running 0 21s web-0 1/1 Terminating 0 12m web-0 0/1 Terminating 0 12m web-0 0/1 Terminating 0 12m web-0 0/1 Terminating 0 12m web-0 0/1 Pending 0 0s web-0 0/1 Pending 0 0s web-0 0/1 ContainerCreating 0 0s web-0 1/1 Running 0 18s | cs |
Pod의 컨테이너를 확인해 본다.
1 2 3 4 | [root@docker-registry web]# for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done k8s.gcr.io/nginx-slim:0.7 k8s.gcr.io/nginx-slim:0.7 k8s.gcr.io/nginx-slim:0.7 | cs |
By moving the "partition"을 0로 변경함으로써, 여러분은 StatefulSet 컨트롤러가 업데이트 프로세스를 계속할 수 있도록 허용하였다.
On Delate
OnDelete" 업데이트 전략은 레거시(1.6 이전) 방식을 이행하는데, 여러분이 이 업데이트 전략을 선택하면, StatefulSet 컨트롤러는 StatefulSet의 ".spec.template" 필드에 수정이 일어날 경우, 자동으로 Pod를 업데이트하지 않을 것이다. 이 전략은 ".spec.template.updateStrategy.type" 을 "OnDelete" 으로 설정함으로써 선택되어질 수 있다.
Deleting StatefulSets
StatefulSet은 비종속과 종속 삭제 모두를 지원한다. 비종속 삭제 방식에서, StatefulSet의 Pod는 StatefulSet이 삭제될때 삭제되지 않는다. 종속삭제 방식의 경우에는 StatefulSet 과 그 Pod 둘 다 삭제된다.
Non-Cascading Delete
터미널 창 하나에서, StatefulSet 내 Pod를 지켜본다.
1 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx | cs |
StatefulSet 삭제를 위해 kubectl delete 을 이용한다
. 명령어에 "--cascade=false" 파라미터를 넣어줘야 함을 주의한다. 이 파라미터는 K8S에게 Pod들은 지우지 삭제하지 말고 오직 StatefulSet만 지우도록 알려준다.
1 2 | [root@docker-registry web]# kubectl delete statefulset web --cascade=false statefulset.apps "web" deleted | cs |
Pod의 상태를 조사해 본다.
1 2 3 4 5 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 1m web-1 1/1 Running 0 2m web-2 1/1 Running 0 6m | cs |
"web"이 삭제되버렸지만, 모든 Pod는 여전히 동작 준비 상태에 있다. "web-0"을 삭제한다.
1 2 | [root@docker-registry web]# kubectl delete pod web-0 pod "web-0" deleted | cs |
StatefulSet의 Pod를 확인한다.
1 2 3 4 5 6 7 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 0/1 Terminating 0 2m web-1 1/1 Running 0 3m web-2 1/1 Running 0 7m web-0 0/1 Terminating 0 2m web-0 0/1 Terminating 0 2m | cs |
"web"
StatefulSet이 삭제되버렸기 때문에, "web-0" 는 다시 시작되지 않았다.
하나의 터미널에서, StatefulSet 내 Pod를 지켜본다.
1 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx | cs |
두번 째 터미널에서, StatefulSet을 재생성한다. 다음을 주의하자. 여러분이 "nginx" 서비스를 삭제하지 않았다면(여러분이 그리하지 말았어야 하는), 이미 존재하는 서비스를 알리는 에러를 볼 수 있을 것이다.
[root@docker-registry web]
# kubectl create -f web.yaml
statefulset.apps
/web
created
Error from server (AlreadyExists): error when creating
"web.yaml"
: services
"nginx"
already exists
에러는 무시한다. 서비스가 이미 존재한다 하더라도 nginx Headless 서비스를 생성하기 위해 만들어 진 의도를 나타낼 뿐이다.
첫번 째 터미널에서 수행한 "kubectl get" 명령의 출력을 조사해 본다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 0/1 ContainerCreating 0 2s web-1 1/1 Running 0 8m web-2 1/1 Running 0 12m web-0 1/1 Running 0 11s web-2 1/1 Terminating 0 12m web-2 0/1 Terminating 0 12m web-2 0/1 Terminating 0 12m web-2 0/1 Terminating 0 12m web-1 1/1 Terminating 0 8m web-1 0/1 Terminating 0 8m web-1 0/1 Terminating 0 8m web-1 0/1 Terminating 0 8m web-1 0/1 Pending 0 0s web-1 0/1 Pending 0 0s web-1 0/1 ContainerCreating 0 0s web-1 1/1 Running 0 19s | cs |
"web" StatefulSet이 재생성 될 때, 먼저 "web-0"을 재시작했다. "web-1" 이 이미 동작 준비 상태였기 때문인데, "web-0"가 동작 준비 상태로 전이될 때, 그저 이 Pod를 채택했던 것이다. "replicas" 가 2인 StatefulSet을 재생성 했기 때문에, 일단 "web-0" 재생성 되어졌고, "web-1"이 이미 동작 준비 상태로 결정되어 버렸다면, "web-2"가 종료되었다.
Pod의 웹서버에 의해 제공되었던 "index.html" 의 내용들을 살펴보자.
1 2 3 | [root@docker-registry web]# for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done web-0 web-1 | cs |
비록 여러분이 StatefulSet과 "web-0"
Pod 둘다 삭제하였다 하더라도, 원래 "index.html" 안에 들어 있는 호스트네임을 제공할 것이다. 이것은 StatefulSet이 Pod에 연계된 PersistentVolumes을 결코 삭제하지 않기 때문이다. StatefulSet을 재생성하고 "web-0"를 재시작할 때, 원래 PersistentVolume이 다시 마운트되어 졌다.
Cascading Delete
하나의 터미널 창에서, StatefulSet 내 Pod를 지켜본다.
1 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx | cs |
또 다른 터미널에서, StatefulSet을 다시 삭제한다. 이번에는, "–cascade=false" 파라미터를 생략한다.
1 2 | [root@docker-registry web]# kubectl delete statefulset web statefulset.apps "web" deleted | cs |
첫번 째 터미널에서 수행한 "kubectl get" 명령의 출력을 조사해 본다. 그리고 모든 Pod들이 종료상태로 전이되는 것을 기다린다.
1 2 3 4 5 6 7 8 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 0/1 Terminating 0 2m web-1 0/1 Terminating 0 2m web-0 0/1 Terminating 0 2m web-0 0/1 Terminating 0 2m web-1 0/1 Terminating 0 2m web-1 0/1 Terminating 0 2m | cs |
Scaling Down 섹션에서 보았듯이, Pod는그것들의 순서 색인의 역순으로 한번에 하나씩 종료된다. Pod를 종료하기 전에, StatefulSet 컨트롤러는 해당 Pod의 후속 Pod가 완전히 종료되는 것을 기다려 준다.
다음을 주목한다. 종속삭제가 StatefulSet과 그것의 Pod들을 지우는 동안에, StatefulSet 과 연계된 Headless 서비스는 삭제하지 않을 것이므로, 여러분은 "nginx" 서비스를 수동으로 삭제 해줘야 한다.
1 2 | [root@docker-registry web]# kubectl delete service nginx service "nginx" deleted | cs |
StatefulSet과 Headless 서비스를 한번 더 재생성 한다.
1 2 3 | [root@docker-registry web]# kubectl create -f web.yaml service/nginx created statefulset.apps/web created | cs |
StatefulSet의 모든 Pod가 동작 준비 상태로 전이될 때, 그것들의 "index.html" 내용을 다시 불러온다.
1 2 3 | [root@docker-registry web]# for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done web-0 web-1 | cs |
비록 여러분이 완전하게 StatefulSet 과 그것의 모든 Pod를 삭제하였다 할지라도, Pod들은 자신들의 PersistentVolumes을 마운트하여 재생성 되어지고, "web-0"와
"web-1"은 자신들의 호스트네임을 여전히 제공할 것이다.
마지막으로 "web"
StatefulSet과 "nginx" 서비스를 삭제한다.
1 2 3 4 | [root@docker-registry web]# kubectl delete service nginx service "nginx" deleted [root@docker-registry web]# kubectl delete statefulset web statefulset.apps "web" deleted | cs |
Pod Management Policy
일분 분산시스템들에 대해서는, StatefulSet의 순서 보장이 불필요하고/하거나 바람직스럽지 않을 수 있다. 이러한 시스템들은 오직 유일성과 정체성만을 요구한다. K8S 1.7 에서 이와 관련해 다루기 위해, 우리는 StatefulSet API 객체에 대한 ".spec.podManagementPolicy" 를 소개한 바 있다.
OrderedReady Pod Management
StatefulSet 컨트롤러가 위에서 시연했던 순서보장을 중요시함을 말해준다."OrderedReady"
pod 관리는 StatefulSets에 대해 기본사항이다.
Parallel Pod Management
"Parallel"
pod 관리는 StatefulSet 컨트롤러에게 병렬로 모든 Pod들을 개시 또는 종료하도록 전하고, 다른 Pod가 개시되거나 종료되기 이전에 동작 준비 또는 완전 종료상태가 되는 것을 기다리지 않게 한다.
1 | [root@docker-registry web]# vi web-parallel.yaml | cs |
application/web/web-parallel.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: "nginx" podManagementPolicy: "Parallel" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: k8s.gcr.io/nginx-slim:0.8 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 1Gi | cs |
위 예제를 다운로드 하여, 파일이름을 "web-parallel.yaml"로 해서 저장한다.
이 manifest는 "webStatefulSet " 의 ".spec.podManagementPolicy" 을 "Parallel"로 설정하는 부분을 빼고는 여러분의 위에서 다운받았던 것이라 동일하다.
하나의 터미널에서, StatefulSet 내 Pod를 지켜본다.
1 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx | cs |
또 다른 터미널에서, manifest 내 StatefulSet과 서비스를 생성한다.
1 2 3 | [root@docker-registry web]# kubectl create -f web-parallel.yaml service/nginx created statefulset.apps/web created | cs |
첫번 째 터미널에서 여러분이 수행한 "kubectl get" 명령의 출력을 조사해 본다.
1 2 3 4 5 6 7 8 9 10 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 0/1 Pending 0 0s web-0 0/1 Pending 0 0s web-1 0/1 Pending 0 0s web-1 0/1 Pending 0 0s web-0 0/1 ContainerCreating 0 0s web-1 0/1 ContainerCreating 0 0s web-1 1/1 Running 0 10s web-0 1/1 Running 0 18s | cs |
StatefulSet 컨트롤러가 동시에 "web-0"과 "
web-1"에서 개시되었다.
두번 째 터미널을 열어두고, 또 다른 터미널 창에서 StatefulSet을 스케일링한다.
1 2 | [root@docker-registry web]# kubectl scale statefulset/web --replicas=4 statefulset.apps/web scaled | cs |
"kubectl get" 명령이 수행되고 있는 창의 출력을 조사해 본다.
1 2 3 4 5 6 7 8 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 1m web-1 1/1 Running 0 1m web-2 0/1 ContainerCreating 0 2s web-3 0/1 ContainerCreating 0 2s web-3 1/1 Running 0 11s web-2 1/1 Running 0 11s | cs |
StatefulSet 컨트롤러가 새로운 두 개의 Pod들을 개시하였고, 두번 째가 개시되기 전에 첫번 째가 동작 준비 상태가 되는 것을 기다리지 않았다.
이 터미널을 유지하고, 다른 터미널에서 "web" StatefulSet을 삭제한다.
1 2 | [root@docker-registry web]# kubectl delete sts web statefulset.apps "web" deleted | cs |
다시, 다른 터미널에서 동작중인 "kubectl get"의 출력을 조사해 본다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [root@docker-registry ~]# kubectl get pods -w -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Terminating 0 2m web-2 1/1 Terminating 0 1m web-1 1/1 Terminating 0 2m web-3 1/1 Terminating 0 1m web-1 0/1 Terminating 0 2m web-3 0/1 Terminating 0 1m web-0 0/1 Terminating 0 2m web-2 0/1 Terminating 0 1m web-0 0/1 Terminating 0 2m web-0 0/1 Terminating 0 2m web-2 0/1 Terminating 0 1m web-2 0/1 Terminating 0 1m web-1 0/1 Terminating 0 2m web-1 0/1 Terminating 0 2m web-3 0/1 Terminating 0 1m web-3 0/1 Terminating 0 1m | cs |
StatefulSet 컨트롤러는 동시에 모든 Pod를 삭제한다. Pod를 삭제하기에 앞서 하나의 Pod의 순서에 뒤 따르는 Pod가 종료되는 것을 가다리지 않고 있다.
"kubectl get" 명령어가 동작하고 있는 터미널을 닫고 "nginx" 서비스를 삭제한다.
1 2 | [root@docker-registry web]# kubectl delete svc nginx service "nginx" deleted | cs |
Cleaning up
이번 튜토리얼에서 이용된 PersistentVolumes 에 대한 영구 스토리지 매체를 삭제해야 할 것이다. 모든 스토리지가 반환되어지는 것을 분명히하기 위해, 환경, 스토리지 구성 그리고 프로비저닝 방법을 기준으로, 필요한 조치들을 따른다.