mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2026-05-04 22:26:11 +02:00
Merge pull request #4721 from mjlshen/4713-aws-sd-ipv6
Add AWS_INSTANCE_IPV6 support to the AWS-SD provider
This commit is contained in:
commit
4033eec84b
@ -304,6 +304,32 @@ spec:
|
||||
|
||||
This will set the TTL for the DNS record to 60 seconds.
|
||||
|
||||
## IPv6 Support
|
||||
|
||||
If your Kubernetes cluster is configured with IPv6 support, such as an [EKS cluster with IPv6 support](https://docs.aws.amazon.com/eks/latest/userguide/deploy-ipv6-cluster.html), ExternalDNS can
|
||||
also create AAAA DNS records.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/hostname: nginx.external-dns-test.my-org.com
|
||||
external-dns.alpha.kubernetes.io/ttl: "60"
|
||||
spec:
|
||||
ipFamilies:
|
||||
- "IPv6"
|
||||
type: NodePort
|
||||
ports:
|
||||
- port: 80
|
||||
name: http
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: nginx
|
||||
```
|
||||
|
||||
:information_source: The AWS-SD provider does not currently support dualstack load balancers and will only create A records for these at this time. See the AWS provider and the [AWS Load Balancer Controller Tutorial](./aws-load-balancer-controller.md) for dualstack load balancer support.
|
||||
|
||||
## Clean up
|
||||
|
||||
|
||||
@ -41,6 +41,7 @@ const (
|
||||
sdNamespaceTypePrivate = "private"
|
||||
|
||||
sdInstanceAttrIPV4 = "AWS_INSTANCE_IPV4"
|
||||
sdInstanceAttrIPV6 = "AWS_INSTANCE_IPV6"
|
||||
sdInstanceAttrCname = "AWS_INSTANCE_CNAME"
|
||||
sdInstanceAttrAlias = "AWS_ALIAS_DNS_NAME"
|
||||
)
|
||||
@ -186,10 +187,15 @@ func (p *AWSSDProvider) instancesToEndpoint(ns *sdtypes.NamespaceSummary, srv *s
|
||||
newEndpoint.RecordType = endpoint.RecordTypeCNAME
|
||||
newEndpoint.Targets = append(newEndpoint.Targets, inst.Attributes[sdInstanceAttrAlias])
|
||||
|
||||
// IP-based target
|
||||
// IPv4-based target
|
||||
} else if inst.Attributes[sdInstanceAttrIPV4] != "" {
|
||||
newEndpoint.RecordType = endpoint.RecordTypeA
|
||||
newEndpoint.Targets = append(newEndpoint.Targets, inst.Attributes[sdInstanceAttrIPV4])
|
||||
|
||||
// IPv6-based target
|
||||
} else if inst.Attributes[sdInstanceAttrIPV6] != "" {
|
||||
newEndpoint.RecordType = endpoint.RecordTypeAAAA
|
||||
newEndpoint.Targets = append(newEndpoint.Targets, inst.Attributes[sdInstanceAttrIPV6])
|
||||
} else {
|
||||
log.Warnf("Invalid instance \"%v\" found in service \"%v\"", inst, srv.Name)
|
||||
}
|
||||
@ -485,15 +491,18 @@ func (p *AWSSDProvider) RegisterInstance(ctx context.Context, service *sdtypes.S
|
||||
|
||||
attr := make(map[string]string)
|
||||
|
||||
if ep.RecordType == endpoint.RecordTypeCNAME {
|
||||
switch ep.RecordType {
|
||||
case endpoint.RecordTypeCNAME:
|
||||
if p.isAWSLoadBalancer(target) {
|
||||
attr[sdInstanceAttrAlias] = target
|
||||
} else {
|
||||
attr[sdInstanceAttrCname] = target
|
||||
}
|
||||
} else if ep.RecordType == endpoint.RecordTypeA {
|
||||
case endpoint.RecordTypeA:
|
||||
attr[sdInstanceAttrIPV4] = target
|
||||
} else {
|
||||
case endpoint.RecordTypeAAAA:
|
||||
attr[sdInstanceAttrIPV6] = target
|
||||
default:
|
||||
return fmt.Errorf("invalid endpoint type (%v)", ep)
|
||||
}
|
||||
|
||||
@ -597,16 +606,17 @@ func (p *AWSSDProvider) parseHostname(hostname string) (namespace string, servic
|
||||
|
||||
// determine service routing policy based on endpoint type
|
||||
func (p *AWSSDProvider) routingPolicyFromEndpoint(ep *endpoint.Endpoint) sdtypes.RoutingPolicy {
|
||||
if ep.RecordType == endpoint.RecordTypeA {
|
||||
if ep.RecordType == endpoint.RecordTypeA || ep.RecordType == endpoint.RecordTypeAAAA {
|
||||
return sdtypes.RoutingPolicyMultivalue
|
||||
}
|
||||
|
||||
return sdtypes.RoutingPolicyWeighted
|
||||
}
|
||||
|
||||
// determine service type (A, CNAME) from given endpoint
|
||||
// determine service type (A, AAAA, CNAME) from given endpoint
|
||||
func (p *AWSSDProvider) serviceTypeFromEndpoint(ep *endpoint.Endpoint) sdtypes.RecordType {
|
||||
if ep.RecordType == endpoint.RecordTypeCNAME {
|
||||
switch ep.RecordType {
|
||||
case endpoint.RecordTypeCNAME:
|
||||
// FIXME service type is derived from the first target only. Theoretically this may be problem.
|
||||
// But I don't see a scenario where one endpoint contains targets of different types.
|
||||
if p.isAWSLoadBalancer(ep.Targets[0]) {
|
||||
@ -614,8 +624,11 @@ func (p *AWSSDProvider) serviceTypeFromEndpoint(ep *endpoint.Endpoint) sdtypes.R
|
||||
return sdtypes.RecordTypeA
|
||||
}
|
||||
return sdtypes.RecordTypeCname
|
||||
case endpoint.RecordTypeAAAA:
|
||||
return sdtypes.RecordTypeAaaa
|
||||
default:
|
||||
return sdtypes.RecordTypeA
|
||||
}
|
||||
return sdtypes.RecordTypeA
|
||||
}
|
||||
|
||||
// determine if a given hostname belongs to an AWS load balancer
|
||||
|
||||
@ -307,6 +307,19 @@ func TestAWSSDProvider_Records(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
},
|
||||
"aaaa-srv": {
|
||||
Id: aws.String("aaaa-srv"),
|
||||
Name: aws.String("service4"),
|
||||
Description: aws.String("owner-id"),
|
||||
DnsConfig: &sdtypes.DnsConfig{
|
||||
NamespaceId: aws.String("private"),
|
||||
RoutingPolicy: sdtypes.RoutingPolicyWeighted,
|
||||
DnsRecords: []sdtypes.DnsRecord{{
|
||||
Type: sdtypes.RecordTypeAaaa,
|
||||
TTL: aws.Int64(100),
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -341,12 +354,21 @@ func TestAWSSDProvider_Records(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"aaaa-srv": {
|
||||
"0000:0000:0000:0000:abcd:abcd:abcd:abcd": {
|
||||
Id: aws.String("0000:0000:0000:0000:abcd:abcd:abcd:abcd"),
|
||||
Attributes: map[string]string{
|
||||
sdInstanceAttrIPV6: "0000:0000:0000:0000:abcd:abcd:abcd:abcd",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expectedEndpoints := []*endpoint.Endpoint{
|
||||
{DNSName: "service1.private.com", Targets: endpoint.Targets{"1.2.3.4", "1.2.3.5"}, RecordType: endpoint.RecordTypeA, RecordTTL: 100, Labels: map[string]string{endpoint.AWSSDDescriptionLabel: "owner-id"}},
|
||||
{DNSName: "service2.private.com", Targets: endpoint.Targets{"load-balancer.us-east-1.elb.amazonaws.com"}, RecordType: endpoint.RecordTypeCNAME, RecordTTL: 100, Labels: map[string]string{endpoint.AWSSDDescriptionLabel: "owner-id"}},
|
||||
{DNSName: "service3.private.com", Targets: endpoint.Targets{"cname.target.com"}, RecordType: endpoint.RecordTypeCNAME, RecordTTL: 80, Labels: map[string]string{endpoint.AWSSDDescriptionLabel: "owner-id"}},
|
||||
{DNSName: "service4.private.com", Targets: endpoint.Targets{"0000:0000:0000:0000:abcd:abcd:abcd:abcd"}, RecordType: endpoint.RecordTypeAAAA, RecordTTL: 100, Labels: map[string]string{endpoint.AWSSDDescriptionLabel: "owner-id"}},
|
||||
}
|
||||
|
||||
api := &AWSSDClientStub{
|
||||
@ -557,6 +579,28 @@ func TestAWSSDProvider_CreateService(t *testing.T) {
|
||||
NamespaceId: aws.String("private"),
|
||||
}
|
||||
|
||||
// AAAA type
|
||||
provider.CreateService(context.Background(), aws.String("private"), aws.String("AAAA-srv"), &endpoint.Endpoint{
|
||||
Labels: map[string]string{
|
||||
endpoint.AWSSDDescriptionLabel: "AAAA-srv",
|
||||
},
|
||||
RecordType: endpoint.RecordTypeAAAA,
|
||||
RecordTTL: 60,
|
||||
Targets: endpoint.Targets{"::1234:5678:"},
|
||||
})
|
||||
expectedServices["AAAA-srv"] = &sdtypes.Service{
|
||||
Name: aws.String("AAAA-srv"),
|
||||
Description: aws.String("AAAA-srv"),
|
||||
DnsConfig: &sdtypes.DnsConfig{
|
||||
RoutingPolicy: sdtypes.RoutingPolicyMultivalue,
|
||||
DnsRecords: []sdtypes.DnsRecord{{
|
||||
Type: sdtypes.RecordTypeAaaa,
|
||||
TTL: aws.Int64(60),
|
||||
}},
|
||||
},
|
||||
NamespaceId: aws.String("private"),
|
||||
}
|
||||
|
||||
// CNAME type
|
||||
provider.CreateService(context.Background(), aws.String("private"), aws.String("CNAME-srv"), &endpoint.Endpoint{
|
||||
Labels: map[string]string{
|
||||
@ -768,6 +812,19 @@ func TestAWSSDProvider_RegisterInstance(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
},
|
||||
"aaaa-srv": {
|
||||
Id: aws.String("aaaa-srv"),
|
||||
Name: aws.String("service4"),
|
||||
Description: aws.String("owner-id"),
|
||||
DnsConfig: &sdtypes.DnsConfig{
|
||||
NamespaceId: aws.String("private"),
|
||||
RoutingPolicy: sdtypes.RoutingPolicyWeighted,
|
||||
DnsRecords: []sdtypes.DnsRecord{{
|
||||
Type: sdtypes.RecordTypeAaaa,
|
||||
TTL: aws.Int64(100),
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -781,7 +838,7 @@ func TestAWSSDProvider_RegisterInstance(t *testing.T) {
|
||||
|
||||
expectedInstances := make(map[string]*sdtypes.Instance)
|
||||
|
||||
// IP-based instance
|
||||
// IPv4-based instance
|
||||
provider.RegisterInstance(context.Background(), services["private"]["a-srv"], &endpoint.Endpoint{
|
||||
RecordType: endpoint.RecordTypeA,
|
||||
DNSName: "service1.private.com.",
|
||||
@ -849,6 +906,20 @@ func TestAWSSDProvider_RegisterInstance(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
// IPv6-based instance
|
||||
provider.RegisterInstance(context.Background(), services["private"]["aaaa-srv"], &endpoint.Endpoint{
|
||||
RecordType: endpoint.RecordTypeAAAA,
|
||||
DNSName: "service4.private.com.",
|
||||
RecordTTL: 300,
|
||||
Targets: endpoint.Targets{"0000:0000:0000:0000:abcd:abcd:abcd:abcd"},
|
||||
})
|
||||
expectedInstances["0000:0000:0000:0000:abcd:abcd:abcd:abcd"] = &sdtypes.Instance{
|
||||
Id: aws.String("0000:0000:0000:0000:abcd:abcd:abcd:abcd"),
|
||||
Attributes: map[string]string{
|
||||
sdInstanceAttrIPV6: "0000:0000:0000:0000:abcd:abcd:abcd:abcd",
|
||||
},
|
||||
}
|
||||
|
||||
// validate instances
|
||||
for _, srvInst := range api.instances {
|
||||
for id, inst := range srvInst {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user