CloudNetaStudy - Kubernets Networtk 3기 실습 스터디 게시글입니다.
7. Ingress
인그레스 소개 : 클러스터 내부의 서비스(ClusterIP, NodePort, Loadbalancer)를 외부로 노출(HTTP/HTTPS) - Web Proxy 역할
- AWS Load Balancer Controller + Ingress (ALB) IP 모드 동작 with AWS VPC CNI
그림처럼 EKS Cluster 는 없고, AWS kOps 클러스터가 배포되어 있음 - 서비스/파드 배포 테스트 with Ingress(ALB) - ALB
# 게임 파드와 Service, Ingress 배포 curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/3/ingress1.yaml cat ingress1.yaml kubectl apply -f ingress1.yaml # 모니터링 watch -d kubectl get pod,ingress,svc,ep -n game-2048 # 생성 확인 kubectl get-all -n game-2048 kubectl get ingress,svc,ep,pod -n game-2048 kubectl get targetgroupbindings -n game-2048 # ALB 생성 확인 aws elbv2 describe-load-balancers --query 'LoadBalancers[?contains(LoadBalancerName, `k8s-game2048`) == `true`]' | jq ALB_ARN=$(aws elbv2 describe-load-balancers --query 'LoadBalancers[?contains(LoadBalancerName, `k8s-game2048`) == `true`].LoadBalancerArn' | jq -r '.[0]') aws elbv2 describe-target-groups --load-balancer-arn $ALB_ARN TARGET_GROUP_ARN=$(aws elbv2 describe-target-groups --load-balancer-arn $ALB_ARN | jq -r '.TargetGroups[0].TargetGroupArn') aws elbv2 describe-target-health --target-group-arn $TARGET_GROUP_ARN | jq # Ingress 확인 kubectl describe ingress -n game-2048 ingress-2048 kubectl get ingress -n game-2048 ingress-2048 -o jsonpath="{.status.loadBalancer.ingress[*].hostname}{'\n'}" # 게임 접속 : ALB 주소로 웹 접속 kubectl get ingress -n game-2048 ingress-2048 -o jsonpath={.status.loadBalancer.ingress[0].hostname} | awk '{ print "Game URL = http://"$1 }' # 파드 IP 확인 kubectl get pod -n game-2048 -owide
ALB 대상 그룹에 등록된 대상 확인 : ALB에서 파드 IP로 직접 전달
- 파드 3개로 증가
# 터미널1 watch kubectl get pod -n game-2048 while true; do aws elbv2 describe-target-health --target-group-arn $TARGET_GROUP_ARN --output text; echo; done # 터미널2 : 파드 3개로 증가 kubectl scale deployment -n game-2048 deployment-2048 --replicas 3
- 파드 1개로 감소
# 터미널2 : 파드 1개로 감소 kubectl scale deployment -n game-2048 deployment-2048 --replicas 1
- 실습 리소스 삭제
kubectl delete ingress ingress-2048 -n game-2048 kubectl delete svc service-2048 -n game-2048 && kubectl delete deploy deployment-2048 -n game-2048 && kubectl delete ns game-2048
- 파드 3개로 증가
- Exposing Kubernetes Applications, Part 1: Service and Ingress Resources - 링크
- Exposing a Service : In-tree Service Controller
- Ingress Implementations : External Load Balancer
- Ingress Implementations : Internal Reverse Proxy
- Kubernetes Gateway API
- Exposing a Service : In-tree Service Controller
8. ExternalDNS
소개 : K8S 서비스/인그레스 생성 시 도메인을 설정하면, AWS(Route 53), Azure(DNS), GCP(Cloud DNS) 에 A 레코드(TXT 레코드)로 자동 생성/삭제
- ExternalDNS CTRL 권한 주는 방법 3가지 : Node IAM Role, Static credentials, IRSA
- AWS Route 53 정보 확인 & 변수 지정 : Public 도메인 소유를 하고 계셔야 합니다!
# 자신의 도메인 변수 지정 : 소유하고 있는 자신의 도메인을 입력하시면 됩니다 MyDomain=<자신의 도메인> MyDomain=gasida.link echo "export MyDomain=gasida.link" >> /etc/profile # 자신의 Route 53 도메인 ID 조회 및 변수 지정 aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." | jq aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Name" aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Id" --output text MyDnzHostedZoneId=`aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Id" --output text` echo $MyDnzHostedZoneId # (옵션) NS 레코드 타입 첫번째 조회 aws route53 list-resource-record-sets --output json --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'NS']" | jq -r '.[0].ResourceRecords[].Value' # (옵션) A 레코드 타입 모두 조회 aws route53 list-resource-record-sets --output json --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'A']" # A 레코드 타입 조회 aws route53 list-resource-record-sets --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'A']" | jq aws route53 list-resource-record-sets --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'A'].Name" | jq aws route53 list-resource-record-sets --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'A'].Name" --output text # A 레코드 값 반복 조회 while true; do aws route53 list-resource-record-sets --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'A']" | jq ; date ; echo ; sleep 1; done
- (참고) 기존에 ExternalDNS를 통해 사용한 A/TXT 레코드가 있는 존의 경우에 policy 정책을 upsert-only 로 설정 후 사용 하자 - Link
- #--policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
- (참고) 기존에 ExternalDNS를 통해 사용한 A/TXT 레코드가 있는 존의 경우에 policy 정책을 upsert-only 로 설정 후 사용 하자 - Link
- ExternalDNS 설치 - 링크
# EKS 배포 시 Node IAM Role 설정되어 있음 # eksctl create cluster ... --external-dns-access ... # MyDomain=<자신의 도메인> MyDomain=gasida.link # 자신의 Route 53 도메인 ID 조회 및 변수 지정 MyDnzHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Id" --output text) # 변수 확인 echo $MyDomain, $MyDnzHostedZoneId # ExternalDNS 배포 curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/aews/externaldns.yaml cat externaldns.yaml MyDomain=$MyDomain MyDnzHostedZoneId=$MyDnzHostedZoneId envsubst < externaldns.yaml | kubectl apply -f - # 확인 및 로그 모니터링 kubectl get pod -l app.kubernetes.io/name=external-dns -n kube-system kubectl logs deploy/external-dns -n kube-system -f
- Service(NLB) + 도메인 연동(ExternalDNS) - 도메인체크
# 터미널1 (모니터링) watch -d 'kubectl get pod,svc' kubectl logs deploy/external-dns -n kube-system -f # 테트리스 디플로이먼트 배포 cat <<EOF | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: tetris labels: app: tetris spec: replicas: 1 selector: matchLabels: app: tetris template: metadata: labels: app: tetris spec: containers: - name: tetris image: bsord/tetris --- apiVersion: v1 kind: Service metadata: name: tetris annotations: service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true" service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http" #service.beta.kubernetes.io/aws-load-balancer-healthcheck-port: "80" spec: selector: app: tetris ports: - port: 80 protocol: TCP targetPort: 80 type: LoadBalancer loadBalancerClass: service.k8s.aws/nlb EOF # 배포 확인 kubectl get deploy,svc,ep tetris # NLB에 ExternanDNS 로 도메인 연결 kubectl annotate service tetris "external-dns.alpha.kubernetes.io/hostname=tetris.$MyDomain" while true; do aws route53 list-resource-record-sets --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'A']" | jq ; date ; echo ; sleep 1; done # Route53에 A레코드 확인 aws route53 list-resource-record-sets --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'A']" | jq aws route53 list-resource-record-sets --hosted-zone-id "${MyDnzHostedZoneId}" --query "ResourceRecordSets[?Type == 'A'].Name" | jq .[] # 확인 dig +short tetris.$MyDomain @8.8.8.8 dig +short tetris.$MyDomain # 도메인 체크 echo -e "My Domain Checker = https://www.whatsmydns.net/#A/tetris.$MyDomain" # 웹 접속 주소 확인 및 접속 echo -e "Tetris Game URL = http://tetris.$MyDomain"
- 웹 접속(http) → 화살표키, 일시중지(space bar)
- 리소스 삭제 : kubectl delete deploy,svc tetris ← 삭제 시 externaldns 에 의해서 A레코드도 같이 삭제됨
- 실습해보기
- Service(NLB + TLS) + 도메인 연동(ExternalDNS)
- Ingress(ALB + HTTPS) + 도메인 연동(ExternalDNS) ← 직접 실습해보시기바랍니다!
- (참고) ACM 퍼블릭 인증서 요청 및 해당 인증서에 대한 Route53 도메인 검증 설정 with AWS CLI
# 각자 자신의 도메인 변수 지정 MyDomain=<각자 자신의 도메인> # ACM 퍼블릭 인증서 요청 CERT_ARN=$(aws acm request-certificate \ --domain-name $MyDomain \ --validation-method 'DNS' \ --key-algorithm 'RSA_2048' \ |jq --raw-output '.CertificateArn') # 생성한 인증서 CNAME 이름 가져오기 CnameName=$(aws acm describe-certificate \ --certificate-arn $CERT_ARN \ --query 'Certificate.DomainValidationOptions[*].ResourceRecord.Name' \ --output text) # 생성한 인증서 CNAME 값 가져오기 CnameValue=$(aws acm describe-certificate \ --certificate-arn $CERT_ARN \ --query 'Certificate.DomainValidationOptions[*].ResourceRecord.Value' \ --output text) # 정상 출력 확인하기 echo $CERT_ARN, $CnameName, $CnameValue # 레코드 파일 cat <<EOT > cname.json { "Comment": "create a acm's CNAME record", "Changes": [ { "Action": "CREATE", "ResourceRecordSet": { "Name": "CnameName", "Type": "CNAME", "TTL": 300, "ResourceRecords": [ { "Value": "CnameValue" } ] } } ] } EOT # CNAME 이름, 값 치환하기 sed -i "s/CnameName/$CnameName/g" cname.json sed -i "s/CnameValue/$CnameValue/g" cname.json cat cname.json # 해당 인증서에 대한 Route53 도메인 검증 설정을 위한 Route53 레코드 생성 aws route53 change-resource-record-sets --hosted-zone-id $MyDnzHostedZoneId --change-batch file://cname.json
9. CoreDNS
Kubernetes에서 DNS 다루는 방법 - 도메인을 찾아서 - 링크
찾
- (심화) Recent changes to the CoreDNS add-on - Link
- EKS CoreDNS 애드온 구성 스키마에 topologySpreadConstraints 설정 추가
# CoreDNS 기본 정보 확인 : volumes - configMap - Corefile - coredns kubectl get deploy coredns -n kube-system -o yaml | kubectl neat kubectl get cm -n kube-system coredns -o yaml | kubectl neat data: Corefile: | .:53 { errors health { lameduck 5s } ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa } prometheus :9153 forward . /etc/resolv.conf cache 30 loop reload loadbalance } # JSON 구성 스키마에 topologySpreadConstraints 매개변수를 추가 aws eks describe-addon-configuration --addon-name coredns --addon-version v1.10.1-eksbuild.2 --query 'configurationSchema' --output text | jq . aws eks describe-addon-configuration --addon-name coredns --addon-version v1.10.1-eksbuild.2 --query 'configurationSchema' --output text | jq . | grep -A3 topologySpreadConstraints # check coredns deployment - it returns an empty output because it is not set by default kubectl get deploy -n kube-system coredns -o yaml | grep topologySpreadConstraints -A8 # aws eks describe-addon --cluster-name $CLUSTER_NAME --addon-name coredns | jq { "addon": { "addonName": "coredns", "clusterName": "myeks", "status": "ACTIVE", "addonVersion": "v1.10.1-eksbuild.7", "health": { "issues": [] }, "addonArn": "arn:aws:eks:ap-northeast-2:911283464785:addon/myeks/coredns/4ec712ea-54eb-05df-5d57-7b52ef1efc6f", "createdAt": "2024-03-10T09:47:58.100000+09:00", "modifiedAt": "2024-03-10T09:48:06.073000+09:00", "tags": {} } } # add-on configuration YAML blob cat << EOT > topologySpreadConstraints.yaml "topologySpreadConstraints": - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: k8s-app: kube-dns EOT # apply change to add-on aws eks update-addon --cluster-name $CLUSTER_NAME --addon-name coredns --configuration-values 'file://topologySpreadConstraints.yaml' # check add-on configuration to see if it is in ACTIVE status aws eks describe-addon --cluster-name $CLUSTER_NAME --addon-name coredns | jq kubectl get deploy coredns -n kube-system -o yaml | kubectl neat ... topologySpreadConstraints: - labelSelector: matchLabels: k8s-app: kube-dns maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway ...
- coredns 애드온에 PDB(Pod Disruption Budget) 추가
- PDB는 두 개의 복제본 Pod가 있는 coredns와 같이 노드 종료 중에 동시에 작동이 중지되는 복제된 애플리케이션의 Pod 수를 제한
# "coredns" add-on v1.9.3-eksbuid.5 and v1.9.3-eksbuid.6 kubectl get pdb -n kube-system coredns NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE coredns 1 N/A 1 13h # "coredns" add-on v1.10.1-eksbuild.2 and v1.10.1-eksbuild.3 kubectl get pdb -n kube-system coredns NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE coredns N/A 1 1 27h
- DNS 확인 실패를 최소화하기 위해 기본적으로 coreDNS 플러그인에 lameduck 옵션을 추가
- lameduck은 상태 엔드포인트가 여전히 200으로 응답하는 동안 DURATION초 동안 종료를 지연합니다.
- 플러그인에 lameduck을 추가하면 CoreDNS 포드 다시 시작(예: 상태 문제, 노드 종료 등으로 인해) 또는 배포 롤아웃 중에 DNS 확인 실패가 최소화됨
# CoreDNS 기본 정보 확인 kubectl get cm -n kube-system coredns -o yaml | kubectl neat data: Corefile: | .:53 { errors health { lameduck 5s } ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa } prometheus :9153 forward . /etc/resolv.conf cache 30 loop reload loadbalance }
- CoreDNS의 readinessProbe 에서 /health 대신 /ready를 사용
# kubectl get deploy coredns -n kube-system -o yaml | kubectl neat ... readinessProbe: failureThreshold: 3 httpGet: path: /ready port: 8181 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 ... # The “ready” plugin is already part of the “coredns” ConfigMap: kubectl get cm -n kube-system coredns -o yaml | kubectl neat data: Corefile: | .:53 { errors health { lameduck 5s } ready kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa } prometheus :9153 forward . /etc/resolv.conf cache 30 loop reload loadbalance }
- EKS 관리형 Add-On Pod에 대한 라벨 설정
# 파드 Labels 확인 kubectl get deploy coredns -n kube-system -o yaml | kubectl neat # pod labels aws eks describe-addon-configuration --addon-name coredns --addon-version v1.10.1-eksbuild.3 \ --query 'configurationSchema' --output text | jq . | grep -A4 '\"podLabels\"' "podLabels": { "properties": {}, "title": "The podLabels Schema", "type": "object" }, # YAML configuration blob cat << EOT > podLabels.yaml podLabels: foo: bar EOT # apply changes : 적용 시 coredns 파드 재시작됨 aws eks update-addon --cluster-name $CLUSTER_NAME --addon-name coredns --configuration-values 'file://podLabels.yaml' watch -d kubectl get pod -n kube-system # wait a while until the add-on is ACTIVE again aws eks describe-addon --cluster-name $CLUSTER_NAME --addon-name coredns # 파드 Labels 확인 kubectl get deploy coredns -n kube-system -o yaml | kubectl neat kubectl get pod -n kube-system -l foo=bar kubectl get po -n kube-system -l=k8s-app=kube-dns -o custom-columns="POD-NAME":.metadata.name,"POD-LABELS":.metadata.labels
- PDB는 두 개의 복제본 Pod가 있는 coredns와 같이 노드 종료 중에 동시에 작동이 중지되는 복제된 애플리케이션의 Pod 수를 제한
- EKS CoreDNS 애드온 구성 스키마에 topologySpreadConstraints 설정 추가
'Kubernetes' 카테고리의 다른 글
[kubernetes] 1. Container service 개요 (0) | 2025.02.23 |
---|---|
[ Kans 3 Study - 9w ] 4. Topology Aware Routing / Network Policies with VPC CNI (0) | 2024.11.02 |
[ Kans 3 Study - 9w ] 2. Service & AWS LoadBalancer Controller / Ingress (1) | 2024.11.02 |
[ Kans 3 Study - 9w ] 1. AWS VPC CNI (6) | 2024.10.29 |
[ Kans 3 Study - 8w ] 3. Cilium Egress Gateway (3) | 2024.10.27 |