sigs.k8s.io/external-dns@v0.14.1/docs/tutorials/hostport.md (about) 1 # Setting up ExternalDNS for Headless Services 2 3 This tutorial describes how to setup ExternalDNS for usage in conjunction with a Headless service. 4 5 ## Use cases 6 The main use cases that inspired this feature is the necessity for fixed addressable hostnames with services, such as Kafka when trying to access them from outside the cluster. In this scenario, quite often, only the Node IP addresses are actually routable and as in systems like Kafka more direct connections are preferable. 7 8 ## Setup 9 10 We will go through a small example of deploying a simple Kafka with use of a headless service. 11 12 ### External DNS 13 14 A simple deploy could look like this: 15 ### Manifest (for clusters without RBAC enabled) 16 ```yaml 17 apiVersion: apps/v1 18 kind: Deployment 19 metadata: 20 name: external-dns 21 spec: 22 strategy: 23 type: Recreate 24 selector: 25 matchLabels: 26 app: external-dns 27 template: 28 metadata: 29 labels: 30 app: external-dns 31 spec: 32 containers: 33 - name: external-dns 34 image: registry.k8s.io/external-dns/external-dns:v0.14.0 35 args: 36 - --log-level=debug 37 - --source=service 38 - --source=ingress 39 - --namespace=dev 40 - --domain-filter=example.org. 41 - --provider=aws 42 - --registry=txt 43 - --txt-owner-id=dev.example.org 44 ``` 45 46 ### Manifest (for clusters with RBAC enabled) 47 ```yaml 48 apiVersion: v1 49 kind: ServiceAccount 50 metadata: 51 name: external-dns 52 --- 53 apiVersion: rbac.authorization.k8s.io/v1 54 kind: ClusterRole 55 metadata: 56 name: external-dns 57 rules: 58 - apiGroups: [""] 59 resources: ["services","endpoints","pods"] 60 verbs: ["get","watch","list"] 61 - apiGroups: ["extensions","networking.k8s.io"] 62 resources: ["ingresses"] 63 verbs: ["get","watch","list"] 64 - apiGroups: [""] 65 resources: ["nodes"] 66 verbs: ["list"] 67 --- 68 apiVersion: rbac.authorization.k8s.io/v1 69 kind: ClusterRoleBinding 70 metadata: 71 name: external-dns-viewer 72 roleRef: 73 apiGroup: rbac.authorization.k8s.io 74 kind: ClusterRole 75 name: external-dns 76 subjects: 77 - kind: ServiceAccount 78 name: external-dns 79 namespace: default 80 --- 81 apiVersion: apps/v1 82 kind: Deployment 83 metadata: 84 name: external-dns 85 spec: 86 strategy: 87 type: Recreate 88 selector: 89 matchLabels: 90 app: external-dns 91 template: 92 metadata: 93 labels: 94 app: external-dns 95 spec: 96 serviceAccountName: external-dns 97 containers: 98 - name: external-dns 99 image: registry.k8s.io/external-dns/external-dns:v0.14.0 100 args: 101 - --log-level=debug 102 - --source=service 103 - --source=ingress 104 - --namespace=dev 105 - --domain-filter=example.org. 106 - --provider=aws 107 - --registry=txt 108 - --txt-owner-id=dev.example.org 109 ``` 110 111 112 ### Kafka Stateful Set 113 114 First lets deploy a Kafka Stateful set, a simple example(a lot of stuff is missing) with a headless service called `ksvc` 115 116 ```yaml 117 apiVersion: apps/v1 118 kind: StatefulSet 119 metadata: 120 name: kafka 121 spec: 122 serviceName: ksvc 123 replicas: 3 124 template: 125 metadata: 126 labels: 127 component: kafka 128 spec: 129 containers: 130 - name: kafka 131 image: confluent/kafka 132 ports: 133 - containerPort: 9092 134 hostPort: 9092 135 name: external 136 command: 137 - bash 138 - -c 139 - " export DOMAIN=$(hostname -d) && \ 140 export KAFKA_BROKER_ID=$(echo $HOSTNAME|rev|cut -d '-' -f 1|rev) && \ 141 export KAFKA_ZOOKEEPER_CONNECT=$ZK_CSVC_SERVICE_HOST:$ZK_CSVC_SERVICE_PORT && \ 142 export KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://$HOSTNAME.example.org:9092 && \ 143 /etc/confluent/docker/run" 144 volumeMounts: 145 - name: datadir 146 mountPath: /var/lib/kafka 147 volumeClaimTemplates: 148 - metadata: 149 name: datadir 150 annotations: 151 volume.beta.kubernetes.io/storage-class: st1 152 spec: 153 accessModes: [ "ReadWriteOnce" ] 154 resources: 155 requests: 156 storage: 500Gi 157 ``` 158 Very important here, is to set the `hostPort`(only works if the PodSecurityPolicy allows it)! and in case your app requires an actual hostname inside the container, unlike Kafka, which can advertise on another address, you have to set the hostname yourself. 159 160 ### Headless Service 161 162 Now we need to define a headless service to use to expose the Kafka pods. There are generally two approaches to use expose the nodeport of a Headless service: 163 164 1. Add `--fqdn-template={{name}}.example.org` 165 2. Use a full annotation 166 167 If you go with #1, you just need to define the headless service, here is an example of the case #2: 168 169 ```yaml 170 apiVersion: v1 171 kind: Service 172 metadata: 173 name: ksvc 174 annotations: 175 external-dns.alpha.kubernetes.io/hostname: example.org 176 spec: 177 ports: 178 - port: 9092 179 name: external 180 clusterIP: None 181 selector: 182 component: kafka 183 ``` 184 This will create 3 dns records: 185 ``` 186 kafka-0.example.org 187 kafka-1.example.org 188 kafka-2.example.org 189 ``` 190 191 If you set `--fqdn-template={{name}}.example.org` you can omit the annotation. 192 Generally it is a better approach to use `--fqdn-template={{name}}.example.org`, because then 193 you would get the service name inside the generated A records: 194 195 ``` 196 kafka-0.ksvc.example.org 197 kafka-1.ksvc.example.org 198 kafka-2.ksvc.example.org 199 ``` 200 201 #### Using pods' HostIPs as targets 202 203 Add the following annotation to your `Service`: 204 205 ```yaml 206 external-dns.alpha.kubernetes.io/endpoints-type: HostIP 207 ``` 208 209 external-dns will now publish the value of the `.status.hostIP` field of the pods backing your `Service`. 210 211 #### Using node external IPs as targets 212 213 Add the following annotation to your `Service`: 214 215 ```yaml 216 external-dns.alpha.kubernetes.io/endpoints-type: NodeExternalIP 217 ``` 218 219 external-dns will now publish the node external IP (`.status.addresses` entries of with `type: NodeExternalIP`) of the nodes on which the pods backing your `Service` are running. 220 221 #### Using pod annotations to specify target IPs 222 223 Add the following annotation to the **pods** backing your `Service`: 224 225 ```yaml 226 external-dns.alpha.kubernetes.io/target: "1.2.3.4" 227 ``` 228 229 external-dns will publish the IP specified in the annotation of each pod instead of using the podIP advertised by Kubernetes. 230 231 This can be useful e.g. if you are NATing public IPs onto your pod IPs and want to publish these in DNS.