Skip to content

Amazon EKS 문제 해결 퀴즈

이 퀴즈는 Amazon EKS 클러스터에서 발생할 수 있는 다양한 문제를 진단하고 해결하는 능력을 테스트합니다.

퀴즈 개요

  • 클러스터 생성 및 구성 문제
  • 네트워킹 문제
  • 노드 및 파드 문제
  • 스토리지 문제
  • 보안 및 액세스 문제
  • 성능 및 확장성 문제

객관식 문제

1. Amazon EKS 클러스터 생성이 실패할 때 가장 먼저 확인해야 할 사항은 무엇인가요?

A. 클러스터 이름이 고유한지 확인
B. IAM 권한, VPC 구성 및 서비스 할당량 확인
C. 다른 리전에서 다시 시도
D. 더 큰 인스턴스 유형 선택

정답 및 설명

정답: B. IAM 권한, VPC 구성 및 서비스 할당량 확인

설명: Amazon EKS 클러스터 생성이 실패할 때 가장 먼저 확인해야 할 사항은 IAM 권한, VPC 구성 및 서비스 할당량입니다. 이러한 요소들은 클러스터 생성 실패의 가장 일반적인 원인이며, 체계적으로 확인하면 문제를 신속하게 식별하고 해결할 수 있습니다.

주요 확인 사항:

  1. IAM 권한 확인:

    • 클러스터 생성에 필요한 IAM 권한 보유 여부
    • 서비스 연결 역할 생성 권한
    • 클러스터 역할 및 정책 구성
  2. VPC 구성 확인:

    • 서브넷 구성 (최소 2개의 가용 영역에 분산된 서브넷)
    • 서브넷 CIDR 크기 (최소 /28, 권장 /24)
    • 인터넷 연결 (NAT 게이트웨이 또는 인터넷 게이트웨이)
    • 보안 그룹 및 네트워크 ACL 설정
  3. 서비스 할당량 확인:

    • EKS 클러스터 수 할당량
    • EC2 인스턴스 할당량
    • VPC 및 서브넷 할당량
    • 기타 관련 서비스 할당량

문제 해결 방법:

  1. IAM 권한 문제 해결:

    bash
    # IAM 권한 확인
    aws sts get-caller-identity
    
    # 필요한 정책 연결
    aws iam attach-user-policy \
      --user-name myuser \
      --policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy
    
    # 서비스 연결 역할 생성
    aws iam create-service-linked-role --aws-service-name eks.amazonaws.com
  2. VPC 구성 문제 해결:

    bash
    # VPC 및 서브넷 확인
    aws ec2 describe-vpcs --vpc-ids vpc-12345678
    aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-12345678"
    
    # 서브넷 태그 확인
    aws ec2 describe-tags --filters "Name=resource-id,Values=subnet-12345678"
    
    # 서브넷 태그 추가
    aws ec2 create-tags \
      --resources subnet-12345678 subnet-87654321 \
      --tags Key=kubernetes.io/cluster/my-cluster,Value=shared
  3. 서비스 할당량 문제 해결:

    bash
    # 서비스 할당량 확인
    aws service-quotas list-service-quotas --service-code eks
    
    # 할당량 증가 요청
    aws service-quotas request-service-quota-increase \
      --service-code eks \
      --quota-code L-1194D53C \
      --desired-value 10

일반적인 오류 메시지 및 해결 방법:

  1. IAM 권한 부족:

    • 오류: "User: arn:aws:iam::123456789012:user/myuser is not authorized to perform: eks:CreateCluster"
    • 해결: 필요한 IAM 권한 추가
  2. VPC 서브넷 문제:

    • 오류: "Cannot create cluster 'my-cluster' because us-west-2a, the targeted availability zone, does not have sufficient capacity to support the cluster. Retry after some time or try other availability zones."
    • 해결: 다른 가용 영역의 서브넷 사용 또는 새 서브넷 생성
  3. 서비스 할당량 초과:

    • 오류: "Account cannot create more EKS clusters in region us-west-2. Current limit is 5"
    • 해결: 서비스 할당량 증가 요청 또는 불필요한 클러스터 삭제

모범 사례:

  1. 클러스터 생성 전 준비 사항:

    • 필요한 IAM 권한 확인
    • 적절한 VPC 및 서브넷 구성
    • 서비스 할당량 확인
  2. 체계적인 문제 해결 접근 방식:

    • 오류 메시지 분석
    • AWS CloudTrail 로그 확인
    • 단계별 구성 요소 검증
  3. 자동화된 인프라 구성:

    • AWS CloudFormation 또는 Terraform 사용
    • eksctl과 같은 도구 활용
    • 인프라 구성 버전 관리

실제 구현 예시:

  1. eksctl을 사용한 클러스터 생성 문제 해결:

    bash
    # 디버그 모드로 클러스터 생성
    eksctl create cluster --name my-cluster --region us-west-2 --verbose 4
    
    # 클러스터 생성 상태 확인
    eksctl get cluster --name my-cluster --region us-west-2
  2. AWS CLI를 사용한 클러스터 생성 문제 해결:

    bash
    # 클러스터 생성 시도
    aws eks create-cluster \
      --name my-cluster \
      --role-arn arn:aws:iam::123456789012:role/eks-cluster-role \
      --resources-vpc-config subnetIds=subnet-12345678,subnet-87654321,securityGroupIds=sg-12345678
    
    # 클러스터 상태 확인
    aws eks describe-cluster --name my-cluster
  3. Terraform을 사용한 클러스터 생성 문제 해결:

    hcl
    # EKS 클러스터 정의
    resource "aws_eks_cluster" "main" {
      name     = "my-cluster"
      role_arn = aws_iam_role.eks_cluster.arn
      
      vpc_config {
        subnet_ids         = var.subnet_ids
        security_group_ids = [aws_security_group.eks_cluster.id]
      }
      
      # 의존성 명시
      depends_on = [
        aws_iam_role_policy_attachment.eks_cluster_policy,
        aws_iam_role_policy_attachment.eks_service_policy
      ]
    }
    
    # 오류 발생 시 디버그 출력
    output "cluster_status" {
      value = aws_eks_cluster.main.status
    }

다른 옵션들의 문제점:

  • A. 클러스터 이름이 고유한지 확인: 클러스터 이름이 고유하지 않으면 오류가 발생할 수 있지만, 이는 가장 일반적인 실패 원인이 아닙니다.
  • C. 다른 리전에서 다시 시도: 문제의 근본 원인을 해결하지 않고 회피하는 방법이며, 다른 리전에서도 동일한 문제가 발생할 수 있습니다.
  • D. 더 큰 인스턴스 유형 선택: 인스턴스 유형은 노드 그룹에 적용되며, 클러스터 생성 자체에는 영향을 미치지 않습니다.
### 2. Amazon EKS 클러스터에서 노드가 NotReady 상태일 때 가장 효과적인 문제 해결 접근 방식은 무엇인가요?

A. 즉시 노드 종료 및 교체
B. 노드 로그, 리소스 사용량 및 네트워크 연결 확인
C. 클러스터 API 서버 재시작
D. 모든 파드 삭제 및 재배포

정답 및 설명

정답: B. 노드 로그, 리소스 사용량 및 네트워크 연결 확인

설명: Amazon EKS 클러스터에서 노드가 NotReady 상태일 때 가장 효과적인 문제 해결 접근 방식은 노드 로그, 리소스 사용량 및 네트워크 연결을 확인하는 것입니다. 이 체계적인 접근 방식은 문제의 근본 원인을 식별하고 적절한 해결책을 적용하는 데 도움이 됩니다.

주요 확인 사항:

  1. 노드 상태 및 이벤트 확인:

    • 노드 상태 세부 정보
    • 노드 관련 이벤트
    • 노드 조건(conditions) 확인
  2. 노드 로그 분석:

    • kubelet 로그
    • 시스템 로그
    • 컨테이너 런타임 로그
  3. 리소스 사용량 확인:

    • CPU, 메모리, 디스크 사용량
    • 리소스 제한 및 압박
    • 시스템 프로세스 상태
  4. 네트워크 연결 확인:

    • 컨트롤 플레인과의 연결
    • DNS 해결
    • VPC 및 서브넷 구성

문제 해결 방법:

  1. 노드 상태 및 이벤트 확인:

    bash
    # 노드 상태 확인
    kubectl get nodes
    kubectl describe node <node-name>
    
    # 노드 이벤트 확인
    kubectl get events --field-selector involvedObject.name=<node-name>
  2. 노드 로그 분석:

    bash
    # SSH를 통한 노드 접근 (자체 관리형 노드의 경우)
    ssh ec2-user@<node-ip>
    
    # kubelet 로그 확인
    sudo journalctl -u kubelet
    
    # 시스템 로그 확인
    sudo tail -f /var/log/syslog
    
    # 컨테이너 런타임 로그 확인
    sudo journalctl -u docker  # Docker 사용 시
    sudo journalctl -u containerd  # containerd 사용 시
  3. 리소스 사용량 확인:

    bash
    # 노드 리소스 사용량 확인
    kubectl top node <node-name>
    
    # SSH를 통한 리소스 확인
    ssh ec2-user@<node-ip>
    
    # 디스크 사용량 확인
    df -h
    
    # 메모리 사용량 확인
    free -m
    
    # CPU 사용량 확인
    top
  4. 네트워크 연결 확인:

    bash
    # 노드에서 API 서버 연결 확인
    curl -k https://<api-server-endpoint>
    
    # DNS 해결 확인
    nslookup kubernetes.default.svc.cluster.local
    
    # 네트워크 인터페이스 확인
    ip addr show
    
    # 라우팅 테이블 확인
    ip route

일반적인 NotReady 원인 및 해결 방법:

  1. kubelet 문제:

    • 증상: kubelet 서비스가 실행되지 않거나 API 서버에 연결할 수 없음
    • 해결 방법:
      bash
      # kubelet 서비스 상태 확인
      sudo systemctl status kubelet
      
      # kubelet 서비스 재시작
      sudo systemctl restart kubelet
      
      # kubelet 구성 확인
      sudo cat /etc/kubernetes/kubelet/kubelet-config.json
  2. 네트워크 문제:

    • 증상: 노드가 컨트롤 플레인과 통신할 수 없음
    • 해결 방법:
      bash
      # 보안 그룹 확인
      aws ec2 describe-security-groups --group-ids sg-12345678
      
      # 라우팅 테이블 확인
      aws ec2 describe-route-tables --route-table-ids rtb-12345678
      
      # VPC CNI 파드 상태 확인
      kubectl get pods -n kube-system -l k8s-app=aws-node
      kubectl logs -n kube-system -l k8s-app=aws-node
  3. 리소스 부족:

    • 증상: 노드의 CPU, 메모리 또는 디스크 공간 부족
    • 해결 방법:
      bash
      # 디스크 공간 확보
      sudo du -sh /var/log/*
      sudo journalctl --vacuum-time=1d
      
      # 불필요한 컨테이너 및 이미지 정리
      docker system prune -af  # Docker 사용 시
  4. 인증서 문제:

    • 증상: 인증서 만료 또는 불일치
    • 해결 방법:
      bash
      # 인증서 확인
      sudo ls -la /etc/kubernetes/pki/
      
      # 인증서 갱신 (자체 관리형 노드의 경우)
      sudo kubeadm alpha certs renew all
      
      # 관리형 노드 그룹의 경우 노드 교체
      eksctl replace nodegroup --cluster=my-cluster --name=my-nodegroup

모범 사례:

  1. 체계적인 문제 해결 접근 방식:

    • 증상 식별 및 문서화
    • 관련 로그 및 이벤트 수집
    • 가능한 원인 체계적 검증
  2. 노드 상태 모니터링 구현:

    • CloudWatch 경보 설정
    • 노드 상태 대시보드 구성
    • 자동화된 알림 시스템
  3. 자동 복구 메커니즘 구현:

    • 자체 복구 노드 그룹 구성
    • 상태 확인 및 자동 교체
    • 장애 노드 자동 드레이닝

실제 구현 예시:

  1. 노드 문제 해결 스크립트:

    bash
    #!/bin/bash
    # EKS 노드 문제 해결 스크립트
    
    NODE_NAME=$1
    
    if [ -z "$NODE_NAME" ]; then
      echo "노드 이름을 지정하세요."
      exit 1
    fi
    
    echo "=== 노드 $NODE_NAME 문제 해결 ==="
    
    # 노드 상태 확인
    echo "=== 노드 상태 확인 ==="
    kubectl get node $NODE_NAME -o wide
    kubectl describe node $NODE_NAME
    
    # 노드 이벤트 확인
    echo
    echo "=== 노드 이벤트 확인 ==="
    kubectl get events --field-selector involvedObject.name=$NODE_NAME --sort-by='.lastTimestamp'
    
    # 노드 파드 확인
    echo
    echo "=== 노드 파드 확인 ==="
    kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName=$NODE_NAME
    
    # 시스템 파드 로그 확인
    echo
    echo "=== 시스템 파드 로그 확인 ==="
    NODE_IP=$(kubectl get node $NODE_NAME -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}')
    KUBE_PROXY_POD=$(kubectl get pods -n kube-system -l k8s-app=kube-proxy -o wide | grep $NODE_IP | awk '{print $1}')
    AWS_NODE_POD=$(kubectl get pods -n kube-system -l k8s-app=aws-node -o wide | grep $NODE_IP | awk '{print $1}')
    
    if [ -n "$KUBE_PROXY_POD" ]; then
      echo "kube-proxy 로그:"
      kubectl logs -n kube-system $KUBE_PROXY_POD --tail=50
    fi
    
    if [ -n "$AWS_NODE_POD" ]; then
      echo
      echo "aws-node (VPC CNI) 로그:"
      kubectl logs -n kube-system $AWS_NODE_POD --tail=50
    fi
    
    # 노드 접근 방법 안내
    echo
    echo "=== 노드 접근 방법 ==="
    echo "노드에 직접 접근하려면 다음 명령을 사용하세요:"
    echo "aws ssm start-session --target <instance-id>"
    echo "또는"
    echo "ssh ec2-user@$NODE_IP  # SSH 키 및 보안 그룹 구성 필요"
    
    echo
    echo "=== 문제 해결 완료 ==="
  2. Terraform을 사용한 자체 복구 노드 그룹 구성:

    hcl
    # 자체 복구 노드 그룹
    resource "aws_eks_node_group" "self_healing" {
      cluster_name    = aws_eks_cluster.main.name
      node_group_name = "self-healing"
      node_role_arn   = aws_iam_role.node_role.arn
      subnet_ids      = var.private_subnet_ids
      
      scaling_config {
        desired_size = 3
        min_size     = 3
        max_size     = 6
      }
      
      # 자체 복구 설정
      update_config {
        max_unavailable = 1
      }
      
      # 상태 확인 설정
      health_check {
        type = "EKS"
      }
      
      # 자동 스케일링 그룹 태그
      tags = {
        "k8s.io/cluster-autoscaler/enabled" = "true"
        "k8s.io/cluster-autoscaler/${aws_eks_cluster.main.name}" = "owned"
      }
    }
  3. CloudWatch 경보 및 자동화된 복구 구성:

    bash
    # CloudWatch 경보 생성
    aws cloudwatch put-metric-alarm \
      --alarm-name EKS-Node-NotReady \
      --metric-name NodeNotReady \
      --namespace AWS/EKS \
      --statistic Maximum \
      --period 60 \
      --threshold 0 \
      --comparison-operator GreaterThanThreshold \
      --dimensions Name=ClusterName,Value=my-cluster \
      --evaluation-periods 3 \
      --alarm-actions arn:aws:sns:us-west-2:123456789012:eks-alerts
    
    # AWS Lambda 함수를 사용한 자동 복구
    aws lambda create-function \
      --function-name EKS-Node-Recovery \
      --runtime python3.9 \
      --role arn:aws:iam::123456789012:role/EKS-Node-Recovery-Role \
      --handler index.handler \
      --zip-file fileb://node-recovery.zip

다른 옵션들의 문제점:

  • A. 즉시 노드 종료 및 교체: 문제의 근본 원인을 파악하지 않고 노드를 교체하면 동일한 문제가 새 노드에서도 발생할 수 있으며, 진단 정보가 손실됩니다.
  • C. 클러스터 API 서버 재시작: API 서버는 노드 상태와 직접적인 관련이 없으며, API 서버 재시작은 클러스터 전체에 영향을 미칠 수 있습니다.
  • D. 모든 파드 삭제 및 재배포: 파드를 삭제해도 노드 자체의 문제는 해결되지 않으며, 불필요한 서비스 중단을 초래할 수 있습니다.
### 3. Amazon EKS 클러스터에서 파드가 "ImagePullBackOff" 상태일 때 가장 가능성 높은 원인과 해결 방법은 무엇인가요?

A. 파드 리소스 제한 초과 / 리소스 제한 증가
B. 이미지 이름 오류 또는 인증 문제 / 이미지 이름 확인 및 이미지 풀 시크릿 구성
C. 노드 디스크 공간 부족 / 디스크 공간 확보
D. 네트워크 정책 제한 / 네트워크 정책 수정

정답 및 설명

정답: B. 이미지 이름 오류 또는 인증 문제 / 이미지 이름 확인 및 이미지 풀 시크릿 구성

설명: Amazon EKS 클러스터에서 파드가 "ImagePullBackOff" 상태일 때 가장 가능성 높은 원인은 이미지 이름 오류 또는 인증 문제입니다. 이 문제를 해결하기 위해서는 이미지 이름을 확인하고 필요한 경우 이미지 풀 시크릿을 구성해야 합니다.

주요 원인 및 해결 방법:

  1. 이미지 이름 오류:

    • 잘못된 이미지 이름 또는 태그
    • 존재하지 않는 이미지
    • 레지스트리 URL 오류

    해결 방법:

    bash
    # 파드 정의 확인
    kubectl describe pod <pod-name>
    
    # 이미지 이름 및 태그 수정
    kubectl edit deployment <deployment-name>
    # 또는
    kubectl set image deployment/<deployment-name> container-name=image:tag
  2. 프라이빗 레지스트리 인증 문제:

    • 인증 자격 증명 누락
    • 만료된 자격 증명
    • 권한 부족

    해결 방법:

    bash
    # Docker 레지스트리 시크릿 생성
    kubectl create secret docker-registry regcred \
      --docker-server=<registry-server> \
      --docker-username=<username> \
      --docker-password=<password> \
      --docker-email=<email>
    
    # 파드 또는 서비스 계정에 시크릿 연결
    kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "regcred"}]}'
    # 또는
    kubectl patch pod <pod-name> -p '{"spec":{"imagePullSecrets":[{"name":"regcred"}]}}'
  3. Amazon ECR 인증 문제:

    • ECR 권한 부족
    • 만료된 토큰
    • 크로스 계정 액세스 문제

    해결 방법:

    bash
    # ECR 인증 토큰 가져오기
    aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-west-2.amazonaws.com
    
    # ECR 풀 시크릿 생성
    TOKEN=$(aws ecr get-authorization-token --output text --query 'authorizationData[].authorizationToken')
    echo $TOKEN | base64 -d | cut -d: -f2 > password.txt
    
    kubectl create secret docker-registry ecr-secret \
      --docker-server=123456789012.dkr.ecr.us-west-2.amazonaws.com \
      --docker-username=AWS \
      --docker-password="$(cat password.txt)" \
      --docker-email=no-reply@example.com
    
    rm password.txt
  4. 네트워크 연결 문제:

    • 레지스트리에 대한 네트워크 액세스 제한
    • DNS 해결 문제
    • 프록시 구성 문제

    해결 방법:

    bash
    # 노드에서 레지스트리 연결 확인
    ssh ec2-user@<node-ip>
    curl -v https://<registry-url>
    
    # DNS 해결 확인
    nslookup <registry-url>
    
    # 프라이빗 레지스트리에 대한 VPC 엔드포인트 구성
    aws ec2 create-vpc-endpoint \
      --vpc-id vpc-12345678 \
      --service-name com.amazonaws.us-west-2.ecr.dkr \
      --vpc-endpoint-type Interface \
      --subnet-ids subnet-12345678 \
      --security-group-ids sg-12345678

문제 해결 단계:

  1. 파드 상태 및 이벤트 확인:

    bash
    # 파드 상태 확인
    kubectl get pod <pod-name>
    
    # 파드 세부 정보 및 이벤트 확인
    kubectl describe pod <pod-name>
  2. 이미지 이름 및 레지스트리 확인:

    bash
    # 이미지 이름 확인
    kubectl get pod <pod-name> -o jsonpath='{.spec.containers[0].image}'
    
    # 이미지 존재 여부 확인
    docker pull <image-name>  # 로컬 환경에서
    # 또는
    aws ecr describe-images \
      --repository-name <repository-name> \
      --image-ids imageTag=<tag>  # ECR의 경우
  3. 인증 구성 확인:

    bash
    # 서비스 계정 및 이미지 풀 시크릿 확인
    kubectl get serviceaccount default -o yaml
    
    # 시크릿 내용 확인
    kubectl get secret <secret-name> -o yaml
  4. 임시 해결책 적용:

    bash
    # 로컬에서 이미지 가져오기 및 노드로 전송 (긴급 상황용)
    docker pull <image-name>
    docker save <image-name> -o image.tar
    scp image.tar ec2-user@<node-ip>:~/
    ssh ec2-user@<node-ip> "docker load -i image.tar"

모범 사례:

  1. 이미지 태그 관리:

    • 특정 태그 대신 다이제스트 사용
    • latest 태그 사용 지양
    • 버전 관리 전략 구현
  2. 이미지 풀 시크릿 관리:

    • 서비스 계정에 시크릿 연결
    • 시크릿 정기적 갱신
    • 시크릿 관리 자동화
  3. 이미지 레지스트리 접근성 보장:

    • 프라이빗 레지스트리의 경우 VPC 엔드포인트 구성
    • 네트워크 정책 및 보안 그룹 구성
    • 이미지 캐싱 고려
  4. ECR 사용 시 모범 사례:

    • IAM 역할 기반 인증 사용
    • 자동 토큰 갱신 구현
    • 이미지 스캔 및 수명 주기 정책 구성

실제 구현 예시:

  1. ECR 인증을 위한 Kubernetes 작업:

    yaml
    apiVersion: batch/v1
    kind: CronJob
    metadata:
      name: ecr-credential-updater
      namespace: kube-system
    spec:
      schedule: "*/6 * * * *"  # 6시간마다 실행
      jobTemplate:
        spec:
          template:
            spec:
              serviceAccountName: ecr-credential-updater
              containers:
              - name: ecr-credential-updater
                image: amazon/aws-cli:latest
                command:
                - /bin/sh
                - -c
                - |
                  TOKEN=$(aws ecr get-authorization-token --output text --query 'authorizationData[].authorizationToken')
                  echo $TOKEN | base64 -d | cut -d: -f2 > /tmp/docker-password
                  kubectl delete secret ecr-secret --ignore-not-found
                  kubectl create secret docker-registry ecr-secret \
                    --docker-server=123456789012.dkr.ecr.us-west-2.amazonaws.com \
                    --docker-username=AWS \
                    --docker-password="$(cat /tmp/docker-password)" \
                    --docker-email=no-reply@example.com
                  kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "ecr-secret"}]}'
                env:
                - name: AWS_REGION
                  value: us-west-2
              restartPolicy: OnFailure
  2. Terraform을 사용한 ECR 풀 시크릿 구성:

    hcl
    # ECR 리포지토리
    resource "aws_ecr_repository" "app" {
      name = "my-app"
    }
    
    # ECR 풀 시크릿을 위한 IAM 역할
    resource "aws_iam_role" "ecr_pull" {
      name = "ecr-pull-role"
      
      assume_role_policy = jsonencode({
        Version = "2012-10-17",
        Statement = [{
          Effect = "Allow",
          Principal = {
            Service = "ec2.amazonaws.com"
          },
          Action = "sts:AssumeRole"
        }]
      })
    }
    
    # ECR 풀 정책
    resource "aws_iam_policy" "ecr_pull" {
      name = "ecr-pull-policy"
      
      policy = jsonencode({
        Version = "2012-10-17",
        Statement = [{
          Effect = "Allow",
          Action = [
            "ecr:GetDownloadUrlForLayer",
            "ecr:BatchGetImage",
            "ecr:BatchCheckLayerAvailability",
            "ecr:GetAuthorizationToken"
          ],
          Resource = "*"
        }]
      })
    }
    
    # 정책 연결
    resource "aws_iam_role_policy_attachment" "ecr_pull" {
      role       = aws_iam_role.ecr_pull.name
      policy_arn = aws_iam_policy.ecr_pull.arn
    }
  3. 이미지 풀 문제 해결 스크립트:

    bash
    #!/bin/bash
    # 이미지 풀 문제 해결 스크립트
    
    POD_NAME=$1
    
    if [ -z "$POD_NAME" ]; then
      echo "파드 이름을 지정하세요."
      exit 1
    fi
    
    echo "=== 파드 $POD_NAME 이미지 풀 문제 해결 ==="
    
    # 파드 상태 확인
    echo "=== 파드 상태 확인 ==="
    kubectl get pod $POD_NAME
    
    # 파드 이벤트 확인
    echo
    echo "=== 파드 이벤트 확인 ==="
    kubectl describe pod $POD_NAME | grep -A 20 "Events:"
    
    # 이미지 정보 확인
    echo
    echo "=== 이미지 정보 확인 ==="
    IMAGE=$(kubectl get pod $POD_NAME -o jsonpath='{.spec.containers[0].image}')
    echo "이미지: $IMAGE"
    
    # 이미지 레지스트리 확인
    REGISTRY=$(echo $IMAGE | cut -d/ -f1)
    echo "레지스트리: $REGISTRY"
    
    # 이미지 풀 시크릿 확인
    echo
    echo "=== 이미지 풀 시크릿 확인 ==="
    SA_NAME=$(kubectl get pod $POD_NAME -o jsonpath='{.spec.serviceAccountName}')
    if [ -z "$SA_NAME" ]; then
      SA_NAME="default"
    fi
    echo "서비스 계정: $SA_NAME"
    
    kubectl get serviceaccount $SA_NAME -o yaml
    
    # ECR 레지스트리인 경우
    if [[ $REGISTRY == *.dkr.ecr.*.amazonaws.com ]]; then
      echo
      echo "=== ECR 레지스트리 확인 ==="
      REGION=$(echo $REGISTRY | cut -d. -f4)
      ACCOUNT=$(echo $REGISTRY | cut -d. -f1)
      REPO=$(echo $IMAGE | cut -d/ -f2- | cut -d: -f1)
      TAG=$(echo $IMAGE | cut -d: -f2)
      
      echo "리전: $REGION"
      echo "계정: $ACCOUNT"
      echo "리포지토리: $REPO"
      echo "태그: $TAG"
      
      echo
      echo "ECR 인증 토큰 확인:"
      aws ecr get-authorization-token --region $REGION
    fi
    
    echo
    echo "=== 문제 해결 권장 사항 ==="
    echo "1. 이미지 이름과 태그가 올바른지 확인하세요."
    echo "2. 프라이빗 레지스트리의 경우 이미지 풀 시크릿을 구성하세요."
    echo "3. ECR의 경우 노드 IAM 역할에 ECR 액세스 권한이 있는지 확인하세요."
    echo "4. 네트워크 연결을 확인하세요."

다른 옵션들의 문제점:

  • A. 파드 리소스 제한 초과 / 리소스 제한 증가: 리소스 제한 문제는 일반적으로 "ImagePullBackOff"가 아닌 "OOMKilled" 또는 "Pending" 상태를 유발합니다.
  • C. 노드 디스크 공간 부족 / 디스크 공간 확보: 디스크 공간 부족은 "ImagePullBackOff"의 원인이 될 수 있지만, 이 경우 일반적으로 노드 이벤트에 디스크 공간 관련 오류가 표시되며, 가장 일반적인 원인은 아닙니다.
  • D. 네트워크 정책 제한 / 네트워크 정책 수정: 네트워크 정책은 파드 간 통신에 영향을 미치지만, 일반적으로 이미지 풀 문제의 주요 원인은 아닙니다.
### 4. Amazon EKS 클러스터에서 서비스가 파드에 트래픽을 라우팅하지 않을 때 가장 효과적인 문제 해결 단계는 무엇인가요?

A. 즉시 새 서비스 생성
B. 서비스 및 파드 레이블, 엔드포인트, 네트워크 정책 확인
C. 모든 파드 재시작
D. 클러스터 API 서버 재시작

정답 및 설명

정답: B. 서비스 및 파드 레이블, 엔드포인트, 네트워크 정책 확인

설명: Amazon EKS 클러스터에서 서비스가 파드에 트래픽을 라우팅하지 않을 때 가장 효과적인 문제 해결 단계는 서비스 및 파드 레이블, 엔드포인트, 네트워크 정책을 확인하는 것입니다. 이 체계적인 접근 방식은 서비스 디스커버리 및 트래픽 라우팅 문제의 근본 원인을 식별하는 데 도움이 됩니다.

주요 확인 사항:

  1. 서비스 및 파드 레이블 확인:

    • 서비스 셀렉터와 파드 레이블 일치 여부
    • 레이블 구문 및 오타
    • 네임스페이스 확인
  2. 엔드포인트 확인:

    • 서비스 엔드포인트 생성 여부
    • 엔드포인트 IP 및 파드 IP 일치 여부
    • Ready 상태의 파드 수
  3. 네트워크 정책 확인:

    • 트래픽을 제한하는 네트워크 정책 존재 여부
    • 인그레스 및 이그레스 규칙
    • 네임스페이스 간 통신 제한
  4. 서비스 및 파드 상태 확인:

    • 파드 실행 및 준비 상태
    • 서비스 유형 및 포트 구성
    • 상태 확인 구성

문제 해결 방법:

  1. 서비스 및 파드 레이블 확인:

    bash
    # 서비스 셀렉터 확인
    kubectl get service <service-name> -o yaml | grep -A 5 selector
    
    # 파드 레이블 확인
    kubectl get pods --show-labels
    
    # 셀렉터와 일치하는 파드 확인
    kubectl get pods -l key=value
  2. 엔드포인트 확인:

    bash
    # 서비스 엔드포인트 확인
    kubectl get endpoints <service-name>
    
    # 엔드포인트 세부 정보 확인
    kubectl describe endpoints <service-name>
    
    # 엔드포인트 및 파드 IP 비교
    kubectl get pods -o wide
  3. 네트워크 정책 확인:

    bash
    # 네트워크 정책 확인
    kubectl get networkpolicy
    
    # 네트워크 정책 세부 정보 확인
    kubectl describe networkpolicy <policy-name>
    
    # 임시로 네트워크 정책 비활성화
    kubectl delete networkpolicy <policy-name>
  4. 서비스 연결 테스트:

    bash
    # 임시 디버그 파드 생성
    kubectl run -it --rm debug --image=nicolaka/netshoot -- bash
    
    # 서비스 DNS 해결 테스트
    nslookup <service-name>.<namespace>.svc.cluster.local
    
    # 서비스 연결 테스트
    curl <service-ip>:<port>
    
    # 파드 직접 연결 테스트
    curl <pod-ip>:<container-port>

일반적인 서비스 문제 및 해결 방법:

  1. 레이블 불일치:

    • 증상: 서비스 엔드포인트가 비어 있음
    • 해결 방법:
      bash
      # 서비스 셀렉터 수정
      kubectl edit service <service-name>
      # 또는
      kubectl patch service <service-name> -p '{"spec":{"selector":{"app":"correct-label"}}}'
      
      # 파드 레이블 수정
      kubectl label pods <pod-name> app=correct-label --overwrite
  2. 포트 구성 오류:

    • 증상: 서비스는 연결되지만 애플리케이션 응답 없음
    • 해결 방법:
      bash
      # 서비스 포트 구성 확인
      kubectl describe service <service-name>
      
      # 파드 컨테이너 포트 확인
      kubectl describe pod <pod-name>
      
      # 서비스 포트 수정
      kubectl edit service <service-name>
  3. 네트워크 정책 제한:

    • 증상: 특정 소스에서만 서비스에 액세스할 수 없음
    • 해결 방법:
      bash
      # 네트워크 정책 수정
      kubectl edit networkpolicy <policy-name>
      
      # 허용 규칙 추가
      kubectl apply -f - <<EOF
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-service-access
        namespace: <namespace>
      spec:
        podSelector:
          matchLabels:
            app: <app-label>
        ingress:
        - from:
          - namespaceSelector: {}
        policyTypes:
        - Ingress
      EOF
  4. CoreDNS 문제:

    • 증상: 서비스 이름 해결 실패
    • 해결 방법:
      bash
      # CoreDNS 파드 확인
      kubectl get pods -n kube-system -l k8s-app=kube-dns
      
      # CoreDNS 로그 확인
      kubectl logs -n kube-system -l k8s-app=kube-dns
      
      # CoreDNS 구성 확인
      kubectl get configmap -n kube-system coredns -o yaml

모범 사례:

  1. 체계적인 문제 해결 접근 방식:

    • 서비스 구성부터 시작하여 파드, 네트워크 정책, DNS 순으로 확인
    • 각 단계에서 명확한 증거 수집
    • 한 번에 하나의 변수만 변경
  2. 서비스 디버깅 도구 활용:

    bash
    # kube-proxy 로그 확인
    kubectl logs -n kube-system -l k8s-app=kube-proxy
    
    # iptables 규칙 확인 (자체 관리형 노드의 경우)
    ssh ec2-user@<node-ip>
    sudo iptables-save | grep <service-ip>
    
    # DNS 디버깅
    kubectl run -it --rm dnsutils --image=tutum/dnsutils -- bash
  3. 서비스 모니터링 구현:

    • 서비스 엔드포인트 상태 모니터링
    • 서비스 연결 상태 확인
    • 트래픽 흐름 시각화
  4. 서비스 구성 관리:

    • 일관된 레이블 지정 전략
    • 명시적 포트 이름 지정
    • 서비스 문서화

실제 구현 예시:

  1. 서비스 문제 해결 스크립트:

    bash
    #!/bin/bash
    # 서비스 문제 해결 스크립트
    
    SERVICE_NAME=$1
    NAMESPACE=${2:-default}
    
    if [ -z "$SERVICE_NAME" ]; then
      echo "서비스 이름을 지정하세요."
      exit 1
    fi
    
    echo "=== 서비스 $SERVICE_NAME 문제 해결 ==="
    echo "네임스페이스: $NAMESPACE"
    
    # 서비스 확인
    echo
    echo "=== 서비스 세부 정보 ==="
    kubectl get service $SERVICE_NAME -n $NAMESPACE -o wide
    
    # 서비스 셀렉터 확인
    echo
    echo "=== 서비스 셀렉터 ==="
    SELECTOR=$(kubectl get service $SERVICE_NAME -n $NAMESPACE -o jsonpath='{.spec.selector}' | jq -r 'to_entries | map("\(.key)=\(.value)") | join(",")')
    echo "셀렉터: $SELECTOR"
    
    # 일치하는 파드 확인
    echo
    echo "=== 일치하는 파드 ==="
    if [ -n "$SELECTOR" ]; then
      kubectl get pods -n $NAMESPACE -l $SELECTOR -o wide
      POD_COUNT=$(kubectl get pods -n $NAMESPACE -l $SELECTOR --no-headers | wc -l)
      echo "일치하는 파드 수: $POD_COUNT"
    else
      echo "서비스에 셀렉터가 없습니다."
    fi
    
    # 엔드포인트 확인
    echo
    echo "=== 엔드포인트 ==="
    kubectl get endpoints $SERVICE_NAME -n $NAMESPACE
    kubectl describe endpoints $SERVICE_NAME -n $NAMESPACE
    
    # 네트워크 정책 확인
    echo
    echo "=== 네트워크 정책 ==="
    NETPOL_COUNT=$(kubectl get networkpolicy -n $NAMESPACE --no-headers | wc -l)
    if [ $NETPOL_COUNT -gt 0 ]; then
      kubectl get networkpolicy -n $NAMESPACE
      echo
      echo "네트워크 정책이 서비스 액세스를 제한할 수 있습니다."
    else
      echo "네임스페이스에 네트워크 정책이 없습니다."
    fi
    
    # 서비스 테스트
    echo
    echo "=== 서비스 테스트 ==="
    SERVICE_IP=$(kubectl get service $SERVICE_NAME -n $NAMESPACE -o jsonpath='{.spec.clusterIP}')
    SERVICE_PORT=$(kubectl get service $SERVICE_NAME -n $NAMESPACE -o jsonpath='{.spec.ports[0].port}')
    
    echo "서비스 IP: $SERVICE_IP"
    echo "서비스 포트: $SERVICE_PORT"
    echo
    echo "서비스 연결 테스트를 위해 다음 명령을 실행하세요:"
    echo "kubectl run -it --rm debug --image=nicolaka/netshoot -- bash"
    echo "curl $SERVICE_IP:$SERVICE_PORT"
    
    echo
    echo "=== 문제 해결 권장 사항 ==="
    if [ $POD_COUNT -eq 0 ]; then
      echo "- 서비스 셀렉터와 일치하는 파드가 없습니다. 파드 레이블 또는 서비스 셀렉터를 확인하세요."
    fi
    
    READY_PODS=$(kubectl get pods -n $NAMESPACE -l $SELECTOR -o jsonpath='{.items[?(@.status.phase=="Running")].status.containerStatuses[0].ready}' | grep -o "true" | wc -l)
    if [ $READY_PODS -eq 0 ] && [ $POD_COUNT -gt 0 ]; then
      echo "- 일치하는 파드가 있지만 Ready 상태가 아닙니다. 파드 상태를 확인하세요."
    fi
    
    if [ $NETPOL_COUNT -gt 0 ]; then
      echo "- 네트워크 정책이 서비스 액세스를 제한할 수 있습니다. 네트워크 정책을 검토하세요."
    fi
    
    echo "- 서비스 포트와 파드 컨테이너 포트가 일치하는지 확인하세요."
    echo "- CoreDNS가 올바르게 작동하는지 확인하세요."
  2. Terraform을 사용한 서비스 및 파드 구성:

    hcl
    # 서비스 정의
    resource "kubernetes_service" "app" {
      metadata {
        name      = "app-service"
        namespace = kubernetes_namespace.app.metadata[0].name
      }
      
      spec {
        selector = {
          app = kubernetes_deployment.app.spec[0].template[0].metadata[0].labels.app
        }
        
        port {
          name        = "http"
          port        = 80
          target_port = 8080
        }
        
        type = "ClusterIP"
      }
    }
    
    # 배포 정의
    resource "kubernetes_deployment" "app" {
      metadata {
        name      = "app-deployment"
        namespace = kubernetes_namespace.app.metadata[0].name
      }
      
      spec {
        replicas = 3
        
        selector {
          match_labels = {
            app = "my-app"
          }
        }
        
        template {
          metadata {
            labels = {
              app = "my-app"
            }
          }
          
          spec {
            container {
              name  = "app"
              image = "my-app:latest"
              
              port {
                container_port = 8080
              }
              
              readiness_probe {
                http_get {
                  path = "/health"
                  port = 8080
                }
                
                initial_delay_seconds = 10
                period_seconds        = 5
              }
            }
          }
        }
      }
    }
  3. 서비스 연결 테스트 작업:

    yaml
    apiVersion: batch/v1
    kind: Job
    metadata:
      name: service-test
    spec:
      template:
        spec:
          containers:
          - name: service-test
            image: nicolaka/netshoot
            command:
            - /bin/bash
            - -c
            - |
              echo "=== DNS 해결 테스트 ==="
              nslookup app-service
              nslookup app-service.default.svc.cluster.local
              
              echo
              echo "=== 서비스 연결 테스트 ==="
              curl -v app-service:80
              
              echo
              echo "=== 직접 파드 연결 테스트 ==="
              for POD_IP in $(kubectl get pods -l app=my-app -o jsonpath='{.items[*].status.podIP}'); do
                echo "테스트 파드 IP: $POD_IP"
                curl -v $POD_IP:8080
              done
          restartPolicy: Never

다른 옵션들의 문제점:

  • A. 즉시 새 서비스 생성: 문제의 근본 원인을 파악하지 않고 새 서비스를 생성하면 동일한 문제가 발생할 수 있으며, 진단 정보가 손실됩니다.
  • C. 모든 파드 재시작: 파드를 재시작해도 서비스 구성 문제는 해결되지 않으며, 불필요한 서비스 중단을 초래할 수 있습니다.
  • D. 클러스터 API 서버 재시작: API 서버 재시작은 극단적인 조치이며, 서비스 라우팅 문제와 직접적인 관련이 없습니다. 또한 클러스터 전체에 영향을 미칠 수 있습니다.
### 5. Amazon EKS 클러스터에서 PersistentVolumeClaim이 "Pending" 상태로 유지될 때 가장 가능성 높은 원인과 해결 방법은 무엇인가요?

A. 노드 리소스 부족 / 더 큰 노드 추가
B. 스토리지 클래스 문제 또는 볼륨 프로비저닝 권한 부족 / 스토리지 클래스 확인 및 IAM 권한 구성
C. 파드 우선순위 낮음 / 파드 우선순위 증가
D. 클러스터 자동 스케일러 비활성화 / 자동 스케일러 활성화

정답 및 설명

정답: B. 스토리지 클래스 문제 또는 볼륨 프로비저닝 권한 부족 / 스토리지 클래스 확인 및 IAM 권한 구성

설명: Amazon EKS 클러스터에서 PersistentVolumeClaim(PVC)이 "Pending" 상태로 유지될 때 가장 가능성 높은 원인은 스토리지 클래스 문제 또는 볼륨 프로비저닝 권한 부족입니다. 이 문제를 해결하기 위해서는 스토리지 클래스를 확인하고 필요한 IAM 권한을 구성해야 합니다.

주요 원인 및 해결 방법:

  1. 스토리지 클래스 문제:

    • 존재하지 않는 스토리지 클래스 지정
    • 스토리지 클래스 파라미터 오류
    • 프로비저너 구성 문제

    해결 방법:

    bash
    # 스토리지 클래스 확인
    kubectl get storageclass
    
    # 스토리지 클래스 세부 정보 확인
    kubectl describe storageclass <storage-class-name>
    
    # 기본 스토리지 클래스 설정
    kubectl patch storageclass <storage-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
  2. IAM 권한 부족:

    • EBS CSI 드라이버 서비스 계정 권한 부족
    • 노드 IAM 역할 권한 부족
    • 크로스 계정 액세스 문제

    해결 방법:

    bash
    # EBS CSI 드라이버 서비스 계정 확인
    kubectl get serviceaccount -n kube-system ebs-csi-controller-sa
    
    # IAM 역할 연결 확인
    kubectl describe serviceaccount -n kube-system ebs-csi-controller-sa
    
    # 필요한 IAM 정책 연결
    aws iam attach-role-policy \
      --role-name <role-name> \
      --policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy
  3. 볼륨 바인딩 모드 문제:

    • 가용 영역 불일치
    • WaitForFirstConsumer 설정 문제
    • 토폴로지 제약 조건

    해결 방법:

    bash
    # 볼륨 바인딩 모드 확인
    kubectl get storageclass <storage-class-name> -o jsonpath='{.volumeBindingMode}'
    
    # 스토리지 클래스 수정
    kubectl patch storageclass <storage-class-name> -p '{"volumeBindingMode":"WaitForFirstConsumer"}'
    
    # 새 스토리지 클래스 생성
    kubectl apply -f - <<EOF
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: ebs-sc-waitforfirstconsumer
    provisioner: ebs.csi.aws.com
    volumeBindingMode: WaitForFirstConsumer
    parameters:
      type: gp3
    EOF
  4. CSI 드라이버 문제:

    • CSI 드라이버 미설치 또는 오류
    • 버전 호환성 문제
    • 컨트롤러 파드 오류

    해결 방법:

    bash
    # CSI 드라이버 파드 확인
    kubectl get pods -n kube-system -l app=ebs-csi-controller
    
    # CSI 드라이버 로그 확인
    kubectl logs -n kube-system -l app=ebs-csi-controller -c ebs-plugin
    
    # CSI 드라이버 재설치
    eksctl create addon --name aws-ebs-csi-driver --cluster <cluster-name> --force

문제 해결 단계:

  1. PVC 상태 및 이벤트 확인:

    bash
    # PVC 상태 확인
    kubectl get pvc <pvc-name>
    
    # PVC 세부 정보 및 이벤트 확인
    kubectl describe pvc <pvc-name>
  2. 스토리지 클래스 확인:

    bash
    # 스토리지 클래스 목록 확인
    kubectl get storageclass
    
    # PVC에서 사용하는 스토리지 클래스 확인
    kubectl get pvc <pvc-name> -o jsonpath='{.spec.storageClassName}'
    
    # 스토리지 클래스 세부 정보 확인
    kubectl describe storageclass <storage-class-name>
  3. CSI 드라이버 확인:

    bash
    # CSI 드라이버 파드 확인
    kubectl get pods -n kube-system -l app=ebs-csi-controller
    
    # CSI 드라이버 로그 확인
    kubectl logs -n kube-system -l app=ebs-csi-controller -c ebs-plugin
  4. IAM 권한 확인:

    bash
    # 서비스 계정 확인
    kubectl get serviceaccount -n kube-system ebs-csi-controller-sa -o yaml
    
    # IRSA 구성 확인
    aws eks describe-addon \
      --cluster-name <cluster-name> \
      --addon-name aws-ebs-csi-driver \
      --query "addon.serviceAccountRoleArn"

모범 사례:

  1. 적절한 스토리지 클래스 구성:

    yaml
    # gp3 스토리지 클래스 예시
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: ebs-gp3
      annotations:
        storageclass.kubernetes.io/is-default-class: "true"
    provisioner: ebs.csi.aws.com
    volumeBindingMode: WaitForFirstConsumer
    parameters:
      type: gp3
      encrypted: "true"
    allowVolumeExpansion: true
  2. IRSA(IAM Roles for Service Accounts) 구성:

    bash
    # EBS CSI 드라이버용 IRSA 생성
    eksctl create iamserviceaccount \
      --name ebs-csi-controller-sa \
      --namespace kube-system \
      --cluster <cluster-name> \
      --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy \
      --approve \
      --override-existing-serviceaccounts
  3. PVC 요청 최적화:

    yaml
    # 최적화된 PVC 예시
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: my-pvc
    spec:
      accessModes:
        - ReadWriteOnce
      storageClassName: ebs-gp3
      resources:
        requests:
          storage: 10Gi
  4. 볼륨 바인딩 모드 최적화:

    • WaitForFirstConsumer 사용
    • 파드와 PV의 가용 영역 일치 보장
    • 토폴로지 인식 프로비저닝 활용 실제 구현 예시:
  5. PVC 문제 해결 스크립트:

    bash
    #!/bin/bash
    # PVC 문제 해결 스크립트
    
    PVC_NAME=$1
    NAMESPACE=${2:-default}
    
    if [ -z "$PVC_NAME" ]; then
      echo "PVC 이름을 지정하세요."
      exit 1
    fi
    
    echo "=== PVC $PVC_NAME 문제 해결 ==="
    echo "네임스페이스: $NAMESPACE"
    
    # PVC 상태 확인
    echo
    echo "=== PVC 상태 ==="
    kubectl get pvc $PVC_NAME -n $NAMESPACE
    
    # PVC 세부 정보 확인
    echo
    echo "=== PVC 세부 정보 ==="
    kubectl describe pvc $PVC_NAME -n $NAMESPACE
    
    # 스토리지 클래스 확인
    SC_NAME=$(kubectl get pvc $PVC_NAME -n $NAMESPACE -o jsonpath='{.spec.storageClassName}')
    if [ -z "$SC_NAME" ]; then
      SC_NAME="<default>"
    fi
    
    echo
    echo "=== 스토리지 클래스: $SC_NAME ==="
    kubectl get storageclass $SC_NAME
    kubectl describe storageclass $SC_NAME
    
    # CSI 드라이버 확인
    echo
    echo "=== CSI 드라이버 상태 ==="
    kubectl get pods -n kube-system -l app=ebs-csi-controller
    
    # CSI 드라이버 로그 확인
    echo
    echo "=== CSI 드라이버 로그 ==="
    CSI_POD=$(kubectl get pods -n kube-system -l app=ebs-csi-controller -o jsonpath='{.items[0].metadata.name}')
    if [ -n "$CSI_POD" ]; then
      kubectl logs -n kube-system $CSI_POD -c ebs-plugin --tail=20
    else
      echo "CSI 드라이버 파드를 찾을 수 없습니다."
    fi
    
    # 바인딩된 파드 확인
    echo
    echo "=== 바인딩된 파드 ==="
    kubectl get pods -n $NAMESPACE --field-selector=spec.volumes.persistentVolumeClaim.claimName=$PVC_NAME
    
    echo
    echo "=== 문제 해결 권장 사항 ==="
    PVC_STATUS=$(kubectl get pvc $PVC_NAME -n $NAMESPACE -o jsonpath='{.status.phase}')
    
    if [ "$PVC_STATUS" == "Pending" ]; then
      echo "1. 스토리지 클래스가 올바르게 구성되어 있는지 확인하세요."
      echo "2. EBS CSI 드라이버가 설치되어 있고 올바르게 작동하는지 확인하세요."
      echo "3. 서비스 계정에 볼륨 프로비저닝에 필요한 IAM 권한이 있는지 확인하세요."
      echo "4. 볼륨 바인딩 모드가 WaitForFirstConsumer인 경우 파드가 생성되었는지 확인하세요."
    elif [ "$PVC_STATUS" == "Bound" ]; then
      echo "PVC가 이미 바인딩되어 있습니다. 파드가 볼륨을 마운트할 수 있는지 확인하세요."
    else
      echo "PVC 상태를 확인하고 이벤트를 검토하세요."
    fi
  6. Terraform을 사용한 EBS CSI 드라이버 구성:

    hcl
    # EBS CSI 드라이버용 IAM 역할
    module "ebs_csi_irsa" {
      source  = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
      version = "~> 5.0"
      
      role_name             = "ebs-csi-controller-role"
      attach_ebs_csi_policy = true
      
      oidc_providers = {
        main = {
          provider_arn               = module.eks.oidc_provider_arn
          namespace_service_accounts = ["kube-system:ebs-csi-controller-sa"]
        }
      }
    }
    
    # EBS CSI 드라이버 애드온
    resource "aws_eks_addon" "ebs_csi_driver" {
      cluster_name             = module.eks.cluster_name
      addon_name               = "aws-ebs-csi-driver"
      addon_version            = "v1.16.0-eksbuild.1"
      service_account_role_arn = module.ebs_csi_irsa.iam_role_arn
      
      configuration_values = jsonencode({
        controller = {
          extraVolumeTags = {
            Environment = "production"
            Terraform   = "true"
          }
        }
      })
    }
    
    # 스토리지 클래스
    resource "kubernetes_storage_class" "ebs_gp3" {
      metadata {
        name = "ebs-gp3"
        annotations = {
          "storageclass.kubernetes.io/is-default-class" = "true"
        }
      }
      
      storage_provisioner    = "ebs.csi.aws.com"
      volume_binding_mode    = "WaitForFirstConsumer"
      allow_volume_expansion = true
      
      parameters = {
        type      = "gp3"
        encrypted = "true"
      }
    }
  7. PVC 디버깅 작업:

    yaml
    apiVersion: batch/v1
    kind: Job
    metadata:
      name: pvc-debug
    spec:
      template:
        spec:
          containers:
          - name: debug
            image: amazon/aws-cli:latest
            command:
            - /bin/bash
            - -c
            - |
              echo "=== AWS 계정 정보 ==="
              aws sts get-caller-identity
              
              echo
              echo "=== EBS 볼륨 목록 ==="
              aws ec2 describe-volumes \
                --filters "Name=tag:kubernetes.io/cluster/my-cluster,Values=owned" \
                --query "Volumes[*].{ID:VolumeId,Size:Size,Type:VolumeType,State:State,AZ:AvailabilityZone}"
              
              echo
              echo "=== 가용 영역 정보 ==="
              NODE_AZ=$(kubectl get nodes -o jsonpath='{.items[0].metadata.labels.topology\.kubernetes\.io/zone}')
              echo "노드 가용 영역: $NODE_AZ"
              
              echo
              echo "=== 볼륨 생성 테스트 ==="
              aws ec2 create-volume \
                --availability-zone $NODE_AZ \
                --size 1 \
                --volume-type gp3 \
                --tag-specifications 'ResourceType=volume,Tags=[{Key=test,Value=pvc-debug}]'
              
              sleep 10
              
              aws ec2 describe-volumes \
                --filters "Name=tag:test,Values=pvc-debug" \
                --query "Volumes[*].{ID:VolumeId,State:State}"
          restartPolicy: Never

다른 옵션들의 문제점:

  • A. 노드 리소스 부족 / 더 큰 노드 추가: 노드 리소스 부족은 일반적으로 파드가 "Pending" 상태가 되는 원인이지만, PVC가 "Pending" 상태인 것과는 직접적인 관련이 없습니다.
  • C. 파드 우선순위 낮음 / 파드 우선순위 증가: 파드 우선순위는 스케줄링 결정에 영향을 미치지만, PVC 프로비저닝에는 영향을 미치지 않습니다.
  • D. 클러스터 자동 스케일러 비활성화 / 자동 스케일러 활성화: 자동 스케일러는 노드 수를 조정하는 데 도움이 되지만, PVC 프로비저닝 문제와는 직접적인 관련이 없습니다.
### 6. Amazon EKS 클러스터에서 자동 스케일링이 예상대로 작동하지 않을 때 가장 효과적인 문제 해결 접근 방식은 무엇인가요?

A. 모든 파드에 더 많은 리소스 할당
B. 수동으로 노드 추가
C. HPA, CA, VPA 구성, 메트릭, 권한 및 이벤트 확인
D. 클러스터 재생성

정답 및 설명

정답: C. HPA, CA, VPA 구성, 메트릭, 권한 및 이벤트 확인

설명: Amazon EKS 클러스터에서 자동 스케일링이 예상대로 작동하지 않을 때 가장 효과적인 문제 해결 접근 방식은 HPA(Horizontal Pod Autoscaler), CA(Cluster Autoscaler), VPA(Vertical Pod Autoscaler) 구성, 메트릭, 권한 및 이벤트를 확인하는 것입니다. 이 체계적인 접근 방식은 자동 스케일링 문제의 근본 원인을 식별하고 해결하는 데 도움이 됩니다.

주요 확인 사항:

  1. HPA(Horizontal Pod Autoscaler) 확인:

    • HPA 구성 및 상태
    • 메트릭 가용성 및 값
    • 스케일링 제한 및 동작
  2. CA(Cluster Autoscaler) 확인:

    • CA 배포 및 구성
    • IAM 권한 및 역할
    • 노드 그룹 태그 및 설정
  3. VPA(Vertical Pod Autoscaler) 확인:

    • VPA 구성 및 모드
    • 리소스 권장 사항
    • 업데이트 정책
  4. 메트릭 및 이벤트 확인:

    • 메트릭 서버 상태
    • CloudWatch 메트릭 가용성
    • 자동 스케일링 이벤트 및 로그

문제 해결 방법:

  1. HPA 문제 해결:

    bash
    # HPA 상태 확인
    kubectl get hpa
    
    # HPA 세부 정보 확인
    kubectl describe hpa <hpa-name>
    
    # 메트릭 확인
    kubectl get --raw "/apis/metrics.k8s.io/v1beta1/namespaces/<namespace>/pods"
    
    # 메트릭 서버 상태 확인
    kubectl get pods -n kube-system -l k8s-app=metrics-server
    kubectl logs -n kube-system -l k8s-app=metrics-server
  2. CA 문제 해결:

    bash
    # CA 파드 상태 확인
    kubectl get pods -n kube-system -l app=cluster-autoscaler
    
    # CA 로그 확인
    kubectl logs -n kube-system -l app=cluster-autoscaler
    
    # 노드 그룹 태그 확인
    aws autoscaling describe-auto-scaling-groups \
      --auto-scaling-group-names <asg-name> \
      --query "AutoScalingGroups[].Tags"
    
    # CA 이벤트 확인
    kubectl get events --sort-by='.lastTimestamp' | grep -i "cluster-autoscaler"
  3. VPA 문제 해결:

    bash
    # VPA 상태 확인
    kubectl get vpa
    
    # VPA 세부 정보 확인
    kubectl describe vpa <vpa-name>
    
    # VPA 권장 사항 확인
    kubectl get vpa <vpa-name> -o jsonpath='{.status.recommendation}'
    
    # VPA 컴포넌트 상태 확인
    kubectl get pods -n kube-system -l app=vpa-recommender
  4. 메트릭 및 권한 문제 해결:

    bash
    # 메트릭 서버 상태 확인
    kubectl get apiservices v1beta1.metrics.k8s.io
    
    # IAM 역할 및 정책 확인
    aws iam get-role --role-name <role-name>
    aws iam list-attached-role-policies --role-name <role-name>
    
    # CloudWatch 메트릭 확인
    aws cloudwatch list-metrics \
      --namespace AWS/EC2 \
      --metric-name CPUUtilization \
      --dimensions Name=AutoScalingGroupName,Value=<asg-name>

일반적인 자동 스케일링 문제 및 해결 방법:

  1. HPA 메트릭 문제:

    • 증상: HPA가 스케일링 결정을 내리지 않음
    • 원인: 메트릭 서버 오류 또는 메트릭 가용성 문제
    • 해결 방법:
      bash
      # 메트릭 서버 재설치
      kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
      
      # 메트릭 확인
      kubectl top pods
      kubectl top nodes
  2. CA 권한 문제:

    • 증상: CA가 노드를 추가하지 못함
    • 원인: IAM 권한 부족 또는 ASG 태그 누락
    • 해결 방법:
      bash
      # CA IAM 정책 연결
      aws iam attach-role-policy \
        --role-name <role-name> \
        --policy-arn arn:aws:iam::aws:policy/AutoScalingFullAccess
      
      # ASG 태그 추가
      aws autoscaling create-or-update-tags \
        --tags "ResourceId=<asg-name>,ResourceType=auto-scaling-group,Key=k8s.io/cluster-autoscaler/enabled,Value=true,PropagateAtLaunch=true" \
        "ResourceId=<asg-name>,ResourceType=auto-scaling-group,Key=k8s.io/cluster-autoscaler/<cluster-name>,Value=owned,PropagateAtLaunch=true"
  3. 스케일링 제한 문제:

    • 증상: 스케일링이 특정 값을 초과하지 않음
    • 원인: HPA 또는 CA 제한 설정
    • 해결 방법:
      bash
      # HPA 최대 복제본 수 수정
      kubectl patch hpa <hpa-name> -p '{"spec":{"maxReplicas":20}}'
      
      # ASG 최대 크기 수정
      aws autoscaling update-auto-scaling-group \
        --auto-scaling-group-name <asg-name> \
        --max-size 10
  4. VPA 업데이트 모드 문제:

    • 증상: VPA가 리소스를 업데이트하지 않음
    • 원인: 업데이트 모드가 "Off" 또는 "Initial"로 설정됨
    • 해결 방법:
      bash
      # VPA 업데이트 모드 수정
      kubectl patch vpa <vpa-name> -p '{"spec":{"updatePolicy":{"updateMode":"Auto"}}}'

모범 사례:

  1. 체계적인 문제 해결 접근 방식:

    • 각 자동 스케일링 구성 요소 개별 확인
    • 로그 및 이벤트 분석
    • 단계별 문제 해결
  2. 자동 스케일링 모니터링 구현:

    • 자동 스케일링 활동 모니터링
    • 스케일링 이벤트 알림 설정
    • 스케일링 메트릭 대시보드 구성
  3. 자동 스케일링 구성 최적화:

    • 워크로드 특성에 맞는 스케일링 임계값 설정
    • 스케일링 동작 및 쿨다운 기간 조정
    • 비용과 성능 균형 유지
  4. 다중 자동 스케일링 구성 요소 통합:

    • HPA, CA, VPA 조합 사용
    • 구성 요소 간 충돌 방지
    • 일관된 스케일링 전략 구현

실제 구현 예시:

  1. 자동 스케일링 문제 해결 스크립트:

    bash
    #!/bin/bash
    # 자동 스케일링 문제 해결 스크립트
    
    CLUSTER_NAME=$1
    
    if [ -z "$CLUSTER_NAME" ]; then
      echo "클러스터 이름을 지정하세요."
      exit 1
    fi
    
    echo "=== 자동 스케일링 문제 해결 ==="
    echo "클러스터: $CLUSTER_NAME"
    
    # HPA 확인
    echo
    echo "=== HPA 상태 ==="
    kubectl get hpa --all-namespaces
    
    # 문제가 있는 HPA 확인
    PROBLEM_HPA=$(kubectl get hpa --all-namespaces -o json | jq -r '.items[] | select(.status.currentReplicas != .status.desiredReplicas) | .metadata.name')
    
    if [ -n "$PROBLEM_HPA" ]; then
      echo
      echo "=== 문제가 있는 HPA 세부 정보 ==="
      kubectl describe hpa $PROBLEM_HPA
    fi
    
    # 메트릭 서버 확인
    echo
    echo "=== 메트릭 서버 상태 ==="
    kubectl get apiservices v1beta1.metrics.k8s.io
    kubectl get pods -n kube-system -l k8s-app=metrics-server
    
    # 메트릭 확인
    echo
    echo "=== 메트릭 가용성 ==="
    kubectl top nodes || echo "노드 메트릭을 가져올 수 없습니다."
    kubectl top pods || echo "파드 메트릭을 가져올 수 없습니다."
    
    # CA 확인
    echo
    echo "=== Cluster Autoscaler 상태 ==="
    kubectl get pods -n kube-system -l app=cluster-autoscaler
    
    # CA 로그 확인
    CA_POD=$(kubectl get pods -n kube-system -l app=cluster-autoscaler -o jsonpath='{.items[0].metadata.name}')
    if [ -n "$CA_POD" ]; then
      echo
      echo "=== Cluster Autoscaler 로그 ==="
      kubectl logs -n kube-system $CA_POD --tail=50 | grep -i "scale"
    else
      echo "Cluster Autoscaler 파드를 찾을 수 없습니다."
    fi
    
    # ASG 확인
    echo
    echo "=== Auto Scaling Group 확인 ==="
    ASG_NAMES=$(aws autoscaling describe-auto-scaling-groups --query "AutoScalingGroups[?contains(Tags[?Key=='kubernetes.io/cluster/$CLUSTER_NAME'].Value, 'owned')].AutoScalingGroupName" --output text)
    
    for ASG in $ASG_NAMES; do
      echo "ASG: $ASG"
      aws autoscaling describe-auto-scaling-groups \
        --auto-scaling-group-names $ASG \
        --query "AutoScalingGroups[].{MinSize:MinSize,MaxSize:MaxSize,DesiredCapacity:DesiredCapacity,Instances:Instances[].LifecycleState}" \
        --output table
      
      echo "ASG 태그:"
      aws autoscaling describe-auto-scaling-groups \
        --auto-scaling-group-names $ASG \
        --query "AutoScalingGroups[].Tags[?Key=='k8s.io/cluster-autoscaler/enabled' || Key=='k8s.io/cluster-autoscaler/$CLUSTER_NAME']"
    done
    
    # VPA 확인
    echo
    echo "=== VPA 상태 ==="
    kubectl get vpa --all-namespaces || echo "VPA CRD가 설치되지 않았습니다."
    
    # 자동 스케일링 이벤트 확인
    echo
    echo "=== 자동 스케일링 이벤트 ==="
    kubectl get events --sort-by='.lastTimestamp' | grep -i -E "autoscal|hpa|scale"
    
    echo
    echo "=== 문제 해결 권장 사항 ==="
    if ! kubectl get apiservices v1beta1.metrics.k8s.io -o jsonpath='{.status.conditions[?(@.type=="Available")].status}' | grep -q "True"; then
      echo "- 메트릭 서버가 사용 가능하지 않습니다. 메트릭 서버를 설치하거나 문제를 해결하세요."
    fi
    
    if [ -z "$CA_POD" ]; then
      echo "- Cluster Autoscaler가 설치되지 않았습니다. Cluster Autoscaler를 설치하세요."
    fi
    
    for ASG in $ASG_NAMES; do
      if ! aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names $ASG --query "AutoScalingGroups[].Tags[?Key=='k8s.io/cluster-autoscaler/enabled'].Value" --output text | grep -q "true"; then
        echo "- ASG $ASG에 Cluster Autoscaler 태그가 없습니다. 필요한 태그를 추가하세요."
      fi
    done
    
    echo "- HPA 구성을 검토하고 적절한 메트릭 및 임계값을 설정하세요."
    echo "- 노드 그룹 IAM 역할에 필요한 권한이 있는지 확인하세요."
  2. Terraform을 사용한 자동 스케일링 구성:

    hcl
    # Cluster Autoscaler IAM 역할
    module "cluster_autoscaler_irsa" {
      source  = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
      version = "~> 5.0"
      
      role_name                        = "cluster-autoscaler-role"
      attach_cluster_autoscaler_policy = true
      cluster_autoscaler_cluster_names = [module.eks.cluster_name]
      
      oidc_providers = {
        main = {
          provider_arn               = module.eks.oidc_provider_arn
          namespace_service_accounts = ["kube-system:cluster-autoscaler"]
        }
      }
    }
    
    # Cluster Autoscaler 배포
    resource "helm_release" "cluster_autoscaler" {
      name       = "cluster-autoscaler"
      repository = "https://kubernetes.github.io/autoscaler"
      chart      = "cluster-autoscaler"
      namespace  = "kube-system"
      
      set {
        name  = "autoDiscovery.clusterName"
        value = module.eks.cluster_name
      }
      
      set {
        name  = "rbac.serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
        value = module.cluster_autoscaler_irsa.iam_role_arn
      }
      
      set {
        name  = "extraArgs.scale-down-delay-after-add"
        value = "2m"
      }
      
      set {
        name  = "extraArgs.scale-down-unneeded-time"
        value = "5m"
      }
    }
    
    # 메트릭 서버 배포
    resource "helm_release" "metrics_server" {
      name       = "metrics-server"
      repository = "https://kubernetes-sigs.github.io/metrics-server/"
      chart      = "metrics-server"
      namespace  = "kube-system"
      
      set {
        name  = "args[0]"
        value = "--kubelet-preferred-address-types=InternalIP"
      }
      
      set {
        name  = "args[1]"
        value = "--kubelet-insecure-tls"
      }
    }
    
    # HPA 예시
    resource "kubernetes_horizontal_pod_autoscaler_v2" "app" {
      metadata {
        name      = "app-hpa"
        namespace = kubernetes_namespace.app.metadata[0].name
      }
      
      spec {
        scale_target_ref {
          api_version = "apps/v1"
          kind        = "Deployment"
          name        = kubernetes_deployment.app.metadata[0].name
        }
        
        min_replicas = 2
        max_replicas = 10
        
        metric {
          type = "Resource"
          resource {
            name = "cpu"
            target {
              type                = "Utilization"
              average_utilization = 70
            }
          }
        }
        
        metric {
          type = "Resource"
          resource {
            name = "memory"
            target {
              type                = "Utilization"
              average_utilization = 80
            }
          }
        }
        
        behavior {
          scale_up {
            stabilization_window_seconds = 60
            select_policy                = "Max"
            policy {
              type           = "Pods"
              value          = 4
              period_seconds = 60
            }
            policy {
              type           = "Percent"
              value          = 100
              period_seconds = 60
            }
          }
          
          scale_down {
            stabilization_window_seconds = 300
            select_policy                = "Min"
            policy {
              type           = "Percent"
              value          = 10
              period_seconds = 60
            }
          }
        }
      }
    }
  3. 자동 스케일링 모니터링 대시보드:

    yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: autoscaling-dashboard
      namespace: monitoring
    data:
      autoscaling-dashboard.json: |
        {
          "title": "Autoscaling Dashboard",
          "panels": [
            {
              "title": "HPA Scaling",
              "type": "graph",
              "datasource": "Prometheus",
              "targets": [
                {
                  "expr": "kube_horizontalpodautoscaler_status_current_replicas",
                  "legendFormat": "Current - {{horizontalpodautoscaler}}",
                  "refId": "A"
                },
                {
                  "expr": "kube_horizontalpodautoscaler_spec_min_replicas",
                  "legendFormat": "Min - {{horizontalpodautoscaler}}",
                  "refId": "B"
                },
                {
                  "expr": "kube_horizontalpodautoscaler_spec_max_replicas",
                  "legendFormat": "Max - {{horizontalpodautoscaler}}",
                  "refId": "C"
                },
                {
                  "expr": "kube_horizontalpodautoscaler_status_desired_replicas",
                  "legendFormat": "Desired - {{horizontalpodautoscaler}}",
                  "refId": "D"
                }
              ]
            },
            {
              "title": "Node Count",
              "type": "graph",
              "datasource": "Prometheus",
              "targets": [
                {
                  "expr": "sum(kube_node_info)",
                  "legendFormat": "Total Nodes",
                  "refId": "A"
                }
              ]
            },
            {
              "title": "CPU Utilization",
              "type": "graph",
              "datasource": "Prometheus",
              "targets": [
                {
                  "expr": "sum(rate(container_cpu_usage_seconds_total{container!=\"\"}[5m])) by (pod)",
                  "legendFormat": "{{pod}}",
                  "refId": "A"
                }
              ]
            },
            {
              "title": "Memory Utilization",
              "type": "graph",
              "datasource": "Prometheus",
              "targets": [
                {
                  "expr": "sum(container_memory_working_set_bytes{container!=\"\"}) by (pod)",
                  "legendFormat": "{{pod}}",
                  "refId": "A"
                }
              ]
            }
          ]
        }

다른 옵션들의 문제점:

  • A. 모든 파드에 더 많은 리소스 할당: 이는 근본 원인을 해결하지 않고 자원을 낭비할 수 있으며, 자동 스케일링 문제의 실제 원인을 파악하지 못합니다.
  • B. 수동으로 노드 추가: 이는 임시 해결책일 뿐이며, 자동 스케일링 시스템의 근본적인 문제를 해결하지 않습니다.
  • D. 클러스터 재생성: 이는 극단적인 조치이며, 문제의 근본 원인을 파악하지 못하고 불필요한 다운타임과 작업을 초래합니다.
### 7. Amazon EKS 클러스터에서 네트워크 정책이 예상대로 작동하지 않을 때 가장 효과적인 문제 해결 접근 방식은 무엇인가요?

A. 모든 네트워크 정책 삭제 및 기본값 사용
B. 클러스터 CNI 플러그인, 네트워크 정책 구성, 로그 및 이벤트 확인
C. 모든 파드에 hostNetwork: true 설정
D. 클러스터 VPC 재구성

정답 및 설명

정답: B. 클러스터 CNI 플러그인, 네트워크 정책 구성, 로그 및 이벤트 확인

설명: Amazon EKS 클러스터에서 네트워크 정책이 예상대로 작동하지 않을 때 가장 효과적인 문제 해결 접근 방식은 클러스터 CNI 플러그인, 네트워크 정책 구성, 로그 및 이벤트를 체계적으로 확인하는 것입니다. 이 접근 방식은 네트워크 정책 문제의 근본 원인을 식별하고 해결하는 데 도움이 됩니다.

주요 확인 사항:

  1. CNI 플러그인 확인:

    • 사용 중인 CNI 플러그인 유형 (AWS VPC CNI, Calico, Cilium 등)
    • CNI 플러그인 버전 및 호환성
    • 네트워크 정책 지원 여부
  2. 네트워크 정책 구성 확인:

    • 네트워크 정책 구문 및 선택기
    • 정책 우선순위 및 충돌
    • 네임스페이스 및 라벨 선택기
  3. 로그 및 이벤트 확인:

    • CNI 플러그인 로그
    • 네트워크 정책 컨트롤러 로그
    • 관련 이벤트 및 오류 메시지
  4. 네트워크 연결 테스트:

    • 파드 간 연결 테스트
    • 서비스 연결 테스트
    • 외부 연결 테스트

문제 해결 방법:

  1. CNI 플러그인 확인:

    bash
    # CNI 플러그인 파드 확인
    kubectl get pods -n kube-system -l k8s-app=aws-node  # AWS VPC CNI
    kubectl get pods -n kube-system -l k8s-app=calico-node  # Calico
    kubectl get pods -n kube-system -l k8s-app=cilium  # Cilium
    
    # CNI 플러그인 로그 확인
    kubectl logs -n kube-system -l k8s-app=aws-node
    kubectl logs -n kube-system -l k8s-app=calico-node
    kubectl logs -n kube-system -l k8s-app=cilium
    
    # CNI 구성 확인
    kubectl describe daemonset -n kube-system aws-node
    kubectl describe daemonset -n kube-system calico-node
    kubectl describe daemonset -n kube-system cilium
  2. 네트워크 정책 확인:

    bash
    # 네트워크 정책 목록 확인
    kubectl get networkpolicies --all-namespaces
    
    # 특정 네트워크 정책 세부 정보 확인
    kubectl describe networkpolicy <policy-name> -n <namespace>
    
    # 네트워크 정책 YAML 확인
    kubectl get networkpolicy <policy-name> -n <namespace> -o yaml
  3. 파드 네트워크 정보 확인:

    bash
    # 파드 IP 및 노드 정보 확인
    kubectl get pods -o wide
    
    # 파드 네트워크 인터페이스 확인
    kubectl exec -it <pod-name> -- ip addr
    
    # 파드 라우팅 테이블 확인
    kubectl exec -it <pod-name> -- ip route
  4. 네트워크 연결 테스트:

    bash
    # 디버그 파드 생성
    kubectl run network-debug --rm -it --image=nicolaka/netshoot -- /bin/bash
    
    # 파드 간 연결 테스트
    ping <target-pod-ip>
    nc -zv <target-pod-ip> <port>
    
    # DNS 확인 테스트
    nslookup <service-name>.<namespace>.svc.cluster.local
    
    # 패킷 캡처
    tcpdump -i eth0 -n

일반적인 네트워크 정책 문제 및 해결 방법:

  1. CNI 플러그인 호환성 문제:

    • 증상: 네트워크 정책이 적용되지 않음
    • 원인: 사용 중인 CNI 플러그인이 네트워크 정책을 지원하지 않음
    • 해결 방법:
      bash
      # AWS VPC CNI에 Calico 정책 엔진 추가
      kubectl apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/master/config/master/calico-operator.yaml
      kubectl apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/master/config/master/calico-crs.yaml
      
      # 또는 Cilium으로 전환
      helm repo add cilium https://helm.cilium.io/
      helm install cilium cilium/cilium --namespace kube-system
  2. 네트워크 정책 선택기 문제:

    • 증상: 정책이 예상 파드에 적용되지 않음
    • 원인: 잘못된 라벨 선택기 또는 네임스페이스 선택기
    • 해결 방법:
      bash
      # 파드 라벨 확인
      kubectl get pods --show-labels
      
      # 네트워크 정책 수정
      kubectl edit networkpolicy <policy-name> -n <namespace>
  3. 정책 충돌 문제:

    • 증상: 예상치 못한 연결 차단 또는 허용
    • 원인: 여러 정책 간의 충돌 또는 우선순위 문제
    • 해결 방법:
      bash
      # 모든 네트워크 정책 검토
      kubectl get networkpolicies --all-namespaces -o yaml
      
      # 정책 단순화 또는 재구성
      kubectl apply -f updated-network-policy.yaml
  4. CNI 플러그인 버그 또는 구성 오류:

    • 증상: 간헐적인 연결 문제 또는 일관되지 않은 동작
    • 원인: CNI 플러그인 버그 또는 잘못된 구성
    • 해결 방법:
      bash
      # CNI 플러그인 업데이트
      kubectl set image daemonset/aws-node -n kube-system aws-node=<new-image-version>
      
      # CNI 구성 확인 및 수정
      kubectl edit configmap -n kube-system aws-node

모범 사례:

  1. 체계적인 네트워크 정책 설계:

    • 기본 거부 정책으로 시작
    • 필요한 연결만 명시적으로 허용
    • 네임스페이스 및 라벨 기반 정책 사용
  2. 네트워크 정책 테스트 및 검증:

    • 정책 적용 전 테스트
    • 연결 테스트 자동화
    • 점진적인 정책 적용
  3. 네트워크 모니터링 및 로깅:

    • 네트워크 트래픽 모니터링
    • 연결 거부 로깅
    • 네트워크 성능 모니터링
  4. CNI 플러그인 선택 및 구성:

    • 워크로드 요구 사항에 맞는 CNI 선택
    • 최신 버전 유지
    • 적절한 리소스 할당

실제 구현 예시:

  1. 기본 네트워크 정책 구성:

    yaml
    # 기본 거부 정책
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: default-deny
      namespace: production
    spec:
      podSelector: {}
      policyTypes:
      - Ingress
      - Egress
    
    # 특정 애플리케이션 허용 정책
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: api-allow
      namespace: production
    spec:
      podSelector:
        matchLabels:
          app: api
      policyTypes:
      - Ingress
      - Egress
      ingress:
      - from:
        - namespaceSelector:
            matchLabels:
              name: frontend
          podSelector:
            matchLabels:
              app: web
        ports:
        - protocol: TCP
          port: 8080
      egress:
      - to:
        - namespaceSelector:
            matchLabels:
              name: database
          podSelector:
            matchLabels:
              app: db
        ports:
        - protocol: TCP
          port: 5432
      - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
        ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
  2. 네트워크 정책 문제 해결 스크립트:

    bash
    #!/bin/bash
    # 네트워크 정책 문제 해결 스크립트
    
    NAMESPACE=$1
    POD_NAME=$2
    
    if [ -z "$NAMESPACE" ] || [ -z "$POD_NAME" ]; then
      echo "사용법: $0 <네임스페이스> <파드_이름>"
      exit 1
    fi
    
    echo "=== 네트워크 정책 문제 해결 ==="
    echo "네임스페이스: $NAMESPACE"
    echo "파드: $POD_NAME"
    
    # 파드 정보 확인
    echo
    echo "=== 파드 정보 ==="
    kubectl get pod $POD_NAME -n $NAMESPACE -o wide
    
    # 파드 라벨 확인
    echo
    echo "=== 파드 라벨 ==="
    kubectl get pod $POD_NAME -n $NAMESPACE --show-labels
    
    # 네임스페이스 라벨 확인
    echo
    echo "=== 네임스페이스 라벨 ==="
    kubectl get namespace $NAMESPACE --show-labels
    
    # 네트워크 정책 확인
    echo
    echo "=== 네임스페이스의 네트워크 정책 ==="
    kubectl get networkpolicies -n $NAMESPACE
    
    # 모든 네트워크 정책 세부 정보
    echo
    echo "=== 네트워크 정책 세부 정보 ==="
    POLICIES=$(kubectl get networkpolicies -n $NAMESPACE -o jsonpath='{.items[*].metadata.name}')
    for POLICY in $POLICIES; do
      echo
      echo "정책: $POLICY"
      kubectl describe networkpolicy $POLICY -n $NAMESPACE
    done
    
    # CNI 플러그인 확인
    echo
    echo "=== CNI 플러그인 확인 ==="
    if kubectl get pods -n kube-system -l k8s-app=aws-node &>/dev/null; then
      echo "AWS VPC CNI 사용 중"
      kubectl get pods -n kube-system -l k8s-app=aws-node
      
      # Calico 정책 엔진 확인
      if kubectl get pods -n kube-system -l k8s-app=calico-node &>/dev/null; then
        echo
        echo "Calico 정책 엔진 사용 중"
        kubectl get pods -n kube-system -l k8s-app=calico-node
      else
        echo
        echo "Calico 정책 엔진이 설치되지 않았습니다. AWS VPC CNI는 기본적으로 네트워크 정책을 지원하지 않습니다."
      fi
    elif kubectl get pods -n kube-system -l k8s-app=cilium &>/dev/null; then
      echo "Cilium CNI 사용 중"
      kubectl get pods -n kube-system -l k8s-app=cilium
    else
      echo "알 수 없는 CNI 플러그인 사용 중"
    fi
    
    # 연결 테스트
    echo
    echo "=== 연결 테스트 ==="
    echo "디버그 파드 생성 중..."
    kubectl run network-debug -n $NAMESPACE --rm -it --image=nicolaka/netshoot -- /bin/bash -c "
      echo '=== 파드 IP 정보 ===';
      ip addr;
      echo;
      echo '=== 라우팅 테이블 ===';
      ip route;
      echo;
      echo '=== DNS 확인 테스트 ===';
      nslookup kubernetes.default.svc.cluster.local;
      echo;
      echo '=== 대상 파드 연결 테스트 ===';
      POD_IP=\$(kubectl get pod $POD_NAME -n $NAMESPACE -o jsonpath='{.status.podIP}');
      echo \"파드 IP: \$POD_IP\";
      ping -c 3 \$POD_IP || echo '핑 실패';
      echo;
      echo '=== 서비스 연결 테스트 ===';
      SERVICES=\$(kubectl get svc -n $NAMESPACE -o jsonpath='{.items[*].metadata.name}');
      for SVC in \$SERVICES; do
        echo \"서비스: \$SVC\";
        SVC_PORT=\$(kubectl get svc \$SVC -n $NAMESPACE -o jsonpath='{.spec.ports[0].port}');
        nc -zv \$SVC.\$NAMESPACE.svc.cluster.local \$SVC_PORT -w 2 || echo '연결 실패';
      done;
    "
    
    echo
    echo "=== 문제 해결 권장 사항 ==="
    if ! kubectl get pods -n kube-system -l k8s-app=calico-node &>/dev/null && ! kubectl get pods -n kube-system -l k8s-app=cilium &>/dev/null; then
      echo "- 네트워크 정책을 지원하는 CNI 플러그인이 설치되지 않았습니다. Calico 또는 Cilium을 설치하세요."
    fi
    
    echo "- 파드 및 네임스페이스 라벨이 네트워크 정책 선택기와 일치하는지 확인하세요."
    echo "- 네트워크 정책이 필요한 모든 트래픽(인그레스 및 이그레스)을 허용하는지 확인하세요."
    echo "- 여러 네트워크 정책 간의 충돌이 있는지 확인하세요."
    echo "- CNI 플러그인 로그에서 오류를 확인하세요."
  3. Terraform을 사용한 네트워크 정책 구성:

    hcl
    # Calico 정책 엔진 설치
    resource "helm_release" "calico" {
      name       = "calico"
      repository = "https://docs.projectcalico.org/charts"
      chart      = "tigera-operator"
      namespace  = "tigera-operator"
      create_namespace = true
      
      set {
        name  = "installation.kubernetesProvider"
        value = "EKS"
      }
    }
    
    # 기본 네트워크 정책
    resource "kubernetes_network_policy" "default_deny" {
      metadata {
        name      = "default-deny"
        namespace = kubernetes_namespace.app.metadata[0].name
      }
      
      spec {
        pod_selector {}
        
        policy_types = ["Ingress", "Egress"]
      }
    }
    
    # 애플리케이션별 네트워크 정책
    resource "kubernetes_network_policy" "app_policy" {
      metadata {
        name      = "app-network-policy"
        namespace = kubernetes_namespace.app.metadata[0].name
      }
      
      spec {
        pod_selector {
          match_labels = {
            app = "api"
          }
        }
        
        policy_types = ["Ingress", "Egress"]
        
        ingress {
          from {
            namespace_selector {
              match_labels = {
                name = "frontend"
              }
            }
            
            pod_selector {
              match_labels = {
                app = "web"
              }
            }
          }
          
          ports {
            port     = "8080"
            protocol = "TCP"
          }
        }
        
        egress {
          to {
            namespace_selector {
              match_labels = {
                name = "database"
              }
            }
            
            pod_selector {
              match_labels = {
                app = "db"
              }
            }
          }
          
          ports {
            port     = "5432"
            protocol = "TCP"
          }
        }
        
        # DNS 액세스 허용
        egress {
          to {
            namespace_selector {}
            
            pod_selector {
              match_labels = {
                "k8s-app" = "kube-dns"
              }
            }
          }
          
          ports {
            port     = "53"
            protocol = "UDP"
          }
          
          ports {
            port     = "53"
            protocol = "TCP"
          }
        }
      }
    }
  4. 네트워크 정책 모니터링 구성:

    yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: network-policy-dashboard
      namespace: monitoring
    data:
      network-policy-dashboard.json: |
        {
          "title": "Network Policy Monitoring",
          "panels": [
            {
              "title": "Network Policy Count",
              "type": "stat",
              "datasource": "Prometheus",
              "targets": [
                {
                  "expr": "sum(kube_networkpolicy_info)",
                  "legendFormat": "Total Network Policies",
                  "refId": "A"
                }
              ]
            },
            {
              "title": "Dropped Connections",
              "type": "graph",
              "datasource": "Prometheus",
              "targets": [
                {
                  "expr": "sum(rate(calico_denied_packets[5m])) by (namespace)",
                  "legendFormat": "{{namespace}}",
                  "refId": "A"
                }
              ]
            },
            {
              "title": "Network Policy Events",
              "type": "table",
              "datasource": "Loki",
              "targets": [
                {
                  "expr": "{app=\"calico-node\"} |~ \"policy\"",
                  "refId": "A"
                }
              ]
            }
          ]
        }

다른 옵션들의 문제점:

  • A. 모든 네트워크 정책 삭제 및 기본값 사용: 이는 보안 위험을 초래하고 필요한 네트워크 격리를 제거하며, 근본 원인을 해결하지 않습니다.
  • C. 모든 파드에 hostNetwork: true 설정: 이는 네트워크 정책을 우회하고 보안 위험을 초래하며, 파드 간 격리를 제거합니다.
  • D. 클러스터 VPC 재구성: 이는 극단적인 조치이며, 대부분의 네트워크 정책 문제는 VPC 수준이 아닌 클러스터 내부의 CNI 및 정책 구성과 관련이 있습니다.
### 8. Amazon EKS 클러스터에서 Helm 차트 배포 문제를 해결하는 가장 효과적인 접근 방식은 무엇인가요?

A. 모든 Helm 차트 삭제 및 재설치
B. 클러스터 재생성
C. Helm 버전, 차트 구성, 종속성, 권한 및 로그 체계적 확인
D. 수동으로 모든 리소스 배포

정답 및 설명

정답: C. Helm 버전, 차트 구성, 종속성, 권한 및 로그 체계적 확인

설명: Amazon EKS 클러스터에서 Helm 차트 배포 문제를 해결하는 가장 효과적인 접근 방식은 Helm 버전, 차트 구성, 종속성, 권한 및 로그를 체계적으로 확인하는 것입니다. 이 접근 방식은 Helm 배포 문제의 근본 원인을 식별하고 해결하는 데 도움이 됩니다.

주요 확인 사항:

  1. Helm 버전 및 호환성 확인:

    • Helm 클라이언트 및 Tiller(Helm 2) 버전
    • Kubernetes API 버전 호환성
    • EKS 버전 호환성
  2. 차트 구성 및 값 확인:

    • 차트 구문 오류
    • 값 파일 구성
    • 템플릿 렌더링 문제
  3. 종속성 및 리포지토리 확인:

    • 차트 종속성 가용성
    • 리포지토리 접근성
    • 차트 버전 호환성
  4. 권한 및 RBAC 확인:

    • 서비스 계정 권한
    • RBAC 규칙
    • 네임스페이스 액세스
  5. 로그 및 이벤트 확인:

    • Helm 디버그 로그
    • Kubernetes 이벤트
    • 관련 파드 로그

문제 해결 방법:

  1. Helm 버전 및 구성 확인:

    bash
    # Helm 버전 확인
    helm version
    
    # Helm 환경 변수 확인
    env | grep HELM
    
    # Helm 플러그인 확인
    helm plugin list
    
    # Helm 리포지토리 확인
    helm repo list
    helm repo update
  2. 차트 검증 및 디버깅:

    bash
    # 차트 구문 검증
    helm lint ./my-chart
    
    # 템플릿 렌더링 확인
    helm template ./my-chart --debug
    
    # 차트 종속성 업데이트
    helm dependency update ./my-chart
    
    # 디버그 모드로 설치
    helm install my-release ./my-chart --debug
  3. 릴리스 상태 및 기록 확인:

    bash
    # 릴리스 목록 확인
    helm list -A
    
    # 실패한 릴리스 포함
    helm list -A --failed
    
    # 릴리스 상태 확인
    helm status my-release
    
    # 릴리스 기록 확인
    helm history my-release
    
    # 릴리스 세부 정보 확인
    helm get all my-release
  4. 리소스 및 이벤트 확인:

    bash
    # 배포된 리소스 확인
    kubectl get all -n <namespace> -l app.kubernetes.io/instance=my-release
    
    # 이벤트 확인
    kubectl get events -n <namespace> --sort-by='.lastTimestamp'
    
    # 파드 로그 확인
    kubectl logs -n <namespace> -l app.kubernetes.io/instance=my-release
    
    # 파드 상태 확인
    kubectl describe pods -n <namespace> -l app.kubernetes.io/instance=my-release
  5. 권한 및 RBAC 확인:

    bash
    # 서비스 계정 확인
    kubectl get serviceaccount -n <namespace>
    
    # 역할 및 역할 바인딩 확인
    kubectl get roles,rolebindings -n <namespace>
    
    # 클러스터 역할 및 바인딩 확인
    kubectl get clusterroles,clusterrolebindings -l app.kubernetes.io/instance=my-release
    
    # 서비스 계정 권한 확인
    kubectl auth can-i --list --as=system:serviceaccount:<namespace>:<serviceaccount>

일반적인 Helm 배포 문제 및 해결 방법:

  1. 차트 구문 오류:

    • 증상: helm install 또는 helm template 명령이 실패함
    • 원인: YAML 구문 오류, 잘못된 템플릿 함수 또는 변수
    • 해결 방법:
      bash
      # 차트 구문 검증
      helm lint ./my-chart
      
      # 템플릿 렌더링 확인
      helm template ./my-chart --debug
      
      # 특정 값으로 템플릿 렌더링
      helm template ./my-chart --set key=value --debug
  2. 종속성 문제:

    • 증상: 차트 설치 중 종속성 오류
    • 원인: 누락된 종속성, 버전 불일치 또는 리포지토리 접근 문제
    • 해결 방법:
      bash
      # 종속성 업데이트
      helm dependency update ./my-chart
      
      # 리포지토리 추가 및 업데이트
      helm repo add bitnami https://charts.bitnami.com/bitnami
      helm repo update
      
      # 종속성 빌드
      helm dependency build ./my-chart
  3. 권한 문제:

    • 증상: 권한 거부 오류
    • 원인: 부족한 RBAC 권한 또는 잘못된 서비스 계정 구성
    • 해결 방법:
      bash
      # 필요한 RBAC 리소스 생성
      kubectl apply -f rbac.yaml
      
      # 서비스 계정 지정
      helm install my-release ./my-chart --service-account=my-service-account
      
      # 권한 확인
      kubectl auth can-i create deployments --as=system:serviceaccount:<namespace>:<serviceaccount>
  4. 리소스 충돌:

    • 증상: 이미 존재하는 리소스 오류
    • 원인: 이전 설치의 리소스가 남아 있거나 이름 충돌
    • 해결 방법:
      bash
      # 기존 릴리스 제거
      helm uninstall my-release
      
      # 남은 리소스 확인 및 삭제
      kubectl get all -n <namespace> -l app.kubernetes.io/instance=my-release
      kubectl delete <resource-type> <resource-name> -n <namespace>
      
      # 다른 릴리스 이름으로 설치
      helm install new-release ./my-chart
  5. 값 구성 문제:

    • 증상: 배포된 애플리케이션이 예상대로 작동하지 않음
    • 원인: 잘못된 구성 값 또는 누락된 필수 값
    • 해결 방법:
      bash
      # 현재 값 확인
      helm get values my-release
      
      # 기본값 확인
      helm show values ./my-chart
      
      # 값 파일로 업그레이드
      helm upgrade my-release ./my-chart -f values.yaml
      
      # 특정 값 설정
      helm upgrade my-release ./my-chart --set key=value

모범 사례:

  1. 체계적인 문제 해결 접근 방식:

    • 단계별 확인 및 검증
    • 로그 및 이벤트 분석
    • 증상에서 원인으로 추적
  2. Helm 차트 테스트 및 검증:

    • 배포 전 차트 검증
    • 테스트 환경에서 먼저 테스트
    • CI/CD 파이프라인에 검증 단계 포함
  3. 버전 관리 및 호환성:

    • 호환되는 Helm 및 Kubernetes 버전 사용
    • 차트 버전 명시적 지정
    • 종속성 버전 고정
  4. 문서화 및 값 관리:

    • 차트 값 문서화
    • 환경별 값 파일 관리
    • 민감한 값에 대한 보안 관행 적용

실제 구현 예시:

  1. Helm 차트 문제 해결 스크립트:

    bash
    #!/bin/bash
    # Helm 차트 문제 해결 스크립트
    
    RELEASE_NAME=$1
    NAMESPACE=$2
    
    if [ -z "$RELEASE_NAME" ] || [ -z "$NAMESPACE" ]; then
      echo "사용법: $0 <릴리스_이름> <네임스페이스>"
      exit 1
    fi
    
    echo "=== Helm 차트 문제 해결 ==="
    echo "릴리스: $RELEASE_NAME"
    echo "네임스페이스: $NAMESPACE"
    
    # Helm 버전 확인
    echo
    echo "=== Helm 버전 ==="
    helm version
    
    # 릴리스 상태 확인
    echo
    echo "=== 릴리스 상태 ==="
    helm status $RELEASE_NAME -n $NAMESPACE || echo "릴리스를 찾을 수 없습니다."
    
    # 릴리스 기록 확인
    echo
    echo "=== 릴리스 기록 ==="
    helm history $RELEASE_NAME -n $NAMESPACE || echo "릴리스 기록을 찾을 수 없습니다."
    
    # 릴리스 값 확인
    echo
    echo "=== 릴리스 값 ==="
    helm get values $RELEASE_NAME -n $NAMESPACE || echo "릴리스 값을 찾을 수 없습니다."
    
    # 배포된 리소스 확인
    echo
    echo "=== 배포된 리소스 ==="
    kubectl get all -n $NAMESPACE -l app.kubernetes.io/instance=$RELEASE_NAME
    
    # 파드 상태 확인
    echo
    echo "=== 파드 상태 ==="
    PODS=$(kubectl get pods -n $NAMESPACE -l app.kubernetes.io/instance=$RELEASE_NAME -o jsonpath='{.items[*].metadata.name}')
    if [ -n "$PODS" ]; then
      for POD in $PODS; do
        echo
        echo "파드: $POD"
        kubectl describe pod $POD -n $NAMESPACE
      done
    else
      echo "파드를 찾을 수 없습니다."
    fi
    
    # 파드 로그 확인
    echo
    echo "=== 파드 로그 ==="
    if [ -n "$PODS" ]; then
      for POD in $PODS; do
        echo
        echo "파드: $POD"
        kubectl logs $POD -n $NAMESPACE --tail=50
      done
    else
      echo "파드를 찾을 수 없습니다."
    fi
    
    # 이벤트 확인
    echo
    echo "=== 관련 이벤트 ==="
    kubectl get events -n $NAMESPACE --sort-by='.lastTimestamp' | grep -i $RELEASE_NAME
    
    # 서비스 계정 및 RBAC 확인
    echo
    echo "=== 서비스 계정 및 RBAC ==="
    SA=$(kubectl get deployment -n $NAMESPACE -l app.kubernetes.io/instance=$RELEASE_NAME -o jsonpath='{.items[0].spec.template.spec.serviceAccountName}')
    if [ -n "$SA" ]; then
      echo "서비스 계정: $SA"
      kubectl get serviceaccount $SA -n $NAMESPACE -o yaml
      
      echo
      echo "역할 및 역할 바인딩:"
      kubectl get roles,rolebindings -n $NAMESPACE | grep -i $SA
      
      echo
      echo "클러스터 역할 및 바인딩:"
      kubectl get clusterroles,clusterrolebindings | grep -i $SA
    else
      echo "서비스 계정을 찾을 수 없습니다."
    fi
    
    echo
    echo "=== 문제 해결 권장 사항 ==="
    if ! helm status $RELEASE_NAME -n $NAMESPACE &>/dev/null; then
      echo "- 릴리스가 존재하지 않습니다. 설치 명령을 확인하세요."
    fi
    
    if [ -z "$PODS" ]; then
      echo "- 파드가 생성되지 않았습니다. 차트 구성 및 값을 확인하세요."
    else
      FAILED_PODS=$(kubectl get pods -n $NAMESPACE -l app.kubernetes.io/instance=$RELEASE_NAME -o jsonpath='{.items[?(@.status.phase!="Running")].metadata.name}')
      if [ -n "$FAILED_PODS" ]; then
        echo "- 일부 파드가 실행 중이 아닙니다. 파드 상태 및 로그를 확인하세요."
      fi
    fi
    
    echo "- 차트 구문 및 템플릿을 검증하세요: helm lint, helm template"
    echo "- 차트 종속성을 업데이트하세요: helm dependency update"
    echo "- 값 구성을 확인하세요: helm get values, helm show values"
    echo "- 서비스 계정 권한을 확인하세요: kubectl auth can-i --list --as=system:serviceaccount:$NAMESPACE:$SA"
  2. Terraform을 사용한 Helm 차트 배포:

    hcl
    provider "helm" {
      kubernetes {
        host                   = data.aws_eks_cluster.cluster.endpoint
        cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority[0].data)
        token                  = data.aws_eks_cluster_auth.cluster.token
      }
    }
    
    resource "helm_release" "example" {
      name       = "my-app"
      repository = "https://charts.example.com/"
      chart      = "example-chart"
      version    = "1.2.3"
      namespace  = "my-namespace"
      create_namespace = true
      
      # 기본 타임아웃 증가
      timeout = 600
      
      # 디버그 활성화
      debug = true
      
      # 차트 값 설정
      values = [
        file("${path.module}/values.yaml")
      ]
      
      # 개별 값 설정
      set {
        name  = "replicaCount"
        value = "2"
      }
      
      set {
        name  = "image.tag"
        value = "latest"
      }
      
      # 민감한 값 설정
      set_sensitive {
        name  = "secrets.apiKey"
        value = var.api_key
      }
      
      # 종속성 업데이트
      dependency_update = true
      
      # 배포 전 검증
      lint = true
      
      # 배포 후 검증
      wait = true
      wait_for_jobs = true
      
      # 배포 실패 시 롤백
      atomic = true
      
      # 배포 후 테스트 실행
      verify = true
    }
    
    # 배포 후 검증
    resource "null_resource" "verify_deployment" {
      depends_on = [helm_release.example]
      
      provisioner "local-exec" {
        command = <<-EOT
          kubectl wait --for=condition=available --timeout=300s deployment/my-app -n my-namespace
          kubectl get pods -n my-namespace -l app.kubernetes.io/instance=my-app
        EOT
      }
    }
  3. Helm 차트 테스트 구성:

    yaml
    # templates/tests/test-connection.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: "{{ include "my-chart.fullname" . }}-test-connection"
      labels:
        {{- include "my-chart.labels" . | nindent 4 }}
        app.kubernetes.io/component: test
      annotations:
        "helm.sh/hook": test
        "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
    spec:
      containers:
        - name: wget
          image: busybox
          command: ['wget']
          args: ['{{ include "my-chart.fullname" . }}:{{ .Values.service.port }}']
      restartPolicy: Never
    
    # templates/tests/test-api.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: "{{ include "my-chart.fullname" . }}-test-api"
      labels:
        {{- include "my-chart.labels" . | nindent 4 }}
        app.kubernetes.io/component: test
      annotations:
        "helm.sh/hook": test
        "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
    spec:
      containers:
        - name: api-test
          image: curlimages/curl
          command: ['curl']
          args: ['-f', 'http://{{ include "my-chart.fullname" . }}:{{ .Values.service.port }}/api/health']
      restartPolicy: Never
  4. CI/CD 파이프라인의 Helm 차트 검증:

    yaml
    # .github/workflows/helm-validate.yml
    name: Validate Helm Chart
    
    on:
      pull_request:
        paths:
          - 'charts/**'
    
    jobs:
      lint-and-test:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout
            uses: actions/checkout@v2
            
          - name: Set up Helm
            uses: azure/setup-helm@v1
            with:
              version: 'v3.8.0'
              
          - name: Set up Python
            uses: actions/setup-python@v2
            with:
              python-version: '3.9'
              
          - name: Set up chart-testing
            uses: helm/chart-testing-action@v2.1.0
              
          - name: Lint charts
            run: ct lint --all --config .github/ct.yaml
            
          - name: Set up kind cluster
            uses: helm/kind-action@v1.2.0
            
          - name: Install charts
            run: ct install --all --config .github/ct.yaml
            
          - name: Run chart tests
            run: |
              for chart in charts/*; do
                if [ -d "$chart" ]; then
                  chart_name=$(basename "$chart")
                  echo "Testing chart: $chart_name"
                  helm test "$chart_name" -n "$chart_name"
                fi
              done

다른 옵션들의 문제점:

  • A. 모든 Helm 차트 삭제 및 재설치: 이는 극단적인 조치이며, 데이터 손실을 초래할 수 있고 근본 원인을 해결하지 않습니다.
  • B. 클러스터 재생성: 이는 매우 극단적인 조치이며, 대부분의 Helm 배포 문제는 클러스터 수준이 아닌 차트 구성 또는 권한과 관련이 있습니다.
  • D. 수동으로 모든 리소스 배포: 이는 Helm의 이점을 포기하는 것이며, 복잡한 애플리케이션의 경우 오류가 발생하기 쉽고 관리하기 어렵습니다.
### 9. Amazon EKS 클러스터에서 메모리 누수 문제를 해결하는 가장 효과적인 접근 방식은 무엇인가요?

A. 모든 파드 재시작
B. 클러스터 노드 크기 증가
C. 메모리 사용량 프로파일링, 컨테이너 제한 검토, 애플리케이션 코드 분석
D. 더 많은 노드 추가

정답 및 설명

정답: C. 메모리 사용량 프로파일링, 컨테이너 제한 검토, 애플리케이션 코드 분석

설명: Amazon EKS 클러스터에서 메모리 누수 문제를 해결하는 가장 효과적인 접근 방식은 메모리 사용량 프로파일링, 컨테이너 제한 검토, 애플리케이션 코드 분석을 포함한 체계적인 접근법입니다. 이 방법은 메모리 누수의 근본 원인을 식별하고 해결하는 데 도움이 됩니다.

주요 확인 사항:

  1. 메모리 사용량 프로파일링:

    • 파드 및 노드 수준의 메모리 사용량 모니터링
    • 시간에 따른 메모리 사용 패턴 분석
    • 메모리 누수 징후 식별
  2. 컨테이너 제한 검토:

    • 메모리 요청 및 제한 설정 확인
    • 컨테이너 OOM(Out of Memory) 이벤트 분석
    • 리소스 할당 최적화
  3. 애플리케이션 코드 분석:

    • 애플리케이션 내부 메모리 사용 패턴 검토
    • 메모리 누수 가능성이 있는 코드 식별
    • 애플리케이션 프로파일링 도구 사용
  4. 시스템 구성 요소 검토:

    • kubelet 메모리 관리 설정
    • 노드 시스템 리소스 사용량
    • 클러스터 구성 요소 상태

문제 해결 방법:

  1. 메모리 사용량 모니터링 및 분석:

    bash
    # 노드 메모리 사용량 확인
    kubectl top nodes
    
    # 파드 메모리 사용량 확인
    kubectl top pods -A
    
    # 특정 네임스페이스의 파드 메모리 사용량 확인
    kubectl top pods -n <namespace>
    
    # 컨테이너별 메모리 사용량 확인
    kubectl top pods -n <namespace> --containers
    
    # 메모리 사용량이 높은 파드 식별
    kubectl top pods -A --sort-by=memory
  2. 컨테이너 제한 및 OOM 이벤트 확인:

    bash
    # 파드 메모리 제한 확인
    kubectl get pods -n <namespace> -o jsonpath='{.items[*].spec.containers[*].resources}'
    
    # 파드 세부 정보 확인
    kubectl describe pod <pod-name> -n <namespace>
    
    # OOM 이벤트 확인
    kubectl get events -n <namespace> --sort-by='.lastTimestamp' | grep -i "OOMKilled"
    
    # 노드 OOM 이벤트 확인
    kubectl get events --field-selector involvedObject.kind=Node --sort-by='.lastTimestamp' | grep -i "memory"
  3. 애플리케이션 로그 및 프로파일링:

    bash
    # 애플리케이션 로그 확인
    kubectl logs <pod-name> -n <namespace>
    
    # 이전 파드 로그 확인
    kubectl logs <pod-name> -n <namespace> --previous
    
    # 애플리케이션 프로파일링 도구 실행
    kubectl exec -it <pod-name> -n <namespace> -- <profiling-command>
    
    # 메모리 덤프 생성
    kubectl exec -it <pod-name> -n <namespace> -- <memory-dump-command>
  4. 노드 및 시스템 리소스 확인:

    bash
    # 노드 세부 정보 확인
    kubectl describe node <node-name>
    
    # 노드 메모리 압력 확인
    kubectl get nodes -o jsonpath='{.items[*].status.conditions[?(@.type=="MemoryPressure")]}'
    
    # kubelet 로그 확인
    kubectl logs -n kube-system <kubelet-pod-name>
    
    # 시스템 메모리 통계 확인
    kubectl debug node/<node-name> -it --image=busybox -- sh -c "cat /proc/meminfo"

일반적인 메모리 누수 문제 및 해결 방법:

  1. 애플리케이션 메모리 누수:

    • 증상: 시간이 지남에 따라 메모리 사용량이 지속적으로 증가
    • 원인: 애플리케이션 코드의 메모리 누수, 캐시 관리 부족
    • 해결 방법:
      • 애플리케이션 코드 검토 및 수정
      • 메모리 프로파일링 도구 사용
      • 주기적인 가비지 컬렉션 구성
      • 캐시 크기 제한 및 만료 정책 구현
  2. 컨테이너 메모리 제한 문제:

    • 증상: 빈번한 OOM 종료, 파드 재시작
    • 원인: 부적절한 메모리 제한 설정, 리소스 요청과 제한 간의 큰 차이
    • 해결 방법:
      yaml
      # 적절한 메모리 요청 및 제한 설정
      apiVersion: v1
      kind: Pod
      metadata:
        name: memory-optimized-pod
      spec:
        containers:
        - name: app
          image: app-image
          resources:
            requests:
              memory: "256Mi"
            limits:
              memory: "512Mi"
  3. 시스템 구성 요소 메모리 문제:

    • 증상: 노드 불안정성, kubelet 또는 다른 시스템 구성 요소의 높은 메모리 사용량
    • 원인: kubelet 구성 문제, 시스템 구성 요소 버그
    • 해결 방법:
      • kubelet 구성 최적화
      • 시스템 구성 요소 업데이트
      • 노드 리소스 예약 조정
  4. 메모리 단편화 문제:

    • 증상: 사용 가능한 총 메모리가 충분함에도 OOM 발생
    • 원인: 메모리 단편화, 큰 페이지 할당 실패
    • 해결 방법:
      • 노드 주기적 재부팅 일정 설정
      • 메모리 압력이 높은 워크로드 분산
      • 노드 메모리 오버커밋 감소

모범 사례:

  1. 체계적인 메모리 모니터링:

    • 클러스터, 노드, 파드 수준의 메모리 모니터링
    • 시간에 따른 메모리 사용 패턴 추적
    • 이상 징후에 대한 알림 설정
  2. 적절한 리소스 제한 설정:

    • 워크로드 특성에 맞는 메모리 요청 및 제한 설정
    • 메모리 요청과 제한 간의 적절한 비율 유지
    • 정기적인 리소스 사용량 검토 및 조정
  3. 애플리케이션 최적화:

    • 메모리 효율적인 코드 작성
    • 주기적인 메모리 프로파일링 및 최적화
    • 적절한 캐시 전략 구현
  4. 클러스터 구성 최적화:

    • 노드 메모리 예약 최적화
    • 적절한 kubelet 메모리 관리 설정
    • 워크로드 분산 및 격리

실제 구현 예시:

  1. 메모리 누수 문제 해결 스크립트:

    bash
    #!/bin/bash
    # 메모리 누수 문제 해결 스크립트
    
    NAMESPACE=$1
    POD_PREFIX=$2
    
    if [ -z "$NAMESPACE" ] || [ -z "$POD_PREFIX" ]; then
      echo "사용법: $0 <네임스페이스> <파드_접두사>"
      exit 1
    fi
    
    echo "=== 메모리 누수 문제 해결 ==="
    echo "네임스페이스: $NAMESPACE"
    echo "파드 접두사: $POD_PREFIX"
    
    # 노드 메모리 상태 확인
    echo
    echo "=== 노드 메모리 상태 ==="
    kubectl top nodes --sort-by=memory
    
    # 메모리 사용량이 높은 파드 확인
    echo
    echo "=== 메모리 사용량이 높은 파드 ==="
    kubectl top pods -n $NAMESPACE | grep $POD_PREFIX | sort -k4 -nr
    
    # 파드 메모리 제한 확인
    echo
    echo "=== 파드 메모리 제한 ==="
    PODS=$(kubectl get pods -n $NAMESPACE -l app=$POD_PREFIX -o jsonpath='{.items[*].metadata.name}')
    for POD in $PODS; do
      echo
      echo "파드: $POD"
      kubectl get pod $POD -n $NAMESPACE -o jsonpath='{.spec.containers[*].resources}' | jq
    done
    
    # OOM 이벤트 확인
    echo
    echo "=== OOM 이벤트 ==="
    kubectl get events -n $NAMESPACE --sort-by='.lastTimestamp' | grep -i "OOMKilled" | grep $POD_PREFIX
    
    # 파드 재시작 확인
    echo
    echo "=== 파드 재시작 횟수 ==="
    kubectl get pods -n $NAMESPACE -l app=$POD_PREFIX -o custom-columns=NAME:.metadata.name,RESTARTS:.status.containerStatuses[0].restartCount,STATUS:.status.phase
    
    # 메모리 사용량 추세 수집
    echo
    echo "=== 메모리 사용량 추세 수집 중 ==="
    echo "5분 동안 30초마다 메모리 사용량을 수집합니다..."
    
    for i in {1..10}; do
      echo
      echo "수집 $i/10 ($(date))"
      kubectl top pods -n $NAMESPACE | grep $POD_PREFIX
      sleep 30
    done
    
    # 로그에서 메모리 관련 메시지 확인
    echo
    echo "=== 로그에서 메모리 관련 메시지 ==="
    for POD in $PODS; do
      echo
      echo "파드: $POD"
      kubectl logs $POD -n $NAMESPACE --tail=100 | grep -i "memory\|heap\|GC\|out of memory"
    done
    
    # 애플리케이션별 메모리 프로파일링 명령 예시
    echo
    echo "=== 애플리케이션별 메모리 프로파일링 명령 예시 ==="
    echo
    echo "Java 애플리케이션:"
    echo "kubectl exec -it <pod-name> -n $NAMESPACE -- jmap -heap 1"
    echo "kubectl exec -it <pod-name> -n $NAMESPACE -- jstat -gcutil 1 1000 10"
    echo
    echo "Node.js 애플리케이션:"
    echo "kubectl exec -it <pod-name> -n $NAMESPACE -- node --inspect"
    echo
    echo "Python 애플리케이션:"
    echo "kubectl exec -it <pod-name> -n $NAMESPACE -- python -m memory_profiler <script.py>"
    echo
    echo "Go 애플리케이션:"
    echo "kubectl exec -it <pod-name> -n $NAMESPACE -- go tool pprof <binary> /tmp/profile"
    
    echo
    echo "=== 문제 해결 권장 사항 ==="
    echo "1. 메모리 사용량이 지속적으로 증가하는 파드 식별"
    echo "2. 애플리케이션 코드에서 메모리 누수 가능성 검토"
    echo "3. 적절한 메모리 제한 설정 확인 및 조정"
    echo "4. 애플리케이션별 메모리 프로파일링 도구 사용"
    echo "5. 필요한 경우 애플리케이션 코드 최적화 또는 수정"
  2. 메모리 모니터링 및 알림 구성:

    yaml
    # Prometheus 메모리 사용량 알림 규칙
    apiVersion: monitoring.coreos.com/v1
    kind: PrometheusRule
    metadata:
      name: memory-alerts
      namespace: monitoring
    spec:
      groups:
      - name: memory
        rules:
        - alert: PodMemoryUsageHigh
          expr: sum(container_memory_working_set_bytes{container!="", image!=""}) by (namespace, pod) / sum(kube_pod_container_resource_limits_memory_bytes) by (namespace, pod) > 0.85
          for: 10m
          labels:
            severity: warning
          annotations:
            summary: "Pod 메모리 사용량 높음"
            description: "파드 {{ $labels.pod }}의 메모리 사용량이 제한의 85%를 초과했습니다."
        
        - alert: PodMemoryUsageCritical
          expr: sum(container_memory_working_set_bytes{container!="", image!=""}) by (namespace, pod) / sum(kube_pod_container_resource_limits_memory_bytes) by (namespace, pod) > 0.95
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "Pod 메모리 사용량 심각"
            description: "파드 {{ $labels.pod }}의 메모리 사용량이 제한의 95%를 초과했습니다."
        
        - alert: PodMemoryGrowth
          expr: deriv(container_memory_working_set_bytes{container!="", image!=""}[30m]) > 1024 * 1024 * 5
          for: 30m
          labels:
            severity: warning
          annotations:
            summary: "Pod 메모리 지속적 증가"
            description: "파드 {{ $labels.pod }}의 메모리 사용량이 30분 동안 지속적으로 증가하고 있습니다(>5MB/분)."
        
        - alert: NodeMemoryPressure
          expr: kube_node_status_condition{condition="MemoryPressure", status="true"} == 1
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "노드 메모리 압력"
            description: "노드 {{ $labels.node }}에 메모리 압력이 있습니다."
  3. 메모리 효율적인 애플리케이션 구성:

    yaml
    # Java 애플리케이션을 위한 메모리 최적화 구성
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: java-app
      namespace: production
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: java-app
      template:
        metadata:
          labels:
            app: java-app
        spec:
          containers:
          - name: java-app
            image: java-app:1.0
            resources:
              requests:
                memory: "512Mi"
                cpu: "500m"
              limits:
                memory: "1Gi"
                cpu: "1000m"
            env:
            - name: JAVA_OPTS
              value: "-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.bin -XX:+ExitOnOutOfMemoryError -Xms256m -Xmx768m"
            - name: MEMORY_MONITOR_ENABLED
              value: "true"
            - name: MEMORY_MONITOR_INTERVAL
              value: "60"
            livenessProbe:
              httpGet:
                path: /actuator/health/liveness
                port: 8080
              initialDelaySeconds: 60
              periodSeconds: 30
            readinessProbe:
              httpGet:
                path: /actuator/health/readiness
                port: 8080
              initialDelaySeconds: 30
              periodSeconds: 10
            lifecycle:
              preStop:
                exec:
                  command: ["sh", "-c", "sleep 10"]
  4. Terraform을 사용한 메모리 모니터링 구성:

    hcl
    # Prometheus 및 Grafana 설치
    resource "helm_release" "prometheus" {
      name       = "prometheus"
      repository = "https://prometheus-community.github.io/helm-charts"
      chart      = "kube-prometheus-stack"
      namespace  = "monitoring"
      create_namespace = true
      
      set {
        name  = "prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues"
        value = "false"
      }
      
      set {
        name  = "prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues"
        value = "false"
      }
      
      set {
        name  = "grafana.enabled"
        value = "true"
      }
      
      set {
        name  = "grafana.persistence.enabled"
        value = "true"
      }
      
      set {
        name  = "grafana.persistence.size"
        value = "10Gi"
      }
    }
    
    # 메모리 대시보드 구성
    resource "kubernetes_config_map" "memory_dashboard" {
      metadata {
        name      = "memory-dashboard"
        namespace = "monitoring"
        labels = {
          grafana_dashboard = "1"
        }
      }
      
      data = {
        "memory-dashboard.json" = file("${path.module}/dashboards/memory-dashboard.json")
      }
      
      depends_on = [helm_release.prometheus]
    }
    
    # 메모리 알림 규칙
    resource "kubernetes_manifest" "memory_alerts" {
      manifest = {
        apiVersion = "monitoring.coreos.com/v1"
        kind       = "PrometheusRule"
        metadata = {
          name      = "memory-alerts"
          namespace = "monitoring"
        }
        spec = {
          groups = [
            {
              name = "memory"
              rules = [
                {
                  alert = "PodMemoryUsageHigh"
                  expr  = "sum(container_memory_working_set_bytes{container!=\"\", image!=\"\"}) by (namespace, pod) / sum(kube_pod_container_resource_limits_memory_bytes) by (namespace, pod) > 0.85"
                  for   = "10m"
                  labels = {
                    severity = "warning"
                  }
                  annotations = {
                    summary     = "Pod 메모리 사용량 높음"
                    description = "파드 {{ $labels.pod }}의 메모리 사용량이 제한의 85%를 초과했습니다."
                  }
                },
                {
                  alert = "PodMemoryGrowth"
                  expr  = "deriv(container_memory_working_set_bytes{container!=\"\", image!=\"\"}[30m]) > 1024 * 1024 * 5"
                  for   = "30m"
                  labels = {
                    severity = "warning"
                  }
                  annotations = {
                    summary     = "Pod 메모리 지속적 증가"
                    description = "파드 {{ $labels.pod }}의 메모리 사용량이 30분 동안 지속적으로 증가하고 있습니다(>5MB/분)."
                  }
                }
              ]
            }
          ]
        }
      }
      
      depends_on = [helm_release.prometheus]
    }

다른 옵션들의 문제점:

  • A. 모든 파드 재시작: 이는 일시적인 해결책일 뿐이며, 메모리 누수의 근본 원인을 해결하지 않습니다. 파드가 다시 시작되면 문제가 재발할 것입니다.
  • B. 클러스터 노드 크기 증가: 이는 근본 원인을 해결하지 않고 증상을 숨기는 것에 불과합니다. 메모리 누수가 계속되면 더 큰 노드도 결국 메모리 부족 상태가 될 것입니다.
  • D. 더 많은 노드 추가: 이는 B와 유사하게 근본 원인을 해결하지 않고 증상을 숨기는 것에 불과합니다. 메모리 누수 문제는 노드 수와 관계없이 계속될 것입니다.
### 10. Amazon EKS 클러스터에서 DNS 해결 문제를 해결하는 가장 효과적인 접근 방식은 무엇인가요?

A. 모든 파드에 고정 IP 할당
B. CoreDNS 구성, 네트워크 정책, DNS 정책, 연결성 체계적 확인
C. 모든 서비스에 ExternalName 사용
D. 클러스터 VPC 재구성

정답 및 설명

정답: B. CoreDNS 구성, 네트워크 정책, DNS 정책, 연결성 체계적 확인

설명: Amazon EKS 클러스터에서 DNS 해결 문제를 해결하는 가장 효과적인 접근 방식은 CoreDNS 구성, 네트워크 정책, DNS 정책, 연결성을 체계적으로 확인하는 것입니다. 이 접근 방식은 DNS 문제의 근본 원인을 식별하고 해결하는 데 도움이 됩니다.

주요 확인 사항:

  1. CoreDNS 구성 및 상태 확인:

    • CoreDNS 파드 상태 및 로그
    • CoreDNS ConfigMap 구성
    • CoreDNS 서비스 및 엔드포인트
  2. 네트워크 정책 및 연결성 확인:

    • DNS 포트(53/UDP, 53/TCP)에 대한 네트워크 정책
    • 파드와 CoreDNS 간의 네트워크 연결
    • VPC DNS 설정
  3. DNS 정책 및 구성 확인:

    • 파드 DNS 정책 설정
    • DNS 구성 옵션
    • 호스트 네임스페이스 설정
  4. 클러스터 및 VPC 구성 확인:

    • EKS 클러스터 DNS 설정
    • VPC DNS 속성
    • DHCP 옵션 세트

문제 해결 방법:

  1. CoreDNS 상태 및 구성 확인:

    bash
    # CoreDNS 파드 상태 확인
    kubectl get pods -n kube-system -l k8s-app=kube-dns
    
    # CoreDNS 로그 확인
    kubectl logs -n kube-system -l k8s-app=kube-dns
    
    # CoreDNS ConfigMap 확인
    kubectl get configmap coredns -n kube-system -o yaml
    
    # CoreDNS 서비스 확인
    kubectl get service kube-dns -n kube-system
    
    # CoreDNS 엔드포인트 확인
    kubectl get endpoints kube-dns -n kube-system
  2. DNS 해결 테스트:

    bash
    # 디버그 파드 생성
    kubectl run dns-test --rm -it --image=busybox -- sh
    
    # 클러스터 내부 DNS 해결 테스트
    nslookup kubernetes.default.svc.cluster.local
    
    # 서비스 DNS 해결 테스트
    nslookup <service-name>.<namespace>.svc.cluster.local
    
    # 외부 도메인 해결 테스트
    nslookup google.com
    
    # DNS 서버 확인
    cat /etc/resolv.conf
  3. 네트워크 정책 및 연결성 확인:

    bash
    # DNS 관련 네트워크 정책 확인
    kubectl get networkpolicies --all-namespaces
    
    # CoreDNS로의 연결 테스트
    kubectl run netcat-test --rm -it --image=busybox -- sh -c "nc -zv kube-dns.kube-system.svc.cluster.local 53"
    
    # DNS 패킷 캡처
    kubectl run tcpdump-test --rm -it --image=nicolaka/netshoot -- tcpdump -i any port 53
  4. 파드 DNS 구성 확인:

    bash
    # 파드 DNS 정책 확인
    kubectl get pod <pod-name> -o jsonpath='{.spec.dnsPolicy}'
    
    # 파드 DNS 구성 확인
    kubectl get pod <pod-name> -o jsonpath='{.spec.dnsConfig}'
    
    # 파드 내부 resolv.conf 확인
    kubectl exec -it <pod-name> -- cat /etc/resolv.conf
  5. VPC 및 클러스터 DNS 설정 확인:

    bash
    # VPC DNS 속성 확인
    aws ec2 describe-vpcs --vpc-id <vpc-id> --query 'Vpcs[0].EnableDnsSupport'
    aws ec2 describe-vpcs --vpc-id <vpc-id> --query 'Vpcs[0].EnableDnsHostnames'
    
    # DHCP 옵션 세트 확인
    aws ec2 describe-vpcs --vpc-id <vpc-id> --query 'Vpcs[0].DhcpOptionsId'
    aws ec2 describe-dhcp-options --dhcp-options-id <dhcp-options-id>
    
    # 노드 DNS 구성 확인
    kubectl debug node/<node-name> -it --image=busybox -- cat /etc/resolv.conf

일반적인 DNS 문제 및 해결 방법:

  1. CoreDNS 파드 문제:

    • 증상: DNS 쿼리 실패, CoreDNS 파드 비정상
    • 원인: CoreDNS 파드 충돌, 리소스 부족, 구성 오류
    • 해결 방법:
      bash
      # CoreDNS 파드 재시작
      kubectl rollout restart deployment coredns -n kube-system
      
      # CoreDNS 리소스 증가
      kubectl edit deployment coredns -n kube-system
      # resources 섹션에서 requests 및 limits 증가
      
      # CoreDNS 로그 확인
      kubectl logs -n kube-system -l k8s-app=kube-dns
  2. 네트워크 정책 문제:

    • 증상: 특정 네임스페이스 또는 파드에서만 DNS 해결 실패
    • 원인: 제한적인 네트워크 정책이 DNS 트래픽 차단
    • 해결 방법:
      yaml
      # DNS 트래픽을 허용하는 네트워크 정책
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-dns
        namespace: <namespace>
      spec:
        podSelector: {}
        policyTypes:
        - Egress
        egress:
        - to:
          - namespaceSelector:
              matchLabels:
                kubernetes.io/metadata.name: kube-system
            podSelector:
              matchLabels:
                k8s-app: kube-dns
          ports:
          - protocol: UDP
            port: 53
          - protocol: TCP
            port: 53
  3. DNS 정책 및 구성 문제:

    • 증상: 특정 유형의 DNS 쿼리만 실패
    • 원인: 부적절한 DNS 정책 또는 구성
    • 해결 방법:
      yaml
      # 사용자 지정 DNS 구성으로 파드 생성
      apiVersion: v1
      kind: Pod
      metadata:
        name: dns-custom-pod
      spec:
        containers:
        - name: app
          image: busybox
          command: ["sleep", "3600"]
        dnsPolicy: "None"
        dnsConfig:
          nameservers:
          - "169.254.20.10"  # VPC DNS 서버
          - "8.8.8.8"        # 백업 DNS 서버
          searches:
          - <namespace>.svc.cluster.local
          - svc.cluster.local
          - cluster.local
          options:
          - name: ndots
            value: "5"
  4. VPC DNS 설정 문제:

    • 증상: 외부 도메인 해결 실패
    • 원인: VPC DNS 속성 비활성화 또는 DHCP 옵션 세트 문제
    • 해결 방법:
      bash
      # VPC DNS 속성 활성화
      aws ec2 modify-vpc-attribute --vpc-id <vpc-id> --enable-dns-support
      aws ec2 modify-vpc-attribute --vpc-id <vpc-id> --enable-dns-hostnames
      
      # 사용자 지정 DHCP 옵션 세트 생성
      aws ec2 create-dhcp-options \
        --dhcp-configurations \
        "Key=domain-name-servers,Values=AmazonProvidedDNS" \
        "Key=domain-name,Values=<region>.compute.internal"
      
      # VPC에 DHCP 옵션 세트 연결
      aws ec2 associate-dhcp-options --dhcp-options-id <dhcp-options-id> --vpc-id <vpc-id>
  5. CoreDNS 구성 문제:

    • 증상: 특정 도메인 해결 실패 또는 느린 DNS 해결
    • 원인: CoreDNS 구성 오류 또는 최적화되지 않은 설정
    • 해결 방법:
      yaml
      # CoreDNS ConfigMap 최적화
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: coredns
        namespace: kube-system
      data:
        Corefile: |
          .:53 {
              errors
              health {
                 lameduck 5s
              }
              ready
              kubernetes cluster.local in-addr.arpa ip6.arpa {
                 pods insecure
                 fallthrough in-addr.arpa ip6.arpa
                 ttl 30
              }
              prometheus :9153
              forward . /etc/resolv.conf {
                 max_concurrent 1000
                 health_check 5s
              }
              cache 30
              loop
              reload
              loadbalance
          }

모범 사례:

  1. CoreDNS 모니터링 및 확장:

    • CoreDNS 성능 및 상태 모니터링
    • 클러스터 크기에 따른 CoreDNS 복제본 확장
    • 적절한 리소스 할당
  2. DNS 캐싱 및 최적화:

    • 적절한 TTL 및 캐시 설정
    • 노드 수준 DNS 캐싱 구현
    • 애플리케이션 수준 DNS 캐싱 고려
  3. 네트워크 정책 설계:

    • DNS 트래픽을 명시적으로 허용
    • 최소 권한 원칙 적용
    • 네트워크 정책 테스트 및 검증
  4. DNS 문제 해결 도구 및 프로세스:

    • DNS 문제 해결 도구 및 스크립트 준비
    • 체계적인 문제 해결 프로세스 수립
    • DNS 관련 이벤트 및 로그 모니터링

실제 구현 예시:

  1. DNS 문제 해결 스크립트:

    bash
    #!/bin/bash
    # DNS 문제 해결 스크립트
    
    NAMESPACE=$1
    POD_NAME=$2
    
    if [ -z "$NAMESPACE" ] || [ -z "$POD_NAME" ]; then
      echo "사용법: $0 <네임스페이스> <파드_이름>"
      exit 1
    fi
    
    echo "=== DNS 문제 해결 ==="
    echo "네임스페이스: $NAMESPACE"
    echo "파드: $POD_NAME"
    
    # CoreDNS 상태 확인
    echo
    echo "=== CoreDNS 상태 ==="
    kubectl get pods -n kube-system -l k8s-app=kube-dns
    
    # CoreDNS 서비스 및 엔드포인트 확인
    echo
    echo "=== CoreDNS 서비스 및 엔드포인트 ==="
    kubectl get service kube-dns -n kube-system
    kubectl get endpoints kube-dns -n kube-system
    
    # CoreDNS 구성 확인
    echo
    echo "=== CoreDNS 구성 ==="
    kubectl get configmap coredns -n kube-system -o yaml
    
    # 파드 DNS 구성 확인
    echo
    echo "=== 파드 DNS 구성 ==="
    kubectl get pod $POD_NAME -n $NAMESPACE -o jsonpath='{.spec.dnsPolicy}'
    echo
    kubectl get pod $POD_NAME -n $NAMESPACE -o jsonpath='{.spec.dnsConfig}'
    
    # 파드 내부 DNS 구성 확인
    echo
    echo "=== 파드 내부 DNS 구성 ==="
    kubectl exec -it $POD_NAME -n $NAMESPACE -- cat /etc/resolv.conf
    
    # DNS 해결 테스트
    echo
    echo "=== DNS 해결 테스트 ==="
    echo "클러스터 내부 DNS 해결 테스트:"
    kubectl exec -it $POD_NAME -n $NAMESPACE -- nslookup kubernetes.default.svc.cluster.local
    
    echo
    echo "외부 도메인 해결 테스트:"
    kubectl exec -it $POD_NAME -n $NAMESPACE -- nslookup google.com
    
    # DNS 연결 테스트
    echo
    echo "=== DNS 연결 테스트 ==="
    kubectl exec -it $POD_NAME -n $NAMESPACE -- nc -zv kube-dns.kube-system.svc.cluster.local 53 -w 5
    
    # 네트워크 정책 확인
    echo
    echo "=== 네트워크 정책 확인 ==="
    kubectl get networkpolicies -n $NAMESPACE
    
    # CoreDNS 로그 확인
    echo
    echo "=== CoreDNS 로그 ==="
    kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50
    
    # VPC DNS 설정 확인
    echo
    echo "=== VPC DNS 설정 ==="
    VPC_ID=$(aws eks describe-cluster --name $(kubectl config current-context | cut -d'/' -f2) --query "cluster.resourcesVpcConfig.vpcId" --output text)
    echo "VPC ID: $VPC_ID"
    
    echo "DNS 지원 활성화:"
    aws ec2 describe-vpcs --vpc-id $VPC_ID --query 'Vpcs[0].EnableDnsSupport'
    
    echo "DNS 호스트 이름 활성화:"
    aws ec2 describe-vpcs --vpc-id $VPC_ID --query 'Vpcs[0].EnableDnsHostnames'
    
    echo "DHCP 옵션 세트:"
    DHCP_OPTIONS_ID=$(aws ec2 describe-vpcs --vpc-id $VPC_ID --query 'Vpcs[0].DhcpOptionsId' --output text)
    aws ec2 describe-dhcp-options --dhcp-options-id $DHCP_OPTIONS_ID
    
    echo
    echo "=== 문제 해결 권장 사항 ==="
    if ! kubectl get pods -n kube-system -l k8s-app=kube-dns -o jsonpath='{.items[*].status.phase}' | grep -q "Running"; then
      echo "- CoreDNS 파드가 실행 중이 아닙니다. CoreDNS 파드 상태 및 로그를 확인하세요."
    fi
    
    if ! kubectl exec -it $POD_NAME -n $NAMESPACE -- nslookup kubernetes.default.svc.cluster.local &>/dev/null; then
      echo "- 클러스터 내부 DNS 해결에 실패했습니다. 파드와 CoreDNS 간의 네트워크 연결을 확인하세요."
    fi
    
    if ! kubectl exec -it $POD_NAME -n $NAMESPACE -- nslookup google.com &>/dev/null; then
      echo "- 외부 도메인 해결에 실패했습니다. CoreDNS 구성 및 VPC DNS 설정을 확인하세요."
    fi
    
    if kubectl get networkpolicies -n $NAMESPACE -o json | jq -r '.items[] | select(.spec.egress != null)' | grep -q .; then
      echo "- 네트워크 정책이 DNS 트래픽을 차단할 수 있습니다. DNS 트래픽(UDP/TCP 포트 53)을 허용하는지 확인하세요."
    fi
    
    echo "- CoreDNS ConfigMap 구성을 검토하고 필요한 경우 최적화하세요."
    echo "- 파드 DNS 정책 및 구성을 검토하세요."
    echo "- VPC DNS 속성이 활성화되어 있는지 확인하세요."
  2. CoreDNS 최적화 및 확장 구성:

    yaml
    # CoreDNS 배포 최적화
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: coredns
      namespace: kube-system
    spec:
      replicas: 3  # 클러스터 크기에 따라 조정
      selector:
        matchLabels:
          k8s-app: kube-dns
      template:
        metadata:
          labels:
            k8s-app: kube-dns
        spec:
          priorityClassName: system-cluster-critical
          serviceAccountName: coredns
          affinity:
            podAntiAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
              - weight: 100
                podAffinityTerm:
                  labelSelector:
                    matchExpressions:
                    - key: k8s-app
                      operator: In
                      values:
                      - kube-dns
                  topologyKey: kubernetes.io/hostname
          containers:
          - name: coredns
            image: public.ecr.aws/eks-distro/coredns/coredns:v1.8.7-eks-1-23-13
            resources:
              limits:
                memory: 170Mi
              requests:
                cpu: 100m
                memory: 70Mi
            args: [ "-conf", "/etc/coredns/Corefile" ]
            volumeMounts:
            - name: config-volume
              mountPath: /etc/coredns
              readOnly: true
            ports:
            - containerPort: 53
              name: dns
              protocol: UDP
            - containerPort: 53
              name: dns-tcp
              protocol: TCP
            - containerPort: 9153
              name: metrics
              protocol: TCP
            livenessProbe:
              httpGet:
                path: /health
                port: 8080
                scheme: HTTP
              initialDelaySeconds: 60
              timeoutSeconds: 5
              successThreshold: 1
              failureThreshold: 5
            readinessProbe:
              httpGet:
                path: /ready
                port: 8181
                scheme: HTTP
          volumes:
          - name: config-volume
            configMap:
              name: coredns
              items:
              - key: Corefile
                path: Corefile
  3. 노드 수준 DNS 캐싱 구성:

    yaml
    # NodeLocal DNSCache 배포
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: node-local-dns
      namespace: kube-system
    ---
    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: node-local-dns
      namespace: kube-system
      labels:
        k8s-app: node-local-dns
    spec:
      selector:
        matchLabels:
          k8s-app: node-local-dns
      template:
        metadata:
          labels:
            k8s-app: node-local-dns
        spec:
          priorityClassName: system-node-critical
          serviceAccountName: node-local-dns
          hostNetwork: true
          dnsPolicy: Default
          containers:
          - name: node-cache
            image: public.ecr.aws/eks-distro/kubernetes-dns/k8s-dns-node-cache:1.21.4
            resources:
              requests:
                cpu: 25m
                memory: 5Mi
            args:
            - -localip=169.254.20.10
            - -metrics=0.0.0.0:9253
            - -health-port=9254
            - -config=/etc/coredns/Corefile
            livenessProbe:
              httpGet:
                host: 169.254.20.10
                path: /health
                port: 9254
              initialDelaySeconds: 60
              timeoutSeconds: 5
            volumeMounts:
            - name: config-volume
              mountPath: /etc/coredns
          volumes:
          - name: config-volume
            configMap:
              name: node-local-dns
              items:
              - key: Corefile
                path: Corefile
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: node-local-dns
      namespace: kube-system
    data:
      Corefile: |
        cluster.local:53 {
            errors
            cache {
                success 9984 30
                denial 9984 5
            }
            reload
            loop
            bind 169.254.20.10
            forward . 172.20.0.10 {
                force_tcp
            }
            prometheus :9253
            health 169.254.20.10:9254
        }
        in-addr.arpa:53 {
            errors
            cache 30
            reload
            loop
            bind 169.254.20.10
            forward . 172.20.0.10 {
                force_tcp
            }
            prometheus :9253
        }
        ip6.arpa:53 {
            errors
            cache 30
            reload
            loop
            bind 169.254.20.10
            forward . 172.20.0.10 {
                force_tcp
            }
            prometheus :9253
        }
        .:53 {
            errors
            cache 30
            reload
            loop
            bind 169.254.20.10
            forward . /etc/resolv.conf {
                max_concurrent 1000
            }
            prometheus :9253
            health 169.254.20.10:9254
        }
  4. Terraform을 사용한 DNS 구성:

    hcl
    # CoreDNS 구성 업데이트
    resource "kubernetes_config_map" "coredns" {
      metadata {
        name      = "coredns"
        namespace = "kube-system"
      }
      
      data = {
        Corefile = <<-EOT
          .:53 {
              errors
              health {
                 lameduck 5s
              }
              ready
              kubernetes cluster.local in-addr.arpa ip6.arpa {
                 pods insecure
                 fallthrough in-addr.arpa ip6.arpa
                 ttl 30
              }
              prometheus :9153
              forward . /etc/resolv.conf {
                 max_concurrent 1000
                 health_check 5s
              }
              cache 30
              loop
              reload
              loadbalance
          }
        EOT
      }
    }
    
    # CoreDNS 배포 확장
    resource "kubernetes_deployment" "coredns" {
      metadata {
        name      = "coredns"
        namespace = "kube-system"
      }
      
      spec {
        replicas = 3
        
        selector {
          match_labels = {
            k8s-app = "kube-dns"
          }
        }
        
        template {
          metadata {
            labels = {
              k8s-app = "kube-dns"
            }
          }
          
          spec {
            priority_class_name = "system-cluster-critical"
            service_account_name = "coredns"
            
            affinity {
              pod_anti_affinity {
                preferred_during_scheduling_ignored_during_execution {
                  weight = 100
                  pod_affinity_term {
                    label_selector {
                      match_expressions {
                        key = "k8s-app"
                        operator = "In"
                        values = ["kube-dns"]
                      }
                    }
                    topology_key = "kubernetes.io/hostname"
                  }
                }
              }
            }
            
            container {
              name  = "coredns"
              image = "public.ecr.aws/eks-distro/coredns/coredns:v1.8.7-eks-1-23-13"
              
              resources {
                limits = {
                  memory = "170Mi"
                }
                requests = {
                  cpu    = "100m"
                  memory = "70Mi"
                }
              }
              
              args = ["-conf", "/etc/coredns/Corefile"]
              
              volume_mount {
                name       = "config-volume"
                mount_path = "/etc/coredns"
                read_only  = true
              }
              
              port {
                container_port = 53
                name           = "dns"
                protocol       = "UDP"
              }
              
              port {
                container_port = 53
                name           = "dns-tcp"
                protocol       = "TCP"
              }
              
              port {
                container_port = 9153
                name           = "metrics"
                protocol       = "TCP"
              }
              
              liveness_probe {
                http_get {
                  path   = "/health"
                  port   = 8080
                  scheme = "HTTP"
                }
                initial_delay_seconds = 60
                timeout_seconds       = 5
                success_threshold     = 1
                failure_threshold     = 5
              }
              
              readiness_probe {
                http_get {
                  path   = "/ready"
                  port   = 8181
                  scheme = "HTTP"
                }
              }
            }
            
            volume {
              name = "config-volume"
              config_map {
                name = "coredns"
                items {
                  key  = "Corefile"
                  path = "Corefile"
                }
              }
            }
          }
        }
      }
    }
    
    # VPC DNS 속성 활성화
    resource "aws_vpc" "main" {
      # 기존 VPC 구성...
      
      enable_dns_support   = true
      enable_dns_hostnames = true
    }

다른 옵션들의 문제점:

  • A. 모든 파드에 고정 IP 할당: 이는 DNS 문제를 해결하지 않으며, 파드 IP 할당과 DNS 해결은 별개의 문제입니다. 또한 파드에 고정 IP를 할당하는 것은 Kubernetes의 동적 특성에 반하며 관리 복잡성을 증가시킵니다.
  • C. 모든 서비스에 ExternalName 사용: 이는 특정 사용 사례에만 적합하며, 대부분의 DNS 문제를 해결하지 않습니다. ExternalName은 외부 서비스에 대한 별칭을 제공하는 데 사용되며, 클러스터 내부 DNS 해결 문제를 해결하지 않습니다.
  • D. 클러스터 VPC 재구성: 이는 극단적인 조치이며, 대부분의 DNS 문제는 VPC 수준이 아닌 클러스터 내부의 DNS 구성과 관련이 있습니다. VPC 재구성은 불필요한 다운타임과 복잡성을 초래할 수 있습니다.