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.