본문 바로가기
AWS/EKS

[AEWS2] 2-4. Ingress & External DNS

by okms1017 2024. 3. 17.
728x90

✍ Posted by Immersive Builder  Seong

 

1. Ingress

Ingress 란? 

클러스터 내부의 서비스(ClusterIP, NodePort, LoadBalancer)를 외부로 노출(HTTP/HTTPS)하는 역할을 하는 컴포넌트입니다. AWS 환경에서 Ingress를 구현한 구현체가 ALB가 되며, LoadBalancer Controller에 의해 파드의 IP로 바로 통신이 가능해집니다. 

 

Ingress (CloudNet@)

 

서비스/파드 배포 테스트 (ALB) 

ALB 타입의 서비스와 파드 2개를 배포합니다. 

 


  
$ cat ingress1.yaml
apiVersion: v1
kind: Namespace
metadata:
name: game-2048
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: game-2048
name: deployment-2048
spec:
selector:
matchLabels:
app.kubernetes.io/name: app-2048
replicas: 2
template:
metadata:
labels:
app.kubernetes.io/name: app-2048
spec:
containers:
- image: public.ecr.aws/l6m2t8p7/docker-2048:latest
imagePullPolicy: Always
name: app-2048
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: game-2048
name: service-2048
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
type: NodePort
selector:
app.kubernetes.io/name: app-2048
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: game-2048
name: ingress-2048
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service-2048
port:
number: 80
$ kubectl apply -f ingress1.yaml

 


  
# 생성 확인
$ kubectl get-all -n game-2048
NAME NAMESPACE AGE
configmap/kube-root-ca.crt game-2048 10m
endpoints/service-2048 game-2048 10m
pod/deployment-2048-75db5866dd-8hlck game-2048 10m
pod/deployment-2048-75db5866dd-ljbvw game-2048 10m
serviceaccount/default game-2048 10m
service/service-2048 game-2048 10m
deployment.apps/deployment-2048 game-2048 10m
replicaset.apps/deployment-2048-75db5866dd game-2048 10m
endpointslice.discovery.k8s.io/service-2048-kfdjb game-2048 10m
targetgroupbinding.elbv2.k8s.aws/k8s-game2048-service2-527512209d game-2048 10m
ingress.networking.k8s.io/ingress-2048 game-2048 10m
$ kubectl get targetgroupbindings -n game-2048
NAME SERVICE-NAME SERVICE-PORT TARGET-TYPE AGE
k8s-game2048-service2-527512209d service-2048 80 ip 15m
# ALB 생성 확인
$ aws elbv2 describe-load-balancers --query 'LoadBalancers[?contains(LoadBalancerName, `k8s-game2048`) == `true`]' | jq
```
"LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-2:732659419746:loadbalancer/app/k8s-game2048-ingress2-70d50ce3fd/6a8b580c7172e547",
"DNSName": "k8s-game2048-ingress2-70d50ce3fd-2012380533.ap-northeast-2.elb.amazonaws.com",
"Scheme": "internet-facing",
"State": {
"Code": "active"
},
"Type": "application",
```
$ 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
```
"Target": {
"Id": "192.168.1.217",
"Port": 80,
"AvailabilityZone": "ap-northeast-2a"
},
"HealthCheckPort": "80",
"TargetHealth": {
"State": "healthy"
},
```
"Target": {
"Id": "192.168.2.250",
"Port": 80,
"AvailabilityZone": "ap-northeast-2b"
},
"HealthCheckPort": "80",
"TargetHealth": {
"State": "healthy"
}
```
# Ingress 확인
$ kubectl describe ingress -n game-2048 ingress-2048
Name: ingress-2048
Labels: <none>
Namespace: game-2048
Address: k8s-game2048-ingress2-70d50ce3fd-2012380533.ap-northeast-2.elb.amazonaws.com
Ingress Class: alb
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
*
/ service-2048:80 (192.168.1.217:80,192.168.2.250:80)
Annotations: alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfullyReconciled 30m ingress Successfully reconciled
# ALB URL
$ kubectl get ingress -n game-2048 ingress-2048 -o jsonpath={.status.loadBalancer.ingress[0].hostname} | awk '{ print "Game URL = http://"$1 }'
Game URL = http://k8s-game2048-ingress2-70d50ce3fd-2012380533.ap-northeast-2.elb.amazonaws.com
# 파드 IP 확인
kubectl get pod -n game-2048 -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deployment-2048-75db5866dd-8hlck 1/1 Running 0 32m 192.168.1.217 ip-192-168-1-213.ap-northeast-2.compute.internal <none> <none>
deployment-2048-75db5866dd-ljbvw 1/1 Running 0 32m 192.168.2.250 ip-192-168-2-49.ap-northeast-2.compute.internal <none> <none>

 

AWS 콘솔에서 80 포트로 리스닝 중인 어플리케이션 로드밸런서와 도메인 주소를 확인할 수 있습니다. 

Target Group의 파드 또한 80 포트로 리스닝 중이며 정상 상태(healthy)로 올라와 있습니다. 

네트워크 로드밸런서 IP모드의 서비스와 마찬가지로 파드의 IP로 직접 통신합니다. 

 

AWS Application LoadBalancer Info
AWS Application LoadBalancer - Listener & Rule
Target Group
AWS Application LoadBalancer - Resource Map

잠시 머리 식힐겸.

도메인 주소로 접속하여 게임 한판하겠습니다.

 

이번에는 파드 수를 조정하여 동작을 확인해봅니다. 

 


  
# 파드 수 2 -> 3
$ kubectl scale deployment -n game-2048 deployment-2048 --replicas 3
deployment.apps/deployment-2048 scaled
## 모니터링(Health-check)
$ while true; do aws elbv2 describe-target-health --target-group-arn $TARGET_GROUP_ARN --output text; echo; done
TARGETHEALTHDESCRIPTIONS 80
TARGET ap-northeast-2c 192.168.3.83 80
TARGETHEALTH healthy
TARGETHEALTHDESCRIPTIONS 80
TARGET ap-northeast-2a 192.168.1.217 80
TARGETHEALTH healthy
TARGETHEALTHDESCRIPTIONS 80
TARGET ap-northeast-2b 192.168.2.250 80
TARGETHEALTH healthy
# 파드 수 3 -> 1
$ kubectl scale deployment -n game-2048 deployment-2048 --replicas 1
deployment.apps/deployment-2048 scaled
## 모니터링(Health-check)
$ while true; do aws elbv2 describe-target-health --target-group-arn $TARGET_GROUP_ARN --output text; echo; done
```
TARGETHEALTHDESCRIPTIONS 80
TARGET ap-northeast-2c 192.168.3.83 80
TARGETHEALTH Target deregistration is in progress Target.DeregistrationInProgress draining
TARGETHEALTHDESCRIPTIONS 80
TARGET ap-northeast-2a 192.168.1.217 80
TARGETHEALTH Target deregistration is in progress Target.DeregistrationInProgress draining
TARGETHEALTHDESCRIPTIONS 80
TARGET ap-northeast-2b 192.168.2.250 80
TARGETHEALTH healthy
```
TARGETHEALTHDESCRIPTIONS 80
TARGET ap-northeast-2b 192.168.2.250 80
TARGETHEALTH healthy
```

 


2. External DNS

External DNS 란?

서비스 또는 인그레스의 도메인 주소를 실제 접속하는 주소로 매핑하는 역할을 합니다. 

클라우드 환경에서 AWS Route 53, Azure DNS, GCP Cloud DNS 등으로 구현할 수 있습니다. 

 

External DNS (CloudNet@)

 

구현 방법으로 Node IAM Role, Static credentials, IRSA 3가지가 있습니다. 

여기서는 Node IAM Role을 적용하였습니다. 

 

Node IAM Role - External DNS

 

AWS Route 53 세팅 

소유한 퍼블릭 도메인 주소를 활용합니다. 

 

퍼블릭 도메인 주소(okms1017.name)


  
# 도메인 환경변수 설정
$ MyDomain=okms1017.name
$ echo $MyDomain
okms1017.name
$ MyDnzHostedZoneId=`aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." \
--query "HostedZones[0].Id" --output text`
$ echo $MyDnzHostedZoneId
/hostedzone/Z09617933Q2PHRDLYPQJO
$ while true; do aws route53 list-resource-record-sets --hosted-zone-id "${MyDnzHostedZoneId}" \
--query "ResourceRecordSets[?Type == 'A']" | jq ; date ; echo ; sleep 1; done
[]
Sun Mar 17 03:24:31 KST 2024

 

External DNS 배포 

퍼블릭 도메인 주소(okms1017.name)를 변수 값으로 넣어 External DNS를 배포합니다. 

 


  
# External DNS 배포
$ cat externaldns.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
namespace: kube-system
labels:
app.kubernetes.io/name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: external-dns
labels:
app.kubernetes.io/name: external-dns
rules:
- apiGroups: [""]
resources: ["services","endpoints","pods","nodes"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
labels:
app.kubernetes.io/name: external-dns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: kube-system # change to desired namespace: externaldns, kube-addons
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-dns
namespace: kube-system
labels:
app.kubernetes.io/name: external-dns
spec:
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: external-dns
template:
metadata:
labels:
app.kubernetes.io/name: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.k8s.io/external-dns/external-dns:v0.14.0
args:
- --source=service
- --source=ingress
- --domain-filter=${MyDomain} # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones
- --provider=aws
#- --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization
- --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both)
- --registry=txt
- --txt-owner-id=${MyDnzHostedZoneId}
env:
- name: AWS_DEFAULT_REGION
value: ap-northeast-2 # change to region where EKS is installed(admin@myeks:d
$ MyDomain=$MyDomain MyDnzHostedZoneId=$MyDnzHostedZoneId envsubst < externaldns.yaml | kubectl apply -f -
serviceaccount/external-dns created
clusterrole.rbac.authorization.k8s.io/external-dns created
clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer created
deployment.apps/external-dns created

 

* --policy=upsert-only 옵션 ?

- External DNS을 삭제하더라도 AWS Route 53의 A, TXT 레코드를 그대로 남기는 기능입니다. (권장) 

 

NLB & External DNS 도메인 연동 

이제 테스트 파드를 하나 배포하고 NLB와 External DNS 간 도메인을 연동합니다.

 


  
# 테트리스 디플로이먼트 배포
$ cat <<EOF | kubectl create -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
# External DNS로 NLB 도메인 연결
$ kubectl annotate service tetris "external-dns.alpha.kubernetes.io/hostname=tetris.$MyDomain"
# External DNS 로그 모니터링
$ kubectl logs deploy/external-dns -n kube-system -f
time="2024-03-16T18:50:03Z" level=info msg="Applying provider record filter for domains: [okms1017.name. .okms1017.name.]"
time="2024-03-16T18:50:03Z" level=info msg="Desired change: CREATE cname-tetris.okms1017.name TXT [Id: /hostedzone/Z09617933Q2PHRDLYPQJO]"
time="2024-03-16T18:50:03Z" level=info msg="Desired change: CREATE tetris.okms1017.name A [Id: /hostedzone/Z09617933Q2PHRDLYPQJO]"
time="2024-03-16T18:50:03Z" level=info msg="Desired change: CREATE tetris.okms1017.name TXT [Id: /hostedzone/Z09617933Q2PHRDLYPQJO]"
time="2024-03-16T18:50:03Z" level=info msg="3 record(s) in zone okms1017.name. [Id: /hostedzone/Z09617933Q2PHRDLYPQJO] were successfully updated"
# 모니터링
$ watch -d 'kubectl get deploy,svc,ep tetris'
Every 2.0s: kubectl get deploy,svc,ep tetris Sun Mar 17 03:53:48 2024
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/tetris 1/1 1 1 5m43s
NAME TYPE CLUSTER-IP EXTERNAL-IP
PORT(S) AGE
service/tetris LoadBalancer 10.100.38.223 k8s-default-tetris-5592b1097a-7d37de4b32a494
9e.elb.ap-northeast-2.amazonaws.com 80:31015/TCP 5m43s
NAME ENDPOINTS AGE
endpoints/tetris 192.168.2.29:80 5m43s
# 도메인 조회
$ dig +short tetris.okms1017.name
13.209.108.173
3.39.109.92
43.203.71.198
# URL
$ echo -e "Tetris Game URL = http://tetris.$MyDomain"
Tetris Game URL = http://tetris.okms1017.name

 

Route 53 호스팅 영역에 3개의 레코드(A, TXT)가 추가 생성되고,

NLB의 도메인 주소와 매핑되어 있음을 확인할 수 있습니다. 

 

Amazon Route 53 - NLB 도메인 연동
Network LoadBalancer 도메인 주소

 

하기 사이트에서 도메인 주소가 유효한지 확인할 수 있습니다. 

https://www.whatsmydns.net/

 

DNS Propagation Checker - Global DNS Checker Tool

Instant DNS Propagation Check. Global DNS Propagation Checker - Check DNS records around the world.

www.whatsmydns.net

마지막으로!

 

실제 도메인 주소(tetris.okms1017.name)로 접속하여 

테트리스 게임을 한 판 해주고 리소스를 삭제합니다. 

 

 

 


[출처] 

1) CloudNet@, AEWS 실습 스터디 

2) https://edgehog.blog/a-self-hosted-external-dns-resolver-for-kubernetes-111a27d6fc2c

 

A Self-hosted external DNS resolver for Kubernetes.

Understanding solutions for external DNS resolution in Kubernetes and introducing our k8s_gateway plugin.

edgehog.blog

3) https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md#deploy-externaldns

728x90