mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-07 01:56:57 +02:00
Support a comma separated list for the FQDN template (#512)
* Support a comma separated list for the FQDN template * Add documentation for comma separated FQDN templates * chore: add multiple fqdn templates to changelog
This commit is contained in:
parent
3fa55ab682
commit
321d4d463b
@ -1,3 +1,4 @@
|
|||||||
|
- Support a comma separated list for the FQDN template (#512) @helgi
|
||||||
- Google Provider: Add auto-detection of Google Project when running on GCP (#492) @drzero42
|
- Google Provider: Add auto-detection of Google Project when running on GCP (#492) @drzero42
|
||||||
- Add custom TTL support for DNSimple (#477) @jbowes
|
- Add custom TTL support for DNSimple (#477) @jbowes
|
||||||
- Fix docker build and delete vendor files which were not deleted (#473) @njuettner
|
- Fix docker build and delete vendor files which were not deleted (#473) @njuettner
|
||||||
|
14
docs/faq.md
14
docs/faq.md
@ -40,7 +40,7 @@ Services exposed via `type=LoadBalancer` and for the hostnames defined in Ingres
|
|||||||
|
|
||||||
### How do I specify DNS name for my Kubernetes objects?
|
### How do I specify DNS name for my Kubernetes objects?
|
||||||
|
|
||||||
There are three sources of information for ExternalDNS to decide on DNS name. ExternalDNS will pick one in order as listed below:
|
There are three sources of information for ExternalDNS to decide on DNS name. ExternalDNS will pick one in order as listed below:
|
||||||
|
|
||||||
1. For ingress objects ExternalDNS will create a DNS record based on the host specified for the ingress object. For services ExternalDNS will look for the annotation `external-dns.alpha.kubernetes.io/hostname` on the service and use the corresponding value.
|
1. For ingress objects ExternalDNS will create a DNS record based on the host specified for the ingress object. For services ExternalDNS will look for the annotation `external-dns.alpha.kubernetes.io/hostname` on the service and use the corresponding value.
|
||||||
|
|
||||||
@ -48,6 +48,10 @@ There are three sources of information for ExternalDNS to decide on DNS name. Ex
|
|||||||
|
|
||||||
3. If `--fqdn-template` flag is specified, e.g. `--fqdn-template={{.Name}}.my-org.com`, ExternalDNS will use service/ingress specifications for the provided template to generate DNS name.
|
3. If `--fqdn-template` flag is specified, e.g. `--fqdn-template={{.Name}}.my-org.com`, ExternalDNS will use service/ingress specifications for the provided template to generate DNS name.
|
||||||
|
|
||||||
|
### Can I specify multiple global FQDN templates?
|
||||||
|
|
||||||
|
Yes, yes you can. Pass in a comma separated list to `--fqdn-template`. Beaware this will double (triple, etc) the amount of DNS entries based on how many services, ingresses and so on you have and will get you faster towards the API request limit of your DNS provider.
|
||||||
|
|
||||||
### Which Service and Ingress controllers are supported?
|
### Which Service and Ingress controllers are supported?
|
||||||
|
|
||||||
Regarding Services, we'll support the OSI Layer 4 load balancers that Kubernetes creates on AWS and Google Container Engine, and possibly other clusters running on Google Compute Engine.
|
Regarding Services, we'll support the OSI Layer 4 load balancers that Kubernetes creates on AWS and Google Container Engine, and possibly other clusters running on Google Compute Engine.
|
||||||
@ -91,13 +95,13 @@ Yes — Zalando replaced [Mate](https://github.com/linki/mate) with ExternalDNS
|
|||||||
|
|
||||||
### How can we start using ExternalDNS?
|
### How can we start using ExternalDNS?
|
||||||
|
|
||||||
Check out the following descriptive tutorials on how to run ExternalDNS in [GKE](tutorials/gke.md) and [AWS](tutorials/aws.md).
|
Check out the following descriptive tutorials on how to run ExternalDNS in [GKE](tutorials/gke.md) and [AWS](tutorials/aws.md).
|
||||||
|
|
||||||
### Why is ExternalDNS only adding a single IP address in Route 53 on AWS when using the `nginx-ingress-controller`? How do I get it to use the FQDN of the ELB assigned to my `nginx-ingress-controller` Service instead?
|
### Why is ExternalDNS only adding a single IP address in Route 53 on AWS when using the `nginx-ingress-controller`? How do I get it to use the FQDN of the ELB assigned to my `nginx-ingress-controller` Service instead?
|
||||||
|
|
||||||
By default the `nginx-ingress-controller` assigns a single IP address to an Ingress resource when it's created. ExternalDNS uses what's assigned to the Ingress resource, so it too will use this single IP address when adding the record in Route 53.
|
By default the `nginx-ingress-controller` assigns a single IP address to an Ingress resource when it's created. ExternalDNS uses what's assigned to the Ingress resource, so it too will use this single IP address when adding the record in Route 53.
|
||||||
|
|
||||||
In most AWS deployments, you'll instead want the Route 53 entry to be the FQDN of the ELB that is assigned to the `nginx-ingress-controller` Service. To accomplish this, when you create the `nginx-ingress-controller` Deployment, you need to provide the `--publish-service` option to the `/nginx-ingress-controller` executable under `args`. Once this is deployed new Ingress resources will get the ELB's FQDN and ExternalDNS will use the same when creating records in Route 53.
|
In most AWS deployments, you'll instead want the Route 53 entry to be the FQDN of the ELB that is assigned to the `nginx-ingress-controller` Service. To accomplish this, when you create the `nginx-ingress-controller` Deployment, you need to provide the `--publish-service` option to the `/nginx-ingress-controller` executable under `args`. Once this is deployed new Ingress resources will get the ELB's FQDN and ExternalDNS will use the same when creating records in Route 53.
|
||||||
|
|
||||||
According to the `nginx-ingress-controller` [docs](https://github.com/kubernetes/ingress/tree/master/controllers/nginx) the value you need to provide `--publish-service` is:
|
According to the `nginx-ingress-controller` [docs](https://github.com/kubernetes/ingress/tree/master/controllers/nginx) the value you need to provide `--publish-service` is:
|
||||||
|
|
||||||
@ -208,7 +212,7 @@ Sometimes you need to run an internal and an external dns service.
|
|||||||
The internal one should provision hostnames used on the internal network (perhaps inside a VPC), and the external
|
The internal one should provision hostnames used on the internal network (perhaps inside a VPC), and the external
|
||||||
one to expose DNS to the internet.
|
one to expose DNS to the internet.
|
||||||
|
|
||||||
To do this with ExternalDNS you can use the `--annotation-filter` to specifically tie an instance of ExternalDNS to
|
To do this with ExternalDNS you can use the `--annotation-filter` to specifically tie an instance of ExternalDNS to
|
||||||
an instance of a ingress controller. Let's assume you have two ingress controllers `nginx-internal` and `nginx-external`
|
an instance of a ingress controller. Let's assume you have two ingress controllers `nginx-internal` and `nginx-external`
|
||||||
then you can start two ExternalDNS providers one with `--annotation-filter=kubernetes.io/ingress.class=nginx-internal`
|
then you can start two ExternalDNS providers one with `--annotation-filter=kubernetes.io/ingress.class=nginx-internal`
|
||||||
and one with `--annotation-filter=kubernetes.io/ingress.class=nginx-external`.
|
and one with `--annotation-filter=kubernetes.io/ingress.class=nginx-external`.
|
||||||
|
@ -151,7 +151,7 @@ func (cfg *Config) ParseFlags(args []string) error {
|
|||||||
app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, fake)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "fake")
|
app.Flag("source", "The resource types that are queried for endpoints; specify multiple times for multiple sources (required, options: service, ingress, fake)").Required().PlaceHolder("source").EnumsVar(&cfg.Sources, "service", "ingress", "fake")
|
||||||
app.Flag("namespace", "Limit sources of endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace)
|
app.Flag("namespace", "Limit sources of endpoints to a specific namespace (default: all namespaces)").Default(defaultConfig.Namespace).StringVar(&cfg.Namespace)
|
||||||
app.Flag("annotation-filter", "Filter sources managed by external-dns via annotation using label selector semantics (default: all sources)").Default(defaultConfig.AnnotationFilter).StringVar(&cfg.AnnotationFilter)
|
app.Flag("annotation-filter", "Filter sources managed by external-dns via annotation using label selector semantics (default: all sources)").Default(defaultConfig.AnnotationFilter).StringVar(&cfg.AnnotationFilter)
|
||||||
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)").Default(defaultConfig.FQDNTemplate).StringVar(&cfg.FQDNTemplate)
|
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("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule")
|
app.Flag("compatibility", "Process annotation semantics from legacy implementations (optional, options: mate, molecule)").Default(defaultConfig.Compatibility).EnumVar(&cfg.Compatibility, "", "mate", "molecule")
|
||||||
app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal)
|
app.Flag("publish-internal-services", "Allow external-dns to publish DNS records for ClusterIP services (optional)").BoolVar(&cfg.PublishInternal)
|
||||||
|
|
||||||
|
@ -136,14 +136,14 @@ func getTargetsFromTargetAnnotation(ing *v1beta1.Ingress) endpoint.Targets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sc *ingressSource) endpointsFromTemplate(ing *v1beta1.Ingress) ([]*endpoint.Endpoint, error) {
|
func (sc *ingressSource) endpointsFromTemplate(ing *v1beta1.Ingress) ([]*endpoint.Endpoint, error) {
|
||||||
|
// Process the whole template string
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
err := sc.fqdnTemplate.Execute(&buf, ing)
|
err := sc.fqdnTemplate.Execute(&buf, ing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to apply template on ingress %s: %v", ing.String(), err)
|
return nil, fmt.Errorf("failed to apply template on ingress %s: %v", ing.String(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hostname := buf.String()
|
hostnames := buf.String()
|
||||||
|
|
||||||
ttl, err := getTTLFromAnnotations(ing.Annotations)
|
ttl, err := getTTLFromAnnotations(ing.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -156,7 +156,14 @@ func (sc *ingressSource) endpointsFromTemplate(ing *v1beta1.Ingress) ([]*endpoin
|
|||||||
targets = targetsFromIngressStatus(ing.Status)
|
targets = targetsFromIngressStatus(ing.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
return endpointsForHostname(hostname, targets, ttl), nil
|
var endpoints []*endpoint.Endpoint
|
||||||
|
// splits the FQDN template and removes the trailing periods
|
||||||
|
hostnameList := strings.Split(strings.Replace(hostnames, " ", "", -1), ",")
|
||||||
|
for _, hostname := range hostnameList {
|
||||||
|
hostname = strings.TrimSuffix(hostname, ".")
|
||||||
|
endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl)...)
|
||||||
|
}
|
||||||
|
return endpoints, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterByAnnotations filters a list of ingresses by a given annotation selector.
|
// filterByAnnotations filters a list of ingresses by a given annotation selector.
|
||||||
|
@ -473,6 +473,32 @@ func testIngressEndpoints(t *testing.T) {
|
|||||||
expected: []*endpoint.Endpoint{},
|
expected: []*endpoint.Endpoint{},
|
||||||
fqdnTemplate: "{{.Name}}.ext-dns.test.com",
|
fqdnTemplate: "{{.Name}}.ext-dns.test.com",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "multiple FQDN template hostnames",
|
||||||
|
targetNamespace: "",
|
||||||
|
ingressItems: []fakeIngress{
|
||||||
|
{
|
||||||
|
name: "fake1",
|
||||||
|
namespace: namespace,
|
||||||
|
annotations: map[string]string{},
|
||||||
|
dnsnames: []string{},
|
||||||
|
ips: []string{"8.8.8.8"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: []*endpoint.Endpoint{
|
||||||
|
{
|
||||||
|
DNSName: "fake1.ext-dns.test.com",
|
||||||
|
Targets: endpoint.Targets{"8.8.8.8"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DNSName: "fake1.ext-dna.test.com",
|
||||||
|
Targets: endpoint.Targets{"8.8.8.8"},
|
||||||
|
RecordType: endpoint.RecordTypeA,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fqdnTemplate: "{{.Name}}.ext-dns.test.com, {{.Name}}.ext-dna.test.com",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "ingress rules with annotation",
|
title: "ingress rules with annotation",
|
||||||
targetNamespace: "",
|
targetNamespace: "",
|
||||||
|
@ -162,15 +162,17 @@ func (sc *serviceSource) extractHeadlessEndpoints(svc *v1.Service, hostname stri
|
|||||||
func (sc *serviceSource) endpointsFromTemplate(svc *v1.Service) ([]*endpoint.Endpoint, error) {
|
func (sc *serviceSource) endpointsFromTemplate(svc *v1.Service) ([]*endpoint.Endpoint, error) {
|
||||||
var endpoints []*endpoint.Endpoint
|
var endpoints []*endpoint.Endpoint
|
||||||
|
|
||||||
|
// Process the whole template string
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
err := sc.fqdnTemplate.Execute(&buf, svc)
|
err := sc.fqdnTemplate.Execute(&buf, svc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to apply template on service %s: %v", svc.String(), err)
|
return nil, fmt.Errorf("failed to apply template on service %s: %v", svc.String(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hostname := buf.String()
|
hostnameList := strings.Split(strings.Replace(buf.String(), " ", "", -1), ",")
|
||||||
|
for _, hostname := range hostnameList {
|
||||||
endpoints = sc.generateEndpoints(svc, hostname)
|
endpoints = append(endpoints, sc.generateEndpoints(svc, hostname)...)
|
||||||
|
}
|
||||||
|
|
||||||
return endpoints, nil
|
return endpoints, nil
|
||||||
}
|
}
|
||||||
|
@ -213,6 +213,25 @@ func testServiceSourceEndpoints(t *testing.T) {
|
|||||||
[]*endpoint.Endpoint{},
|
[]*endpoint.Endpoint{},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"FQDN template with multiple hostnames return an endpoint with target IP",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"testing",
|
||||||
|
"foo",
|
||||||
|
v1.ServiceTypeLoadBalancer,
|
||||||
|
"",
|
||||||
|
"{{.Name}}.fqdn.org,{{.Name}}.fqdn.com",
|
||||||
|
map[string]string{},
|
||||||
|
map[string]string{},
|
||||||
|
"",
|
||||||
|
[]string{"1.2.3.4"},
|
||||||
|
[]*endpoint.Endpoint{
|
||||||
|
{DNSName: "foo.fqdn.org", Targets: endpoint.Targets{"1.2.3.4"}},
|
||||||
|
{DNSName: "foo.fqdn.com", Targets: endpoint.Targets{"1.2.3.4"}},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"annotated services with multiple hostnames return an endpoint with target IP",
|
"annotated services with multiple hostnames return an endpoint with target IP",
|
||||||
"",
|
"",
|
||||||
|
Loading…
Reference in New Issue
Block a user