6장 컨트롤러 - 1,2,3절

최시원·2023년 3월 27일
0

쿠버네티스 입문

목록 보기
5/7

지난번 발생한 오류 해결

minikube와 docker desktop을 같이 설치하여 발생한 오류이다. 이 경우 kubectl이 기본으로 바라보는 클러스터가 minikube가 생성한 것이기 때문이다.

kubectl config get-contexts

명령어로 이를 확인해보면, '*' 표시가 minikube에 찍혀있음을 확인할 수 있다.

이를

kubectl config use-context docker-desktop

명령어로 docker-desktop을 기본으로 보게끔 지정해주면 해결할 수 있다.

컨트롤러Controller는 파드Pod들을 관리하는 역할을 한다.

오랜 시간동안 계속 실행되어야 할 파드들 - 레플리케이션 컨트롤러, 레플리카셋, 디플로이먼트
클러스터의 전체 노드에 같은 파드를 실행할 때 - 데몬세트
사용하는 컨테이너를 상태가 있는 statefull 앱을 실행할때 사용하도록 할때 - 스테이트풀세트
1회성 작업 - 잡
주기적인 배치작업을 실행할때 - 크론잡cronjob

6.1 레플리케이션 컨트롤러

쿠버네티스 프로젝트의 초기부터 있었던 가장 기본적인 컨트롤러이다.
지정한 숫자만큼의 파드가 항상 클러스터 안에서 실행되도록 관리한다.
ex) 파드 2개를 명시해둔 레플리케이션 컨트롤러가 있다면 장애나 다른 이유로 파드 개수가 2개보다 적을때 다시 새로운 파드를 실행해 개수를 항상 2개로 맞춘다. 이보다 많아져도 마찬가지이다.

컨트롤러를 사용하지 않고 파드를 직접 실행한다면 파드에 이상이 생겨 종료/삭제되었을 때 재시작하기 어렵다. 파드를 실행하던 노드에 장애가 발생해 파드가 종료되었을 때, 이 레플리케이션 컨트롤러를 이용해 실행한 파드라면 클러스터 안 다른 정상적인 노드에 파드를 다시 실행시킨다.

레플리케이션 컨트롤러는 쿠버네티스에 처음부터 있었으나, 요즘은 비슷한 역할을 하는 레플리카세트를 사용한다. 앱의 배포에는 디플로이먼트를 주로 사용한다.

6.2 레플리카세트

레플리케이션 컨트롤러의 발전형이다. 같은 동작을 하지만 집합기반set-based의 셀렉터selector를 지원하는 차이점이 존재한다.
ex) 레-컨트롤러는 셀렉터가 등호기반equality-based이므로 레이블을 선택할때 같은지 다른지(= or !=) 만 확인한다. 하지만 집합 기반 셀렉터는 in, notin, exists와 같은 연산자를 지원한다.

또한 레-컨트롤러는 kubectl에서 rolling-update 옵션을 사용할 수 있으나, 레플리카세트는 사용할수 없다. 만약 rolling-update 옵션이 필요할때는 디플로이먼트를 사용해야 한다.

레플리카세트 사용하기

탬플릿 예시yaml파일을 참고하며 레플리카세트의 파드 관리 예시를 보자

apiVersion: apps/v1
kind: ReplicaSet
metadata:
	name: nginx-replicaset
spec:
	template:	------------------------- 1
    	metadata:
        	name: nginx-replicaset
            labels:
            	app: nginx-replicaset
		spec:	------------------------- 2
        	containers:
            - name: nginx-replicaset
              image: nginx
              ports:
              - containerPort: 80
	replicas: 3	------------------------- 3
    selector:	------------------------- 4
    	matchLabels:
        	app: nginx_replicaset
  1. 자세한 명세는 .spec 필드에 설정한다. .spec.template 필드에는 레플리카세트가 어떤 파드를 실행할지에 관한 정보를 설정한다.
    그래서 이 하위필드로 .metadata와 .spec이라는 필드가 있다. 여기에서는 파드 이름으로 nginx-replicaset, 오브젝트를 식별하는 레이블이 앱 컨테이너고 nginx-replicaset라고 식별함을 설정하였다. 파드탬플릿에 설정하는 내용과 동일하다고 기억하자

  2. .sepc.template.spec.containers[] 필드는 하위에 .name, .image, .ports[], .containersPort 필드를 이용해 컨테이너의 구체적 명세를 설정한다

  3. spec.replicas는 파드를 몇개 유지할지 설정한다. 기본값은 1이며 예시에선 3으로 설정되었다.

  4. .spec.selector는 어떤 레이블(.labels) 의 파드를 선택해서 관리할지 설정한다. 레이블을 기준으로 파드를 관리하므로 실행중인 파드를 중단하거나 재시작하지 않고 레플리케이션 컨트롤러가 관리하는 파드를 변경할 수 있다. 따라서 최초 레플리케이션 컨트롤러를 생성시에 .spec.template..metadat.labels의 하위필드 설정과 .spec.selector.matchLabels의 하위필드 설정이 같아야 한다. 만약 이것이 다르다면 kube-apiserver에서 유효하지 않은 요청으로 판단하여 파드변경을 거부한다. 탬플릿에 별도설정이 없다면 .spec.template..metadat.labels.app에 있는 내용을 기본값으로 설정한다.

예시 코드를 저장하고

kubectl apply -f replicaset-nginx.yaml

명령어로 클러스터에 저장하자. 그리고 kubectl get pods 명령으로 현재 파드정보를 확인한다.

위 과정을 실습한 내용이다

replicas: 3으로 설정하였기 때문에 3개가 만들어진 모습이다.

이후 delete 명령으로 pod 하나를 지우려고 해 보았다.

djp5t는 지워졌지만 replicaset에 지정한 내용대로 3개의 pod를 유지해야 하기 때문에 새로이 48gwg가 만들어진 모습이다.

그럼 pod 개수를 조정하려면 어떻게 해야 하는가? replicaset-nginx.yaml 파일 안의 .spec.replicas 필드 값을 조정한 후 다시 apply 명령을 실행해주면 된다. 2로 수정해보겠다.

수정한 대로 pod개수가 2개가 되어 있는 모습니다.

레플리카세트와 파드의 연관 관계

파드는 레이블 기준으로 관리하므로 레플리카세트와 느슨히 결합되어 있다.
다시 말해 레플리카세트와 파드를 한꺼번에 삭제할 때는

kubectl delete replicaset [컨테이너이름]

명령을 실행하면 된다.
그럼 레플리카세트가 관리하는 파드에 영향을 미치지 않고 레플리카세트만 따로 삭제하고 싶을때는? --cascade=orphan 옵션을 사용하면 된다.

--cascade=orphan 옵션을 적용한 후 다시 replicaset-nginx.yaml 파일을 apply 시켜 확인한 결과다. pods를 하나 지워도 새로 만들어 기존에 설정된 파드의 개수 2개를 맞추는 것이 보인다. 새로 만들어진 replicaset이라도 기존의 pods들을 관리하는 모습을 확인할 수 있다.

이번에는 .metadata.labels.app 필드를 수정했을 때 어떤 일이 일어나는지 확인해보자
최초 설정한 갯수 3개로 지정하고

kubectl edit pod [컨테이너이름]

을 통해 해당 필드를 수정하였다.

이후 다음과 같이 변하였다.

pods 개수가 4개로 변하였다. replicaset는 label을 통해 pod를 관리하고 그 label은 .metadata.labels.app의 nginx-replicaset 이었다. 파드 셋중 하나의 이 값을 nginx-other로 바꾸니 replicaset가 관리하는 pods는 2개가 된 것이고 따라서 새로 하나를 만든것이다.

kubectl get pods -o=jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.metadata.labels}{'\n'}{end}"

위 명령어를 통해 각 pods의 .metadata.labels.app 필드 설정을 확인해보면, rzr7f 필드만 값이 다른것을 확인 가능하다.

6.3 디플로이먼트

디플로이먼트deployment는 k8s에서 상태가 없는 stateless 앱을 배포할 때 사용하는 가장 기본적인 컨트롤러이다. k8s가 처음 등장했을 때는 replication controller에서 앱을 배포해 왔다. 최근은 이 deployment를 기본적인 앱 배포에 사용한다.

deployment는 replicaset를 관리하며 앱 배포를 더 세밀하게 관리한다. 배포 기능을 세분화 한 것. 단순히 실행시켜야 할 파드 개수 유지만 하는게 아니라 배포 시 rolling update, 배포 도중 잠시 멈췄다 다시 배포하기, 앱 배포 후 이전 버전 롤백 등의 기능이 있다.

디플로이먼트 사용하기

deployment-nginx.yaml 탬플릿이다.

apiVersion: apps/v1
kind: Deplyment
metadata:
  name: nginx-deployment
  labels:
    app: nginx-deployment
spec:
  replicas: 3	---------------------- 1
  selector:
    matchLabels:
      app: nginx-deployment	---------- 2
  template:
    metadata:
      labels:
        app: nginx-deployment
    spec:
      containers:
      - name: nginx-deployment	------ 3
        image: nginx	-------------- 3
        ports:
        - containerPort: 80
  • 1 파드를 몇개 실행할 것인지는 여기도 마찬가지로 이렇게 지정한다. 3으로 설정했다.
  • 2 .spec.selector.matchLabels 의 하위 필드는 .metadata.labels의 하위 필드와 같은 설정을 해야 한다. 여기서는 nginx-deployment로 설정하였다.
  • 3 파드 설정 정보가 있는 .spec.template.spec.containers[] 필드를 살펴보면 실제 사용하려는 컨테이너 이름 .name: nginx-deployment 과 이미지 .image: nginx 정보가 있다.

이를

kubectl apply -f deployemtn-nginx.yaml

로 적용해보자.

이후

kubectl get deploy,rs,rc,pods

로 확인해보자. rc는 replication controller, rs는 replicaset을 의미한다. 해당 컨트롤러를 사용하지 않음을 확인하려고 넣었다. 다음과 같다.

nginx-deployment라는 디플로이먼트가 있고, 이 디플로이먼트가 관리하는 nginx-deployemtn-dfcbd5fd6 이라는 레플리카세트도 생성되었다. 뒤의 문자는 UUID 해시 문자이다. 마지막으로 레플리카세트가 관리하는 nginx-deployemtn-dfcbd5fd6-xxxxx 형식의 파드들이 생성되었다.

이 상태에서 nignx-deployment 의 컨테이너 이미지 설정 정보를 업데이트해보자. 업데이트 방법에는 다음 세가지가 있다

  • 1 kubectl set 명령으로 직접 컨테이너 이미지 지정
  • 2 kubectl edit 명령으로 현재 파드의 설정 정보를 연 다음 컨테이너 이미지 정보 수정
  • 3 처음 적용했던 템플릿의 컨테이너 이미지 정보를 수정한 다음 kubectl apply 명령 실행해서 변경

다음 명령으로 실행중인 디플로이먼트에서 image 필드값만 변경하겠다.

kubectl set image deployment/nginx-deployment nginx-deployment=nginx:1.9.1

컨테이너 이미지를 업데이트하며 nginx-deployment 디플로이먼트가 관리하는 nginx-deployment-7887b6dc45 라는 새로운 레플리카세트가 생겼다. 기존 파드는 해당 레플리카세트가 관리하는 형식으로 변경됨을 확인 가능하다.
플로이먼트 설정을 변경할 때마다 이렇게 새로운 레플리카세트가 생성되고 그에 맞게 파드가 변경된다는 점을 기억하자.

kubectl get deploy nginx-deployment -o=jsonpath="{.spec.template.spec.containers[0].image}{'\n'}"

위 명령으로 nginx 컨테이너이미지의 버전이 nginx:1.9.1 로 변경된 것을 확인 가능하다.

edit 명령으로 .spec.template.spec.containers[].image 필드 값을 변경해보자. 이후 확인하면 다음과 같이 표시된다.

마지막으로 deployment-nginx.yaml의 내용을 수정해 컨테이너이미지 설정정보를 바꾸고 싶다면, 역시 탬플릿의 .spec.template.spec.containers[].image 필드 값을 nginx:1.10.1 로 수정한 후 다시 apply 해주면 된다.

디플로이먼트 롤백

컨테이너 이미지 변경 내역은

kubectl rollout history deploy nginx-deployment

리비전이 3개 보이며 현재 리비전은 3이다. 이 3번째 리비전의 상세 내용을 확인해보자. --revision=3 옵션을 사용하면 된다.

revision #3은 앞에서 kubectl edit deploy 명령으로 컨테이너 이미지 설정 정보를 변경한 사항이다. 이 상태에서 kubectl set image 명령을 사용했던 revision #2로 되돌려보자.

kubectl rollout undo deploy nginx-deployment

이미지를 되돌리며, 앞에서 kubectl set image로 변경한 7887b~ replicaset와 해당 replicaset가 관리하는 형식의 파드들로 되돌려지는 모습을 실시간으로 확인가능하다.

nginx 이미지 버전도 되돌려졌을까? 확인해보자.

nginx: 1.9.1 로 되돌려진 것을 확인할 수 있다.

다음으로 리비전 숫자를 확인해보자

리비전2가 리비전4로 변경되었다.
특정 리비전으로 살행중인 파드를 되돌리려면 --to-revision=리비전숫자 옵션을 사용한다. 3으로 되돌리고 확인해보자.

되돌릴 수 있는 리비전 숫자는 디플로이먼트 탬플릿의 .spec.revisionHistoryLimit 필드값을 설정하면 된다. 기본값은 10이다.

rollout 명령을 실행했을때 출력결과중 CHANGE-CAUSE 항목은 으로 되어있었따. 이는 해당 리비전의 주요 내용을 나타낸다. 계속 디플로이먼트를 수정하다 보면 리비전 숫자만으론 헷갈릴것이다. 이럴때 이 항목에 변경사항을 알 수 있는 버전 숫자나 변경내용을 메모하면 확인하기 쉬울 것이다.

이는 탬플릿에 .metadata.anotation 필드를 추가하여 사용한다. 하위 필드로 kubernetes.io/change-cause: version 1.10.1 를 만들어 apply로 적용한 후 디플로이먼트 내역을 확인하겠다.

다음과 같이 잘 적용된 모습이다.

파드 개수 조정하기

파드 개수를 조정하려면 kubectl scale 명령을 사용한다. --replicas 옵션에 파드 개수를 입력해 조정한다.

kubectl scale deploy nginx-deployment --replicas=5

새로이 파드가 2개 생성되어 5개로 맞춰진다.

디플로이먼트 배포 정지, 배포 재개, 재시작하기

kubectl rollout 명령으로 진행중인 배포를 잠시 멈췄다 다시 시작할 수 있다.

kubectl rollout pause deployment/nginx-deployment

kubectl patch deployment/nginx-deployment -p "{\"metadata\":{\"annodations\":{\"kubernetes.io/change-cause\":\"version 1.11\"}}}"

책 내용대로 진행했으나 어째서인지 두번째 명령어에서 오류가 발생한다. change-cause 항목은 그대로지만 pause 기능은 테스트 가능하였다. resume 명령어로 pause를 해제하니 배포가 진행되는 모습을 볼 수 있다.

재시작은

kubectl rollout restart

명령으로 한다

디플로이먼트 상태

배포 중에는 디플로이먼트 상태status가 변한다. 우선 진행progressing 이었다 성공이면 완료complete 실패면 failed로 바뀐다.

kubectl rollout status

명령으로 배포 진행상태를 확인할 수 있다.

다음 작업을 하는 동안 상태가 Progressing으로 표시된다.

  1. 디플로이먼트가 새로운 레플리카세트를 만들때
  2. 디플로이먼트가 새로운 레플리카세트의 파드 개수를 늘릴때
  3. 디플로이먼트가 예전 레플리카세트의 파드 개수를 줄일때
  4. 새로운 파드가 준비 상태가 되거나 이용 가능한 상태가 되었을 때

배포가 이상없이 끝나면 배포상태는 Complete가 된다. 다음 조건을 확인해서 완료로 표시한다. 종료코드가 0으로 표시된다.

  1. 디플로이먼트가 관리하는 모든 레플리카세트가 업데이트 완료되었을 때
  2. 모든 레플리카세트가 사용 가능해졌을 때
  3. 예전 레플리카세트가 모두 종료되었을 때

배포중 이상이 있으면 Fail 이 된다. 다음 이유 때문이다.

  1. 쿼터 부족
  2. readinessProbe 진단 실패
  3. 컨테이너이미지 가져오기 에러
  4. 권한 부족
  5. 제한 범위 초과
  6. 앱 실행 조건을 잘못 지정

그럼 한번 실패시켜보자. 탬플릿에 .spec.progressDeadlineSeconds 항목은 지정된 시간이 지나면 상태를 Failed로 바꾼다. 2초로 짧게 지정하자.

kubectl patch deployment/nginx-deployment -p "{\"spec\":{\"progressDeadlineSeconds\":2}}"

아마도 "" 때문에 오류가 발생하는것 같다. 그냥 탬플릿 자체를 수정하여 진행했다.

다음과 같이 Progressing의 Status가 False인 모습을 확인할 수 있고, Reason으로 ProgressDeadlineExceeded가 지정된 모습을 확인할 수 있다. 배포해야 할 기준 시간이 지났다는 의미이다.

0개의 댓글