[kubernetes] Controller

728x90

Controller

워크로드는 쿠버네티스에서 구동되는 애플리케이션이다. 컨트롤러는 하나 이상의 파드의 집합이다.

각 Pod 를 직접 관리할 필요는 없도록 만들었다. 대신, 사용자를 대신하여 파드 집합을 관리하는 워크로드 리소스를 사용할 수 있다. 이러한 리소스는 지정한 상태와 일치하도록 올바른 수의 올바른 파드 유형이 실행되고 있는지 확인하는 컨트롤러를 구성한다.

쿠버네티스는 다음과 같이 여러 가지 빌트인(built-in) 워크로드 리소스를 제공한다.

  • Deployment 및 ReplicaSet (레거시 리소스 레플리케이션 컨트롤러(ReplicationController)를 대체). Deployment 는 Deployment 의 모든 Pod 가 필요 시 교체 또는 상호 교체 가능한 경우, 클러스터의 스테이트리스 애플리케이션 워크로드를 관리하기에 적합하다.
  • StatefulSet는 어떻게든 스테이트(state)를 추적하는 하나 이상의 파드를 동작하게 해준다. 예를 들면, 워크로드가 데이터를 지속적으로 기록하는 경우, 사용자는 Pod 와 PersistentVolume을 연계하는 StatefulSet 을 실행할 수 있다. 전체적인 회복력 향상을 위해서, StatefulSet 의 Pods 에서 동작 중인 코드는 동일한 StatefulSet 의 다른 Pods 로 데이터를 복제할 수 있다.
  • DaemonSet은 노드-로컬 기능(node-local facilities)을 제공하는 Pods 를 정의한다. 이러한 기능들은 클러스터를 운용하는 데 기본적인 것일 것이다. 예를 들면, 네트워킹 지원 도구 또는 add-on 등이 있다. DaemonSet 의 명세에 맞는 노드를 클러스터에 추가할 때마다, 컨트롤 플레인은 해당 신규 노드에 DaemonSet 을 위한 Pod 를 스케줄한다.
  • Job 및 CronJob은 실행 완료 후 중단되는 작업을 정의한다. CronJobs 이 스케줄에 따라 반복되는 반면, 잡은 단 한 번의 작업을 나타낸다.

Replication Controller

디플로이먼트나 레플리카셋을 더 추천한다.

레플리케이션 컨트롤러의 동작방식

파드가 너무 많으면 레플리케이션 컨트롤러가 추가적인 파드를 제거한다. 너무 적으면 레플리케이션 컨트롤러는 더 많은 파드를 시작한다. 수동으로 생성된 파드와 달리 레플리케이션 컨트롤러가 유지 관리하는 파드는 실패하거나 삭제되거나 종료되는 경우 자동으로 교체(새로운 파드를 만들어서 교체)된다.

예를 들어, 커널 업그레이드와 같이 파괴적인 유지 보수 작업을 하고 난 이후의 노드에서 파드가 다시 생성된다. 따라서 애플리케이션에 하나의 파드만 필요한 경우에도 레플리케이션 컨트롤러를 사용해야 한다.

레플리케이션 컨트롤러는 프로세스 감시자(supervisor)와 유사하지만 단일 노드에서 개별 프로세스를 감시하는 대신 레플리케이션 컨트롤러는 여러 노드에서 여러 파드를 감시한다.

레플리케이션 컨트롤러는 디스커션에서 종종 "rc"로 축약되며 kubectl 명령에서 숏컷으로 사용된다.

간단한 경우는 하나의 레플리케이션 컨트롤러 오브젝트를 생성하여 한 개의 파드 인스턴스를 영구히 안정적으로 실행하는 것이다. 보다 복잡한 사용 사례는 웹 서버와 같이 복제된 서비스의 동일한 레플리카를 여러 개 실행하는 것이다.

vagrant@node-1 cont/rc » kubectl explain rc.spec
KIND:     ReplicationController
VERSION:  v1

RESOURCE: spec 

DESCRIPTION:
     Spec defines the specification of the desired behavior of the replication
     controller. More info:
     <https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status>

     ReplicationControllerSpec is the specification of a replication controller.

FIELDS:
   minReadySeconds      
     Minimum number of seconds for which a newly created pod should be ready
     without any of its container crashing, for it to be considered available.
     Defaults to 0 (pod will be considered available as soon as it is ready)

   replicas     
     Replicas is the number of desired replicas. This is a pointer to
     distinguish between explicit zero and unspecified. Defaults to 1. More
     info:
     <https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller>

   selector     <map[string]string>
     Selector is a label query over pods that should match the Replicas count.
     If Selector is empty, it is defaulted to the labels present on the Pod
     template. Label keys and values that must match in order to be controlled
     by this replication controller, if empty defaulted to labels on Pod
     template. More info:
     <https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors>

   template     
     Template is the object that describes the pod that will be created if
     insufficient replicas are detected. This takes precedence over a
     TemplateRef. More info:
     <https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template>
</map[string]string>

rc.spec.replicas → 내가 설정하고 싶은 복제본 갯수

rc.spec.template → Pod 를 만들 템플릿을 정의

rc.spec.template.metadata → 여기서 반드시 Pod 의 label 을 지정해줘야 한다.

rc.spec.template.spec → Pod 의 spec 을 정의

rc.spec.selector → 수많은 Pod 중에 원하는 label 을 갖는 Pod 의 key, value 를 입력한다.

apiVersion: v1
kind: ReplicationController
metadata:
  name: myweb-rc
spec:
  replicas: 3
  # template 에서 생성된 Pod 의 label 을 확인하고 가져올 수 있다.  
  selector:
    app: web

  # Pod Configuration
  # 여기서 Pod 를 구성하고 label 을 붙인다.
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: myweb
          image: httpd
          ports:
            - containerPort: 80
              protocol: TCP

RC 스케일링

replace

명령형 커맨드

kubectl scale rc <RC_이름> --replicas=5

yml 파일에서 replicas 를 3개에서 2개로 변경 후에 변경사항을 적용시키고 싶다.

apiVersion: v1
kind: ReplicationController
metadata:
  name: myweb-rc
spec:
#  replicas: 3
  replicas: 2 
  selector: 
    app: web

  # Pod Configuration
  template:
    metadata:
      labels: 
        app: web
        env: dev
    spec:
      containers:
        - name: myweb
          image: httpd
          ports: 
            - containerPort: 80
              protocol: TCP

이때는 replace 명령어를 사용한다. replace 명령어를 사용하면 변경한 필드값을 업데이트 할 수 있다.

kubectl replace -f <파일명.yml>

물론 업데이트가 불가능한 필드도 있다. 업데이트가 가능하고 불가능한 필드를 확인하기 위해서 explain 명령어를 사용해서 확인 가능하다.

단, template 을 변경하고 새로 적용하고 싶다면 pod 를 일부러 지워야 한다.

왜냐하면 template 은 RC 를 새로 만들 때 적용되기 때문이다.

kubectl delete pods -l <labels_key=labels_value>

patch

kubectl patch -f <파일_이름.yml> -p '{"spec": {"replicas": 2}}'
kubectl patch rc <RC_이름> -p '{"spec": {"replicas": 2}}'
kubectl patch rc <RC_이름> --patch-file <파일_이름.json>

kubectl patch -f myweb-rc.yml -p '{"spec": {"replicas": 2}}'
kubectl patch rc myweb-rc -p '{"spec": {"replicas": 2}}'ㅣ
kubectl patch rc myweb-rc --patch-file replace.json

여기서 파일 이름을 적었다고 해서 파일을 수정하는 것이 아니라 어떤 리소스를 수정할 지 찾기 위해 사용하는 것이다. 변경할 수 없는 값은 변경할 수 없다.

replace 는 파일을 수정하고 replace 명령어를 사용하여 업데이트 한다. 즉, 파일의 spec 자체가 변경된 것이다. replace 는 완전한 구조(yml 파일 자체)를 제공해야 한다.

patch 는 JSON 형태로 일부만 제공하여 업데이트 할 수 있다. 즉, 필요한 부분만 골라서 업데이트할 수 있다는 것이다.

edit

kubectl edit -f <파일_이름.yml>
kubectl edit rc/<RC_이름>
kubectl edit rc <RC_이름>

파일 이름을 적었다고 해서 파일을 수정하는 것이 아니라 어떤 리소스를 수정할 지 찾기 위해 사용하는 것이다.

edit 를 사용하면 etcd 에 저장된 파일 자체를 수정할 수 있다. 변경할 수 없는 값은 변경할 수 없다.

apply

선언형 오브젝트 구성

kubectl apply -f <파일_이름.yml>
kubectl apply rc <RC_이름>

없으면 생성해주고 변경됐으면 변경사항을 적용해준다. 즉, create 로 RC 를 생성하지 않고 apply 로도 생성이 가능하다. 변경 사항이 생겼을 경우에도 apply 를 사용하면 자동으로 업데이트가 된다.

logs

kubectl logs rc/<RC_이름>

기본적으로 logs 명령어는 pods 로그를 디폴트로해서 로그를 찾기 때문에 pods 가 아닌 리소스의 로그를 찾을 때는 어떤 리소스 타입인지 표기해야 한다.

ReplicaSet

ReplicationController → ReplicaSet

ReplicaSet 은 파드의 metadata.ownerReferences 필드를 통해 파드에 연결ㅏ되며, 이는 현재 오브젝트가 소유한 리소스를 명시한다. 레플리카셋이 가지고 있는 모든 파드의 ownerReferences 필드는 해당 파드를 소유한 레플리카셋을 식별하기 위한 소유자 정보를 가진다. 이 링크를 통해 레플리카셋은 자신이 유지하는 파드의 상태를 확인하고 이에 따라 관리 한다.

레플리카셋은 셀렉터를 이용해서 필요한 새 파드를 식별한다. 만약 파드에 OwnerReference이 없거나 OwnerReference가 컨트롤러(Controller) 가 아니고 레플리카셋의 셀렉터와 일치한다면 레플리카셋이 즉각 파드를 가지게 될 것이다.

파드에 어떤 컨트롤러에 의해 관리되는지 정보가 추가 되어 파드의 labels 가 같더라도 컨트롤러에 따라 별개로 작동한다.

레플리카셋을 사용하는 시기

레플리카셋은 지정된 수의 파드 레플리카가 항상 실행되도록 보장한다. 그러나 디플로이먼트는 레플리카셋을 관리하고 다른 유용한 기능과 함께 파드에 대한 선언적 업데이트를 제공하는 상위 개념이다.

따라서 우리는 사용자 지정 오케스트레이션이 필요하거나 업데이트가 전혀 필요하지 않은 경우라면 레플리카셋을 직접적으로 사용하기 보다는 디플로이먼트를 사용하는 것을 권장한다.

이는 레플리카셋 오브젝트를 직접 조작할 필요가 없다는 것을 의미한다. 대신 디플로이먼트를 이용하고 사양 부분에서 애플리케이션을 정의하면 된다.

myweb-rs-set.yml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myweb-rs-set
spec:
  replicas: 2
  selector:
    matchExpressions:
      - key: app
        operator: In
        values: 
          - web
      - key: env
        operator: Exists
  template:
    metadata:
      labels:
        app: web
        env: dev
    spec:
      containers:
        - name: myweb
          image: nginx
          ports: 
            - containerPort: 8080
              protocol: TCP

frontend-rs.yml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: guestbook
    tier: frontend
spec:
  # 케이스에 따라 레플리카를 수정한다.
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: php-redis
        image: gcr.io/google_samples/gb-frontend:v3

메타데이터의 ownerReferences 필드에 설정되어 있는 프런트엔드 레플리카셋의 정보가 다음과 유사하게 나오는 것을 볼 수 있다.

kubectl get pods frontend-b2zdv -o yaml

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2022-05-12T07:06:16Z"
  generateName: frontend-
  labels:
    tier: frontend
  name: frontend-b2zdv
  namespace: default
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: frontend
    uid: f391f6db-bb9b-4c09-ae74-6a1f77f3d5cf
...
728x90