Amazon EKS 문제 해결 퀴즈
이 퀴즈는 Amazon EKS 클러스터에서 발생할 수 있는 다양한 문제를 진단하고 해결하는 능력을 테스트합니다.
퀴즈 개요
- 클러스터 생성 및 구성 문제
- 네트워킹 문제
- 노드 및 파드 문제
- 스토리지 문제
- 보안 및 액세스 문제
- 성능 및 확장성 문제
객관식 문제
1. Amazon EKS 클러스터 생성이 실패할 때 가장 먼저 확인해야 할 사항은 무엇인가요?
A. 클러스터 이름이 고유한지 확인
B. IAM 권한, VPC 구성 및 서비스 할당량 확인
C. 다른 리전에서 다시 시도
D. 더 큰 인스턴스 유형 선택
정답 및 설명
정답: B. IAM 권한, VPC 구성 및 서비스 할당량 확인
설명: Amazon EKS 클러스터 생성이 실패할 때 가장 먼저 확인해야 할 사항은 IAM 권한, VPC 구성 및 서비스 할당량입니다. 이러한 요소들은 클러스터 생성 실패의 가장 일반적인 원인이며, 체계적으로 확인하면 문제를 신속하게 식별하고 해결할 수 있습니다.
주요 확인 사항:
IAM 권한 확인:
- 클러스터 생성에 필요한 IAM 권한 보유 여부
- 서비스 연결 역할 생성 권한
- 클러스터 역할 및 정책 구성
VPC 구성 확인:
- 서브넷 구성 (최소 2개의 가용 영역에 분산된 서브넷)
- 서브넷 CIDR 크기 (최소 /28, 권장 /24)
- 인터넷 연결 (NAT 게이트웨이 또는 인터넷 게이트웨이)
- 보안 그룹 및 네트워크 ACL 설정
서비스 할당량 확인:
- EKS 클러스터 수 할당량
- EC2 인스턴스 할당량
- VPC 및 서브넷 할당량
- 기타 관련 서비스 할당량
문제 해결 방법:
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.comVPC 구성 문제 해결:
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서비스 할당량 문제 해결:
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
일반적인 오류 메시지 및 해결 방법:
IAM 권한 부족:
- 오류: "User: arn:aws:iam::123456789012:user/myuser is not authorized to perform: eks:CreateCluster"
- 해결: 필요한 IAM 권한 추가
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."
- 해결: 다른 가용 영역의 서브넷 사용 또는 새 서브넷 생성
서비스 할당량 초과:
- 오류: "Account cannot create more EKS clusters in region us-west-2. Current limit is 5"
- 해결: 서비스 할당량 증가 요청 또는 불필요한 클러스터 삭제
모범 사례:
클러스터 생성 전 준비 사항:
- 필요한 IAM 권한 확인
- 적절한 VPC 및 서브넷 구성
- 서비스 할당량 확인
체계적인 문제 해결 접근 방식:
- 오류 메시지 분석
- AWS CloudTrail 로그 확인
- 단계별 구성 요소 검증
자동화된 인프라 구성:
- AWS CloudFormation 또는 Terraform 사용
- eksctl과 같은 도구 활용
- 인프라 구성 버전 관리
실제 구현 예시:
eksctl을 사용한 클러스터 생성 문제 해결:
bash# 디버그 모드로 클러스터 생성 eksctl create cluster --name my-cluster --region us-west-2 --verbose 4 # 클러스터 생성 상태 확인 eksctl get cluster --name my-cluster --region us-west-2AWS 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-clusterTerraform을 사용한 클러스터 생성 문제 해결:
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. 더 큰 인스턴스 유형 선택: 인스턴스 유형은 노드 그룹에 적용되며, 클러스터 생성 자체에는 영향을 미치지 않습니다.
A. 즉시 노드 종료 및 교체
B. 노드 로그, 리소스 사용량 및 네트워크 연결 확인
C. 클러스터 API 서버 재시작
D. 모든 파드 삭제 및 재배포
정답 및 설명
정답: B. 노드 로그, 리소스 사용량 및 네트워크 연결 확인
설명: Amazon EKS 클러스터에서 노드가 NotReady 상태일 때 가장 효과적인 문제 해결 접근 방식은 노드 로그, 리소스 사용량 및 네트워크 연결을 확인하는 것입니다. 이 체계적인 접근 방식은 문제의 근본 원인을 식별하고 적절한 해결책을 적용하는 데 도움이 됩니다.
주요 확인 사항:
노드 상태 및 이벤트 확인:
- 노드 상태 세부 정보
- 노드 관련 이벤트
- 노드 조건(conditions) 확인
노드 로그 분석:
- kubelet 로그
- 시스템 로그
- 컨테이너 런타임 로그
리소스 사용량 확인:
- CPU, 메모리, 디스크 사용량
- 리소스 제한 및 압박
- 시스템 프로세스 상태
네트워크 연결 확인:
- 컨트롤 플레인과의 연결
- DNS 해결
- VPC 및 서브넷 구성
문제 해결 방법:
노드 상태 및 이벤트 확인:
bash# 노드 상태 확인 kubectl get nodes kubectl describe node <node-name> # 노드 이벤트 확인 kubectl get events --field-selector involvedObject.name=<node-name>노드 로그 분석:
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 사용 시리소스 사용량 확인:
bash# 노드 리소스 사용량 확인 kubectl top node <node-name> # SSH를 통한 리소스 확인 ssh ec2-user@<node-ip> # 디스크 사용량 확인 df -h # 메모리 사용량 확인 free -m # CPU 사용량 확인 top네트워크 연결 확인:
bash# 노드에서 API 서버 연결 확인 curl -k https://<api-server-endpoint> # DNS 해결 확인 nslookup kubernetes.default.svc.cluster.local # 네트워크 인터페이스 확인 ip addr show # 라우팅 테이블 확인 ip route
일반적인 NotReady 원인 및 해결 방법:
kubelet 문제:
- 증상: kubelet 서비스가 실행되지 않거나 API 서버에 연결할 수 없음
- 해결 방법:bash
# kubelet 서비스 상태 확인 sudo systemctl status kubelet # kubelet 서비스 재시작 sudo systemctl restart kubelet # kubelet 구성 확인 sudo cat /etc/kubernetes/kubelet/kubelet-config.json
네트워크 문제:
- 증상: 노드가 컨트롤 플레인과 통신할 수 없음
- 해결 방법: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
리소스 부족:
- 증상: 노드의 CPU, 메모리 또는 디스크 공간 부족
- 해결 방법:bash
# 디스크 공간 확보 sudo du -sh /var/log/* sudo journalctl --vacuum-time=1d # 불필요한 컨테이너 및 이미지 정리 docker system prune -af # Docker 사용 시
인증서 문제:
- 증상: 인증서 만료 또는 불일치
- 해결 방법:bash
# 인증서 확인 sudo ls -la /etc/kubernetes/pki/ # 인증서 갱신 (자체 관리형 노드의 경우) sudo kubeadm alpha certs renew all # 관리형 노드 그룹의 경우 노드 교체 eksctl replace nodegroup --cluster=my-cluster --name=my-nodegroup
모범 사례:
체계적인 문제 해결 접근 방식:
- 증상 식별 및 문서화
- 관련 로그 및 이벤트 수집
- 가능한 원인 체계적 검증
노드 상태 모니터링 구현:
- CloudWatch 경보 설정
- 노드 상태 대시보드 구성
- 자동화된 알림 시스템
자동 복구 메커니즘 구현:
- 자체 복구 노드 그룹 구성
- 상태 확인 및 자동 교체
- 장애 노드 자동 드레이닝
실제 구현 예시:
노드 문제 해결 스크립트:
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 "=== 문제 해결 완료 ==="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" } }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. 모든 파드 삭제 및 재배포: 파드를 삭제해도 노드 자체의 문제는 해결되지 않으며, 불필요한 서비스 중단을 초래할 수 있습니다.
A. 파드 리소스 제한 초과 / 리소스 제한 증가
B. 이미지 이름 오류 또는 인증 문제 / 이미지 이름 확인 및 이미지 풀 시크릿 구성
C. 노드 디스크 공간 부족 / 디스크 공간 확보
D. 네트워크 정책 제한 / 네트워크 정책 수정
정답 및 설명
정답: B. 이미지 이름 오류 또는 인증 문제 / 이미지 이름 확인 및 이미지 풀 시크릿 구성
설명: Amazon EKS 클러스터에서 파드가 "ImagePullBackOff" 상태일 때 가장 가능성 높은 원인은 이미지 이름 오류 또는 인증 문제입니다. 이 문제를 해결하기 위해서는 이미지 이름을 확인하고 필요한 경우 이미지 풀 시크릿을 구성해야 합니다.
주요 원인 및 해결 방법:
이미지 이름 오류:
- 잘못된 이미지 이름 또는 태그
- 존재하지 않는 이미지
- 레지스트리 URL 오류
해결 방법:
bash# 파드 정의 확인 kubectl describe pod <pod-name> # 이미지 이름 및 태그 수정 kubectl edit deployment <deployment-name> # 또는 kubectl set image deployment/<deployment-name> container-name=image:tag프라이빗 레지스트리 인증 문제:
- 인증 자격 증명 누락
- 만료된 자격 증명
- 권한 부족
해결 방법:
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"}]}}'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네트워크 연결 문제:
- 레지스트리에 대한 네트워크 액세스 제한
- 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
문제 해결 단계:
파드 상태 및 이벤트 확인:
bash# 파드 상태 확인 kubectl get pod <pod-name> # 파드 세부 정보 및 이벤트 확인 kubectl describe pod <pod-name>이미지 이름 및 레지스트리 확인:
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의 경우인증 구성 확인:
bash# 서비스 계정 및 이미지 풀 시크릿 확인 kubectl get serviceaccount default -o yaml # 시크릿 내용 확인 kubectl get secret <secret-name> -o yaml임시 해결책 적용:
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"
모범 사례:
이미지 태그 관리:
- 특정 태그 대신 다이제스트 사용
latest태그 사용 지양- 버전 관리 전략 구현
이미지 풀 시크릿 관리:
- 서비스 계정에 시크릿 연결
- 시크릿 정기적 갱신
- 시크릿 관리 자동화
이미지 레지스트리 접근성 보장:
- 프라이빗 레지스트리의 경우 VPC 엔드포인트 구성
- 네트워크 정책 및 보안 그룹 구성
- 이미지 캐싱 고려
ECR 사용 시 모범 사례:
- IAM 역할 기반 인증 사용
- 자동 토큰 갱신 구현
- 이미지 스캔 및 수명 주기 정책 구성
실제 구현 예시:
ECR 인증을 위한 Kubernetes 작업:
yamlapiVersion: 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: OnFailureTerraform을 사용한 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 }이미지 풀 문제 해결 스크립트:
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. 네트워크 정책 제한 / 네트워크 정책 수정: 네트워크 정책은 파드 간 통신에 영향을 미치지만, 일반적으로 이미지 풀 문제의 주요 원인은 아닙니다.
A. 즉시 새 서비스 생성
B. 서비스 및 파드 레이블, 엔드포인트, 네트워크 정책 확인
C. 모든 파드 재시작
D. 클러스터 API 서버 재시작
정답 및 설명
정답: B. 서비스 및 파드 레이블, 엔드포인트, 네트워크 정책 확인
설명: Amazon EKS 클러스터에서 서비스가 파드에 트래픽을 라우팅하지 않을 때 가장 효과적인 문제 해결 단계는 서비스 및 파드 레이블, 엔드포인트, 네트워크 정책을 확인하는 것입니다. 이 체계적인 접근 방식은 서비스 디스커버리 및 트래픽 라우팅 문제의 근본 원인을 식별하는 데 도움이 됩니다.
주요 확인 사항:
서비스 및 파드 레이블 확인:
- 서비스 셀렉터와 파드 레이블 일치 여부
- 레이블 구문 및 오타
- 네임스페이스 확인
엔드포인트 확인:
- 서비스 엔드포인트 생성 여부
- 엔드포인트 IP 및 파드 IP 일치 여부
- Ready 상태의 파드 수
네트워크 정책 확인:
- 트래픽을 제한하는 네트워크 정책 존재 여부
- 인그레스 및 이그레스 규칙
- 네임스페이스 간 통신 제한
서비스 및 파드 상태 확인:
- 파드 실행 및 준비 상태
- 서비스 유형 및 포트 구성
- 상태 확인 구성
문제 해결 방법:
서비스 및 파드 레이블 확인:
bash# 서비스 셀렉터 확인 kubectl get service <service-name> -o yaml | grep -A 5 selector # 파드 레이블 확인 kubectl get pods --show-labels # 셀렉터와 일치하는 파드 확인 kubectl get pods -l key=value엔드포인트 확인:
bash# 서비스 엔드포인트 확인 kubectl get endpoints <service-name> # 엔드포인트 세부 정보 확인 kubectl describe endpoints <service-name> # 엔드포인트 및 파드 IP 비교 kubectl get pods -o wide네트워크 정책 확인:
bash# 네트워크 정책 확인 kubectl get networkpolicy # 네트워크 정책 세부 정보 확인 kubectl describe networkpolicy <policy-name> # 임시로 네트워크 정책 비활성화 kubectl delete networkpolicy <policy-name>서비스 연결 테스트:
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>
일반적인 서비스 문제 및 해결 방법:
레이블 불일치:
- 증상: 서비스 엔드포인트가 비어 있음
- 해결 방법: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
포트 구성 오류:
- 증상: 서비스는 연결되지만 애플리케이션 응답 없음
- 해결 방법:bash
# 서비스 포트 구성 확인 kubectl describe service <service-name> # 파드 컨테이너 포트 확인 kubectl describe pod <pod-name> # 서비스 포트 수정 kubectl edit service <service-name>
네트워크 정책 제한:
- 증상: 특정 소스에서만 서비스에 액세스할 수 없음
- 해결 방법: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
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
모범 사례:
체계적인 문제 해결 접근 방식:
- 서비스 구성부터 시작하여 파드, 네트워크 정책, DNS 순으로 확인
- 각 단계에서 명확한 증거 수집
- 한 번에 하나의 변수만 변경
서비스 디버깅 도구 활용:
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서비스 모니터링 구현:
- 서비스 엔드포인트 상태 모니터링
- 서비스 연결 상태 확인
- 트래픽 흐름 시각화
서비스 구성 관리:
- 일관된 레이블 지정 전략
- 명시적 포트 이름 지정
- 서비스 문서화
실제 구현 예시:
서비스 문제 해결 스크립트:
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가 올바르게 작동하는지 확인하세요."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 } } } } } }서비스 연결 테스트 작업:
yamlapiVersion: 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 서버 재시작은 극단적인 조치이며, 서비스 라우팅 문제와 직접적인 관련이 없습니다. 또한 클러스터 전체에 영향을 미칠 수 있습니다.
A. 노드 리소스 부족 / 더 큰 노드 추가
B. 스토리지 클래스 문제 또는 볼륨 프로비저닝 권한 부족 / 스토리지 클래스 확인 및 IAM 권한 구성
C. 파드 우선순위 낮음 / 파드 우선순위 증가
D. 클러스터 자동 스케일러 비활성화 / 자동 스케일러 활성화
정답 및 설명
정답: B. 스토리지 클래스 문제 또는 볼륨 프로비저닝 권한 부족 / 스토리지 클래스 확인 및 IAM 권한 구성
설명: Amazon EKS 클러스터에서 PersistentVolumeClaim(PVC)이 "Pending" 상태로 유지될 때 가장 가능성 높은 원인은 스토리지 클래스 문제 또는 볼륨 프로비저닝 권한 부족입니다. 이 문제를 해결하기 위해서는 스토리지 클래스를 확인하고 필요한 IAM 권한을 구성해야 합니다.
주요 원인 및 해결 방법:
스토리지 클래스 문제:
- 존재하지 않는 스토리지 클래스 지정
- 스토리지 클래스 파라미터 오류
- 프로비저너 구성 문제
해결 방법:
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"}}}'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볼륨 바인딩 모드 문제:
- 가용 영역 불일치
- 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 EOFCSI 드라이버 문제:
- 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
문제 해결 단계:
PVC 상태 및 이벤트 확인:
bash# PVC 상태 확인 kubectl get pvc <pvc-name> # PVC 세부 정보 및 이벤트 확인 kubectl describe pvc <pvc-name>스토리지 클래스 확인:
bash# 스토리지 클래스 목록 확인 kubectl get storageclass # PVC에서 사용하는 스토리지 클래스 확인 kubectl get pvc <pvc-name> -o jsonpath='{.spec.storageClassName}' # 스토리지 클래스 세부 정보 확인 kubectl describe storageclass <storage-class-name>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-pluginIAM 권한 확인:
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"
모범 사례:
적절한 스토리지 클래스 구성:
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: trueIRSA(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-serviceaccountsPVC 요청 최적화:
yaml# 최적화된 PVC 예시 apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: accessModes: - ReadWriteOnce storageClassName: ebs-gp3 resources: requests: storage: 10Gi볼륨 바인딩 모드 최적화:
- WaitForFirstConsumer 사용
- 파드와 PV의 가용 영역 일치 보장
- 토폴로지 인식 프로비저닝 활용 실제 구현 예시:
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 상태를 확인하고 이벤트를 검토하세요." fiTerraform을 사용한 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" } }PVC 디버깅 작업:
yamlapiVersion: 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 프로비저닝 문제와는 직접적인 관련이 없습니다.
A. 모든 파드에 더 많은 리소스 할당
B. 수동으로 노드 추가
C. HPA, CA, VPA 구성, 메트릭, 권한 및 이벤트 확인
D. 클러스터 재생성
정답 및 설명
정답: C. HPA, CA, VPA 구성, 메트릭, 권한 및 이벤트 확인
설명: Amazon EKS 클러스터에서 자동 스케일링이 예상대로 작동하지 않을 때 가장 효과적인 문제 해결 접근 방식은 HPA(Horizontal Pod Autoscaler), CA(Cluster Autoscaler), VPA(Vertical Pod Autoscaler) 구성, 메트릭, 권한 및 이벤트를 확인하는 것입니다. 이 체계적인 접근 방식은 자동 스케일링 문제의 근본 원인을 식별하고 해결하는 데 도움이 됩니다.
주요 확인 사항:
HPA(Horizontal Pod Autoscaler) 확인:
- HPA 구성 및 상태
- 메트릭 가용성 및 값
- 스케일링 제한 및 동작
CA(Cluster Autoscaler) 확인:
- CA 배포 및 구성
- IAM 권한 및 역할
- 노드 그룹 태그 및 설정
VPA(Vertical Pod Autoscaler) 확인:
- VPA 구성 및 모드
- 리소스 권장 사항
- 업데이트 정책
메트릭 및 이벤트 확인:
- 메트릭 서버 상태
- CloudWatch 메트릭 가용성
- 자동 스케일링 이벤트 및 로그
문제 해결 방법:
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-serverCA 문제 해결:
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"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메트릭 및 권한 문제 해결:
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>
일반적인 자동 스케일링 문제 및 해결 방법:
HPA 메트릭 문제:
- 증상: HPA가 스케일링 결정을 내리지 않음
- 원인: 메트릭 서버 오류 또는 메트릭 가용성 문제
- 해결 방법:bash
# 메트릭 서버 재설치 kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml # 메트릭 확인 kubectl top pods kubectl top nodes
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"
스케일링 제한 문제:
- 증상: 스케일링이 특정 값을 초과하지 않음
- 원인: 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
VPA 업데이트 모드 문제:
- 증상: VPA가 리소스를 업데이트하지 않음
- 원인: 업데이트 모드가 "Off" 또는 "Initial"로 설정됨
- 해결 방법:bash
# VPA 업데이트 모드 수정 kubectl patch vpa <vpa-name> -p '{"spec":{"updatePolicy":{"updateMode":"Auto"}}}'
모범 사례:
체계적인 문제 해결 접근 방식:
- 각 자동 스케일링 구성 요소 개별 확인
- 로그 및 이벤트 분석
- 단계별 문제 해결
자동 스케일링 모니터링 구현:
- 자동 스케일링 활동 모니터링
- 스케일링 이벤트 알림 설정
- 스케일링 메트릭 대시보드 구성
자동 스케일링 구성 최적화:
- 워크로드 특성에 맞는 스케일링 임계값 설정
- 스케일링 동작 및 쿨다운 기간 조정
- 비용과 성능 균형 유지
다중 자동 스케일링 구성 요소 통합:
- HPA, CA, VPA 조합 사용
- 구성 요소 간 충돌 방지
- 일관된 스케일링 전략 구현
실제 구현 예시:
자동 스케일링 문제 해결 스크립트:
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 역할에 필요한 권한이 있는지 확인하세요."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 } } } } }자동 스케일링 모니터링 대시보드:
yamlapiVersion: 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. 클러스터 재생성: 이는 극단적인 조치이며, 문제의 근본 원인을 파악하지 못하고 불필요한 다운타임과 작업을 초래합니다.
A. 모든 네트워크 정책 삭제 및 기본값 사용
B. 클러스터 CNI 플러그인, 네트워크 정책 구성, 로그 및 이벤트 확인
C. 모든 파드에 hostNetwork: true 설정
D. 클러스터 VPC 재구성
정답 및 설명
정답: B. 클러스터 CNI 플러그인, 네트워크 정책 구성, 로그 및 이벤트 확인
설명: Amazon EKS 클러스터에서 네트워크 정책이 예상대로 작동하지 않을 때 가장 효과적인 문제 해결 접근 방식은 클러스터 CNI 플러그인, 네트워크 정책 구성, 로그 및 이벤트를 체계적으로 확인하는 것입니다. 이 접근 방식은 네트워크 정책 문제의 근본 원인을 식별하고 해결하는 데 도움이 됩니다.
주요 확인 사항:
CNI 플러그인 확인:
- 사용 중인 CNI 플러그인 유형 (AWS VPC CNI, Calico, Cilium 등)
- CNI 플러그인 버전 및 호환성
- 네트워크 정책 지원 여부
네트워크 정책 구성 확인:
- 네트워크 정책 구문 및 선택기
- 정책 우선순위 및 충돌
- 네임스페이스 및 라벨 선택기
로그 및 이벤트 확인:
- CNI 플러그인 로그
- 네트워크 정책 컨트롤러 로그
- 관련 이벤트 및 오류 메시지
네트워크 연결 테스트:
- 파드 간 연결 테스트
- 서비스 연결 테스트
- 외부 연결 테스트
문제 해결 방법:
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네트워크 정책 확인:
bash# 네트워크 정책 목록 확인 kubectl get networkpolicies --all-namespaces # 특정 네트워크 정책 세부 정보 확인 kubectl describe networkpolicy <policy-name> -n <namespace> # 네트워크 정책 YAML 확인 kubectl get networkpolicy <policy-name> -n <namespace> -o yaml파드 네트워크 정보 확인:
bash# 파드 IP 및 노드 정보 확인 kubectl get pods -o wide # 파드 네트워크 인터페이스 확인 kubectl exec -it <pod-name> -- ip addr # 파드 라우팅 테이블 확인 kubectl exec -it <pod-name> -- ip route네트워크 연결 테스트:
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
일반적인 네트워크 정책 문제 및 해결 방법:
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
네트워크 정책 선택기 문제:
- 증상: 정책이 예상 파드에 적용되지 않음
- 원인: 잘못된 라벨 선택기 또는 네임스페이스 선택기
- 해결 방법:bash
# 파드 라벨 확인 kubectl get pods --show-labels # 네트워크 정책 수정 kubectl edit networkpolicy <policy-name> -n <namespace>
정책 충돌 문제:
- 증상: 예상치 못한 연결 차단 또는 허용
- 원인: 여러 정책 간의 충돌 또는 우선순위 문제
- 해결 방법:bash
# 모든 네트워크 정책 검토 kubectl get networkpolicies --all-namespaces -o yaml # 정책 단순화 또는 재구성 kubectl apply -f updated-network-policy.yaml
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
모범 사례:
체계적인 네트워크 정책 설계:
- 기본 거부 정책으로 시작
- 필요한 연결만 명시적으로 허용
- 네임스페이스 및 라벨 기반 정책 사용
네트워크 정책 테스트 및 검증:
- 정책 적용 전 테스트
- 연결 테스트 자동화
- 점진적인 정책 적용
네트워크 모니터링 및 로깅:
- 네트워크 트래픽 모니터링
- 연결 거부 로깅
- 네트워크 성능 모니터링
CNI 플러그인 선택 및 구성:
- 워크로드 요구 사항에 맞는 CNI 선택
- 최신 버전 유지
- 적절한 리소스 할당
실제 구현 예시:
기본 네트워크 정책 구성:
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네트워크 정책 문제 해결 스크립트:
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 플러그인 로그에서 오류를 확인하세요."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" } } } }네트워크 정책 모니터링 구성:
yamlapiVersion: 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 및 정책 구성과 관련이 있습니다.
A. 모든 Helm 차트 삭제 및 재설치
B. 클러스터 재생성
C. Helm 버전, 차트 구성, 종속성, 권한 및 로그 체계적 확인
D. 수동으로 모든 리소스 배포
정답 및 설명
정답: C. Helm 버전, 차트 구성, 종속성, 권한 및 로그 체계적 확인
설명: Amazon EKS 클러스터에서 Helm 차트 배포 문제를 해결하는 가장 효과적인 접근 방식은 Helm 버전, 차트 구성, 종속성, 권한 및 로그를 체계적으로 확인하는 것입니다. 이 접근 방식은 Helm 배포 문제의 근본 원인을 식별하고 해결하는 데 도움이 됩니다.
주요 확인 사항:
Helm 버전 및 호환성 확인:
- Helm 클라이언트 및 Tiller(Helm 2) 버전
- Kubernetes API 버전 호환성
- EKS 버전 호환성
차트 구성 및 값 확인:
- 차트 구문 오류
- 값 파일 구성
- 템플릿 렌더링 문제
종속성 및 리포지토리 확인:
- 차트 종속성 가용성
- 리포지토리 접근성
- 차트 버전 호환성
권한 및 RBAC 확인:
- 서비스 계정 권한
- RBAC 규칙
- 네임스페이스 액세스
로그 및 이벤트 확인:
- Helm 디버그 로그
- Kubernetes 이벤트
- 관련 파드 로그
문제 해결 방법:
Helm 버전 및 구성 확인:
bash# Helm 버전 확인 helm version # Helm 환경 변수 확인 env | grep HELM # Helm 플러그인 확인 helm plugin list # Helm 리포지토리 확인 helm repo list helm repo update차트 검증 및 디버깅:
bash# 차트 구문 검증 helm lint ./my-chart # 템플릿 렌더링 확인 helm template ./my-chart --debug # 차트 종속성 업데이트 helm dependency update ./my-chart # 디버그 모드로 설치 helm install my-release ./my-chart --debug릴리스 상태 및 기록 확인:
bash# 릴리스 목록 확인 helm list -A # 실패한 릴리스 포함 helm list -A --failed # 릴리스 상태 확인 helm status my-release # 릴리스 기록 확인 helm history my-release # 릴리스 세부 정보 확인 helm get all my-release리소스 및 이벤트 확인:
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권한 및 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 배포 문제 및 해결 방법:
차트 구문 오류:
- 증상:
helm install또는helm template명령이 실패함 - 원인: YAML 구문 오류, 잘못된 템플릿 함수 또는 변수
- 해결 방법:bash
# 차트 구문 검증 helm lint ./my-chart # 템플릿 렌더링 확인 helm template ./my-chart --debug # 특정 값으로 템플릿 렌더링 helm template ./my-chart --set key=value --debug
- 증상:
종속성 문제:
- 증상: 차트 설치 중 종속성 오류
- 원인: 누락된 종속성, 버전 불일치 또는 리포지토리 접근 문제
- 해결 방법:bash
# 종속성 업데이트 helm dependency update ./my-chart # 리포지토리 추가 및 업데이트 helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update # 종속성 빌드 helm dependency build ./my-chart
권한 문제:
- 증상: 권한 거부 오류
- 원인: 부족한 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>
리소스 충돌:
- 증상: 이미 존재하는 리소스 오류
- 원인: 이전 설치의 리소스가 남아 있거나 이름 충돌
- 해결 방법: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
값 구성 문제:
- 증상: 배포된 애플리케이션이 예상대로 작동하지 않음
- 원인: 잘못된 구성 값 또는 누락된 필수 값
- 해결 방법: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
모범 사례:
체계적인 문제 해결 접근 방식:
- 단계별 확인 및 검증
- 로그 및 이벤트 분석
- 증상에서 원인으로 추적
Helm 차트 테스트 및 검증:
- 배포 전 차트 검증
- 테스트 환경에서 먼저 테스트
- CI/CD 파이프라인에 검증 단계 포함
버전 관리 및 호환성:
- 호환되는 Helm 및 Kubernetes 버전 사용
- 차트 버전 명시적 지정
- 종속성 버전 고정
문서화 및 값 관리:
- 차트 값 문서화
- 환경별 값 파일 관리
- 민감한 값에 대한 보안 관행 적용
실제 구현 예시:
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"Terraform을 사용한 Helm 차트 배포:
hclprovider "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 } }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: NeverCI/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의 이점을 포기하는 것이며, 복잡한 애플리케이션의 경우 오류가 발생하기 쉽고 관리하기 어렵습니다.
A. 모든 파드 재시작
B. 클러스터 노드 크기 증가
C. 메모리 사용량 프로파일링, 컨테이너 제한 검토, 애플리케이션 코드 분석
D. 더 많은 노드 추가
정답 및 설명
정답: C. 메모리 사용량 프로파일링, 컨테이너 제한 검토, 애플리케이션 코드 분석
설명: Amazon EKS 클러스터에서 메모리 누수 문제를 해결하는 가장 효과적인 접근 방식은 메모리 사용량 프로파일링, 컨테이너 제한 검토, 애플리케이션 코드 분석을 포함한 체계적인 접근법입니다. 이 방법은 메모리 누수의 근본 원인을 식별하고 해결하는 데 도움이 됩니다.
주요 확인 사항:
메모리 사용량 프로파일링:
- 파드 및 노드 수준의 메모리 사용량 모니터링
- 시간에 따른 메모리 사용 패턴 분석
- 메모리 누수 징후 식별
컨테이너 제한 검토:
- 메모리 요청 및 제한 설정 확인
- 컨테이너 OOM(Out of Memory) 이벤트 분석
- 리소스 할당 최적화
애플리케이션 코드 분석:
- 애플리케이션 내부 메모리 사용 패턴 검토
- 메모리 누수 가능성이 있는 코드 식별
- 애플리케이션 프로파일링 도구 사용
시스템 구성 요소 검토:
- kubelet 메모리 관리 설정
- 노드 시스템 리소스 사용량
- 클러스터 구성 요소 상태
문제 해결 방법:
메모리 사용량 모니터링 및 분석:
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컨테이너 제한 및 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"애플리케이션 로그 및 프로파일링:
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>노드 및 시스템 리소스 확인:
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"
일반적인 메모리 누수 문제 및 해결 방법:
애플리케이션 메모리 누수:
- 증상: 시간이 지남에 따라 메모리 사용량이 지속적으로 증가
- 원인: 애플리케이션 코드의 메모리 누수, 캐시 관리 부족
- 해결 방법:
- 애플리케이션 코드 검토 및 수정
- 메모리 프로파일링 도구 사용
- 주기적인 가비지 컬렉션 구성
- 캐시 크기 제한 및 만료 정책 구현
컨테이너 메모리 제한 문제:
- 증상: 빈번한 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"
시스템 구성 요소 메모리 문제:
- 증상: 노드 불안정성, kubelet 또는 다른 시스템 구성 요소의 높은 메모리 사용량
- 원인: kubelet 구성 문제, 시스템 구성 요소 버그
- 해결 방법:
- kubelet 구성 최적화
- 시스템 구성 요소 업데이트
- 노드 리소스 예약 조정
메모리 단편화 문제:
- 증상: 사용 가능한 총 메모리가 충분함에도 OOM 발생
- 원인: 메모리 단편화, 큰 페이지 할당 실패
- 해결 방법:
- 노드 주기적 재부팅 일정 설정
- 메모리 압력이 높은 워크로드 분산
- 노드 메모리 오버커밋 감소
모범 사례:
체계적인 메모리 모니터링:
- 클러스터, 노드, 파드 수준의 메모리 모니터링
- 시간에 따른 메모리 사용 패턴 추적
- 이상 징후에 대한 알림 설정
적절한 리소스 제한 설정:
- 워크로드 특성에 맞는 메모리 요청 및 제한 설정
- 메모리 요청과 제한 간의 적절한 비율 유지
- 정기적인 리소스 사용량 검토 및 조정
애플리케이션 최적화:
- 메모리 효율적인 코드 작성
- 주기적인 메모리 프로파일링 및 최적화
- 적절한 캐시 전략 구현
클러스터 구성 최적화:
- 노드 메모리 예약 최적화
- 적절한 kubelet 메모리 관리 설정
- 워크로드 분산 및 격리
실제 구현 예시:
메모리 누수 문제 해결 스크립트:
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. 필요한 경우 애플리케이션 코드 최적화 또는 수정"메모리 모니터링 및 알림 구성:
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 }}에 메모리 압력이 있습니다."메모리 효율적인 애플리케이션 구성:
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"]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와 유사하게 근본 원인을 해결하지 않고 증상을 숨기는 것에 불과합니다. 메모리 누수 문제는 노드 수와 관계없이 계속될 것입니다.
A. 모든 파드에 고정 IP 할당
B. CoreDNS 구성, 네트워크 정책, DNS 정책, 연결성 체계적 확인
C. 모든 서비스에 ExternalName 사용
D. 클러스터 VPC 재구성
정답 및 설명
정답: B. CoreDNS 구성, 네트워크 정책, DNS 정책, 연결성 체계적 확인
설명: Amazon EKS 클러스터에서 DNS 해결 문제를 해결하는 가장 효과적인 접근 방식은 CoreDNS 구성, 네트워크 정책, DNS 정책, 연결성을 체계적으로 확인하는 것입니다. 이 접근 방식은 DNS 문제의 근본 원인을 식별하고 해결하는 데 도움이 됩니다.
주요 확인 사항:
CoreDNS 구성 및 상태 확인:
- CoreDNS 파드 상태 및 로그
- CoreDNS ConfigMap 구성
- CoreDNS 서비스 및 엔드포인트
네트워크 정책 및 연결성 확인:
- DNS 포트(53/UDP, 53/TCP)에 대한 네트워크 정책
- 파드와 CoreDNS 간의 네트워크 연결
- VPC DNS 설정
DNS 정책 및 구성 확인:
- 파드 DNS 정책 설정
- DNS 구성 옵션
- 호스트 네임스페이스 설정
클러스터 및 VPC 구성 확인:
- EKS 클러스터 DNS 설정
- VPC DNS 속성
- DHCP 옵션 세트
문제 해결 방법:
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-systemDNS 해결 테스트:
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네트워크 정책 및 연결성 확인:
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파드 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.confVPC 및 클러스터 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 문제 및 해결 방법:
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
네트워크 정책 문제:
- 증상: 특정 네임스페이스 또는 파드에서만 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
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"
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>
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 }
모범 사례:
CoreDNS 모니터링 및 확장:
- CoreDNS 성능 및 상태 모니터링
- 클러스터 크기에 따른 CoreDNS 복제본 확장
- 적절한 리소스 할당
DNS 캐싱 및 최적화:
- 적절한 TTL 및 캐시 설정
- 노드 수준 DNS 캐싱 구현
- 애플리케이션 수준 DNS 캐싱 고려
네트워크 정책 설계:
- DNS 트래픽을 명시적으로 허용
- 최소 권한 원칙 적용
- 네트워크 정책 테스트 및 검증
DNS 문제 해결 도구 및 프로세스:
- DNS 문제 해결 도구 및 스크립트 준비
- 체계적인 문제 해결 프로세스 수립
- DNS 관련 이벤트 및 로그 모니터링
실제 구현 예시:
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 속성이 활성화되어 있는지 확인하세요."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노드 수준 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 }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 재구성은 불필요한 다운타임과 복잡성을 초래할 수 있습니다.