From da3fe0463cbb72caa6b6346fb116c1b322b0d59b Mon Sep 17 00:00:00 2001 From: John Gardiner Myers Date: Sun, 23 Jul 2023 13:15:11 -0700 Subject: [PATCH] Document the Service source --- docs/sources/ingress.md | 2 +- docs/sources/service.md | 108 ++++++++++++++++++++++++++++++++++++++++ docs/sources/sources.md | 2 +- mkdocs.yml | 1 + source/service.go | 2 +- 5 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 docs/sources/service.md diff --git a/docs/sources/ingress.md b/docs/sources/ingress.md index f622a10fc..619b95361 100644 --- a/docs/sources/ingress.md +++ b/docs/sources/ingress.md @@ -33,7 +33,7 @@ or the Ingress had an or the Ingress had an `external-dns.alpha.kubernetes.io/ingress-hostname-source: defined-hosts-only` annotation. -* If no endpoints were produced for an Ingress by the previous steps +* If no DNS entries were produced for an Ingress by the previous steps or the `--combine-fqdn-annotation` flag was specified, then adds hostnames generated from any`--fqdn-template` flag. diff --git a/docs/sources/service.md b/docs/sources/service.md new file mode 100644 index 000000000..5aa313bc3 --- /dev/null +++ b/docs/sources/service.md @@ -0,0 +1,108 @@ +# Ingress source + +The service source creates DNS entries based on `Service` resources. + +## Filtering the Services considered + +The `--service-type-filter` flag filters Service resources by their `spec.type`. +The flag may be specified multiple times to allow multiple service types. + +This source supports the `--label-filter` flag, which filters Service resources +by a set of labels. + +## Domain names + +The domain names of the DNS entries created from a Service are sourced from the following places: + +* Adds the domain names from any `external-dns.alpha.kubernetes.io/hostname` and/or +`external-dns.alpha.kubernetes.io/internal-hostname` annotation. +This behavior is suppressed if the `--ignore-hostname-annotation` flag was specified. + +* If no DNS entries were produced for a Service by the previous steps +and the `--compatibility` flag was specified, then adds DNS entries per the +selected compatibility mode. + +* If no DNS entries were produced for a Service by the previous steps +or the `--combine-fqdn-annotation` flag was specified, then adds domain names +generated from any`--fqdn-template` flag. + +### Domain names for headless service pods + +If a headless service (without an `external-dns.alpha.kubernetes.io/target` annotation) creates DNS entries with targets from +a Pod that has a non-empty `spec.hostname` field, additional DNS entries are created for that Pod, containing the targets from that Pod. +For each domain name created for the Service, the additional DNS entry for the Pod has that domain name prefixed with +the value of the Pod's `spec.hostname` field and a `.`. + +## Targets + +If the Service has an `external-dns.alpha.kubernetes.io/target` annotation, uses +the values from that. Otherwise, the targets of the DNS entries created from a service are sourced depending +on the Service's `spec.type`: + +### LoadBalancer + +* If the hostname came from an `external-dns.alpha.kubernetes.io/internal-hostname` annotation, uses +the Service's `spec.clusterIP` field. If that field has the value `None`, does not generate +any targets for the hostname. + +* Otherwise, if the Service has one or more `spec.externalIPs`, uses the values in that field. + +* Otherwise, iterates over each `status.loadBalancer.ingress`, adding any non-empty `ip` and/or `hostname`. +If the `--resolve-service-load-balancer-hostname` flag was specified, any non-empty `hostname` +is instead queried through DNS and any resulting IP addresses are added instead. +A DNS query failure results in zero targets being added for that load balancer's ingress hostname. + +### ClusterIP (headless) + +Iterates over all of the Service's Endpoints's `subsets.addresses`. +If the Service's `spec.publishNotReadyAddresses` is `true` or the `--always-publish-not-ready-addresses` flag is specified, +also iterates over the Endpoints's `subsets.notReadyAddresses`. + +* If an address does not target a `Pod` that matches the Service's `spec.selector`, it is ignored. + +* If the target pod has an `external-dns.alpha.kubernetes.io/target` annotation, uses +the values from that. + +* Otherwise, if the Service has an `external-dns.alpha.kubernetes.io/endpoints-type: NodeExternalIP` +annotation, uses the addresses from the Pod's Node's `status.addresses` that are either of type +`ExternalIP` or IPv6 addresses of type `InternalIP`. + +* Otherwise, if the Service has an `external-dns.alpha.kubernetes.io/endpoints-type: HostIP` annotation +or the `--publish-host-ip` flag was specified, uses the Pod's `status.hostIP` field. + +* Otherwise uses the `ip` field of the address from the Endpoints. + +### ClusterIP (not headless) + +* If the `--publish-internal-services` flag is specified, uses the `spec.ServiceIP`. + +* Otherwise, does not create any targets. + +### NodePort + +If `spec.ExternalTrafficPolicy` is `Local`, iterates over each Node that both matches the Service's `spec.selector` +and has a `status.phase` of `Running`. Otherwise iterates over all Nodes, of any phase. + +Iterates over each relevant Node's `status.addresses`: + +* If there is an `external-dns.alpha.kubernetes.io/access: public` annotation on the Service, uses both addresses with +a `type` of `ExternalIP` and IPv6 addresses with a `type` of `InternalIP`. + +* Otherwise, if there is an `external-dns.alpha.kubernetes.io/access: private` annotation on the Service, uses addresses with +a `type` of `InternalIP`. + +* Otherwise, if there is at least one address with a `type` of `ExternalIP`, uses both addresses with +a `type` of `ExternalIP` and IPv6 addresses with a `type` of `InternalIP`. + +* Otherwise, uses addresses with a `type` of `InternalIP`. + +Also iterates over the Service's `spec.ports`, creating a SRV record for each port which has a `nodePort`. +The SRV record has a service of the Service's `name`, a protocol taken from the port's `protocol` field, +a priority of `0` and a weight of `50`. +In order for SRV records to be created, the `--managed-record-types`must have been specified, including `SRV` +as one of the values. + +### ExternalName + +* Creates a target with the value of the Service's `externalName` field. + diff --git a/docs/sources/sources.md b/docs/sources/sources.md index 7506bbce3..e0224c4c3 100644 --- a/docs/sources/sources.md +++ b/docs/sources/sources.md @@ -21,6 +21,6 @@ | node | Node | Yes | | | openshift-route | Route.route.openshift.io | Yes | Yes | | pod | Pod | | | -| service | Service | Yes | Yes | +| [service](service.md) | Service | Yes | Yes | | skipper-routegroup | RouteGroup.zalando.org | Yes | | | traefik-proxy | IngressRoute.traefik.io IngressRouteTCP.traefik.io IngressRouteUDP.traefik.io | Yes | | diff --git a/mkdocs.yml b/mkdocs.yml index b9ee2801e..e464d717f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -17,6 +17,7 @@ nav: - Sources: - About: sources/sources.md - Ingress: sources/ingress.md + - Service: sources/service.md - Registries: - About: registry/registry.md - TXT: registry/txt.md diff --git a/source/service.go b/source/service.go index b19ba4882..80659a106 100644 --- a/source/service.go +++ b/source/service.go @@ -671,7 +671,7 @@ func (sc *serviceSource) extractNodePortEndpoints(svc *v1.Service, hostname stri // _service._proto.name. TTL class SRV priority weight port // see https://en.wikipedia.org/wiki/SRV_record - // build a target with a priority of 0, weight of 0, and pointing the given port on the given host + // build a target with a priority of 0, weight of 50, and pointing the given port on the given host target := fmt.Sprintf("0 50 %d %s", port.NodePort, hostname) // take the service name from the K8s Service object