Skip to content

Commit

Permalink
fixed review comments
Browse files Browse the repository at this point in the history
- incorporated changes from PR #3468 to allow for arbitrary annotations
  to be used no matter the hostNetwork property's value
- updated docs to make clear how the annotations are used for pods
  • Loading branch information
peterhoneder authored and raoulbhatia committed Sep 27, 2024
1 parent f1424a2 commit d926862
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 48 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
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
73 changes: 39 additions & 34 deletions source/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (ps *podSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error
for _, pod := range pods {
targets := getTargetsFromTargetAnnotation(pod.Annotations)

// accept hostname annotations that point to the pod's IP, no matter if the pod spec uses the host network
// accept internal hostname annotations that point to the pod's IP
if domainAnnotation, ok := pod.Annotations[internalHostnameAnnotationKey]; ok {
domainList := splitHostnameAnnotation(domainAnnotation)
for _, domain := range domainList {
Expand All @@ -99,46 +99,44 @@ func (ps *podSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error
}
}

// accept annotations that point to the node's external IP (or IPv6 NodeInternalIP) only for pods using the host network
if pod.Spec.HostNetwork {
if domainAnnotation, ok := pod.Annotations[hostnameAnnotationKey]; ok {
domainList := splitHostnameAnnotation(domainAnnotation)
for _, domain := range domainList {
if len(targets) == 0 {
node, _ := ps.nodeInformer.Lister().Get(pod.Spec.NodeName)
for _, address := range node.Status.Addresses {
recordType := suitableType(address.Address)
// IPv6 addresses are labeled as NodeInternalIP despite being usable externally as well.
if address.Type == corev1.NodeExternalIP || (address.Type == corev1.NodeInternalIP && recordType == endpoint.RecordTypeAAAA) {
addToEndpointMap(endpointMap, domain, recordType, address.Address)
}
}
} else {
for _, target := range targets {
addToEndpointMap(endpointMap, domain, suitableType(target), target)
// accept internal hostname annotations that point to the pod's IP (or IPv6 NodeInternalIP)
if domainAnnotation, ok := pod.Annotations[hostnameAnnotationKey]; ok {
domainList := splitHostnameAnnotation(domainAnnotation)
for _, domain := range domainList {
if len(targets) == 0 {
node, _ := ps.nodeInformer.Lister().Get(pod.Spec.NodeName)
for _, address := range node.Status.Addresses {
recordType := suitableType(address.Address)
// IPv6 addresses are labeled as NodeInternalIP despite being usable externally as well.
if address.Type == corev1.NodeExternalIP || (address.Type == corev1.NodeInternalIP && recordType == endpoint.RecordTypeAAAA) {
addToEndpointMap(endpointMap, domain, recordType, address.Address)
}
}
} else {
for _, target := range targets {
addToEndpointMap(endpointMap, domain, suitableType(target), target)
}
}
}
}

if ps.compatibility == "kops-dns-controller" {
if domainAnnotation, ok := pod.Annotations[kopsDNSControllerInternalHostnameAnnotationKey]; ok {
domainList := splitHostnameAnnotation(domainAnnotation)
for _, domain := range domainList {
addToEndpointMap(endpointMap, domain, suitableType(pod.Status.PodIP), pod.Status.PodIP)
}
if ps.compatibility == "kops-dns-controller" {
if domainAnnotation, ok := pod.Annotations[kopsDNSControllerInternalHostnameAnnotationKey]; ok {
domainList := splitHostnameAnnotation(domainAnnotation)
for _, domain := range domainList {
addToEndpointMap(endpointMap, domain, suitableType(pod.Status.PodIP), pod.Status.PodIP)
}
}

if domainAnnotation, ok := pod.Annotations[kopsDNSControllerHostnameAnnotationKey]; ok {
domainList := splitHostnameAnnotation(domainAnnotation)
for _, domain := range domainList {
node, _ := ps.nodeInformer.Lister().Get(pod.Spec.NodeName)
for _, address := range node.Status.Addresses {
recordType := suitableType(address.Address)
// IPv6 addresses are labeled as NodeInternalIP despite being usable externally as well.
if address.Type == corev1.NodeExternalIP || (address.Type == corev1.NodeInternalIP && recordType == endpoint.RecordTypeAAAA) {
addToEndpointMap(endpointMap, domain, recordType, address.Address)
}
if domainAnnotation, ok := pod.Annotations[kopsDNSControllerHostnameAnnotationKey]; ok {
domainList := splitHostnameAnnotation(domainAnnotation)
for _, domain := range domainList {
node, _ := ps.nodeInformer.Lister().Get(pod.Spec.NodeName)
for _, address := range node.Status.Addresses {
recordType := suitableType(address.Address)
// IPv6 addresses are labeled as NodeInternalIP despite being usable externally as well.
if address.Type == corev1.NodeExternalIP || (address.Type == corev1.NodeInternalIP && recordType == endpoint.RecordTypeAAAA) {
addToEndpointMap(endpointMap, domain, recordType, address.Address)
}
}
}
Expand All @@ -160,5 +158,12 @@ func addToEndpointMap(endpointMap map[endpoint.EndpointKey][]string, domain stri
if _, ok := endpointMap[key]; !ok {
endpointMap[key] = []string{}
}

// check that only unique addresses are added
for _, existingAddress := range endpointMap[key] {
if existingAddress == address {
return
}
}
endpointMap[key] = append(endpointMap[key], address)
}
24 changes: 15 additions & 9 deletions source/pod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func TestPodSource(t *testing.T) {
"kops-dns-controller",
[]*endpoint.Endpoint{
{DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1", "54.10.11.2"}, RecordType: endpoint.RecordTypeA},
{DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1", "10.0.1.2"}, RecordType: endpoint.RecordTypeA},
{DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1", "10.0.1.2", "10.0.1.3"}, RecordType: endpoint.RecordTypeA},
},
false,
[]*corev1.Node{
Expand Down Expand Up @@ -178,7 +178,9 @@ func TestPodSource(t *testing.T) {
PodIP: "10.0.1.2",
},
},
// this pod must be ignored because it's not in the host network and kops requires this
// non-HostNetwork pod
// - internal hostname annotation will use the PodIP
// - external hostname annotation will use the NodeExternalIP
{
ObjectMeta: metav1.ObjectMeta{
Name: "my-pod3",
Expand Down Expand Up @@ -264,7 +266,9 @@ func TestPodSource(t *testing.T) {
PodIP: "2001:DB8::2",
},
},
// this pod's internal hostname annotation must not be ignored even though it's not in the host network
// this pod's hostname annotations (both internal and not) must not be ignored even though it's not in the host network
// - internal hostname annotation uses the PodIP
// - external hostname annotation uses the NodeInternalIP
{
ObjectMeta: metav1.ObjectMeta{
Name: "my-pod3",
Expand All @@ -290,7 +294,7 @@ func TestPodSource(t *testing.T) {
"kops-dns-controller",
[]*endpoint.Endpoint{
{DNSName: "a.foo.example.org", Targets: endpoint.Targets{"2001:DB8::1", "2001:DB8::2"}, RecordType: endpoint.RecordTypeAAAA},
{DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"2001:DB8::1", "2001:DB8::2"}, RecordType: endpoint.RecordTypeAAAA},
{DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"2001:DB8::1", "2001:DB8::2", "2001:DB8::3"}, RecordType: endpoint.RecordTypeAAAA},
},
false,
[]*corev1.Node{
Expand Down Expand Up @@ -350,7 +354,9 @@ func TestPodSource(t *testing.T) {
PodIP: "2001:DB8::2",
},
},
// this pod must be ignored because it's not in the host network and kops requires this (no matter the type of hostname annotation)
// this pod's hostname annotations (both internal and not) must not be ignored even though it's not in the host network
// - internal hostname annotation uses the PodIP
// - external hostname annotation uses the NodeInternalIP
{
ObjectMeta: metav1.ObjectMeta{
Name: "my-pod3",
Expand All @@ -375,7 +381,7 @@ func TestPodSource(t *testing.T) {
"",
"",
[]*endpoint.Endpoint{
{DNSName: "a.foo.example.org", Targets: endpoint.Targets{"208.1.2.1", "208.1.2.2"}, RecordType: endpoint.RecordTypeA},
{DNSName: "a.foo.example.org", Targets: endpoint.Targets{"208.1.2.1", "208.1.2.2", "208.1.2.3"}, RecordType: endpoint.RecordTypeA},
{DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"208.1.2.1", "208.1.2.2", "208.1.2.3"}, RecordType: endpoint.RecordTypeA},
},
false,
Expand Down Expand Up @@ -440,7 +446,7 @@ func TestPodSource(t *testing.T) {
PodIP: "10.0.1.2",
},
},
// this pod's internal hostname annotation must not be ignored even though it's not in the host network (even when using a custom target annotation)
// test non-HostNetwork pod
{
ObjectMeta: metav1.ObjectMeta{
Name: "my-pod3",
Expand Down Expand Up @@ -532,11 +538,11 @@ func TestPodSource(t *testing.T) {
},
},
{
"internal hostname annotations of pods with hostNetwore=false should still be added as valid records",
"hostname annotations of pods with hostNetwork=false should still be added as valid records",
"",
"",
[]*endpoint.Endpoint{
{DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1"}, RecordType: endpoint.RecordTypeA},
{DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1", "54.10.11.2"}, RecordType: endpoint.RecordTypeA},
{DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1", "100.0.1.2"}, RecordType: endpoint.RecordTypeA},
// this annotation is part of a comma separated hostname list in the annotation
{DNSName: "internal.b.foo.example.org", Targets: endpoint.Targets{"10.0.1.1"}, RecordType: endpoint.RecordTypeA},
Expand Down

0 comments on commit d926862

Please sign in to comment.