External DNS란 Ingress 리소스를 생성함과 동시에 Route 53 ↔ ALB ↔ Node ↔ Pod로 트래픽이 단번에 라우팅될 수 있도록 한다.
=> ALB가 생성될 때 자동으로 Route53 Record에 등록되기 위함이다.
관련 자료
https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md
+ Security Context 관련 트러블슈팅 자료
https://git.blindage.org/Kubernetes/external-dns/commit/c97781a49dd3a1b7c8a1ccdf6d594217f3a28a17
=> IRSA를 통해 특정 Pod에 대해서만 External DNS에 대한 권한을 부여하고 싶었는데 securityContext 관련 권한 문제가 발생하였음. 그 이후, securityContext 수정한 뒤 아래처럼 정상적으로 배포된 것을 확인할 수 있었다.
⇒ /var/run/secrets/eks.amazonaws.com/serviceaccount/token: permission denied"
Controller 파드가 AWS 리소스에 대한 최소한의 권한을 지닌 Role을 생성한 뒤,
External DNS 컨트롤러를 생성하기 위한 매니페스트 파일 배포 후 Ingress를 생성하면 된다.
혹시 본 글을 보고 따라하고자 하는 사람이 있다면, ALB Ingress Controller도 추가적으로 생성해줘야 한다.
1. IAM Role
IAM Role For Service Account (IRSA)를 활용하여 해당 컨트롤러 역할을 하는 파드에 최소한의 권한만 부여해주었다.
IAM Role 및 Policy는 Terraform 코드로 생성하였다.
2. External DNS YAML 파일
Change here 부분을 본인의 환경에 맞게 수정해주면 된다.
SecurityContext는 위에 설명했듯이 ExternalDNS가 Kubernetes 및 AWS 토큰 파일을 읽을 수 있도록 하기 위해 설정
# Version : 2.0.0
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
namespace: kube-system
annotations:
eks.amazonaws.com/role-arn: {EXTERNAL DNS Role ARN} # Change here
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: external-dns
rules:
- apiGroups: [""]
resources: ["services"]
verbs: ["get","watch","list"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-dns
namespace: kube-system
spec:
selector:
matchLabels:
app: external-dns
strategy:
type: Recreate
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: bitnami/external-dns:0.7.1
args:
- --source=service
- --source=ingress
- --domain-filter=pingping2.shop # Change Here // # Change here # 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=Z0875279DO6K545JISB2 # Change here # Hosted zone ID
securityContext:
fsGroup: 65534
Deployment 리소스 배포
Demo 애플리케이션 배포 및 External DNS 적용 확인
그럼, Ingress에서 External DNS를 사용하겠다고 정의하면 정상적으로 Route53 Record에 등록되는지 확인이 필요하다.
Namespace 생성
➜ external-dns git:(main) ✗ kubectl create ns demo-springboot
namespace/demo-springboot created
Deployment, Service YAML
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: demo-springboot
labels:
app: demo-springboot
name: demo-springboot
spec:
replicas: 2
selector:
matchLabels:
app: demo-springboot
strategy: {}
template:
metadata:
labels:
app: demo-springboot
spec:
containers:
- image: {AccountID}.dkr.ecr.ap-northeast-2.amazonaws.com/demo-maven-springboot:0.1
name: demo-maven-springboot
resources:
limits:
memory: 512Mi
cpu: "0.5"
requests:
memory: 256Mi
cpu: "0.2"
---
apiVersion: v1
kind: Service
metadata:
namespace: demo-springboot
labels:
app: demo-springboot
name: demo-springboot-svc
spec:
ports:
- name: demo-springboot-svc-8080
port: 8080
protocol: TCP
nodePort: 30010
targetPort: 8080
selector:
app: demo-springboot
type: NodePort
배포
➜ EKSProj git:(main) ✗ kubectl apply -f kubernetes/demo-springboot/app.yaml
deployment.apps/demo-springboot created
service/demo-springboot-svc created
➜ EKSProj git:(main) ✗ kubectl get all -n demo-springboot
NAME READY STATUS RESTARTS AGE
pod/demo-springboot-867856fc47-l6bgf 1/1 Running 0 11s
pod/demo-springboot-867856fc47-pf86f 1/1 Running 0 11s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/demo-springboot-svc NodePort 172.20.246.38 <none> 8080:30010/TCP 11s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/demo-springboot 2/2 2 2 11s
NAME DESIRED CURRENT READY AGE
replicaset.apps/demo-springboot-867856fc47 2 2 2 11s
확인
SpringBoot가 배포된 Pod에 접속한 뒤 curl을 다운로드받고 Service에 curl을 날려본다.
위에서 볼수 있듯이 Service의 Cluster IP가 172.20.246.38이며, 8080 Port가 Poc Container와 연결되어 있다.
고로, 서비스에 curl을 날리면 백엔드 파드와 연결될 것으로 예상할 수 있다.
root@demo-springboot-867856fc47-pf86f:/data# curl 172.20.246.38:8080
<!DOCTYPE html>
<html>
<head>
<title>Sample Maven Web</title>
<link type="text/css" rel="stylesheet" href="css/sample.css" />
</head>
<body class="permission_denied">
<div id="tsparticles"></div>
<div class="denied__wrapper">
<h1>Sample Maven Web</h1>
<h3>Demo project</h3>
<h3>Current Version : v0.1</h3>
<h3>Pipeline Test Application</h3>
<h3>this application deployed by Nyyang</h3>
<div class="hynix">
<img id="astronaut" src="images/astronaut.svg" />
<img id="planet" src="images/planet.svg" />
</div>
</div>
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/tsparticles@1.18.11/dist/tsparticles.min.js"></script>
<script type="text/javascript" src="js/page.js"></script>
</body>
</html>root@demo-springboot-867856fc47-pf86f:/data#
Ingress Controller 및 External DNS를 사용하여 자동으로 Domain Name 및 ALB에 등록되도록 설정
Ingress 생성
자동으로 ACM 인증서가 ALB에 등록 및 ALB 생성, Route 53 레코드에 등록될 것이다.
ACM의 ARN은 본인의 ACM을 등록해주면 되고, hostname은 Route 53의 호스트 네임을 기입해주면 된다.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
namespace: demo-springboot
name: demo-springboot-ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/certificate-arn: {ACM ARN}
alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-2016-08
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80,"HTTPS": 443}]'
alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
external-dns.alpha.kubernetes.io/hostname: pingping2.shop
spec:
rules:
- http:
paths:
- path: /*
backend:
serviceName: demo-springboot-svc
servicePort: 8080
어떤 일들이 발생하는지 확인하기 위해 -f 옵션으로 파드의 로그를 확인해준다.
External DNS Controller 파드 로그
time="2021-11-23T08:33:01Z" level=info msg="All records are already up to date"
time="2021-11-23T08:34:01Z" level=info msg="All records are already up to date"
time="2021-11-23T08:35:01Z" level=info msg="Desired change: CREATE pingping2.shop A [Id: /hostedzone/Z0875279DO6K545JISB2]"
time="2021-11-23T08:35:01Z" level=info msg="Desired change: CREATE pingping2.shop TXT [Id: /hostedzone/Z0875279DO6K545JISB2]"
time="2021-11-23T08:35:02Z" level=info msg="2 record(s) in zone pingping2.shop. [Id: /hostedzone/Z0875279DO6K545JISB2] were successfully updated"
Route 53 Record에 자동으로 등록
ALB 자동 생성 및 타겟 그룹 정상 등록
정상적으로 트래픽이 연결된 모습
수정 !
External DNS 및 ALB Ingress Controller 부분은 잘 세팅이 되었지만 Ingress YAML 파일에서 수정할 부분이 있다.
- path: /*
backend:
serviceName: ssl-redirect
servicePort: use-annotation
- path: /*
backend:
serviceName: demo-springboot-svc
servicePort: 80
=> 이렇게 해야 Redirect가 가능하다. 관련 문서는 공식 Docs를 통해 확인할 수 있다.
https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/guide/tasks/ssl_redirect/
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: demo-springboot
labels:
app: demo-springboot
name: demo-springboot
spec:
replicas: 2
selector:
matchLabels:
app: demo-springboot
strategy: {}
template:
metadata:
labels:
app: demo-springboot
spec:
containers:
- image: {ACCOUNT_ID}.dkr.ecr.ap-northeast-2.amazonaws.com/demo-maven-springboot:{VERSION}
name: demo-maven-springboot
resources:
limits:
memory: 512Mi
cpu: "0.5"
requests:
memory: 256Mi
cpu: "0.2"
---
apiVersion: v1
kind: Service
metadata:
namespace: demo-springboot
labels:
app: demo-springboot
name: demo-springboot-svc
spec:
ports:
- name: demo-springboot-svc-8080
port: 80
protocol: TCP
nodePort: 30010
targetPort: 8080
selector:
app: demo-springboot
type: NodePort
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
namespace: demo-springboot
name: demo-springboot-ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-2:{ACCOUNT_ID}:certificate/28ff71d5-f0d6-4958-abcb-ece79efb6323
alb.ingress.kubernetes.io/tags: createdBy=aws-load-balancer-controller
alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-2016-08
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
external-dns.alpha.kubernetes.io/hostname: pingping2.shop
spec:
rules:
- http:
paths:
- path: /*
backend:
serviceName: ssl-redirect
servicePort: use-annotation
- path: /*
backend:
serviceName: demo-springboot-svc
servicePort: 80
후에 배포해보면 정상적으로 리디렉션이 되는 것을 확인 가능
'AWS' 카테고리의 다른 글
[EKS] Jenkins로 CI 수행하기 - Maven Build 및 Image ECR Push (0) | 2021.11.26 |
---|---|
[EKS] Amazon EBS CSI Driver 설치 및 사용하기 (0) | 2021.11.24 |
[EKS] Terraform으로 EKS Cluster 생성 (2) | 2021.11.20 |
[Shell Script] CLB 인스턴스 상태 및 등록, 해제하는 쉘 스크립트 (0) | 2021.11.17 |
[Lambda] AWS에서 발생하는 Event를 Slack으로 알림 받기 (2) | 2021.11.06 |