ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Kubernetes] 워크로드 리소스 - StatefulSets, DaemonSet
    공부/데이터 2025. 1. 29. 17:01

    StatefulSets

    StatefulSet은 Kubernetes에서 상태를 유지해야 하는 애플리케이션을 관리하기 위한 워크로드 API 객체입니다. 일반적인 Deployment와 달리 StatefulSet은 각 파드에 고유한 식별자를 부여하고 이를 유지하여 상태를 보장합니다. 즉, StatefulSet은 각 파드에 이름표를 달아주고, 그 이름표를 잃어버리지 않도록 관리하는 역할을 하여 상태를 유지해야 하는 애플리케이션을 안정적으로 운영할 수 있습니다.

    특징

    • 고유한 식별자: 각 파드에 고유한 ID를 부여하여 파드의 순서와 고유성을 보장합니다.
    • 영구 저장소: 영구 저장소를 사용하여 데이터를 지속적으로 유지할 수 있습니다.
    • 안정적인 네트워크 ID: 안정적인 네트워크 ID를 통해 다른 서비스에서 StatefulSet의 파드를 안정적으로 참조할 수 있습니다.
      • 특정 파드에 부여된 IP 주소가 재배포나 스케일링 등의 이벤트 발생 시에도 변하지 않고 유지되는 것을 의미
    • 순서 보장: 파드가 생성되는 순서를 보장하여 순서에 의존적인 작업을 수행할 수 있습니다.
    • 스토리지 볼륨: 스토리지 볼륨을 사용하여 데이터 지속성을 제공합니다.

    용도

    • 상태 저장 애플리케이션: 데이터베이스, 상태 저장 미들웨어 등 상태를 유지해야 하는 애플리케이션에 적합합니다.
    • 순서에 의존적인 작업: 특정 순서로 실행되어야 하는 작업에 적합합니다.
    • 안정적인 네트워크 ID가 필요한 경우: 다른 서비스에서 StatefulSet의 파드를 안정적으로 참조해야 하는 경우에 적합합니다.

    Deployment와의 차이점

    • 고유 식별자: StatefulSet은 고유 식별자를 사용하여 파드를 관리하지만 Deployment는 파드를 익명적으로 관리합니다.
    • 순서 보장: StatefulSet은 파드 생성 순서를 보장하지만 Deployment는 순서를 보장하지 않습니다.
    • 스토리지: StatefulSet은 스토리지 볼륨을 사용하여 데이터를 지속적으로 유지할 수 있지만 Deployment는 일반적으로 스토리지 볼륨을 사용하지 않습니다.

    제한사항

    • 스토리지: 지정된 파드의 스토리지는 요청된 스토리지 클래스에 따라 PersistentVolume Provisioner에 의해 프로비저닝되어야 하거나 관리자에 의해 사전에 프로비저닝되어야 합니다.
    • 삭제 및 스케일링: StatefulSet을 삭제하거나 스케일 다운해도 해당 StatefulSet과 연결된 볼륨은 삭제되지 않습니다. 이는 데이터 안전성을 보장하기 위한 것이며, 일반적으로 모든 관련 StatefulSet 리소스를 자동으로 삭제하는 것보다 데이터 안전성이 더 중요합니다.
    • 네트워크 ID: 현재 StatefulSet은 파드의 네트워크 ID를 관리하기 위해 Headless Service를 필요로 합니다. 이 서비스는 사용자가 직접 생성해야 합니다.
    • 삭제 시 종료: StatefulSet을 삭제할 때 파드의 종료에 대한 보장은 제공되지 않습니다. StatefulSet을 0으로 스케일 다운한 후 삭제하면 Pod의 정렬된 종료를 달성할 수 있습니다.
    • Rolling Updates: 기본 Pod Management Policy인 OrderedReady를 사용하여 롤링 업데이트를 수행할 경우, 복구를 위해 수동 개입이 필요한 상태가 발생할 수 있습니다.

    구성요소

    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:
      selector:
        matchLabels:
          app: nginx # has to match .spec.template.metadata.labels
      serviceName: "nginx"
      replicas: 3 # by default is 1
      minReadySeconds: 10 # by default is 0
      template:
        metadata:
          labels:
            app: nginx # has to match .spec.selector.matchLabels
        spec:
          terminationGracePeriodSeconds: 10
          containers:
          - name: nginx
            image: registry.k8s.io/nginx-slim:0.24
            ports:
            - containerPort: 80
              name: web
            volumeMounts:
            - name: www
              mountPath: /usr/share/nginx/html
      volumeClaimTemplates:
      - metadata:
          name: www
        spec:
          accessModes: [ "ReadWriteOnce" ]
          storageClassName: "my-storage-class"
          resources:
            requests:
              storage: 1Gi

    예시에서는 nginx라는 이름의 헤드리스 서비스가 네트워크 도메인을 제어하는 데 사용됩니다. web이라는 이름의 StatefulSet은 고유한 파드에서 3개의 nginx 컨테이너 복제본이 시작됨을 나타내는 spec을 가지고 있습니다. volumeClaimTemplates은 PersistentVolume Provisioner가 프로비저닝한 PersistentVolume을 사용하여 안정적인 스토리지를 제공합니다.

    파드 Selector

    StatefulSet의 spec.selector 필드를 해당 spec.template.metadata.labels의 레이블과 일치하도록 설정해야 합니다. 일치하는 파드 selector를 지정하지 않으면 StatefulSet 생성 중에 유효성 검사 오류가 발생합니다.

    Volume Claim Templates

    spec.volumeClaimTemplates 필드를 설정하여 PersistentVolumeClaim을 생성할 수 있습니다. 이렇게 하면 다음 중 하나에 해당하는 경우 StatefulSet에 안정적인 스토리지를 제공할 수 있습니다.

    • 볼륨 클레임에 지정된 StorageClass가 동적 프로비저닝을 사용하도록 설정
    • 클러스터에는 이미 올바른 StorageClass와 충분한 가용 저장 공간이 있는 퍼시스턴트볼륨이 포함

    Minimum ready seconds

    spec.minReadySeconds는 새로 생성된 파드가 컨테이너 충돌 없이 실행되고 준비되어야 사용 가능한 것으로 간주되는 최소 시간(초)을 지정하는 선택적 필드이다. 이는 롤링 업데이트 전략을 사용할 때 롤아웃의 진행 상황을 확인하는 데 사용됩니다. 이 필드의 기본값은 0이다(파드가 준비되는 즉시 사용 가능한 것으로 간주된다). 파드가 준비된 것으로 간주되는 시점에 대해 자세히 알아보려면 컨테이너 프로브를 참고한다.

    spec.minReadySeconds는 새로 생성된 파드가 준비 상태로 유지되어야 하는 최소 시간(초)을 지정하는 선택적 필드입니다. 롤링 업데이트 전략을 사용할 때 롤아웃의 진행 상황을 확인하는 데 사용됩니다. 기본값은 0이고 0으로 설정할 경우, 파드가 준비되는 즉시 사용 가능한 것으로 간주됩니다.

    • 파드가 준비된 것으로 간주되는 시점에 대해 자세히 알아보려면 컨테이너 프로브를 참고

    파드 Identity

    StatefulSet 파드는 서수(첫째, 둘째 셋째 등), 안정적인 네트워크 아이덴티티, 안정적인 스토리지로 구성된 고유한 아이덴티티를 가지고 있습니다. 이 아이덴티티는 어떤 노드에서 (재)스케줄링되었는지에 관계없이 파드에 고정됩니다.

    Ordinal Index

    N개의 레플리카가 있는 StatefulSet의 경우, StatefulSet의 각 파드에는 세트 전체에서 고유한 정수형의 서수가 할당됩니다. 기본적으로 파드에는 0에서 N-1까지의 서수가 할당됩니다. StatefulSet 컨트롤러는 또한 이 인덱스가 있는 파드 label(apps.kubernetes.io/pod-index)을 추가합니다.

    Start ordinal

    spec.ordinals는 각 파드에 할당된 정수형의 서수를 구성할 수 있는 선택적 필드입니다. 기본값은 nil이고 필드 내에서 다음 옵션을 구성할 수 있습니다.

    • spec.ordinals.start: spec.ordinals.start 필드가 설정되어 있으면, 파드는 spec.ordinals.start부터 spec.ordinals.start + spec.replicas - 1까지의 서수를 할당받음

    Stable Network ID

    StatefulSet의 각 파드는 StatefulSet의 이름과 파드의 서수에서 호스트명을 도출합니다. 생성된 호스트명의 패턴은 $(statefulset name)-$(ordinal) 입니다. 위의 예는 web-0, web-1, web-2라는 이름의 세 개의 파드를 생성합니다.

    StatefulSet은 헤드리스 서비스를 사용하여 파드의 도메인을 제어할 수 있습니다. 이 서비스가 관리하는 도메인은 $(service name).$(namespace).svc.cluster.local의 형식이며 여기서 "cluster.local"은 클러스터 도메인입니다. 각 파드가 생성될 때 $(podname).$(governing service domain) 형식의 DNS 서브도메인을 할당받습니다. 여기서 governing service domain은 StatefulSet에서 지정한 헤드리스 서비스의 도메인이며 StatefulSet의 spec.serviceName 필드에 정의되어 있습니다.

    클러스터의 DNS 구성에 따라 새로 생성된 파드의 DNS 이름을 즉시 조회하지 못할 수 있습니다. 이는 클러스터 내의 다른 클라이언트가 파드가 생성되기 전에 이미 파드의 호스트네임에 대한 쿼리를 이미 보냈고 (생성 이전에 호출했기 때문에 결과는 실패됨) 이 실패한 룩업 결과가 DNS 캐시에 저장되어 있기 때문입니다.

    파드가 생성된 후 즉시 검색해야 하는 경우 몇 가지 옵션이 있습니다

    • DNS 룩업(=조회)에 의존하지 않고 직접(예: 워치를 사용하여) Kubernetes API를 쿼리
    • 쿠버네티스 DNS 공급자의 캐싱 시간을 줄이기
      • 30초 동안 캐싱하는 CoreDNS의 config map을 편집하는 것을 의미

    제한 사항의 언급과 같이 파드의 네트워크 ID를 담당하는 헤드리스 서비스는 사용자가 생성해야 합니다.

    다음은 클러스터 도메인, 서비스 이름, StatefulSet 이름에 대한 선택 사항과 이것이 StatefulSet의 파드에 대한 DNS 이름에 미치는 영향에 대한 몇 가지 예시입니다.

    Cluster Domain Service (ns/name) StatefulSet (ns/name) StatefulSet Domain Pod DNS Pod Hostname
    cluster.local default/nginx default/web nginx.default.svc.cluster.local web-{0..N-1}.nginx.default.svc.cluster.local web-{0..N-1}
    cluster.local foo/nginx foo/web nginx.foo.svc.cluster.local web-{0..N-1}.nginx.foo.svc.cluster.local web-{0..N-1}
    kube.local foo/nginx foo/web nginx.foo.svc.kube.local web-{0..N-1}.nginx.foo.svc.kube.local web-{0..N-1}

    클러스터 도메인은 별도로 구성하지 않는 한 cluster.local로 설정됩니다.

    Stable Storage

    StatefulSet에 정의된 각 VolumeClaimTemplate 항목에 대해 각 파드는 하나의 PersistentVolumeClaim을 받습니다. 위의 nginx 예시에서 각 파드는 StorageClass가 my-storage-class이고 프로비저닝된 스토리지가 1기가바이트인 단일 PersistentVolume을 받습니다. 만약 StorageClass를 지정하지 않으면 기본 스토리지클래스가 사용됩니다. 파드가 노드에 (재)스케줄되면 해당 volumeMounts는 PersistentVolume Claims과 연결된 PersistentVolumes을 마운트합니다. 파드 또는 StatefulSet이 삭제될 때 파드의 PersistentVolume Claims과 연결된 PersistentVolumes은 삭제되지 않으므로 수동으로 제거를 해야 합니다.

    Pod Name Label

    StatefulSet 컨트롤러가 파드를 생성할 때, 파드의 이름으로 설정된 label인 statefulset.kubernetes.io/pod-name을 추가합니다. 이 label을 사용하면 스테이트풀셋의 특정 파드에 서비스를 연결할 수 있습니다.

    Pod index label

    StatefulSet 컨트롤러가 파드를 생성하면 새 파드에는 apps.kubernetes.io/pod-index로 label이 붙습니다. 이 label의 값은 파드의 서수 인덱스입니다. 이 label을 사용하면 특정 파드 인덱스로 트래픽을 라우팅하고 파드 인덱스 label을 사용하여 로그/메트릭을 필터링하는 등의 작업을 수행할 수 있습니다. 이 기능에 대해 기능 게이트인 PodIndexLabel은 기본적으로 활성화되어 있고 변경이 불가능하며 비활성화하려면 사용자가 서버 에뮬레이트 버전 v1.31을 사용해야 합니다.

    배포와 스케일링 보장

    N개의 레플리카가 있는 StatefulSet의 경우, 파드가 배포될 때 {0..N-1}부터 순서대로 순차적으로 생성되며 삭제될 땐 {N-1..0}부터 역순으로 종료됩니다. 스케일링 작업을 파드에 적용하기 전에 모든 선행 파드가 실행 중이고 준비 상태여야 하며 파드를 종료하기 전엔 모든 후속 파드를 완전히 종료해야 합니다.

    StatefulSet에서 pod.Spec.TerminationGracePeriodSeconds를 0으로 지정한다면 안전하지 않으므로 권장하지 않습니다.

    위의 nginx 예시를 생성하면 3개의 파드가 web-0, web-1, web-2의 순서로 배포됩니다. web-1은 web-0이 실행 및 준비되기 전에 배포되지 않으며 web-2는 web-1이 실행 및 준비될 때까지 배포되지 않습니다. web-1이 실행 중이고 준비된 상태이지만 web-2가 시작되기 전에 web-0이 실패하면 web-0이 성공적으로 재시작되어 실행 중이고 준비된 상태가 될 때까지 web-2가 시작되지 않습니다.

    만약 사용자가 replicas=1이 되도록 스테이트풀셋을 수정하여 배포했을 경우, web-2가 먼저 종료됩니다. web-1은 web-2가 완전히 종료되고 삭제될 때까지 종료되지 않습니다. web-2가 종료되고 완전히 종료된 후 web-1이 종료되기 전에 web-0이 실패하는 경우, web-1은 web-0이 실행 및 준비 상태가 될 때까지 종료되지 않습니다.

    Pod Management Policies

    StatefulSet은 spec.podManagementPolicy 필드를 통해 고유성과 신원 보장을 유지하면서 순서 보장을 완화할 수 있습니다.

    OrderedReady Pod Management

    • OrderedReady 파드 관리는 StatefulSet의 기본값으로 위에서 설명한 동작을 구현합니다.

    Parallel Pod Management

    • Parallel 파드 관리는 StatefulSet 컨트롤러가 모든 파드를 병렬로 시작하거나 종료하고 다른 파드를 시작하거나 종료하기 전에 파드가 실행 및 준비 상태가 되거나 완전히 종료될 때까지 기다리지 않도록 지시합니다. 이 옵션은 스케일링 작업의 동작에만 영향을 미치며 파드 이미지, 환경 변수 변경과 같은 업데이트 작업은 기존 순차 방식으로 이뤄집니다.

    Update strategies

    StatefulSet의 spec.updateStrategy 필드를 사용하면 StatefulSet의 컨테이너, label, 리소스 요청/제한 및 어노테이션에 대한 자동 롤링 업데이트를 구성하고 비활성화할 수 있습니다.

    • OnDelete
      • StatefulSet의 spec.updateStrategy.type이 OnDelete로 설정되면 StatefulSet 컨트롤러는 스테이트풀셋의 파드를 자동으로 업데이트하지 않습니다. 사용자가 파드를 수동으로 삭제해야 컨트롤러가 StatefulSet의 spec.template에 대한 수정 사항을 반영하는 새 파드를 생성하도록 합니다.
    • RollingUpdate
      • RollingUpdate 업데이트 전략은 StatefulSet의 파드에 대한 자동화된 롤링 업데이트를 구현하며 기본값입니다.

    Rolling Updates

    StatefulSet의 spec.updateStrategy.type이 RollingUpdate로 설정되면 StatefulSet 컨트롤러는 StatefulSet의 각 파드를 삭제하고 다시 생성합니다. 파드 종료와 동일한 순서(가장 큰 서수부터 가장 작은 서수까지)로 진행되며 각 파드를 한 번에 하나씩 업데이트합니다.

    쿠버네티스 컨트롤 플레인은 이전 파드를 업데이트하기 전에 업데이트된 파드가 실행 중이고 준비될 때까지 기다립니다. spec.minReadySeconds를 설정한 경우 컨트롤 플레인은 파드가 준비 상태가 된 후 해당 시간 동안 추가로 대기한 후 계속 진행합니다.

    Partitioned rolling updates

    RollingUpdate 업데이트 전략은 spec.updateStrategy.rollingUpdate.partition을 지정하여 파티션을 분할할 수 있습니다. 파티션을 지정하면, StatefulSet의 spec.template이 업데이트될 때 파티션보다 크거나 같은 서수를 가진 모든 파드가 업데이트됩니다. 서수가 파티션보다 작은 모든 파드는 업데이트되지 않으며 삭제되더라도 이전 버전으로 다시 생성됩니다.

    StatefulSet의 spec.updateStrategy.rollingUpdate.partition이 spec.replicas보다 크면, spec.template에 대한 업데이트가 파드에 전파되지 않습니다. 대부분의 경우 파티션을 사용할 필요는 없지만 업데이트를 스테이징하거나 카나리아를 롤아웃하거나 점진적 롤아웃을 수행하려는 경우 유용합니다.

    Maximum unavailable Pods

    spec.updateStrategy.rollingUpdate.maxUnavailable 필드를 지정하여 업데이트 중에 사용할 수 없는 최대 파드 수를 제어할 수 있습니다. 이 값은 절대값이나 백분율로 설정합니다. 절대값은 백분율 값에서 반올림하여 계산합니다. 기본값은 1이며 0은 설정할 수 없습니다.

    이 필드는 0 ~ replicas - 1 범위의 모든 파드에 적용됩니다. 만약 0 ~ replicas - 1 범위에서 사용할 수 없는 파드가 있는 경우, maxUnavailable에 계산됩니다.

    Forced rollback

    기본 Pod 관리 정책(OrderedReady)을 사용하여 롤링 업데이트를 수행할 때, 잘못된 구성으로 인해 파드가 준비 상태가 되지 않는 경우, StatefulSet은 롤아웃을 중단하고 대기합니다. 이때, 파드 템플릿을 원래대로 복원해도 즉시 복구되지 않습니다. 잘못된 구성으로 실행하려던 파드를 먼저 삭제한 후에 템플릿을 복원해야 StatefulSet이 정상적으로 파드를 재생성할 수 있습니다.

    PersistentVolumeClaim retention

    spec.persistentVolumeClaimRetentionPolicy 선택 필드는 StatefulSet의 수명 주기 동안 PVC를 삭제할지 여부와 삭제 방법을 제어합니다. 이 필드를 사용하려면 API 서버와 컨트롤러 관리자에서 StatefulSetAutoDeletePVC 기능 게이트를 활성화해야 합니다. 활성화되면 각 스테이트풀셋에 대해 두 가지 정책을 구성할 수 있습니다:

    • whenDeleted
      • StatefulSet이 삭제될 때 적용되는 볼륨 유지 정책
    • whenScaled
      • StatefulSet의 복제본 수가 줄어들 때(예: 세트를 축소할 때) 적용되는 볼륨 유지 정책

    각 정책에 대해 값을 Delete 또는 Retain으로 설정할 수 있습니다.

    • Delete
      • whenDeleted 정책에서 StatefulSet이 삭제된 후, 해당 StatefulSet의 volumeClaimTemplate에서 생성된 모든 PVC가 삭제
      • whenScaled 정책에서 스케일 다운되는 파드에 해당하는 PVC만 삭제
    • Retain (기본값)
      • volumeClaimTemplate에서 생성된 PVC는 해당 파드가 삭제되더라도 유지

    이러한 정책은 StatefulSet이 삭제되거나 스케일 다운될 때 파드가 제거되는 경우에만 적용됩니다. 예를 들어, 노드 장애로 인해 파드가 실패하고 컨트롤 플레인이 대체 파드를 생성하는 경우, 기존 PVC는 유지되며 새로운 파드에 연결됩니다.

    Replicas

    spec.replicas는 원하는 파드 수를 지정하는 선택적 필드이며 기본값은 1입니다.

    수동으로 StatefulSet의 replicas 수를 조정한 후, 해당 StatefulSet을 매니페스트로 업데이트하면 수동 스케일링 설정이 덮어쓰입니다. 만약 HorizontalPodAutoscaler 또는 유사한 수평 스케일링 기능이 활성화된 경우, StatefulSet의 spec.replicas 필드를 직접 설정하지 말고 Kubernetes 컨트롤 플레인이 자동으로 관리하는 것이 좋습니다.

    DaemonSet

    DaemonSet은 각 노드에서 실행되어야 하는 특정 기능을 제공하는 파드를 정의합니다. 이러한 기능은 클러스터 운영에 필수적인 네트워킹 도구, 로그 수집, 노드 모니터링 등과 같이 노드 단위로 필요한 서비스를 제공합니다. 노드가 클러스터에 추가되면 파드가 추가된 노드에 생성됩니다. 노드가 클러스터에서 제거되면 해당 파드는 정리되고 DaemonSet을 삭제하면 생성된 파드가 정리됩니다.

    특징

    • 모든 노드에 배포
      • DaemonSet은 모든 노드(또는 선택한 노드)에 동일한 Pod를 배포합니다.
      • 노드에 한개씩 배포되기 때문에 replica를 지정할 필요가 없습니다.
    • 자동 관리
      • 새로운 노드가 추가되면 해당 노드에 자동으로 Pod를 생성합니다.
      • 노드가 제거되면 해당 노드에서 실행 중이던 Pod를 자동으로 삭제합니다.
      • DaemonSet 자체를 삭제하면 해당 DaemonSet에 의해 생성된 모든 Pod가 정리됩니다.

    용도

    • 클러스터 스토리지: 각 노드에 스토리지 데몬을 배포하여 클러스터 전체의 스토리지 기능을 지원합니다.
    • 로그 수집: 각 노드에서 로그를 수집하는 데몬을 배포하여 클러스터 전체의 로그를 모니터링합니다.
    • 노드 모니터링: 각 노드에서 모니터링 에이전트를 배포하여 노드의 상태를 실시간으로 모니터링합니다.
    • 유연한 구성
      • 단순한 경우에는 하나의 DaemonSet으로 모든 노드에 동일한 서비스를 배포할 수 있습니다.
      • 복잡한 경우에는 하드웨어 유형, 노드 역할 등에 따라 다른 설정(플래그, 리소스 요청 등)을 가진 여러 개의 DaemonSet를 사용하여 더욱 유연하게 서비스를 배포할 수 있습니다.

    DaemonSet은 클러스터의 각 노드에서 일관된 기능을 제공하는 데 필수적인 워크로드입니다. 자동화된 배포 및 관리 기능을 통해 클러스터 운영을 효율적으로 지원합니다.

    구성요소

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: fluentd-elasticsearch
      namespace: kube-system
      labels:
        k8s-app: fluentd-logging
    spec:
      selector:
        matchLabels:
          name: fluentd-elasticsearch
      template:
        metadata:
          labels:
            name: fluentd-elasticsearch
        spec:
          tolerations:
          # these tolerations are to have the daemonset runnable on control plane nodes
          # remove them if your control plane nodes should not run pods
          - key: node-role.kubernetes.io/control-plane
            operator: Exists
            effect: NoSchedule
          - key: node-role.kubernetes.io/master
            operator: Exists
            effect: NoSchedule
          containers:
          - name: fluentd-elasticsearch
            image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
            resources:
              limits:
                memory: 200Mi
              requests:
                cpu: 100m
                memory: 200Mi
            volumeMounts:
            - name: varlog
              mountPath: /var/log
          # it may be desirable to set a high priority class to ensure that a DaemonSet Pod
          # preempts running Pods
          # priorityClassName: important
          terminationGracePeriodSeconds: 30
          volumes:
          - name: varlog
            hostPath:
              path: /var/log

    필수 필드

    다른 모든 쿠버네티스 구성과 마찬가지로 DaemonSet에는 apiVersion, kind 및 메타데이터 필드가 필요합니다.

    Pod Template

    spec.template 필드는 spec 내의 필수 필드 중 하나로 파드 템플릿입니다. 파드와 동일한 구조를 가지지만 중첩되어 있으며 apiVersion 및 kind 필드가 없습니다. 파드 필드 외에도 DaemonSet 내의 파드 템플릿은 적절한 label을 지정해야 합니다. DaemonSet 내의 파드 템플릿은 RestartPolicy가 Always로 설정되어 있어야 하며 명시적으로 지정되지 않은 경우 기본값으로 Always가 적용됩니다.

    Pod Selector

    spec.selector 필드는 파드 selector입니다. 이는 Job의 spec.selector와 동일한 방식으로 작동합니다. spec.template의 label과 일치하는 파드 selector를 지정해야 합니다. 또한, DaemonSet이 생성된 후에는 spec.selector를 변경할 수 없습니다. 파드 selector를 변경하면 의도치 않게 파드가 고아 상태가 될 수 있으며 사용자에게 혼란을 줄 수 있습니다.

    spec.selector는 두 개의 필드로 구성된 객체입니다.

    • matchLabels: ReplicationController의 spec.selector와 동일하게 작동합니다.
    • matchExpressions: 키, 값 목록, 키와 값의 관계를 나타내는 연산자를 지정하여 보다 복잡한 selector를 구성할 수 있습니다.

    두 필드가 모두 지정된 경우, AND 조건으로 결합됩니다. spec.selector는 spec.template.metadata.labels와 일치해야 합니다. 두 값이 일치하지 않으면 API에서 거부됩니다.

    선택한 노드에서 Pod 실행

    spec.template.spec.nodeSelector를 지정하면, DaemonSet 컨트롤러는 해당 노드 selector와 일치하는 노드에 파드를 생성합니다. 마찬가지로 spec.template.spec.affinity를 지정하면 DaemonSet 컨트롤러는 해당 노드 affinity와 일치하는 노드에 파드를 생성합니다. 둘 중 하나를 지정하지 않으면 데몬셋 컨트롤러는 모든 노드에 파드를 생성합니다.

    Daemon 파드가 예약되는 방식

    DaemonSet은 각 노드에 하나의 파드를 실행하도록 보장하는 Kubernetes 워크로드입니다. 이를 통해 네트워킹, 로그 수집, 모니터링 등 노드 단위로 필요한 서비스를 제공합니다.

    DaemonSet 컨트롤러는 각 노드에 대응하는 파드를 생성합니다. 이후 생성된 파드의 spec.affinity.nodeAffinity 필드는 해당 노드와 일치하도록 설정됩니다. 기본 스케줄러는 이 정보를 바탕으로 파드를 해당 노드에 할당하고, spec.nodeName 필드에 해당 노드의 이름을 설정합니다. 새로운 파드가 해당 노드에 배치될 수 없는 경우, 기본 스케줄러는 우선순위에 따라 기존 파드를 옮기거나 제거할 수 있습니다.

    사용자는 DaemonSet의 spec.template.spec.schedulerName 필드를 설정하여 DaemonSet의 파드에 대해 다른 스케줄러를 지정할 수 있습니다.

    DaemonSet 컨트롤러는 파드를 배치할 적절한 노드를 평가할 때 spec.template.spec.affinity.nodeAffinity 필드에 지정된 노드 친화성을 고려합니다. 하지만 생성된 파드에는 해당 노드의 이름과 일치하는 노드 친화성으로 대체됩니다.

    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchFields:
          - key: metadata.name
            operator: In
            values:
            - target-host-name

    Taints and tolerations

    DaemonSet 컨트롤러는 자동으로 일련의 허용 조건(tolerations)을 DaemonSet 파드에 추가합니다. 허용 조건 (Tolerations)이란 파드가 특정 노드에서 실행될 때 발생할 수 있는 태인팅(Taints)을 허용하는 설정입니다. 태인팅 (Taints)이란 노드에 특정 조건을 설정하여 특정 파드가 해당 노드에 스케줄링되지 않도록 하는 메커니즘입니다. 예를 들어, 특정 노드에 "noSchedule" 태인트를 적용하면 이 태인트를 허용하지 않는 파드는 해당 노드에 스케줄링되지 않습니다.

    tolerations:
    - key: "key1"
      operator: "Equal"
      value: "value1"
      effect: "NoSchedule"

    위 예시는 key1이라는 키에 value1 값을 가진 태인트가 있는 노드에는 스케줄링되지 않도록 설정합니다. 하지만 이미 해당 노드에 존재하는 파드는 영향을 받지 않습니다.

    Toleration key Effect 세부정보
    node.kubernetes.io/not-ready NoExecute DaemonSet 파드는 정상적이지 않거나 파드를 수락할 준비가 되지 않은 노드에 스케줄링할 수 있습니다. 이러한 노드에서 실행 중인 DaemonSet 파드는 퇴출되지 않습니다.
    node.kubernetes.io/unreachable NoExecute DaemonSet 파드는 노드 컨트롤러에서 연결할 수 없는 노드에 스케줄링할 수 있습니다. 이러한 노드에서 실행 중인 DaemonSet 파드는 퇴출되지 않습니다.
    node.kubernetes.io/disk-pressure NoSchedule DaemonSet 파드는 디스크 부하 문제가 있는 노드에도 스케줄링될 수 있습니다.
    node.kubernetes.io/memory-pressure NoSchedule DaemonSet 파드는 메모리 부하 문제가 있는 노드에도 스케줄링될 수 있습니다.
    node.kubernetes.io/pid-pressure NoSchedule DaemonSet 파드는 프로세스 부하 문제가 있는 노드에도 스케줄링될 수 있습니다.
    node.kubernetes.io/unschedulable NoSchedule DaemonSet 파드는 스케줄링할 수 없는 노드에도 스케줄링될 수 있습니다.
    node.kubernetes.io/network-unavailable NoSchedule spec.hostNetwork: true를 요청하는 DaemonSet 파드에만 추가됩니다. 즉, 호스트 네트워크를 사용하는 파드입니다. 이러한 DaemonSet 파드는 네트워크를 사용할 수 없는 노드에 스케줄링될 수 있습니다.

    DaemonSet 파드에도 직접 허용 조건(tolerations)을 설정할 수 있습니다. 이는 DaemonSet의 파드 템플릿에 정의하면 됩니다. DaemonSet 컨트롤러는 자동으로 node.kubernetes.io/unschedulable:NoSchedule 허용 조건을 설정합니다. 덕분에 Kubernetes는 스케줄링되지 않도록 표시된 노드에도 DaemonSet 파드를 실행할 수 있습니다. DaemonSet을 사용하여 클러스터 네트워킹과 같은 중요한 노드 수준 기능을 제공하는 경우, Kubernetes가 노드가 준비 상태가 되기 전에 DaemonSet 파드를 배치하는 것이 유용합니다. 예를 들어, 이 특별한 허용 조건이 없다면 노드에서 네트워크 플러그인이 실행되지 않아 노드가 준비 상태로 표시되지 않고, 동시에 노드가 아직 준비되지 않았기 때문에 네트워크 플러그인이 해당 노드에서 실행되지 않는 상황(deadlock)이 발생할 수 있습니다.

    Daemon 파드와 통신하기

    DaemonSet 내의 파드와 통신하기 위한 몇 가지 가능한 패턴은 다음과 같습니다.

    • push: DaemonSet 내의 파드가 통계 데이터베이스와 같은 다른 서비스로 업데이트를 전송하도록 구성됩니다. 이 경우, 파드에는 클라이언트가 없습니다.
    • NodeIP 및 알려진 포트: DaemonSet 내의 파드는 hostPort를 사용하여 노드 IP를 통해 접근 가능합니다. 클라이언트는 노드 IP 목록을 어떤 방식으로든 알고 있으며, 규칙에 따라 포트를 인식합니다.
    • DNS: 동일한 파드 selector를 사용하는 헤드리스 서비스를 생성하고 endpoints 리소스를 사용하거나 DNS에서 여러 A 레코드를 검색하여 DaemonSet을 검색합니다.
    • service: 동일한 pod selector를 사용하는 서비스를 생성하고 해당 서비스를 사용하여 임의의 노드에서 데몬에 접근합니다. (특정 노드에 접근할 방법은 없습니다.)

    DaemonSet 업데이트

    노드 label이 변경되, DaemonSet은 즉시 일치하는 새로운 노드에 파드를 추가하고 일치하지 않게 된 노드에서 파드를 삭제합니다.

    DaemonSet은 생성하는 파드를 수정할 수 있습니다. 그러나 파드는 모든 필드를 업데이트할 수 있는 것은 아닙니다. 또한 DaemonSet 컨트롤러는 동일한 이름의 노드가 새로 생성될 때마다 원래의 템플릿을 사용합니다.

    DaemonSet을 삭제할 수 있습니다. kubectl delete 명령에 -cascade=orphan 옵션을 지정하면 파드는 노드에 남아있게 됩니다. 이후 동일한 selector를 사용하여 새로운 DaemonSet을 생성하면 새로운 DaemonSet이 기존의 파드를 인계받습니다. 필요한 경우, DaemonSet은 업데이트 전략에 따라 파드를 교체합니다.

    DaemonSet에 대해 롤링 업데이트를 수행할 수 있습니다.

    DaemonSet의 대안

    초기화 스크립트

    노드에서 직접 데몬 프로세스를 실행할 수 있습니다(예: init, upstartd, systemd 사용). 이 방법도 가능하지만, DaemonSet을 사용하면 여러 가지 장점이 있습니다.

    • 통합된 로그 관리: 데몬의 로그를 애플리케이션과 동일한 방식으로 모니터링하고 관리할 수 있습니다.
    • 일관된 구성 및 도구: 데몬과 애플리케이션에 동일한 구성 언어(파드 템플릿) 및 도구(kubectl)를 사용할 수 있습니다.
    • 리소스 격리 향상: 데몬을 컨테이너 내에서 실행하면 다른 애플리케이션 컨테이너와의 격리를 향상할 수 있습니다. 단, 반드시 파드 내에서 실행할 필요는 없으며, 컨테이너 내에서 독립적으로 실행할 수도 있습니다.

    Bare 파드

    특정 노드에서 실행될 파드를 직접 생성할 수도 있습니다. 이러한 파드를 Bare 파드라고 합니다. 하지만 DaemonSet은 노드 장애나 커널 업그레이드와 같은 이유로 삭제되거나 종료된 파드를 자동으로 대체합니다. 따라서 개별적으로 파드를 생성하는 대신 DaemonSet을 사용하는 것이 권장됩니다.

    정적 파드

    정적 파드는 Kubelet이 감시하는 특정 디렉토리에 파일을 작성하여 파드를 생성하는 방법입니다. 정적 파드는 kubectl 등의 Kubernetes API 클라이언트로 관리할 수 없습니다. apiserver에 의존하지 않기 때문에 클러스터 초기화(부트스트래핑) 시 유용하지만 향후 지원이 중단될 수 있습니다.

    Deployments

    DaemonSet은 둘 다 파드를 생성하고 해당 파드에는 종료되지 않을 것으로 예상되는 프로세스(예: 웹 서버, 스토리지 서버)가 있다는 점에서 Deployments와 유사합니다.

    파드가 실행되는 호스트를 정확히 제어하는 것보다 replicas 수를 확장 및 축소하고 업데이트를 롤아웃하는 것이 더 중요한 프론트엔드 같은 stateless 서비스에는 Deployments를 사용합니다. DaemonSet이 특정 노드에서 다른 파드가 올바르게 실행되도록 하는 노드 수준 기능을 제공하는 경우, 파드의 사본이 항상 모든 또는 특정 호스트에서 실행되는 것이 중요할 때 DaemonSet을 사용합니다.

    예를 들어, 네트워크 플러그인에는 종종 DaemonSet으로 실행되는 컴포넌트가 포함되어 있습니다. DaemonSet 컴포넌트는 실행 중인 노드에 클러스터 네트워킹이 작동하는지 확인합니다.

    레퍼런스

    https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/

    https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/

     

    StatefulSets

    A StatefulSet runs a group of Pods, and maintains a sticky identity for each of those Pods. This is useful for managing applications that need persistent storage or a stable, unique network identity.

    kubernetes.io

     

     

    댓글