Amazon Route53, Google cloud DNS 를 활용한 kubernetes service DNS 자동화 (3/3)
3. Google cloud DNS managed zone과 External DNS로 kubernetes service 연결하기
지난 2개의 글(https://bryan.wiki/305, https://bryan.wiki/306) 에 이어서, 이번에는 Google cloud DNS에 hosted-zone을 생성하여 Local kubernetes 의 external-dns를 통해 deploy 되는 service를 연결해 보자. 시리즈 처음 글에서 Google cloud DNS 측에 생성한 gcloud.kube.click 도메인을 사용한다.
Google cloud DNS project의 managed zone 확인
GCP console 좌측 메뉴에서 Network services > Cloud DNS > Zone details 을 통해서도 확인할 수 있다
Google cloud DNS의 managed zone은 프로젝트에 귀속되는 리소스이다
$ export PROJECT_NAME="dns-hosting-poc"
$ gcloud config set project $PROJECT_NAME
$ export CUSTOM_DOMAIN="gcloud.kube.click"
$ export DNS_ZONE_NAME="subdomain-route53"
$ export IAM_ACCOUNT="gcloud-dns-admin"
$ gcloud dns record-sets list --zone=$DNS_ZONE_NAME
----------
NAME TYPE TTL DATA
gcloud.kube.click. NS 21600 ns-cloud-e1.googledomains.com.,ns-cloud-e2.googledomains.com.,ns-cloud-e3.googledomains.com.,ns-cloud-e4.googledomains.com.
gcloud.kube.click. SOA 21600 ns-cloud-e1.googledomains.com. cloud-dns-hostmaster.google.com. 1 21600 3600 259200 300
- IAM service-account 생성, roles/dns.admin 과 바인딩하고 credential key 다운로드
$ gcloud --project $PROJECT_NAME iam service-accounts create $IAM_ACCOUNT --display-name "Service Account to support external-dns"
$ gcloud projects add-iam-policy-binding $PROJECT_NAME --member serviceAccount:$IAM_ACCOUNT@$PROJECT_NAME.iam.gserviceaccount.com --role roles/dns.admin
$ gcloud --project $PROJECT_NAME iam service-accounts list
----------
DISPLAY NAME EMAIL DISABLED
Service Account to support external-dns gcloud-dns-admin@dns-hosting-poc.iam.gserviceaccount.com False
$ gcloud iam service-accounts keys create key.json --iam-account=$IAM_ACCOUNT@$PROJECT_NAME.iam.gserviceaccount.com
다운로드 된 credential 로부터 Kubernetes secret 등록한다. 이 credential을 사용해서 external-dns가 Google cloud DNS에 접근하게 된다
Bitnami 버전의 external-dns 컨테이너는 Google cloud DNS 접근을 위한 인증 키 값을 credentials.json 에서 읽어 들인다
$ kubectl create secret generic gcloud-dns-key --from-file=credentials.json=./key.json
Kubernetes external-dns deploy
Helm을 통해 external-dns 를 deploy 한다.
txtOwnerId 로는 본 프로젝트의 목적과 연결되는 것이 확인 되도록 적당히 gcloudpoc를 사용한다
$ helm install external-dns bitnami/external-dns \
--set provider=google \
--set google.project=$PROJECT_NAME \
--set google.serviceAccountSecret=gcloud-dns-key \
--set txtOwnerId=gcloudpoc \
--set domainFilters\[0\]=$CUSTOM_DOMAIN \
--set policy=sync
$ kubectl logs external-dns-bfbcb5dc9-7djnz
----------
...
time="2020-09-13T16:04:08Z" level=info msg="Instantiating new Kubernetes client"
time="2020-09-13T16:04:08Z" level=info msg="Using inCluster-config based on serviceaccount-token"
time="2020-09-13T16:04:08Z" level=info msg="Created Kubernetes client https://10.100.0.1:443"
time="2020-09-13T16:04:17Z" level=info msg="All records are already up to date"
time="2020-09-13T16:05:19Z" level=info msg="All records are already up to date"
접속 대상인 Kubernetes service deploy
Nginx 로 이루어진 kubernetes service 를 다음과 같이 정의하자.
Type을 LoadBalancer 로 하고 svc1 서비스에 대해 Kubernetes cluster 에서 사용 가능한 주소 대역이 할당되도록 설정하면 되는데, 여기서 보이는 10.0.0.* 대역의 IP가 지금은 사설 IP 대역이지만 실제 운영시에는 공인 IP 대역으로, 외부 접근 가능한 주소로 보면 된다(annotation의 도메인 부분을 제외하면 Route53 경우와 거의 유사함)
service-example.yaml
apiVersion: v1
kind: Service
metadata:
name: svc1
annotations:
external-dns.alpha.kubernetes.io/hostname: svc1.gcloud.kube.click
labels:
app: nginx
spec:
type: LoadBalancer
ports:
- port: 80
name: http
targetPort: 80
selector:
app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
name: http
$ kubectl apply -f service-example.yaml
----------
service/svc1 created
deployment.apps/nginx created
$ kubectl get service -l app=nginx
----------
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc1 LoadBalancer 10.100.89.153 10.0.0.201 80:32221/TCP 1m
약간의 시간이 흐른 후 External-dns 의 log 를 살펴 보면 다음과 같은 내용과 함께, Route53 에 새로운 A 레코드와 TXT 레코드가 추가되 어 있는 것을 볼 수 있다.
Curl 또는 웹 브라우저로 도메인 접속
$ curl http://10.0.0.201
----------
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Kubernetes service 삭제
External-dns deploy 옵션에서 policy=sync 로 설정했기 때문에, 접속 대상이 되는 service를 삭제하면 Google cloud DNS의 gcloud.kube.click 호스팅 영역의 svc1.gcloud.kube.click 레코드도 자동으로 삭제된다
$ kubectl delete -f service-example.yaml
----------
service/svc1 deleted
deployment.apps/nginx deleted
약간의 시간이 흐른 후 External-dns 의 log 를 살펴 보면 다음과 같은 내용과 함께, Cloud DNS의 svc1에 대한 A 레코드와 TXT 레코드가 삭제되어 있는 것을 볼 수 있다.
$ kubectl logs external-dns-bfbcb5dc9-7djnz
----------
...
time="2020-09-20T16:31:11Z" level=info msg="All records are already up to date"
time="2020-09-20T16:32:11Z" level=info msg="All records are already up to date"
time="2020-09-20T16:33:13Z" level=info msg="Change zone: subdomain-route53 batch #0"
time="2020-09-20T16:33:13Z" level=info msg="Del records: svc1.gcloud.kube.click. A [10.0.0.201] 10"
time="2020-09-20T16:33:13Z" level=info msg="Del records: svc1.gcloud.kube.click. TXT [\"heritage=external-dns,external-dns/owner=gcloudpoc,external-dns/resource=service/default/svc1\"] 300"
...
$ gcloud dns record-sets list --zone=$DNS_ZONE_NAME
----------
NAME TYPE TTL DATA
gcloud.kube.click. NS 21600 ns-cloud-e1.googledomains.com.,ns-cloud-e2.googledomains.com.,ns-cloud-e3.googledomains.com.,ns-cloud-e4.googledomains.com.
gcloud.kube.click. SOA 21600 ns-cloud-e1.googledomains.com. cloud-dns-hostmaster.google.com. 1 21600 3600 259200 300
Barracuda