Expose Kubernetes Service with External DNS and Route53

Andrea Wang
3 min readApr 26, 2020

--

There are 3 ways you can expose your service on kubernetes for external accessing

1. LoadBalancer

2. NodePort the service address would be your worker node with node port assigned <NodeIP>:<NodePort>

3. Ingress (Note. there is a pre-requisite for AWS ALB Ingress Controller https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html)

We can use External DNS to sync the exposed service and ingress with AWS Route53

To know more about Kubernetes external DNS https://github.com/kubernetes-sigs/external-dns

External DNS

If EKS version > 1.13, you can use an IAM service account directly as below

  1. Create Hosted Zone on AWS Route53
aws route53 create-hosted-zone --name "external-dns-test.my-org.com." --caller-reference "external-dns-test-$(date +%s)"

2. Create IAM policy

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/*"
]
},
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:ListResourceRecordSets"
],
"Resource": [
"*"
]
}
]
}

3. Create IAM role for service account

eksctl create iamserviceaccount \
— name
external-dns \
— namespace kube-system \
— cluster YOUR_CLUSTER_NAME \
— attach-policy-arn YOUR_IAM_POLICY_ARN \
— approve

4. Check service account IAM role

kubectl describe sa external-dns -n kube-system

5. Deploy External DNS

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: external-dns
rules:
- apiGroups: [""]
resources: ["services","endpoints","pods"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["list","watch"]
---
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:
strategy:
type: Recreate
selector:
matchLabels:
app: external-dns
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.opensource.zalan.do/teapot/external-dns:latest
args:
- --source=service
- --source=ingress
- --domain-filter=external-dns-test.my-org.com # 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=my-hostedzone-identifier
securityContext:
fsGroup: 65534 # For ExternalDNS to be able to read Kubernetes and AWS token files
LoadBalancer

LoadBalancer

To use LoadBalancer, change your service yaml file type:LoadBalancer and add annotation for your external DNS hostname external-dns.alpha.kubernetes.io/hostname

apiVersion: v1
kind: Service
metadata:
name: test
annotations:
external-dns.alpha.kubernetes.io/hostname: yourservice.external-dns-test.my-org.com
spec:
type: LoadBalancer
ports:
- port: 80
name: http
targetPort: 80
selector:
app: test

NodePort

To use NodePort, change your service yaml file type: Nodeportand add annotation for your external DNS hostname

apiVersion: v1
kind: Service
metadata:
annotations:
external-dns.alpha.kubernetes.io/hostname: yourservice.external-dns-test.my-org.com
name: test
spec:
externalIPs:
- 1.2.3.4
- 4.5.6.7
externalTrafficPolicy: Cluster
ports:
- nodePort: 30001 #will give you a random 3XXXX port
port: 5000
protocol: TCP
targetPort: 5000
selector:
app: test
type: NodePort

Ingress

To use Ingress, add the following yaml file with annotation for your external DNS hostname. (Note. there is a pre-requisite for AWS ALB Ingress Controller https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html)

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
external-dns.alpha.kubernetes.io/hostname: yourservice.external-dns-test.my-org.com
kubernetes.io/ingress.class: alb
name: test
spec:
rules:
- http:
paths:
- backend:
serviceName: test
servicePort: 80
path: /

My Working Version

--

--