Skip to content

주관식 문제

  1. Kubernetes 클러스터에서 etcd 데이터베이스의 백업 및 복원 절차를 설명하세요.
정답 보기

정답:

etcd 백업 절차:

  1. etcdctl 도구 설치 확인:

    bash
    etcdctl version
  2. 백업 명령 실행:

    bash
    ETCDCTL_API=3 etcdctl snapshot save snapshot.db \
      --endpoints=https://127.0.0.1:2379 \
      --cacert=/etc/kubernetes/pki/etcd/ca.crt \
      --cert=/etc/kubernetes/pki/etcd/server.crt \
      --key=/etc/kubernetes/pki/etcd/server.key
  3. 백업 파일 확인:

    bash
    ETCDCTL_API=3 etcdctl snapshot status snapshot.db --write-out=table
  4. 백업 파일을 안전한 위치에 저장:

    • 클러스터 외부 스토리지
    • 클라우드 스토리지(S3, GCS 등)
    • 다른 물리적 위치

etcd 복원 절차:

  1. 복원을 위해 모든 API 서버 중지:

    bash
    sudo systemctl stop kube-apiserver
  2. etcd 서비스 중지:

    bash
    sudo systemctl stop etcd
  3. 데이터 디렉토리 백업(선택 사항):

    bash
    sudo mv /var/lib/etcd /var/lib/etcd.bak
  4. 스냅샷에서 새 데이터 디렉토리 생성:

    bash
    ETCDCTL_API=3 etcdctl snapshot restore snapshot.db \
      --data-dir=/var/lib/etcd-restore \
      --name=master \
      --initial-cluster=master=https://127.0.0.1:2380 \
      --initial-cluster-token=etcd-cluster-1 \
      --initial-advertise-peer-urls=https://127.0.0.1:2380
  5. 복원된 데이터 디렉토리를 etcd가 사용하도록 설정:

    bash
    sudo mv /var/lib/etcd-restore /var/lib/etcd
    sudo chown -R etcd:etcd /var/lib/etcd
  6. etcd 서비스 재시작:

    bash
    sudo systemctl start etcd
  7. etcd 상태 확인:

    bash
    ETCDCTL_API=3 etcdctl endpoint health \
      --endpoints=https://127.0.0.1:2379 \
      --cacert=/etc/kubernetes/pki/etcd/ca.crt \
      --cert=/etc/kubernetes/pki/etcd/server.crt \
      --key=/etc/kubernetes/pki/etcd/server.key
  8. API 서버 재시작:

    bash
    sudo systemctl start kube-apiserver
  9. 클러스터 상태 확인:

    bash
    kubectl get nodes
    kubectl get pods --all-namespaces

모범 사례:

  • 정기적인 백업 일정 설정(예: 매일)
  • 백업 전에 etcd 클러스터 상태 확인
  • 백업 파일의 무결성 검증
  • 복원 절차 정기적으로 테스트
  • 백업 파일에 타임스탬프 포함
  • 여러 백업 버전 유지
  • 백업 및 복원 절차 문서화
  1. Kubernetes 클러스터에서 노드 유지 보수를 위한 절차를 설명하고, cordon, drain, uncordon 명령의 차이점을 설명하세요.
정답 보기

정답:

노드 유지 보수 절차:

  1. 노드 상태 확인:

    bash
    kubectl get nodes
    kubectl describe node <노드_이>
  2. 노드 cordon(차단):

    bash
    kubectl cordon <노드_이>
  3. 노드 drain(비우기):

    bash
    kubectl drain <노드_이> --ignore-daemonsets --delete-emptydir-data
  4. 유지 보수 작업 수행:

    • 소프트웨어 업데이트
    • 커널 업그레이드
    • 하드웨어 교체
    • 구성 변경
  5. 작업 완료 후 노드 uncordon(차단 해제):

    bash
    kubectl uncordon <노드_이>
  6. 노드 상태 확인:

    bash
    kubectl get nodes

명령어 차이점:

  1. kubectl cordon <노드_이름>:

    • 노드를 스케줄 불가능(unschedulable)으로 표시합니다.
    • 새로운 포드가 노드에 스케줄링되지 않습니다.
    • 이미 실행 중인 포드는 계속 실행됩니다.
    • 노드 상태에 SchedulingDisabled 표시가 나타납니다.
  2. kubectl drain <노드_이름>:

    • 노드를 스케줄 불가능으로 표시합니다(cordon 포함).
    • 노드에서 실행 중인 포드를 안전하게 축출(evict)합니다.
    • 포드는 다른 노드로 재스케줄링됩니다.
    • DaemonSet 포드는 기본적으로 무시됩니다(--ignore-daemonsets 플래그 필요).
    • emptyDir 볼륨을 사용하는 포드는 데이터 손실 가능성이 있으므로 특별한 처리가 필요합니다(--delete-emptydir-data 플래그).
    • PodDisruptionBudget을 존중합니다.
  3. kubectl uncordon <노드_이름>:

    • 노드를 다시 스케줄 가능(schedulable)으로 표시합니다.
    • 새로운 포드가 노드에 스케줄링될 수 있습니다.
    • 이전에 축출된 포드는 자동으로 돌아오지 않습니다.

유지 보수 시 고려 사항:

  • 클러스터에 충분한 여유 용량이 있는지 확인
  • 중요 워크로드에 PodDisruptionBudget 설정
  • 한 번에 하나의 노드만 유지 보수
  • 유지 보수 기간 동안 자동 확장 설정 조정
  • 유지 보수 전후에 워크로드 상태 확인
  • 롤링 업데이트 전략 사용
  1. Kubernetes 클러스터에서 리소스 사용량을 모니터링하고 관리하는 방법을 설명하세요. 포함해야 할 도구와 기술을 나열하세요.
정답 보기

정답:

Kubernetes 리소스 모니터링 및 관리 방법:

1. 기본 모니터링 도구:

  • Metrics Server:

    • 기본적인 CPU 및 메모리 사용량 메트릭 제공
    • kubectl top 명령 지원
    • 설치 방법:
      bash
      kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
    • 사용 예:
      bash
      kubectl top nodes
      kubectl top pods --all-namespaces
  • Kubernetes Dashboard:

    • 클러스터 상태 및 리소스 사용량의 시각적 표현
    • 포드, 노드, 네임스페이스 등의 리소스 관리 인터페이스 제공

2. 고급 모니터링 스택:

  • Prometheus + Grafana:

    • Prometheus: 메트릭 수집 및 저장
    • Grafana: 메트릭 시각화 및 대시보드
    • kube-prometheus-stack 또는 Prometheus Operator로 설치 가능
    • 사용자 정의 알림 규칙 및 대시보드 지원
  • ELK/EFK 스택:

    • Elasticsearch: 로그 저장 및 검색
    • Logstash/Fluentd: 로그 수집 및 처리
    • Kibana: 로그 시각화 및 분석

3. 리소스 관리 기술:

  • 리소스 요청 및 제한 설정:

    yaml
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
  • 네임스페이스 수준 리소스 할당량(ResourceQuota):

    yaml
    apiVersion: v1
    kind: ResourceQuota
    metadata:
      name: compute-quota
      namespace: dev
    spec:
      hard:
        pods: "10"
        requests.cpu: "4"
        requests.memory: 8Gi
        limits.cpu: "8"
        limits.memory: 16Gi
  • 기본 리소스 제한(LimitRange):

    yaml
    apiVersion: v1
    kind: LimitRange
    metadata:
      name: default-limits
      namespace: dev
    spec:
      limits:
      - default:
          cpu: 500m
          memory: 512Mi
        defaultRequest:
          cpu: 200m
          memory: 256Mi
        type: Container
  • Horizontal Pod Autoscaler(HPA):

    yaml
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: web-app
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: web-app
      minReplicas: 2
      maxReplicas: 10
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 80
  • Vertical Pod Autoscaler(VPA):

    • 포드의 CPU 및 메모리 요청을 자동으로 조정
    • 리소스 사용 패턴에 기반한 권장 사항 제공
  • Cluster Autoscaler:

    • 워크로드 요구 사항에 따라 클러스터 노드 수 자동 조정
    • 리소스 부족 시 노드 추가, 사용률 낮을 때 노드 제거

4. 모니터링 모범 사례:

  • 모든 포드에 리소스 요청 및 제한 설정
  • 중요 메트릭에 대한 알림 구성
  • 과거 사용량 분석을 통한 리소스 계획
  • 정기적인 리소스 감사 수행
  • 비용 최적화를 위한 리소스 사용량 추세 분석
  • 개발, 스테이징, 프로덕션 환경에 적절한 리소스 할당량 설정
  • 노드 레벨 및 포드 레벨 메트릭 모두 모니터링
  1. Kubernetes 클러스터 업그레이드 과정에서 발생할 수 있는 주요 위험과 이를 완화하기 위한 전략을 설명하세요.
정답 보기

정답:

Kubernetes 클러스터 업그레이드 위험 및 완화 전략:

1. 주요 위험:

  • API 호환성 문제:

    • 새 버전에서 API가 변경되거나 제거될 수 있음
    • 일부 사용자 정의 리소스 정의(CRD) 또는 API 버전이 더 이상 지원되지 않을 수 있음
  • 워크로드 중단:

    • 컨트롤 플레인 구성 요소 재시작으로 인한 일시적 API 서버 사용 불가
    • 노드 업그레이드 중 포드 재스케줄링으로 인한 서비스 중단
  • 기능 변경:

    • 기본 동작이 변경되어 기존 워크로드에 영향을 줄 수 있음
    • 보안 정책 변경으로 인한 권한 문제
  • 성능 문제:

    • 새 버전에서 리소스 요구 사항이 증가할 수 있음
    • 초기 안정화 기간 동안 성능 저하 가능성
  • 롤백 복잡성:

    • 일부 업그레이드는 쉽게 롤백할 수 없음
    • 데이터 형식 변경으로 인한 롤백 제한

2. 완화 전략:

  • 철저한 계획 및 준비:

    • 변경 로그 검토: 새 버전의 변경 사항, 제거된 기능, 알려진 이슈 확인
    • 업그레이드 경로 확인: 현재 버전에서 대상 버전으로의 직접 업그레이드가 지원되는지 확인
    • 리소스 요구 사항 검토: 새 버전의 최소 요구 사항 확인
  • 테스트 환경에서 먼저 테스트:

    • 프로덕션과 유사한 테스트 클러스터에서 업그레이드 수행
    • 모든 중요 워크로드 및 사용자 정의 리소스 테스트
    • 자동화된 테스트 스위트 실행
  • API 호환성 확인:

    • 사용 중인 API 버전 확인:
      bash
      kubectl api-resources -o wide
    • 더 이상 사용되지 않는 API 사용 확인:
      bash
      kubectl get -A | grep "deprecated"
    • 필요한 경우 매니페스트 업데이트
  • 백업 및 복구 계획:

    • etcd 데이터베이스 백업:
      bash
      ETCDCTL_API=3 etcdctl snapshot save snapshot.db
    • 모든 중요 매니페스트 백업:
      bash
      kubectl get all --all-namespaces -o yaml > all-resources.yaml
    • 복구 절차 문서화 및 테스트
  • 점진적 업그레이드 접근 방식:

    • 컨트롤 플레인 구성 요소 먼저 업그레이드:
      • 고가용성 설정에서는 한 번에 하나의 컨트롤 플레인 노드 업그레이드
    • 워커 노드 롤링 업그레이드:
      • 노드 그룹을 작은 배치로 나누어 업그레이드
      • 각 배치 후 안정성 확인
  • 워크로드 보호:

    • PodDisruptionBudget 설정:
      yaml
      apiVersion: policy/v1
      kind: PodDisruptionBudget
      metadata:
        name: app-pdb
      spec:
        minAvailable: 2  # 또는 maxUnavailable: 1
        selector:
          matchLabels:
            app: my-app
    • 노드 드레이닝 시 주의:
      bash
      kubectl drain <노드_이> --ignore-daemonsets --delete-emptydir-data
  • 모니터링 강화:

    • 업그레이드 전, 중, 후에 클러스터 상태 모니터링
    • 주요 메트릭 및 로그 집중 관찰
    • 알림 임계값 일시적 조정
  • 롤백 계획:

    • 롤백 트리거 조건 정의
    • 롤백 절차 문서화
    • 롤백에 필요한 모든 구성 요소 및 이미지 보존
  • 커뮤니케이션 계획:

    • 모든 이해관계자에게 업그레이드 일정 및 예상되는 영향 공지
    • 업그레이드 중 상태 업데이트 제공
    • 문제 발생 시 에스컬레이션 경로 정의

3. 버전별 특별 고려 사항:

  • 마이너 버전 업그레이드(예: 1.24 → 1.25):

    • 제거된 API 및 기능 변경에 특히 주의
    • 한 번에 한 마이너 버전씩 업그레이드
  • 패치 버전 업그레이드(예: 1.24.0 → 1.24.1):

    • 일반적으로 더 안전하지만 여전히 테스트 필요
    • 보안 패치의 경우 더 빠른 배포 고려
  1. Kubernetes 클러스터에서 발생할 수 있는 일반적인 네트워킹 문제와 이를 진단하고 해결하는 방법을 설명하세요.
정답 보기

정답:

Kubernetes 네트워킹 문제 진단 및 해결:

1. 포드 간 통신 문제:

  • 증상:

    • 포드가 다른 포드와 통신할 수 없음
    • 서비스 이름으로 연결할 수 없음
    • 네트워크 타임아웃 오류
  • 진단 방법:

    • 네트워크 정책 확인:
      bash
      kubectl get networkpolicy --all-namespaces
    • 테스트 포드 생성하여 연결 테스트:
      bash
      kubectl run -it --rm debug --image=busybox -- sh
      # 포드 내에서
      ping <대상_포드_IP>
      wget -O- <서비스_이>:<>
    • CNI 플러그인 포드 상태 확인:
      bash
      kubectl get pods -n kube-system | grep -E 'calico|flannel|weave|cilium'
  • 해결 방법:

    • CNI 플러그인 재설치 또는 업데이트
    • 네트워크 정책 수정 또는 제거
    • 노드 네트워크 인터페이스 확인
    • 방화벽 규칙 확인

2. 서비스 디스커버리 및 DNS 문제:

  • 증상:

    • 서비스 이름으로 연결할 수 없음
    • DNS 조회 실패
    • 간헐적인 연결 문제
  • 진단 방법:

    • CoreDNS 포드 상태 확인:
      bash
      kubectl get pods -n kube-system -l k8s-app=kube-dns
      kubectl logs -n kube-system -l k8s-app=kube-dns
    • DNS 조회 테스트:
      bash
      kubectl run -it --rm debug --image=busybox -- sh
      # 포드 내에서
      nslookup kubernetes.default.svc.cluster.local
      nslookup <서비스_이>.<네임스페이>.svc.cluster.local
      cat /etc/resolv.conf
    • 서비스 엔드포인트 확인:
      bash
      kubectl get endpoints <서비스_이>
  • 해결 방법:

    • CoreDNS 포드 재시작:
      bash
      kubectl rollout restart deployment coredns -n kube-system
    • DNS 구성 확인 및 수정:
      bash
      kubectl edit configmap coredns -n kube-system
    • kubelet DNS 설정 확인

3. 서비스 및 인그레스 문제:

  • 증상:

    • 서비스에 외부에서 접근할 수 없음
    • 인그레스 규칙이 작동하지 않음
    • 로드 밸런서가 생성되지 않음
  • 진단 방법:

    • 서비스 상태 확인:
      bash
      kubectl describe service <서비스_이>
    • 인그레스 상태 확인:
      bash
      kubectl describe ingress <인그레스_이>
    • 인그레스 컨트롤러 포드 로그 확인:
      bash
      kubectl logs -n <인그레스_네임스페이> <인그레스_컨트롤러_포>
    • 엔드포인트 확인:
      bash
      kubectl get endpoints <서비스_이>
  • 해결 방법:

    • 서비스 셀렉터와 포드 레이블 일치 확인
    • 인그레스 컨트롤러 재설치 또는 업데이트
    • 서비스 타입 및 포트 구성 확인
    • 클라우드 제공자 로드 밸런서 설정 확인

4. 노드 네트워킹 문제:

  • 증상:

    • 노드가 클러스터에서 분리됨
    • 노드 간 통신 실패
    • kubelet 연결 오류
  • 진단 방법:

    • 노드 상태 확인:
      bash
      kubectl describe node <노드_이>
    • 노드 네트워크 인터페이스 확인:
      bash
      # 노드에서 직접
      ip addr
      ip route
    • 방화벽 규칙 확인:
      bash
      # 노드에서 직접
      iptables -L
    • kubelet 로그 확인:
      bash
      journalctl -u kubelet
  • 해결 방법:

    • 노드 네트워크 인터페이스 재구성
    • 방화벽 규칙 수정
    • kubelet 재시작
    • 필요한 경우 노드 재부팅

5. 네트워크 정책 문제:

  • 증상:

    • 예상치 못한 연결 차단
    • 특정 네임스페이스 간 통신 불가
    • 일부 포드만 접근 가능
  • 진단 방법:

    • 네트워크 정책 확인:
      bash
      kubectl get networkpolicy -A
      kubectl describe networkpolicy <정책_이> -n <네임스페이>
    • 포드 레이블 확인:
      bash
      kubectl get pods --show-labels
    • 네트워크 플러그인이 네트워크 정책을 지원하는지 확인
  • 해결 방법:

    • 네트워크 정책 수정 또는 삭제
    • 포드 레이블 수정
    • 네트워크 정책 디버깅 도구 사용

6. 일반적인 네트워킹 디버깅 도구:

  • 네트워크 디버깅 포드:

    yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: network-debug
    spec:
      containers:
      - name: debug
        image: nicolaka/netshoot
        command: ["sleep", "3600"]
  • 유용한 명령어:

    bash
    # 포드 내에서
    ping <IP>
    traceroute <IP>
    dig <서비스_이>.<네임스페이>.svc.cluster.local
    curl -v <URL>
    tcpdump -i any
    netstat -tuln
  • CNI 플러그인별 디버깅 도구:

    • Calico: calicoctl
    • Cilium: cilium
    • Weave: weave

7. 모범 사례:

  • 네트워크 토폴로지 문서화
  • 정기적인 연결성 테스트 수행
  • 네트워크 정책 변경 전 영향 분석
  • 클러스터 네트워크 CIDR 범위 계획
  • 네트워크 모니터링 도구 구현
## 실습 문제
  1. 다음 요구 사항에 맞는 ResourceQuota 매니페스트를 작성하세요:
    • 네임스페이스: development
    • 최대 포드 수: 20
    • 최대 CPU 요청: 4 코어
    • 최대 메모리 요청: 8Gi
    • 최대 PVC 수: 10
    • 최대 스토리지 요청: 100Gi
정답 보기

정답:

yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: dev-quota
  namespace: development
spec:
  hard:
    pods: "20"
    requests.cpu: "4"
    requests.memory: 8Gi
    persistentvolumeclaims: "10"
    requests.storage: 100Gi

이 ResourceQuota는 'development' 네임스페이스에 다음과 같은 제한을 설정합니다:

  • 최대 20개의 포드
  • 총 CPU 요청 4 코어
  • 총 메모리 요청 8Gi
  • 최대 10개의 PersistentVolumeClaim
  • 총 스토리지 요청 100Gi

ResourceQuota를 적용하려면:

bash
kubectl apply -f resource-quota.yaml

현재 할당량 사용량을 확인하려면:

bash
kubectl describe quota dev-quota -n development

참고: ResourceQuota를 적용하려면 네임스페이스가 이미 존재해야 합니다. 네임스페이스가 없는 경우 먼저 생성해야 합니다:

bash
kubectl create namespace development
  1. 클러스터의 모든 노드에서 kubelet 서비스 상태를 확인하고, 문제가 있는 경우 해결하는 스크립트를 작성하세요.
정답 보기

정답:

bash
#!/bin/bash
# 파일명: check_kubelet.sh
# 설명: 모든 노드에서 kubelet 서비스 상태를 확인하고 문제 해결

# 노드 목록 가져오기
NODES=$(kubectl get nodes -o jsonpath='{.items[*].metadata.name}')

# 각 노드에 대해 반복
for NODE in $NODES; do
  echo "===== 노드 확인: $NODE ====="
  
  # 노드 상태 확인
  NODE_STATUS=$(kubectl get node $NODE -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}')
  echo "노드 상태: $NODE_STATUS"
  
  # SSH를 통해 kubelet 상태 확인
  echo "kubelet 서비스 상태 확인 중..."
  ssh $NODE "sudo systemctl status kubelet | grep Active"
  
  # kubelet이 실행 중이 아니면 시작
  if ssh $NODE "sudo systemctl is-active kubelet" != "active"; then
    echo "kubelet이 실행 중이 아닙니다. 서비스 시작 중..."
    ssh $NODE "sudo systemctl start kubelet"
    
    # 시작 후 상태 다시 확인
    sleep 5
    if ssh $NODE "sudo systemctl is-active kubelet" == "active"; then
      echo "kubelet 서비스가 성공적으로 시작되었습니다."
    else
      echo "kubelet 서비스 시작 실패. 로그 확인 중..."
      ssh $NODE "sudo journalctl -u kubelet --no-pager -n 50"
    fi
  else
    echo "kubelet 서비스가 정상적으로 실행 중입니다."
  fi
  
  # kubelet 구성 확인
  echo "kubelet 구성 확인 중..."
  ssh $NODE "sudo cat /var/lib/kubelet/config.yaml | grep -E 'address|authentication|authorization'"
  
  echo "===== $NODE 확인 완료 ====="
  echo ""
done

이 스크립트는 다음 작업을 수행합니다:

  1. kubectl get nodes를 사용하여 클러스터의 모든 노드 목록을 가져옵니다.
  2. 각 노드에 대해:
    • 노드의 Ready 상태를 확인합니다.
    • SSH를 통해 노드에 연결하여 kubelet 서비스 상태를 확인합니다.
    • kubelet이 실행 중이 아니면 서비스를 시작합니다.
    • 서비스 시작 후 상태를 다시 확인합니다.
    • 시작에 실패한 경우 로그를 확인합니다.
    • kubelet 구성 파일의 주요 설정을 확인합니다.

사용 방법:

bash
chmod +x check_kubelet.sh
./check_kubelet.sh

참고 사항:

  • 이 스크립트를 실행하려면 모든 노드에 SSH 접근 권한이 필요합니다.
  • 프로덕션 환경에서는 SSH 키 기반 인증을 사용하는 것이 좋습니다.
  • 클라우드 환경에서는 노드에 직접 SSH 접근이 제한될 수 있으므로, 클라우드 제공자의 노드 관리 도구를 사용해야 할 수 있습니다.
  1. 클러스터의 etcd 데이터베이스를 백업하고, 백업 파일을 안전한 위치에 저장하는 cron 작업을 설정하세요.
정답 보기

정답:

1. 백업 스크립트 생성:

bash
#!/bin/bash
# 파일명: backup_etcd.sh
# 설명: etcd 데이터베이스 백업 및 원격 저장

# 변수 설정
BACKUP_DIR="/opt/etcd-backup"
REMOTE_BACKUP_DIR="/mnt/remote-storage/etcd-backups"
DATE=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE="etcd-snapshot-$DATE.db"
ETCD_ENDPOINTS="https://127.0.0.1:2379"
ETCD_CACERT="/etc/kubernetes/pki/etcd/ca.crt"
ETCD_CERT="/etc/kubernetes/pki/etcd/server.crt"
ETCD_KEY="/etc/kubernetes/pki/etcd/server.key"
RETENTION_DAYS=7

# 백업 디렉토리 생성
mkdir -p $BACKUP_DIR

# etcd 스냅샷 생성
ETCDCTL_API=3 etcdctl snapshot save $BACKUP_DIR/$BACKUP_FILE \
  --endpoints=$ETCD_ENDPOINTS \
  --cacert=$ETCD_CACERT \
  --cert=$ETCD_CERT \
  --key=$ETCD_KEY

# 백업 성공 확인
if [ $? -eq 0 ]; then
  echo "etcd 백업 성공: $BACKUP_FILE"
  
  # 백업 파일 상태 확인
  ETCDCTL_API=3 etcdctl snapshot status $BACKUP_DIR/$BACKUP_FILE --write-out=table
  
  # 백업 파일 압축
  gzip $BACKUP_DIR/$BACKUP_FILE
  
  # 원격 저장소에 복사
  mkdir -p $REMOTE_BACKUP_DIR
  cp $BACKUP_DIR/$BACKUP_FILE.gz $REMOTE_BACKUP_DIR/
  
  # 오래된 백업 파일 정리 (로컬)
  find $BACKUP_DIR -name "etcd-snapshot-*.db.gz" -type f -mtime +$RETENTION_DAYS -delete
  
  # 오래된 백업 파일 정리 (원격)
  find $REMOTE_BACKUP_DIR -name "etcd-snapshot-*.db.gz" -type f -mtime +$RETENTION_DAYS -delete
  
  echo "백업 완료 및 원격 저장소에 복사됨: $REMOTE_BACKUP_DIR/$BACKUP_FILE.gz"
else
  echo "etcd 백업 실패"
  exit 1
fi

2. 스크립트에 실행 권한 부여:

bash
chmod +x /opt/etcd-backup/backup_etcd.sh

3. cron 작업 설정:

bash
# root 사용자의 crontab 편집
sudo crontab -e

다음 내용 추가:

# 매일 새벽 2시에 etcd 백업 실행
0 2 * * * /opt/etcd-backup/backup_etcd.sh >> /var/log/etcd-backup.log 2>&1

4. 백업 로그 로테이션 설정:

/etc/logrotate.d/etcd-backup 파일 생성:

/var/log/etcd-backup.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0644 root root
}

5. 백업 테스트:

bash
sudo /opt/etcd-backup/backup_etcd.sh

6. 백업 모니터링 설정 (선택 사항):

백업 실패 시 알림을 받기 위해 모니터링 도구(예: Prometheus)와 통합할 수 있습니다. 백업 스크립트에 다음과 같은 코드를 추가할 수 있습니다:

bash
# 백업 성공 여부를 나타내는 파일 생성
if [ $? -eq 0 ]; then
  echo "success" > /var/lib/node_exporter/etcd_backup_status.prom
else
  echo "failure" > /var/lib/node_exporter/etcd_backup_status.prom
fi

참고 사항:

  • 백업 파일은 클러스터 외부의 안전한 위치에 저장해야 합니다.
  • 클라우드 환경에서는 S3, GCS 등의 객체 스토리지를 사용하는 것이 좋습니다.
  • 정기적으로 백업 복원 테스트를 수행하여 백업의 유효성을 확인해야 합니다.
  • 고가용성 etcd 클러스터의 경우 하나의 etcd 인스턴스에서만 백업을 수행하면 됩니다.
4. 클러스터의 모든 노드에 대해 롤링 업데이트를 수행하는 절차를 작성하세요. 업데이트 중에도 워크로드 가용성을 유지해야 합니다.
정답 보기

정답:

노드 롤링 업데이트 절차:

bash
#!/bin/bash
# 파일명: node_rolling_update.sh
# 설명: 클러스터 노드 롤링 업데이트 수행

# 변수 설정
UPGRADE_COMMAND="sudo apt update && sudo apt upgrade -y"
REBOOT_REQUIRED_CHECK="[ -f /var/run/reboot-required ]"
MAX_UNAVAILABLE=1  # 한 번에 업데이트할 노드 수

# 클러스터 상태 확인
echo "클러스터 상태 확인 중..."
kubectl get nodes
kubectl get pods --all-namespaces -o wide

# PodDisruptionBudget 확인
echo "PodDisruptionBudget 확인 중..."
kubectl get poddisruptionbudget --all-namespaces

# 노드 목록 가져오기
NODES=$(kubectl get nodes -o jsonpath='{.items[*].metadata.name}')
NODE_COUNT=$(echo $NODES | wc -w)

echo "총 $NODE_COUNT 개의 노드를 업데이트합니다."
echo "노드 목록: $NODES"
echo "한 번에 최대 $MAX_UNAVAILABLE 개의 노드가 업데이트됩니다."
echo "계속하려면 Enter 키를 누르세요. 취소하려면 Ctrl+C를 누르세요."
read

# 각 노드에 대해 반복
for NODE in $NODES; do
  echo "===== 노드 업데이트: $NODE ====="
  
  # 노드 cordon
  echo "노드 cordon 중..."
  kubectl cordon $NODE
  
  # 노드 drain
  echo "노드 drain 중..."
  kubectl drain $NODE --ignore-daemonsets --delete-emptydir-data --force
  
  # 노드 업데이트
  echo "노드 업데이트 중..."
  ssh $NODE "$UPGRADE_COMMAND"
  
  # 재부팅 필요 여부 확인
  REBOOT_REQUIRED=$(ssh $NODE "$REBOOT_REQUIRED_CHECK && echo 'true' || echo 'false'")
  
  if [ "$REBOOT_REQUIRED" == "true" ]; then
    echo "노드 재부팅 필요. 재부팅 중..."
    ssh $NODE "sudo reboot"
    
    # 노드가 다시 Ready 상태가 될 때까지 대기
    echo "노드 재부팅 중. Ready 상태가 될 때까지 대기 중..."
    while true; do
      STATUS=$(kubectl get node $NODE -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}')
      if [ "$STATUS" == "True" ]; then
        echo "노드가 Ready 상태가 되었습니다."
        break
      fi
      echo "노드가 아직 Ready 상태가 아닙니다. 10초 후 다시 확인합니다."
      sleep 10
    done
  else
    echo "노드 재부팅이 필요하지 않습니다."
  fi
  
  # 노드 uncordon
  echo "노드 uncordon 중..."
  kubectl uncordon $NODE
  
  # 노드 상태 확인
  echo "노드 상태 확인 중..."
  kubectl get node $NODE
  
  # 포드가 노드에 다시 스케줄링될 때까지 대기
  echo "포드가 노드에 다시 스케줄링될 때까지 대기 중..."
  sleep 30
  
  # 클러스터 상태 확인
  echo "클러스터 상태 확인 중..."
  kubectl get pods --all-namespaces -o wide | grep $NODE
  
  echo "===== $NODE 업데이트 완료 ====="
  echo ""
  
  # 다음 노드로 진행하기 전에 사용자 확인 (선택 사항)
  echo "다음 노드로 진행하려면 Enter 키를 누르세요. 취소하려면 Ctrl+C를 누르세요."
  read
done

echo "모든 노드 업데이트 완료!"
kubectl get nodes

롤링 업데이트 전 준비 사항:

  1. PodDisruptionBudget 설정: 중요 워크로드에 대해 PDB를 설정하여 가용성을 보장합니다.

    yaml
    apiVersion: policy/v1
    kind: PodDisruptionBudget
    metadata:
      name: app-pdb
      namespace: default
    spec:
      minAvailable: 2  # 또는 maxUnavailable: 1
      selector:
        matchLabels:
          app: my-app
  2. 충분한 리소스 확보: 노드 하나가 제거되어도 나머지 노드가 모든 워크로드를 처리할 수 있는지 확인합니다.

  3. 백업 수행: 업데이트 전에 etcd 데이터베이스 백업을 수행합니다.

롤링 업데이트 모범 사례:

  1. 점진적 접근:

    • 한 번에 하나의 노드만 업데이트
    • 각 노드 업데이트 후 클러스터 상태 확인
  2. 자동화 및 멱등성:

    • 스크립트를 사용하여 프로세스 자동화
    • 실패 시 안전하게 재시도할 수 있도록 설계
  3. 모니터링 강화:

    • 업데이트 중 클러스터 메트릭 모니터링
    • 애플리케이션 상태 및 성능 모니터링
  4. 롤백 계획:

    • 문제 발생 시 롤백 절차 준비
    • 이전 상태로 복원할 수 있는 방법 확보
  5. 커뮤니케이션:

    • 업데이트 일정 및 예상되는 영향 공지
    • 업데이트 진행 상황 정기적으로 보고

참고 사항:

  • 클라우드 환경에서는 관리형 Kubernetes 서비스(EKS, GKE, AKS 등)의 노드 업데이트 기능을 활용할 수 있습니다.
  • 노드 그룹이 여러 개인 경우 그룹별로 업데이트를 수행합니다.
  • 중요 시스템 포드(CoreDNS, kube-proxy 등)의 상태를 특별히 모니터링합니다.
  1. 클러스터에서 리소스 사용량이 높은 포드를 식별하고, 해당 정보를 보고서로 생성하는 스크립트를 작성하세요.
정답 보기

정답:

bash
#!/bin/bash
# 파일명: resource_usage_report.sh
# 설명: 클러스터의 리소스 사용량이 높은 포드 식별 및 보고서 생성

# 변수 설정
REPORT_DIR="/tmp/k8s-reports"
DATE=$(date +%Y%m%d-%H%M%S)
REPORT_FILE="$REPORT_DIR/resource-usage-report-$DATE.txt"
TOP_N=10  # 상위 N개 포드 표시

# 보고서 디렉토리 생성
mkdir -p $REPORT_DIR

# 보고서 헤더 작성
echo "===== Kubernetes 클러스터 리소스 사용량 보고서 =====" > $REPORT_FILE
echo "생성 시간: $(date)" >> $REPORT_FILE
echo "" >> $REPORT_FILE

# 클러스터 정보 추가
echo "===== 클러스터 정보 =====" >> $REPORT_FILE
kubectl cluster-info >> $REPORT_FILE 2>&1
echo "" >> $REPORT_FILE

# 노드 리소스 사용량
echo "===== 노드 리소스 사용량 =====" >> $REPORT_FILE
kubectl top nodes | sort -k 3 -hr >> $REPORT_FILE
echo "" >> $REPORT_FILE

# CPU 사용량이 높은 상위 포드
echo "===== CPU 사용량 상위 $TOP_N 포드 =====" >> $REPORT_FILE
kubectl top pods --all-namespaces | sort -k 3 -hr | head -n $((TOP_N + 1)) >> $REPORT_FILE
echo "" >> $REPORT_FILE

# 메모리 사용량이 높은 상위 포드
echo "===== 메모리 사용량 상위 $TOP_N 포드 =====" >> $REPORT_FILE
kubectl top pods --all-namespaces | sort -k 4 -hr | head -n $((TOP_N + 1)) >> $REPORT_FILE
echo "" >> $REPORT_FILE

# 네임스페이스별 리소스 사용량
echo "===== 네임스페이스별 리소스 사용량 =====" >> $REPORT_FILE
echo "CPU 사용량 (코어):" >> $REPORT_FILE
kubectl top pods --all-namespaces | tail -n +2 | awk '{print $2, $3}' | sed 's/m//' | awk '{ns[$1] += $2} END {for (namespace in ns) print namespace, ns[namespace]/1000}' | sort -k 2 -hr >> $REPORT_FILE
echo "" >> $REPORT_FILE

echo "메모리 사용량 (GiB):" >> $REPORT_FILE
kubectl top pods --all-namespaces | tail -n +2 | awk '{print $2, $4}' | sed 's/Mi//' | awk '{ns[$1] += $2} END {for (namespace in ns) print namespace, ns[namespace]/1024}' | sort -k 2 -hr >> $REPORT_FILE
echo "" >> $REPORT_FILE

# 리소스 요청 대비 사용량이 높은 포드 식별
echo "===== 리소스 요청 대비 사용량이 높은 포드 =====" >> $REPORT_FILE
echo "포드 정보 수집 중..." >> $REPORT_FILE

# 임시 파일 생성
PODS_USAGE_FILE="$REPORT_DIR/pods-usage-$DATE.tmp"
PODS_REQUESTS_FILE="$REPORT_DIR/pods-requests-$DATE.tmp"

# 현재 사용량 수집
kubectl top pods --all-namespaces | tail -n +2 > $PODS_USAGE_FILE

# 모든 네임스페이스의 포드 리소스 요청 수집
echo "네임스페이스,포드,CPU요청(m),메모리요청(Mi)" > $PODS_REQUESTS_FILE
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
  kubectl get pods -n $ns -o jsonpath='{range .items[*]}{.metadata.namespace},{.metadata.name},{range .spec.containers[*]}{.resources.requests.cpu}{","}{.resources.requests.memory}{"\n"}{end}{end}' | sed 's/$/,/' | sed 's/,$//' >> $PODS_REQUESTS_FILE
done

# 리소스 요청 대비 사용량 계산 및 보고서에 추가
echo "CPU 사용률이 높은 포드 (사용량/요청 > 80%):" >> $REPORT_FILE
while read line; do
  ns=$(echo $line | awk '{print $1}')
  pod=$(echo $line | awk '{print $2}')
  cpu_usage=$(echo $line | awk '{print $3}' | sed 's/m//')
  
  # 해당 포드의 CPU 요청 찾기
  cpu_request=$(grep "$ns,$pod," $PODS_REQUESTS_FILE | awk -F, '{print $3}' | sed 's/[^0-9m.]//g' | sed 's/m//')
  
  # CPU 요청이 없으면 "미설정"으로 표시
  if [ -z "$cpu_request" ] || [ "$cpu_request" == "" ]; then
    echo "$ns/$pod: CPU 사용량 ${cpu_usage}m, 요청 미설정" >> $REPORT_FILE
  else
    # CPU 사용률 계산
    cpu_percentage=$(echo "scale=2; $cpu_usage / $cpu_request * 100" | bc)
    
    # 사용률이 80% 이상인 경우만 표시
    if (( $(echo "$cpu_percentage >= 80" | bc -l) )); then
      echo "$ns/$pod: CPU 사용량 ${cpu_usage}m, 요청 ${cpu_request}m, 사용률 ${cpu_percentage}%" >> $REPORT_FILE
    fi
  fi
done < $PODS_USAGE_FILE

echo "" >> $REPORT_FILE
echo "메모리 사용률이 높은 포드 (사용량/요청 > 80%):" >> $REPORT_FILE
while read line; do
  ns=$(echo $line | awk '{print $1}')
  pod=$(echo $line | awk '{print $2}')
  mem_usage=$(echo $line | awk '{print $4}' | sed 's/Mi//')
  
  # 해당 포드의 메모리 요청 찾기
  mem_request=$(grep "$ns,$pod," $PODS_REQUESTS_FILE | awk -F, '{print $4}' | sed 's/[^0-9Mi.]//g' | sed 's/Mi//')
  
  # 메모리 요청이 없으면 "미설정"으로 표시
  if [ -z "$mem_request" ] || [ "$mem_request" == "" ]; then
    echo "$ns/$pod: 메모리 사용량 ${mem_usage}Mi, 요청 미설정" >> $REPORT_FILE
  else
    # 메모리 사용률 계산
    mem_percentage=$(echo "scale=2; $mem_usage / $mem_request * 100" | bc)
    
    # 사용률이 80% 이상인 경우만 표시
    if (( $(echo "$mem_percentage >= 80" | bc -l) )); then
      echo "$ns/$pod: 메모리 사용량 ${mem_usage}Mi, 요청 ${mem_request}Mi, 사용률 ${mem_percentage}%" >> $REPORT_FILE
    fi
  fi
done < $PODS_USAGE_FILE

echo "" >> $REPORT_FILE

# 리소스 요청이 설정되지 않은 포드 식별
echo "===== 리소스 요청이 설정되지 않은 포드 =====" >> $REPORT_FILE
kubectl get pods --all-namespaces -o json | jq -r '.items[] | select((.spec.containers[].resources.requests.cpu == null) or (.spec.containers[].resources.requests.memory == null)) | .metadata.namespace + "/" + .metadata.name' >> $REPORT_FILE
echo "" >> $REPORT_FILE

# 임시 파일 정리
rm -f $PODS_USAGE_FILE $PODS_REQUESTS_FILE

# 보고서 요약
echo "===== 보고서 요약 =====" >> $REPORT_FILE
echo "총 노드 수: $(kubectl get nodes | tail -n +2 | wc -l)" >> $REPORT_FILE
echo "총 포드 수: $(kubectl get pods --all-namespaces | tail -n +2 | wc -l)" >> $REPORT_FILE
echo "총 네임스페이스 수: $(kubectl get ns | tail -n +2 | wc -l)" >> $REPORT_FILE
echo "보고서 생성 완료: $REPORT_FILE" >> $REPORT_FILE

# 보고서 위치 출력
echo "보고서가 생성되었습니다: $REPORT_FILE"

# HTML 보고서 생성 (선택 사항)
HTML_REPORT="${REPORT_FILE%.txt}.html"
echo "<html><head><title>Kubernetes 리소스 사용량 보고서</title>" > $HTML_REPORT
echo "<style>body{font-family:Arial;margin:20px}h1{color:#326ce5}table{border-collapse:collapse;width:100%}th,td{border:1px solid #ddd;padding:8px}th{background-color:#f2f2f2}</style>" >> $HTML_REPORT
echo "</head><body>" >> $HTML_REPORT
echo "<h1>Kubernetes 클러스터 리소스 사용량 보고서</h1>" >> $HTML_REPORT
echo "<p>생성 시간: $(date)</p>" >> $HTML_REPORT

# 보고서 내용을 HTML로 변환
awk '/===== 클러스터 정보 =====/{flag=1;print "<h2>클러스터 정보</h2><pre>"}/===== 노드 리소스 사용량 =====/{flag=0;print "</pre><h2>노드 리소스 사용량</h2><table><tr><th>노드</th><th>CPU(%)</th><th>메모리(%)</th></tr>"}/===== CPU 사용량 상위/{flag=0;print "</table><h2>CPU 사용량 상위 포드</h2><table><tr><th>네임스페이스</th><th>포드</th><th>CPU(m)</th><th>메모리(Mi)</th></tr>"}/===== 메모리 사용량 상위/{flag=0;print "</table><h2>메모리 사용량 상위 포드</h2><table><tr><th>네임스페이스</th><th>포드</th><th>CPU(m)</th><th>메모리(Mi)</th></tr>"}/===== 네임스페이스별 리소스 사용량 =====/{flag=0;print "</table><h2>네임스페이스별 리소스 사용량</h2>"}/CPU 사용량 \(코어\):/{flag=0;print "<h3>CPU 사용량 (코어)</h3><table><tr><th>네임스페이스</th><th>CPU(코어)</th></tr>"}/메모리 사용량 \(GiB\):/{flag=0;print "</table><h3>메모리 사용량 (GiB)</h3><table><tr><th>네임스페이스</th><th>메모리(GiB)</th></tr>"}/===== 리소스 요청 대비 사용량이 높은 포드 =====/{flag=0;print "</table><h2>리소스 요청 대비 사용량이 높은 포드</h2>"}/CPU 사용률이 높은 포드/{flag=0;print "<h3>CPU 사용률이 높은 포드 (사용량/요청 > 80%)</h3><ul>"}/메모리 사용률이 높은 포드/{flag=0;print "</ul><h3>메모리 사용률이 높은 포드 (사용량/요청 > 80%)</h3><ul>"}/===== 리소스 요청이 설정되지 않은 포드 =====/{flag=0;print "</ul><h2>리소스 요청이 설정되지 않은 포드</h2><ul>"}/===== 보고서 요약 =====/{flag=0;print "</ul><h2>보고서 요약</h2><ul>"}{if(flag==1)print;else if($0 ~ /^NAME/){print "<tr>";for(i=1;i<=NF;i++)print "<th>"$i"</th>";print "</tr>"}else if($0 ~ /^[a-z].*[0-9]%/){print "<tr>";for(i=1;i<=NF;i++)print "<td>"$i"</td>";print "</tr>"}else if($0 ~ /^[a-z].*[0-9]m/){print "<tr>";for(i=1;i<=NF;i++)print "<td>"$i"</td>";print "</tr>"}else if($0 ~ /^[a-z].* [0-9]/){print "<tr><td>"$1"</td><td>"$2"</td></tr>"}else if($0 ~ /^[a-z].*\//){print "<li>"$0"</li>"}else if($0 ~ /^총/){print "<li>"$0"</li>"}}' $REPORT_FILE >> $HTML_REPORT

echo "</ul></body></html>" >> $HTML_REPORT
echo "HTML 보고서가 생성되었습니다: $HTML_REPORT"

스크립트 사용 방법:

bash
chmod +x resource_usage_report.sh
./resource_usage_report.sh

스크립트 기능:

  1. 클러스터 정보 수집
  2. 노드 리소스 사용량 수집
  3. CPU 및 메모리 사용량이 높은 상위 포드 식별
  4. 네임스페이스별 리소스 사용량 계산
  5. 리소스 요청 대비 사용량이 높은 포드 식별
  6. 리소스 요청이 설정되지 않은 포드 식별
  7. 텍스트 및 HTML 형식의 보고서 생성

참고 사항:

  • 이 스크립트를 실행하려면 kubectl, jq, bc 도구가 필요합니다.
  • Metrics Server가 클러스터에 설치되어 있어야 합니다.
  • 대규모 클러스터에서는 스크립트 실행 시간이 길어질 수 있습니다.
  • 정기적인 보고서 생성을 위해 cron 작업으로 설정할 수 있습니다.
  • 보고서를 이메일로 전송하거나 모니터링 시스템과 통합할 수 있습니다.
## 고급 주제
  1. Kubernetes 클러스터에서 etcd 성능 최적화를 위한 주요 설정 매개변수와 모범 사례는 무엇인가요?
    • A) --max-request-bytes, --quota-backend-bytes, 정기적인 압축
    • B) --max-concurrent-requests, --max-connections, 디스크 RAID 구성
    • C) --auto-compaction-retention, --snapshot-count, SSD 스토리지 사용
    • D) --max-txn-ops, --max-result-buffer, 메모리 증설
정답 보기

정답: C) --auto-compaction-retention, --snapshot-count, SSD 스토리지 사용

설명: etcd는 Kubernetes 클러스터의 핵심 데이터 저장소로, 그 성능은 전체 클러스터 성능에 직접적인 영향을 미칩니다. etcd 성능 최적화를 위한 주요 설정 매개변수와 모범 사례는 다음과 같습니다:

  1. --auto-compaction-retention: etcd는 모든 변경 사항의 기록을 유지하는 append-only 저장소입니다. 이 매개변수는 이전 버전의 키를 자동으로 압축하는 주기를 설정합니다. 기본값은 0(비활성화)이지만, 프로덕션 환경에서는 일반적으로 1시간(1h) 또는 24시간(24h)으로 설정합니다. 이를 통해 디스크 공간을 절약하고 성능을 향상시킬 수 있습니다.

  2. --snapshot-count: etcd가 스냅샷을 생성하기 전에 커밋할 트랜잭션 수를 지정합니다. 기본값은 100,000이지만, 대규모 클러스터에서는 이 값을 조정하여 스냅샷 생성 빈도를 최적화할 수 있습니다. 값이 작을수록 스냅샷이 더 자주 생성되어 복구 시간이 단축되지만, 디스크 I/O가 증가합니다.

  3. SSD 스토리지 사용: etcd는 디스크 I/O에 민감하므로, SSD(Solid State Drive)를 사용하면 성능이 크게 향상됩니다. 특히 대규모 클러스터에서는 SSD 사용이 필수적입니다.

기타 중요한 최적화 설정 및 모범 사례:

  • 전용 디스크 사용: etcd 데이터를 위한 전용 디스크를 사용하여 다른 애플리케이션과의 I/O 경합을 방지합니다.
  • 적절한 메모리 할당: etcd는 성능을 위해 데이터를 메모리에 캐시하므로, 충분한 메모리를 할당해야 합니다.
  • 클러스터 크기 최적화: 일반적으로 3-5개의 etcd 멤버가 최적의 성능과 가용성을 제공합니다.
  • 네트워크 지연 시간 최소화: etcd 멤버 간의 네트워크 지연 시간을 최소화하기 위해 동일한 데이터 센터 또는 가용 영역에 배치합니다.
  • 정기적인 백업 및 압축: 데이터 안전성을 보장하고 디스크 공간을 효율적으로 사용하기 위해 정기적인 백업과 압축을 수행합니다.

--max-request-bytes--quota-backend-bytes는 실제 etcd 매개변수이지만, 주로 성능보다는 리소스 제한에 관련됩니다. --max-concurrent-requests, --max-connections, --max-txn-ops, --max-result-buffer는 실제 etcd 매개변수가 아니거나 성능 최적화의 주요 요소가 아닙니다.

  1. Kubernetes 클러스터에서 컨트롤 플레인 고가용성(HA)을 구현하는 가장 효과적인 방법은 무엇인가요?
    • A) 단일 마스터 노드에 여러 API 서버 인스턴스 실행
    • B) 여러 마스터 노드와 로드 밸런서를 사용한 etcd 클러스터 구성
    • C) API 서버를 StatefulSet으로 배포하고 PersistentVolume 사용
    • D) 마스터 노드에 자동 복구 기능이 있는 감시 프로세스 구현
정답 보기

정답: B) 여러 마스터 노드와 로드 밸런서를 사용한 etcd 클러스터 구성

설명: Kubernetes 컨트롤 플레인의 고가용성(HA)을 구현하는 가장 효과적인 방법은 여러 마스터 노드와 로드 밸런서를 사용하여 etcd 클러스터를 구성하는 것입니다. 이 접근 방식은 다음과 같은 구성 요소로 이루어집니다:

  1. 여러 마스터 노드: 일반적으로 3개 또는 5개의 마스터 노드를 서로 다른 가용 영역에 배포하여 단일 장애점을 제거합니다. 각 마스터 노드는 다음 컨트롤 플레인 구성 요소를 실행합니다:

    • kube-apiserver: API 요청을 처리하는 서버
    • kube-controller-manager: 컨트롤러 프로세스 실행
    • kube-scheduler: 포드 스케줄링 결정
  2. etcd 클러스터: etcd는 분산 키-값 저장소로, Kubernetes의 모든 클러스터 데이터를 저장합니다. 고가용성을 위해 일반적으로 3개 또는 5개의 etcd 인스턴스를 실행합니다. etcd는 마스터 노드에서 직접 실행하거나 별도의 전용 노드에서 실행할 수 있습니다.

  3. 로드 밸런서: 클라이언트 요청을 여러 kube-apiserver 인스턴스에 분산하기 위한 로드 밸런서가 필요합니다. 이는 일반적으로 클라우드 제공자의 로드 밸런서 서비스나 HAProxy, Nginx 등의 소프트웨어 로드 밸런서를 사용하여 구현합니다.

이 구성의 주요 이점:

  • 내결함성: 하나의 마스터 노드가 실패해도 클러스터는 계속 작동합니다.
  • 고가용성: 여러 가용 영역에 걸쳐 배포하면 데이터 센터 수준의 장애에도 대응할 수 있습니다.
  • 확장성: API 서버 요청을 여러 인스턴스에 분산하여 처리할 수 있습니다.
  • 데이터 일관성: etcd의 Raft 합의 알고리즘을 통해 데이터 일관성을 보장합니다.

다른 옵션들의 문제점:

  • 단일 마스터 노드에 여러 API 서버 인스턴스를 실행하는 것은 노드 자체가 단일 장애점이 됩니다.
  • API 서버를 StatefulSet으로 배포하는 것은 일반적인 접근 방식이 아니며, 컨트롤 플레인 구성 요소는 일반적으로 Kubernetes 외부에서 관리됩니다.
  • 감시 프로세스는 도움이 될 수 있지만, 그 자체로는 진정한 고가용성 솔루션이 아닙니다.
  1. Kubernetes 클러스터에서 감사 로깅(Audit Logging)을 구성할 때 가장 중요한 고려 사항은 무엇인가요?
    • A) 모든 API 요청을 로깅하여 완전한 감사 추적 보장
    • B) 감사 정책을 사용하여 중요한 이벤트만 선택적으로 로깅
    • C) 감사 로그를 외부 SIEM 시스템으로 실시간 전송
    • D) 감사 로그에 대한 접근을 관리자로 제한
정답 보기

정답: B) 감사 정책을 사용하여 중요한 이벤트만 선택적으로 로깅

설명: Kubernetes 감사 로깅(Audit Logging)을 구성할 때 가장 중요한 고려 사항은 감사 정책을 사용하여 중요한 이벤트만 선택적으로 로깅하는 것입니다. 이는 다음과 같은 이유로 중요합니다:

  1. 성능 영향 최소화: 모든 API 요청을 로깅하면 API 서버에 상당한 부하가 발생하고 성능이 저하될 수 있습니다. 특히 대규모 클러스터에서는 초당 수천 개의 API 요청이 발생할 수 있습니다.

  2. 스토리지 효율성: 모든 이벤트를 로깅하면 로그 데이터의 양이 급격히 증가하여 스토리지 비용이 증가하고 로그 분석이 어려워집니다.

  3. 관련 정보 집중: 중요한 이벤트만 로깅함으로써 보안 분석가가 중요한 정보에 집중할 수 있습니다.

  4. 규정 준수: 많은 규정 준수 요구 사항은 모든 이벤트가 아닌 특정 유형의 이벤트 로깅을 요구합니다.

Kubernetes 감사 정책은 다음과 같은 감사 수준을 지원합니다:

  • None: 이벤트를 로깅하지 않습니다.
  • Metadata: 요청 메타데이터(사용자, 타임스탬프, 리소스, 동작 등)만 로깅하고 요청/응답 본문은 제외합니다.
  • Request: 메타데이터와 요청 본문은 로깅하지만 응답 본문은 제외합니다.
  • RequestResponse: 메타데이터, 요청 본문, 응답 본문을 모두 로깅합니다.

효과적인 감사 정책의 예:

yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# 인증 및 권한 부여 요청에 대한 로깅 수준 설정
- level: Metadata
  users: ["system:anonymous"]
  verbs: ["get", "list", "watch"]

# Secret, ConfigMap 등 민감한 리소스에 대한 변경 사항 자세히 로깅
- level: Request
  resources:
  - group: ""
    resources: ["secrets", "configmaps"]
  verbs: ["create", "update", "patch", "delete"]

# 중요한 리소스 변경 사항 자세히 로깅
- level: RequestResponse
  resources:
  - group: ""
    resources: ["pods"]
  verbs: ["create", "update", "patch", "delete"]

# 기본적으로 메타데이터만 로깅
- level: Metadata

다른 옵션들의 문제점:

  • 모든 API 요청을 로깅하는 것은 성능 및 스토리지 문제를 일으킬 수 있습니다.
  • 외부 SIEM 시스템으로의 실시간 전송은 중요하지만, 로깅할 내용을 결정하는 것보다 우선순위가 낮습니다.
  • 감사 로그에 대한 접근 제한은 중요하지만, 로깅 정책 자체보다는 보안 조치에 해당합니다.
  1. Kubernetes 클러스터에서 노드 자동 복구(Node Auto-Repair)를 구현하는 가장 효과적인 방법은 무엇인가요?
    • A) 노드 상태를 모니터링하고 문제가 있는 노드를 자동으로 재부팅하는 DaemonSet 배포
    • B) 클라우드 제공자의 관리형 노드 그룹 및 자동 복구 기능 활용
    • C) Node Problem Detector와 사용자 정의 컨트롤러를 사용한 노드 상태 모니터링 및 복구
    • D) 노드 상태를 주기적으로 확인하고 문제가 있는 노드를 재생성하는 cron 작업 구현
정답 보기

정답: C) Node Problem Detector와 사용자 정의 컨트롤러를 사용한 노드 상태 모니터링 및 복구

설명: Kubernetes 클러스터에서 노드 자동 복구(Node Auto-Repair)를 구현하는 가장 효과적인 방법은 Node Problem Detector와 사용자 정의 컨트롤러를 함께 사용하는 것입니다. 이 접근 방식은 다음과 같은 이점을 제공합니다:

  1. 정확한 문제 감지: Node Problem Detector(NPD)는 다양한 노드 문제를 감지할 수 있는 특수 목적의 도구입니다. 이는 다음과 같은 문제를 감지할 수 있습니다:

    • 커널 오류 및 충돌
    • 하드웨어 문제
    • 파일 시스템 문제
    • 네트워크 문제
    • 리소스 부족 문제
  2. 유연한 대응: 사용자 정의 컨트롤러를 사용하면 감지된 문제에 대해 다양한 복구 전략을 구현할 수 있습니다:

    • 경미한 문제: 노드 재부팅
    • 심각한 문제: 노드 교체
    • 특정 유형의 문제: 특정 서비스 재시작
  3. Kubernetes 네이티브 통합: NPD는 노드 상태를 NodeCondition으로 보고하므로, 기존 Kubernetes 메커니즘과 잘 통합됩니다.

  4. 클라우드 독립적: 이 접근 방식은 모든 환경(온프레미스, 다양한 클라우드 제공자)에서 작동합니다.

구현 단계:

  1. Node Problem Detector 배포:

    bash
    kubectl apply -f https://raw.githubusercontent.com/kubernetes/node-problem-detector/master/deployment/node-problem-detector.yaml
  2. 사용자 정의 컨트롤러 구현:

    • Kubernetes 이벤트 및 노드 상태 변경을 감시
    • 특정 NodeCondition에 대응하는 로직 구현
    • 복구 작업 수행(SSH를 통한 명령 실행, 클라우드 API를 통한 노드 재생성 등)
  3. 알림 및 로깅 설정:

    • 복구 작업에 대한 알림 구성
    • 문제 및 복구 작업 로깅

다른 옵션들의 문제점:

  • DaemonSet 접근 방식: 노드에 심각한 문제가 있는 경우 DaemonSet 자체가 영향을 받을 수 있으며, 모든 유형의 문제를 감지하기 어렵습니다.

  • 클라우드 제공자의 관리형 노드 그룹: 특정 클라우드 제공자에 종속되며, 온프레미스 환경에서는 사용할 수 없습니다. 또한 감지할 수 있는 문제 유형이 제한적일 수 있습니다.

  • cron 작업 접근 방식: 반응 시간이 느리고, 문제 감지 능력이 제한적이며, 클러스터 외부에서 실행되어야 하는 단점이 있습니다.

Node Problem Detector와 사용자 정의 컨트롤러를 결합하면 다양한 환경에서 작동하는 강력하고 유연한 노드 자동 복구 솔루션을 구현할 수 있습니다.

  1. Kubernetes 클러스터에서 RBAC(Role-Based Access Control)를 효과적으로 관리하기 위한 모범 사례는 무엇인가요?
    • A) 모든 사용자에게 cluster-admin 역할을 부여하여 관리 용이성 확보
    • B) 네임스페이스별로 세분화된 역할을 정의하고 최소 권한 원칙 적용
    • C) 모든 권한을 단일 ClusterRole에 통합하여 일관성 유지
    • D) 인증을 위해 서비스 계정 대신 항상 사용자 인증서 사용
정답 보기

정답: B) 네임스페이스별로 세분화된 역할을 정의하고 최소 권한 원칙 적용

설명: Kubernetes 클러스터에서 RBAC(Role-Based Access Control)를 효과적으로 관리하기 위한 모범 사례는 네임스페이스별로 세분화된 역할을 정의하고 최소 권한 원칙을 적용하는 것입니다. 이 접근 방식은 다음과 같은 이점을 제공합니다:

  1. 최소 권한 원칙: 사용자와 서비스 계정에 필요한 최소한의 권한만 부여하여 보안 위험을 최소화합니다. 이는 의도하지 않은 변경이나 악의적인 행위로부터 클러스터를 보호하는 데 도움이 됩니다.

  2. 네임스페이스 격리: 네임스페이스별로 역할을 정의하면 팀이나 애플리케이션 간의 논리적 격리를 강화할 수 있습니다. 이를 통해 한 팀의 실수가 다른 팀의 리소스에 영향을 미치는 것을 방지할 수 있습니다.

  3. 세분화된 접근 제어: 특정 리소스 유형이나 작업에 대한 권한을 세밀하게 제어할 수 있습니다. 예를 들어, 개발자에게는 포드와 서비스를 관리할 수 있는 권한을 부여하되, 시크릿이나 네임스페이스 자체를 수정할 수 있는 권한은 제한할 수 있습니다.

  4. 감사 용이성: 세분화된 역할을 사용하면 누가 어떤 작업을 수행할 수 있는지 명확하게 문서화되므로, 감사 및 규정 준수가 용이해집니다.

RBAC 모범 사례 구현 예시:

  1. 네임스페이스별 역할 정의:

    yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: developer
      namespace: development
    rules:
    - apiGroups: [""]
      resources: ["pods", "services", "configmaps"]
      verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
    - apiGroups: ["apps"]
      resources: ["deployments", "replicasets"]
      verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "list", "watch"]  # 시크릿 읽기만 허용
  2. 역할 바인딩 생성:

    yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: developer-binding
      namespace: development
    subjects:
    - kind: Group
      name: developers
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: Role
      name: developer
      apiGroup: rbac.authorization.k8s.io
  3. 클러스터 수준 역할은 제한적으로 사용:

    yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: pod-reader
    rules:
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list", "watch"]
  4. 서비스 계정에 대한 세분화된 권한:

    yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: app-role
      namespace: production
    rules:
    - apiGroups: [""]
      resources: ["configmaps"]
      resourceNames: ["app-config"]  # 특정 ConfigMap만 접근 가능
      verbs: ["get"]

다른 옵션들의 문제점:

  • 모든 사용자에게 cluster-admin 역할 부여: 이는 심각한 보안 위험을 초래합니다. 모든 사용자가 클러스터의 모든 리소스에 대한 완전한 접근 권한을 갖게 되어, 의도하지 않은 변경이나 악의적인 행위에 취약해집니다.

  • 모든 권한을 단일 ClusterRole에 통합: 이는 세분화된 접근 제어를 불가능하게 만들고, 최소 권한 원칙에 위배됩니다.

  • 항상 사용자 인증서 사용: 서비스 계정은 애플리케이션에 대한 인증에 적합하며, 모든 상황에서 사용자 인증서를 사용하는 것은 관리 부담을 증가시킵니다. 상황에 따라 적절한 인증 메커니즘을 선택하는 것이 중요합니다.