Skip to content

Commit

Permalink
Allow to register all pods and their associated PTR record
Browse files Browse the repository at this point in the history
Add two new options:
- --ignore-non-host-network-pods
- --pod-source-domain

Combined toghether, they can be used to register the IPs
of all pods with their associated PTR record.
  • Loading branch information
foyerunix committed Jan 13, 2025
1 parent dfe8e78 commit ee3887a
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 26 deletions.
4 changes: 3 additions & 1 deletion docs/annotations/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ Specifies the domain for the resource's DNS records.
Multiple hostnames can be specified through a comma-separated list, e.g.
`svc.mydomain1.com,svc.mydomain2.com`.

For `Pods`, uses the `Pod`'s `Status.PodIP`, unless they are `hostNetwork: true` in which case the NodeExternalIP is used for IPv4 and NodeInternalIP for IPv6.

## external-dns.alpha.kubernetes.io/ingress-hostname-source

Specifies where to get the domain for an `Ingress` resource.
Expand All @@ -80,7 +82,7 @@ Specifies the domain for the resource's DNS records that are for use from intern

For `Services` of type `LoadBalancer`, uses the `Service`'s `ClusterIP`.

For `Pods`, uses the `Pod`'s `Status.PodIP`.
For `Pods`, uses the `Pod`'s `Status.PodIP`, unless they are `hostNetwork: true` in which case the NodeExternalIP is used for IPv4 and NodeInternalIP for IPv6.

## external-dns.alpha.kubernetes.io/target

Expand Down
2 changes: 2 additions & 0 deletions docs/flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@
| `--fqdn-template=""` | A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN. |
| `--[no-]combine-fqdn-annotation` | Combine FQDN template and Annotations instead of overwriting |
| `--[no-]ignore-hostname-annotation` | Ignore hostname annotation when generating DNS names, valid only when --fqdn-template is set (default: false) |
| `--[no-]ignore-non-host-network-pods` | Ignore pods not running on host network when using pod source (default: true) |
| `--[no-]ignore-ingress-tls-spec` | Ignore the spec.tls section in Ingress resources (default: false) |
| `--gateway-namespace=GATEWAY-NAMESPACE` | Limit Gateways of Route endpoints to a specific namespace (default: all namespaces) |
| `--gateway-label-filter=GATEWAY-LABEL-FILTER` | Filter Gateways of Route endpoints via label selector (default: all gateways) |
| `--compatibility=` | Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller) |
| `--[no-]ignore-ingress-rules-spec` | Ignore the spec.rules section in Ingress resources (default: false) |
| `--pod-source-domain=""` | Domain to use for pods records (optional) |
| `--[no-]publish-internal-services` | Allow external-dns to publish DNS records for ClusterIP services (optional) |
| `--[no-]publish-host-ip` | Allow external-dns to publish host-ip for headless services (optional) |
| `--[no-]always-publish-not-ready-addresses` | Always publish also not ready addresses for headless services (optional) |
Expand Down
25 changes: 25 additions & 0 deletions docs/sources/pod.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Pod Source

The pod source creates DNS entries based on `Pod` resources.

## Pods not running with host networking

By default, the pod source will not consider the pods that aren't running with host networking enabled. You can override this behavior by using the `--ignore-non-host-network-pods` option.

## Using a default domain for pods

By default, the pod source will look into the pod annotations to find the FQDN associated with a pod. You can also use the option `--pod-source-domain=example.org` to build the FQDN of the pods. The pod named "test-pod" will then be registered as "test-pod.example.org".

## Configuration for registering all pods with their associated PTR record

A use case where combining these options can be pertinent is when you are running on-premise Kubernetes clusters without SNAT enabled for the pod network. You might want to register all the pods in the DNS with their associated PTR record so that the source of some traffic outside of the cluster can be rapidly associated with a workload using the "nslookup" or "dig" command on the pod IP. This can be particularly useful if you are running a large number of Kubernetes clusters.

You will then use the following mix of options:
- `--domain-filter=example.org`
- `--domain-filter=10.0.0.in-addr.arpa`
- `--source=pod`
- `--pod-source-domain=example.org`
- `--no-ignore-non-host-network-pods`
- `--rfc2136-create-ptr`
- `--rfc2136-zone=example.org`
- `--rfc2136-zone=10.0.0.in-addr.arpa`
6 changes: 2 additions & 4 deletions docs/tutorials/kops-dns-controller.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@ The DNS record mappings try to "do the right thing", but what this means is diff

### Pods

For the external annotation, ExternalDNS will map a HostNetwork=true Pod to the external IPs of the Node.
For the external annotation, ExternalDNS will map a Pod to the external IPs of the Node.

For the internal annotation, ExternalDNS will map a HostNetwork=true Pod to the internal IPs of the Node.

ExternalDNS ignore Pods that are not HostNetwork=true
For the internal annotation, ExternalDNS will map a Pod to the internal IPs of the Node.

Annotations added to Pods will always result in an A record being created.

Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,13 @@ func main() {
FQDNTemplate: cfg.FQDNTemplate,
CombineFQDNAndAnnotation: cfg.CombineFQDNAndAnnotation,
IgnoreHostnameAnnotation: cfg.IgnoreHostnameAnnotation,
IgnoreNonHostNetworkPods: cfg.IgnoreNonHostNetworkPods,
IgnoreIngressTLSSpec: cfg.IgnoreIngressTLSSpec,
IgnoreIngressRulesSpec: cfg.IgnoreIngressRulesSpec,
GatewayNamespace: cfg.GatewayNamespace,
GatewayLabelFilter: cfg.GatewayLabelFilter,
Compatibility: cfg.Compatibility,
PodSourceDomain: cfg.PodSourceDomain,
PublishInternal: cfg.PublishInternal,
PublishHostIP: cfg.PublishHostIP,
AlwaysPublishNotReadyAddresses: cfg.AlwaysPublishNotReadyAddresses,
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/externaldns/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@ type Config struct {
FQDNTemplate string
CombineFQDNAndAnnotation bool
IgnoreHostnameAnnotation bool
IgnoreNonHostNetworkPods bool
IgnoreIngressTLSSpec bool
IgnoreIngressRulesSpec bool
GatewayNamespace string
GatewayLabelFilter string
Compatibility string
PodSourceDomain string
PublishInternal bool
PublishHostIP bool
AlwaysPublishNotReadyAddresses bool
Expand Down Expand Up @@ -286,6 +288,7 @@ var defaultConfig = &Config{
PDNSServerID: "localhost",
PDNSAPIKey: "",
PDNSSkipTLSVerify: false,
PodSourceDomain: "",
TLSCA: "",
TLSClientCert: "",
TLSClientCertKey: "",
Expand Down Expand Up @@ -442,11 +445,13 @@ func App(cfg *Config) *kingpin.Application {
app.Flag("fqdn-template", "A templated string that's used to generate DNS names from sources that don't define a hostname themselves, or to add a hostname suffix when paired with the fake source (optional). Accepts comma separated list for multiple global FQDN.").Default(defaultConfig.FQDNTemplate).StringVar(&cfg.FQDNTemplate)
app.Flag("combine-fqdn-annotation", "Combine FQDN template and Annotations instead of overwriting").BoolVar(&cfg.CombineFQDNAndAnnotation)
app.Flag("ignore-hostname-annotation", "Ignore hostname annotation when generating DNS names, valid only when --fqdn-template is set (default: false)").BoolVar(&cfg.IgnoreHostnameAnnotation)
app.Flag("ignore-non-host-network-pods", "Ignore pods not running on host network when using pod source (default: true)").BoolVar(&cfg.IgnoreNonHostNetworkPods)
app.Flag("ignore-ingress-tls-spec", "Ignore the spec.tls section in Ingress resources (default: false)").BoolVar(&cfg.IgnoreIngressTLSSpec)
app.Flag("gateway-namespace", "Limit Gateways of Route endpoints to a specific namespace (default: all namespaces)").StringVar(&cfg.GatewayNamespace)
app.Flag("gateway-label-filter", "Filter Gateways of Route endpoints via label selector (default: all gateways)").StringVar(&cfg.GatewayLabelFilter)
app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule, kops-dns-controller)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule", "kops-dns-controller")
app.Flag("ignore-ingress-rules-spec", "Ignore the spec.rules section in Ingress resources (default: false)").BoolVar(&cfg.IgnoreIngressRulesSpec)
app.Flag("pod-source-domain", "Domain to use for pods records (optional)").Default(defaultConfig.PodSourceDomain).StringVar(&cfg.PodSourceDomain)
app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal)
app.Flag("publish-host-ip", "Allow external-dns to publish host-ip for headless services (optional)").BoolVar(&cfg.PublishHostIP)
app.Flag("always-publish-not-ready-addresses", "Always publish also not ready addresses for headless services (optional)").BoolVar(&cfg.AlwaysPublishNotReadyAddresses)
Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/externaldns/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ var (
Sources: []string{"service", "ingress", "connector"},
Namespace: "namespace",
IgnoreHostnameAnnotation: true,
IgnoreNonHostNetworkPods: false,
IgnoreIngressTLSSpec: true,
IgnoreIngressRulesSpec: true,
FQDNTemplate: "{{.Name}}.service.example.com",
Expand Down Expand Up @@ -197,6 +198,7 @@ var (
TLSCA: "/path/to/ca.crt",
TLSClientCert: "/path/to/cert.pem",
TLSClientCertKey: "/path/to/key.pem",
PodSourceDomain: "example.org",
Policy: "upsert-only",
Registry: "noop",
TXTOwnerID: "owner-1",
Expand Down Expand Up @@ -265,6 +267,7 @@ func TestParseFlags(t *testing.T) {
"--source=connector",
"--namespace=namespace",
"--fqdn-template={{.Name}}.service.example.com",
"--no-ignore-non-host-network-pods",
"--ignore-hostname-annotation",
"--ignore-ingress-tls-spec",
"--ignore-ingress-rules-spec",
Expand Down Expand Up @@ -301,6 +304,7 @@ func TestParseFlags(t *testing.T) {
"--tls-ca=/path/to/ca.crt",
"--tls-client-cert=/path/to/cert.pem",
"--tls-client-cert-key=/path/to/key.pem",
"--pod-source-domain=example.org",
"--domain-filter=example.org",
"--domain-filter=company.com",
"--exclude-domains=xapi.example.org",
Expand Down Expand Up @@ -385,6 +389,7 @@ func TestParseFlags(t *testing.T) {
"EXTERNAL_DNS_SOURCE": "service\ningress\nconnector",
"EXTERNAL_DNS_NAMESPACE": "namespace",
"EXTERNAL_DNS_FQDN_TEMPLATE": "{{.Name}}.service.example.com",
"EXTERNAL_DNS_IGNORE_NON_HOST_NETWORK_PODS": "0",
"EXTERNAL_DNS_IGNORE_HOSTNAME_ANNOTATION": "1",
"EXTERNAL_DNS_IGNORE_INGRESS_TLS_SPEC": "1",
"EXTERNAL_DNS_IGNORE_INGRESS_RULES_SPEC": "1",
Expand Down Expand Up @@ -413,6 +418,7 @@ func TestParseFlags(t *testing.T) {
"EXTERNAL_DNS_INMEMORY_ZONE": "example.org\ncompany.com",
"EXTERNAL_DNS_OVH_ENDPOINT": "ovh-ca",
"EXTERNAL_DNS_OVH_API_RATE_LIMIT": "42",
"EXTERNAL_DNS_POD_SOURCE_DOMAIN": "example.org",
"EXTERNAL_DNS_DOMAIN_FILTER": "example.org\ncompany.com",
"EXTERNAL_DNS_EXCLUDE_DOMAINS": "xapi.example.org\nxapi.company.com",
"EXTERNAL_DNS_REGEX_DOMAIN_FILTER": "(example\\.org|company\\.com)$",
Expand Down
38 changes: 26 additions & 12 deletions source/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,17 @@ import (
)

type podSource struct {
client kubernetes.Interface
namespace string
podInformer coreinformers.PodInformer
nodeInformer coreinformers.NodeInformer
compatibility string
client kubernetes.Interface
namespace string
podInformer coreinformers.PodInformer
nodeInformer coreinformers.NodeInformer
compatibility string
ignoreNonHostNetworkPods bool
podSourceDomain string
}

// NewPodSource creates a new podSource with the given config.
func NewPodSource(ctx context.Context, kubeClient kubernetes.Interface, namespace string, compatibility string) (Source, error) {
func NewPodSource(ctx context.Context, kubeClient kubernetes.Interface, namespace string, compatibility string, ignoreNonHostNetworkPods bool, podSourceDomain string) (Source, error) {
informerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(kubeClient, 0, kubeinformers.WithNamespace(namespace))
podInformer := informerFactory.Core().V1().Pods()
nodeInformer := informerFactory.Core().V1().Nodes()
Expand All @@ -65,11 +67,13 @@ func NewPodSource(ctx context.Context, kubeClient kubernetes.Interface, namespac
}

return &podSource{
client: kubeClient,
podInformer: podInformer,
nodeInformer: nodeInformer,
namespace: namespace,
compatibility: compatibility,
client: kubeClient,
podInformer: podInformer,
nodeInformer: nodeInformer,
namespace: namespace,
compatibility: compatibility,
ignoreNonHostNetworkPods: ignoreNonHostNetworkPods,
podSourceDomain: podSourceDomain,
}, nil
}

Expand All @@ -84,7 +88,7 @@ func (ps *podSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error

endpointMap := make(map[endpoint.EndpointKey][]string)
for _, pod := range pods {
if !pod.Spec.HostNetwork {
if ps.ignoreNonHostNetworkPods && !pod.Spec.HostNetwork {
log.Debugf("skipping pod %s. hostNetwork=false", pod.Name)
continue
}
Expand Down Expand Up @@ -146,6 +150,16 @@ func (ps *podSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error
}
}
}

if ps.podSourceDomain != "" {
if len(targets) == 0 {
addToEndpointMap(endpointMap, pod.ObjectMeta.Name+"."+ps.podSourceDomain, suitableType(pod.Status.PodIP), pod.Status.PodIP)
} else {
for _, target := range targets {
addToEndpointMap(endpointMap, pod.ObjectMeta.Name+"."+ps.podSourceDomain, suitableType(target), target)
}
}
}
}
endpoints := []*endpoint.Endpoint{}
for key, targets := range endpointMap {
Expand Down
Loading

0 comments on commit ee3887a

Please sign in to comment.