mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-05 17:16:59 +02:00
Merge afc7788578
into 0e7c3af221
This commit is contained in:
commit
980abef294
@ -33,6 +33,10 @@ a Pod that has a non-empty `spec.hostname` field, additional DNS entries are cre
|
||||
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 `.`.
|
||||
|
||||
Another way to create per-pod DNS entries is to annotate headless service with
|
||||
`external-dns.alpha.kubernetes.io/service-pod-endpoints` and values `pod-name` or `fqdn-template`. The former prefixes
|
||||
service domain name with pod name, the latter uses `--fqdn-template` to generate the domain name for each pod in the service.
|
||||
|
||||
## Targets
|
||||
|
||||
If the Service has an `external-dns.alpha.kubernetes.io/target` annotation, uses
|
||||
|
@ -55,4 +55,6 @@ const (
|
||||
ControllerValue = "dns-controller"
|
||||
// The annotation used for defining the desired hostname
|
||||
InternalHostnameKey = AnnotationKeyPrefix + "internal-hostname"
|
||||
// When set on a service, per-pod DNS entries will be created.
|
||||
ServicePodEndpoints = AnnotationKeyPrefix + "service-pod-endpoints"
|
||||
)
|
||||
|
@ -314,6 +314,8 @@ func (sc *serviceSource) extractHeadlessEndpoints(svc *v1.Service, hostname stri
|
||||
publishPodIPs := endpointsType != EndpointsTypeNodeExternalIP && endpointsType != EndpointsTypeHostIP && !sc.publishHostIP
|
||||
publishNotReadyAddresses := svc.Spec.PublishNotReadyAddresses || sc.alwaysPublishNotReadyAddresses
|
||||
|
||||
perPodDNSMode, perPodDNS := svc.Annotations[servicePodEndpointsKey]
|
||||
|
||||
targetsByHeadlessDomainAndType := make(map[endpoint.EndpointKey]endpoint.Targets)
|
||||
for _, endpointSlice := range endpointSlices {
|
||||
for _, ep := range endpointSlice.Endpoints {
|
||||
@ -350,6 +352,21 @@ func (sc *serviceSource) extractHeadlessEndpoints(svc *v1.Service, hostname stri
|
||||
headlessDomains = append(headlessDomains, fmt.Sprintf("%s.%s", pod.Spec.Hostname, hostname))
|
||||
}
|
||||
|
||||
if perPodDNS {
|
||||
switch perPodDNSMode {
|
||||
case ServicePodEndpointsPodName:
|
||||
headlessDomains = append(headlessDomains, fmt.Sprintf("%s.%s", pod.Name, hostname))
|
||||
case ServicePodEndpointsFqdnTemplate:
|
||||
if hostnames, err := fqdn.ExecTemplate(sc.fqdnTemplate, pod); err == nil {
|
||||
headlessDomains = append(headlessDomains, hostnames...)
|
||||
} else {
|
||||
log.Errorf("Error executing template for pod %s: %v", pod.Name, err)
|
||||
}
|
||||
default:
|
||||
log.Errorf("Unknown `service-pod-endpoints` value %s", perPodDNSMode)
|
||||
return endpoints
|
||||
}
|
||||
}
|
||||
for _, headlessDomain := range headlessDomains {
|
||||
targets := annotations.TargetsFromTargetAnnotation(pod.Annotations)
|
||||
if len(targets) == 0 {
|
||||
|
@ -3053,6 +3053,149 @@ func TestHeadlessServices(t *testing.T) {
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"annotated Headless services create DNS name for each pod",
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
v1.ServiceTypeClusterIP,
|
||||
"",
|
||||
"",
|
||||
false,
|
||||
true,
|
||||
map[string]string{"component": "foo"},
|
||||
map[string]string{
|
||||
servicePodEndpointsKey: ServicePodEndpointsPodName,
|
||||
hostnameAnnotationKey: "service.example.org",
|
||||
endpointsTypeAnnotationKey: EndpointsTypeNodeExternalIP,
|
||||
},
|
||||
map[string]string{},
|
||||
v1.ClusterIPNone,
|
||||
[]string{"1.1.1.1", "1.1.1.2", "1.1.1.3"},
|
||||
[]string{"", "", ""},
|
||||
map[string]string{
|
||||
"component": "foo",
|
||||
},
|
||||
[]string{},
|
||||
[]string{"foo1", "foo2", "foo3"},
|
||||
[]string{"", "", ""},
|
||||
[]bool{true, true, true},
|
||||
false,
|
||||
[]v1.Node{
|
||||
{
|
||||
Status: v1.NodeStatus{
|
||||
Addresses: []v1.NodeAddress{
|
||||
{
|
||||
Type: v1.NodeExternalIP,
|
||||
Address: "1.2.3.4",
|
||||
},
|
||||
{
|
||||
Type: v1.NodeInternalIP,
|
||||
Address: "2001:db8::4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]*endpoint.Endpoint{
|
||||
{DNSName: "service.example.org", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"1.2.3.4"}},
|
||||
{DNSName: "service.example.org", RecordType: endpoint.RecordTypeAAAA, Targets: endpoint.Targets{"2001:db8::4"}},
|
||||
{DNSName: "foo1.service.example.org", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"1.2.3.4"}},
|
||||
{DNSName: "foo1.service.example.org", RecordType: endpoint.RecordTypeAAAA, Targets: endpoint.Targets{"2001:db8::4"}},
|
||||
{DNSName: "foo2.service.example.org", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"1.2.3.4"}},
|
||||
{DNSName: "foo2.service.example.org", RecordType: endpoint.RecordTypeAAAA, Targets: endpoint.Targets{"2001:db8::4"}},
|
||||
{DNSName: "foo3.service.example.org", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"1.2.3.4"}},
|
||||
{DNSName: "foo3.service.example.org", RecordType: endpoint.RecordTypeAAAA, Targets: endpoint.Targets{"2001:db8::4"}},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"annotated Headless services create DNS name for each pod using fqdn template",
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
v1.ServiceTypeClusterIP,
|
||||
"",
|
||||
"{{ .Name }}-{{ .Namespace }}.example.org",
|
||||
false,
|
||||
true,
|
||||
map[string]string{"component": "foo"},
|
||||
map[string]string{
|
||||
servicePodEndpointsKey: ServicePodEndpointsFqdnTemplate,
|
||||
hostnameAnnotationKey: "service.example.org",
|
||||
endpointsTypeAnnotationKey: EndpointsTypeNodeExternalIP,
|
||||
},
|
||||
map[string]string{},
|
||||
v1.ClusterIPNone,
|
||||
[]string{"1.1.1.1", "1.1.1.2", "1.1.1.3"},
|
||||
[]string{"", "", ""},
|
||||
map[string]string{
|
||||
"component": "foo",
|
||||
},
|
||||
[]string{},
|
||||
[]string{"foo1", "foo2", "foo3"},
|
||||
[]string{"", "", ""},
|
||||
[]bool{true, true, true},
|
||||
false,
|
||||
[]v1.Node{
|
||||
{
|
||||
Status: v1.NodeStatus{
|
||||
Addresses: []v1.NodeAddress{
|
||||
{
|
||||
Type: v1.NodeExternalIP,
|
||||
Address: "1.2.3.4",
|
||||
},
|
||||
{
|
||||
Type: v1.NodeInternalIP,
|
||||
Address: "2001:db8::4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]*endpoint.Endpoint{
|
||||
{DNSName: "service.example.org", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"1.2.3.4"}},
|
||||
{DNSName: "service.example.org", RecordType: endpoint.RecordTypeAAAA, Targets: endpoint.Targets{"2001:db8::4"}},
|
||||
{DNSName: "foo1-testing.example.org", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"1.2.3.4"}},
|
||||
{DNSName: "foo1-testing.example.org", RecordType: endpoint.RecordTypeAAAA, Targets: endpoint.Targets{"2001:db8::4"}},
|
||||
{DNSName: "foo2-testing.example.org", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"1.2.3.4"}},
|
||||
{DNSName: "foo2-testing.example.org", RecordType: endpoint.RecordTypeAAAA, Targets: endpoint.Targets{"2001:db8::4"}},
|
||||
{DNSName: "foo3-testing.example.org", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"1.2.3.4"}},
|
||||
{DNSName: "foo3-testing.example.org", RecordType: endpoint.RecordTypeAAAA, Targets: endpoint.Targets{"2001:db8::4"}},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"annotated Headless service returns error if incorrect `service-pod-endpoints` value is set",
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
v1.ServiceTypeClusterIP,
|
||||
"",
|
||||
"",
|
||||
false,
|
||||
true,
|
||||
map[string]string{"component": "foo"},
|
||||
map[string]string{
|
||||
servicePodEndpointsKey: "not-valid",
|
||||
hostnameAnnotationKey: "service.example.org",
|
||||
},
|
||||
map[string]string{},
|
||||
v1.ClusterIPNone,
|
||||
[]string{"1.1.1.1", "1.1.1.2", "1.1.1.3"},
|
||||
[]string{"", "", ""},
|
||||
map[string]string{
|
||||
"component": "foo",
|
||||
},
|
||||
[]string{},
|
||||
[]string{"foo1", "foo2", "foo3"},
|
||||
[]string{"", "", ""},
|
||||
[]bool{true, true, true},
|
||||
false,
|
||||
[]v1.Node{{}},
|
||||
[]*endpoint.Endpoint{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"annotated Headless services return dual-stack targets from node external IP if endpoints-type annotation is set and exposeInternalIPv6 flag set",
|
||||
"",
|
||||
|
@ -38,9 +38,13 @@ const (
|
||||
ingressHostnameSourceKey = annotations.IngressHostnameSourceKey
|
||||
controllerAnnotationValue = annotations.ControllerValue
|
||||
internalHostnameAnnotationKey = annotations.InternalHostnameKey
|
||||
servicePodEndpointsKey = annotations.ServicePodEndpoints
|
||||
|
||||
EndpointsTypeNodeExternalIP = "NodeExternalIP"
|
||||
EndpointsTypeHostIP = "HostIP"
|
||||
|
||||
ServicePodEndpointsPodName = "pod-name"
|
||||
ServicePodEndpointsFqdnTemplate = "fqdn-template"
|
||||
)
|
||||
|
||||
// Source defines the interface Endpoint sources should implement.
|
||||
|
Loading…
Reference in New Issue
Block a user