Skip to content

Kubernetes 확장 메커니즘 퀴즈

관련 문서: Kubernetes 확장 메커니즘

객관식 문제

1. CRD(Custom Resource Definition)의 주요 목적은 무엇입니까?

  • A) 기존 Kubernetes 리소스를 수정
  • B) Kubernetes API를 확장하여 사용자 정의 리소스를 정의
  • C) 파드의 네트워크를 구성
  • D) 스토리지 볼륨을 프로비저닝
정답 보기

정답: B) Kubernetes API를 확장하여 사용자 정의 리소스를 정의

설명: CRD는 Kubernetes API를 확장하여 네이티브 Kubernetes 리소스처럼 동작하는 사용자 정의 리소스 유형을 정의할 수 있게 해줍니다.

2. 커스텀 컨트롤러의 조정 루프(Reconciliation Loop)에서 수행하는 주요 작업은?

  • A) 리소스를 즉시 삭제
  • B) 현재 상태와 원하는 상태의 차이를 조정
  • C) API 서버에 새로운 API를 등록
  • D) 네트워크 정책을 적용
정답 보기

정답: B) 현재 상태와 원하는 상태의 차이를 조정

설명: 커스텀 컨트롤러의 조정 루프는 리소스의 현재 상태를 관찰하고, 원하는 상태(spec)와 비교하여 차이가 있으면 원하는 상태를 달성하기 위한 조치를 취합니다.

3. Operator 패턴의 핵심 구성 요소는?

  • A) Deployment와 Service
  • B) CRD와 커스텀 컨트롤러
  • C) ConfigMap과 Secret
  • D) Ingress와 NetworkPolicy
정답 보기

정답: B) CRD와 커스텀 컨트롤러

설명: Operator 패턴은 CRD로 애플리케이션의 구성을 정의하고, 커스텀 컨트롤러로 애플리케이션의 배포, 업그레이드, 복구 등 운영 지식을 자동화합니다.

4. MutatingAdmissionWebhook의 주요 용도는?

  • A) API 요청을 거부
  • B) API 요청을 수정
  • C) API 응답을 로깅
  • D) API 버전을 업그레이드
정답 보기

정답: B) API 요청을 수정

설명: MutatingAdmissionWebhook은 API 요청이 저장되기 전에 요청을 수정할 수 있습니다. 일반적인 용도: 사이드카 컨테이너 주입, 기본값 설정 등입니다.

5. 스케줄러 프레임워크의 Filter 플러그인의 역할은?

  • A) 노드에 점수를 부여
  • B) 파드를 실행할 수 없는 노드를 제외
  • C) 파드를 노드에 바인딩
  • D) 노드의 리소스를 예약
정답 보기

정답: B) 파드를 실행할 수 없는 노드를 제외

설명: Filter 플러그인은 파드의 요구사항을 충족하지 못하는 노드를 필터링하여 제외합니다.

6. Aggregated API Server와 CRD의 차이점은?

  • A) 차이 없음, 동일함
  • B) Aggregated API는 더 많은 제어를 제공하지만 별도 서버 실행 필요
  • C) CRD가 Aggregated API보다 더 많은 기능 제공
  • D) Aggregated API는 더 이상 사용되지 않음
정답 보기

정답: B) Aggregated API는 더 많은 제어를 제공하지만 별도 서버 실행 필요

설명: Aggregated API Server는 API 동작, 커스텀 스토리지 백엔드, 고급 기능에 대한 완전한 제어를 제공하지만 별도의 API 서버를 배포하고 유지 관리해야 합니다. CRD는 더 간단하지만 제한이 있습니다.

7. Kubernetes에서 Finalizer의 목적은?

  • A) 리소스 삭제 속도 향상
  • B) 정리가 완료될 때까지 리소스 삭제 방지
  • C) 실패한 파드 자동 재시작
  • D) 리소스 생성 검증
정답 보기

정답: B) 정리가 완료될 때까지 리소스 삭제 방지

설명: Finalizer는 컨트롤러가 필요한 정리 작업(외부 리소스 삭제 등)을 수행하고 finalizer를 제거할 때까지 리소스 삭제를 차단합니다.

8. 파드가 노드에 바인딩된 후 실행되는 스케줄러 확장 지점은?

  • A) PreFilter
  • B) PostBind
  • C) Reserve
  • D) Score
정답 보기

정답: B) PostBind

설명: PostBind 플러그인은 파드가 노드에 성공적으로 바인딩된 후 호출됩니다. 정보 제공용이며 정리나 알림에 사용됩니다.

9. Istio에서 어드미션 웹훅을 통해 사이드카를 주입하는 데 사용되는 어노테이션은?

  • A) istio.io/inject
  • B) sidecar.istio.io/inject
  • C) istio-injection
  • D) auto-inject.istio.io
정답 보기

정답: B) sidecar.istio.io/inject

설명:sidecar.istio.io/inject 어노테이션은 Istio의 mutating 웹훅이 파드에 Envoy 사이드카를 주입할지 제어합니다. 네임스페이스 수준 제어는 istio-injection 레이블을 사용합니다.

10. 스케줄러 프레임워크에서 Score 플러그인의 목적은?

  • A) 부적합한 노드 필터링
  • B) 노드 순위 지정 및 최적 노드 선택
  • C) 선택된 노드에 파드 바인딩
  • D) 파드 사양 검증
정답 보기

정답: B) 노드 순위 지정 및 최적 노드 선택

설명: Score 플러그인은 필터링을 통과한 노드에 점수를 할당합니다. 스케줄러는 모든 Score 플러그인에서 가장 높은 합산 점수를 가진 노드를 선택합니다.

단답형 문제

1. CRD에서 스키마 검증에 사용되는 표준은 무엇입니까?

정답 보기

정답: OpenAPI v3 Schema (openAPIV3Schema)

설명: CRD의 spec.versions[].schema.openAPIV3Schema에서 OpenAPI v3 스키마를 사용하여 커스텀 리소스의 구조와 유효성 검사 규칙을 정의합니다.

2. Kubernetes 컨트롤러에서 Owner Reference의 역할은?

정답 보기

정답: 리소스 간 소유 관계를 정의하여 가비지 컬렉션과 이벤트 전파를 관리

설명: Owner Reference는 부모-자식 관계를 정의하고, 부모 삭제 시 Kubernetes 가비지 컬렉션을 통해 자식을 자동 삭제합니다.

3. ValidatingAdmissionPolicy와 ValidatingAdmissionWebhook의 차이점은?

정답 보기

정답: ValidatingAdmissionPolicy는 CEL 표현식을 사용하고 프로세스 내에서 실행되며, ValidatingAdmissionWebhook은 외부 HTTP 엔드포인트를 호출합니다.

설명: ValidatingAdmissionPolicy(1.26에서 도입)는 더 나은 성능을 제공하고 외부 웹훅 인프라가 필요 없지만, 웹훅보다 유연성이 떨어집니다.

4. controller-runtime 라이브러리란 무엇이며 왜 일반적으로 사용됩니까?

정답 보기

정답: controller-runtime은 클라이언트 캐싱, 리더 선출, 조정 루프 관리를 포함하여 Kubernetes 컨트롤러 구축을 위한 공통 패턴을 제공하는 라이브러리입니다.

설명: Kubebuilder 프로젝트의 일부인 controller-runtime은 보일러플레이트 코드와 모범 사례를 추상화하여 신뢰할 수 있는 operator를 더 쉽게 구축할 수 있게 합니다.

5. CRD에서 conversion 웹훅의 목적은?

정답 보기

정답: Conversion 웹훅은 동일한 CRD의 다른 API 버전 간에 리소스를 변환합니다.

설명: CRD에 여러 버전(예: v1alpha1, v1beta1, v1)이 있는 경우, conversion 웹훅은 API 진화를 지원하기 위해 버전 간 변환을 처리합니다.

실습 문제

1. 다음 요구사항을 충족하는 CRD를 작성하세요.

  • 이름: WebApp
  • 그룹: apps.example.com
  • 필드: replicas (정수, 최소 1), image (문자열, 필수)
정답 보기
yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: webapps.apps.example.com
spec:
  group: apps.example.com
  names:
    kind: WebApp
    plural: webapps
    singular: webapp
    shortNames:
      - wa
  scope: Namespaced
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              required: ["image"]
              properties:
                replicas:
                  type: integer
                  minimum: 1
                  default: 1
                image:
                  type: string
            status:
              type: object
              properties:
                availableReplicas:
                  type: integer
                conditions:
                  type: array
                  items:
                    type: object
                    properties:
                      type:
                        type: string
                      status:
                        type: string
                      lastTransitionTime:
                        type: string
                        format: date-time
      subresources:
        status: {}
      additionalPrinterColumns:
        - name: Replicas
          type: integer
          jsonPath: .spec.replicas
        - name: Available
          type: integer
          jsonPath: .status.availableReplicas
        - name: Age
          type: date
          jsonPath: .metadata.creationTimestamp

2. "production" 네임스페이스의 모든 Deployment를 검증하는 ValidatingAdmissionWebhook 구성을 작성하세요.

정답 보기
yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: deployment-validator
webhooks:
  - name: validate-deployment.example.com
    clientConfig:
      service:
        name: webhook-service
        namespace: webhook-system
        path: /validate-deployment
      caBundle: <base64-encoded-ca-cert>
    rules:
      - apiGroups: ["apps"]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["deployments"]
        scope: Namespaced
    namespaceSelector:
      matchLabels:
        environment: production
    failurePolicy: Fail
    sideEffects: None
    admissionReviewVersions: ["v1"]
    timeoutSeconds: 10

설명:

  • namespaceSelectorenvironment: production 레이블이 있는 네임스페이스로 웹훅을 제한
  • failurePolicy: Fail은 웹훅을 사용할 수 없을 때 요청을 거부
  • sideEffects: None은 웹훅에 부작용이 없음을 나타냄

3. 커스텀 컨트롤러의 간단한 조정 루프 의사 코드를 작성하세요.

정답 보기
go
func (r *WebAppReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    log := log.FromContext(ctx)

    // 1. WebApp 리소스 가져오기
    var webapp appsv1.WebApp
    if err := r.Get(ctx, req.NamespacedName, &webapp); err != nil {
        if errors.IsNotFound(err) {
            // 리소스 삭제됨, 할 일 없음
            return ctrl.Result{}, nil
        }
        return ctrl.Result{}, err
    }

    // 2. 삭제 중인지 확인 (finalizer 처리)
    if !webapp.DeletionTimestamp.IsZero() {
        if containsFinalizer(webapp, finalizerName) {
            // 정리 수행
            if err := r.cleanupExternalResources(&webapp); err != nil {
                return ctrl.Result{}, err
            }
            // finalizer 제거
            removeFinalizer(&webapp, finalizerName)
            if err := r.Update(ctx, &webapp); err != nil {
                return ctrl.Result{}, err
            }
        }
        return ctrl.Result{}, nil
    }

    // 3. finalizer가 없으면 추가
    if !containsFinalizer(webapp, finalizerName) {
        addFinalizer(&webapp, finalizerName)
        if err := r.Update(ctx, &webapp); err != nil {
            return ctrl.Result{}, err
        }
    }

    // 4. Deployment 생성 또는 업데이트
    deployment := r.constructDeployment(&webapp)
    if err := controllerutil.SetControllerReference(&webapp, deployment, r.Scheme); err != nil {
        return ctrl.Result{}, err
    }
    
    if err := r.CreateOrUpdate(ctx, deployment); err != nil {
        return ctrl.Result{}, err
    }

    // 5. Service 생성 또는 업데이트
    service := r.constructService(&webapp)
    if err := controllerutil.SetControllerReference(&webapp, service, r.Scheme); err != nil {
        return ctrl.Result{}, err
    }
    
    if err := r.CreateOrUpdate(ctx, service); err != nil {
        return ctrl.Result{}, err
    }

    // 6. 상태 업데이트
    webapp.Status.AvailableReplicas = deployment.Status.AvailableReplicas
    if err := r.Status().Update(ctx, &webapp); err != nil {
        return ctrl.Result{}, err
    }

    // 7. 주기적 조정을 위해 재큐
    return ctrl.Result{RequeueAfter: time.Minute * 5}, nil
}

핵심 포인트:

  • 항상 리소스를 찾을 수 없는 경우 처리 (삭제되었을 수 있음)
  • 외부 리소스 정리를 위해 finalizer 사용
  • 가비지 컬렉션을 위해 소유자 참조 설정
  • 상태 하위 리소스를 별도로 업데이트
  • 주기적 검사를 위한 재큐 간격 고려

심화 문제

1. 복잡한 분산 시스템을 위한 Kubernetes Operator를 설계하세요.

정답 보기

CRD 설계:

yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: postgresclusters.database.example.com
spec:
  group: database.example.com
  names:
    kind: PostgresCluster
    plural: postgresclusters
    shortNames:
      - pg
  scope: Namespaced
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              required: ["replicas", "version"]
              properties:
                replicas:
                  type: integer
                  minimum: 1
                  maximum: 10
                version:
                  type: string
                  enum: ["14", "15", "16"]
                storage:
                  type: object
                  properties:
                    size:
                      type: string
                      default: "10Gi"
                    storageClass:
                      type: string
                backup:
                  type: object
                  properties:
                    enabled:
                      type: boolean
                      default: true
                    schedule:
                      type: string
                      default: "0 2 * * *"
                    retention:
                      type: integer
                      default: 7
            status:
              type: object
              properties:
                phase:
                  type: string
                  enum: ["Creating", "Running", "Upgrading", "Failed", "Deleting"]
                primaryEndpoint:
                  type: string
                replicaEndpoints:
                  type: array
                  items:
                    type: string
                currentVersion:
                  type: string
                conditions:
                  type: array
                  items:
                    type: object
                    properties:
                      type:
                        type: string
                      status:
                        type: string
                      reason:
                        type: string
                      message:
                        type: string
                      lastTransitionTime:
                        type: string
                        format: date-time
      subresources:
        status: {}
        scale:
          specReplicasPath: .spec.replicas
          statusReplicasPath: .status.readyReplicas

컨트롤러 핵심 로직:

  • Phase별 상태 관리 (Creating, Running, Upgrading, Failed)
  • 자동 장애 복구 (Primary 장애 시 Failover)
  • Rolling upgrade 전략 (Replica 먼저 업그레이드, 그 다음 Primary)
  • 백업 관리 (예약된 백업을 위한 CronJob)

아키텍처:

PostgresCluster CR
       |
       v
   Controller
       |
       +---> StatefulSet (PostgreSQL 파드)
       +---> Service (Primary 엔드포인트)
       +---> Service (Replica 엔드포인트)
       +---> Secret (자격 증명)
       +---> ConfigMap (PostgreSQL 구성)
       +---> CronJob (백업)
       +---> PodDisruptionBudget

2. 스케줄러 프레임워크를 사용하여 커스텀 스케줄러를 구현하는 방법을 설명하세요.

정답 보기

스케줄러 플러그인 구현:

go
// 여러 확장 지점을 구현하는 플러그인
type CustomSchedulerPlugin struct {
    handle framework.Handle
}

// PreFilter 구현 - 파드 요구사항 확인
func (p *CustomSchedulerPlugin) PreFilter(ctx context.Context, state *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) {
    // 파드에 필수 어노테이션이 있는지 검증
    if _, ok := pod.Annotations["custom-scheduler/zone"]; !ok {
        return nil, framework.NewStatus(framework.Unschedulable, "zone 어노테이션 누락")
    }
    return nil, framework.NewStatus(framework.Success, "")
}

// Filter 구현 - 부적합한 노드 제외
func (p *CustomSchedulerPlugin) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
    requiredZone := pod.Annotations["custom-scheduler/zone"]
    nodeZone := nodeInfo.Node().Labels["topology.kubernetes.io/zone"]
    
    if requiredZone != nodeZone {
        return framework.NewStatus(framework.Unschedulable, "zone 불일치")
    }
    return framework.NewStatus(framework.Success, "")
}

// Score 구현 - 적합한 노드 순위 지정
func (p *CustomSchedulerPlugin) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
    nodeInfo, err := p.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
    if err != nil {
        return 0, framework.NewStatus(framework.Error, err.Error())
    }
    
    // 사용 가능한 리소스 기반으로 점수 계산
    allocatable := nodeInfo.Node().Status.Allocatable
    requested := nodeInfo.Requested
    
    cpuScore := calculateResourceScore(allocatable.Cpu(), requested.Cpu)
    memScore := calculateResourceScore(allocatable.Memory(), requested.Memory)
    
    return (cpuScore + memScore) / 2, framework.NewStatus(framework.Success, "")
}

// 플러그인 등록
func New(_ runtime.Object, h framework.Handle) (framework.Plugin, error) {
    return &CustomSchedulerPlugin{handle: h}, nil
}

스케줄러 구성:

yaml
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
  - schedulerName: custom-scheduler
    plugins:
      preFilter:
        enabled:
          - name: CustomSchedulerPlugin
      filter:
        enabled:
          - name: CustomSchedulerPlugin
      score:
        enabled:
          - name: CustomSchedulerPlugin
        disabled:
          - name: NodeResourcesBalancedAllocation

확장 지점 요약:

확장 지점목적실행 시점
PreFilter파드 수준 검사필터링 전
Filter노드 제거각 노드에 대해
PostFilter스케줄 불가 처리적합한 노드 없을 때
PreScore점수 계산 준비점수 계산 전
Score노드 순위 지정필터링된 노드에 대해
NormalizeScore점수 정규화모든 점수 계산 후
Reserve리소스 예약노드 선택 후
Permit최종 승인바인딩 전
PreBind바인딩 전 작업API 바인딩 전
Bind실제 바인딩API 서버 업데이트
PostBind바인딩 후 정리바인딩 후