-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DigitalOcean: support multiple targets per endpoint #1595
DigitalOcean: support multiple targets per endpoint #1595
Conversation
Thanks for your pull request. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please follow instructions at https://git.k8s.io/community/CLA.md#the-contributor-license-agreement to sign the CLA. It may take a couple minutes for the CLA signature to be fully registered; after that, please reply here with a new comment and we'll verify. Thanks.
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
Welcome @tdyas! |
/assign @hjacobs |
7a34cd0
to
f19d0bc
Compare
/assign @Raffo |
cc @andrewsomething: Just a heads up in case anyone at DigitalOcean has an interest in external-dns or Kubernetes stuff. |
d0af711
to
ba05243
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this PR @tdyas especially for the great explanation of what this is doing, I really enjoyed reading it.
I added a few minor comments, but overall the code looks okay.
ttl = int(endpoint.RecordTTL) | ||
// ApplyChanges applies the given set of generic changes to the provider. | ||
func (p *DigitalOceanProvider) ApplyChanges(ctx context.Context, planChanges *plan.Changes) error { | ||
// TODO: This should only retrieve zones affected by the given `planChanges`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we have this done before merging this PR or do you want to keep it like this? What are the consequences?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not implementing this TODO would leave the status quo in place which is that we would just retrieve all of the records that Records
retrieves, just as the existing version of the provider does. (--domain-filter
would still be applied to limit the provider to only those zones where external-dns is managing records.)
My concern here was for avoiding having to retrieve all of the records if the zone had potentially many records. #1429 was on my mind as it flagged too many API calls as a potential hazard in such cases.
This TODO is a nice to have but should not block landing this PR.
@andrewsomething should you be willing to maintain the DO provider, feel free to ping me here or on slack, we are trying to scale how we maintain providers and we would definitely be happy to have someone from DO maintain the DO provider 😄 |
7174db3
to
84e514b
Compare
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: Raffo, tdyas The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
map multiple DNS records with the same name/type into the external-dns which models such records as a single Endpoint with multiple entries in the Targets attribute. Solution: Generalize the solution introduced to the DigitalOcean provider by kubernetes-sigs#1595 by refactoring the mergeEndpointsByNameType function into the endpoint module. Then use that function in the RFC2136 provider. Authored-by: Tom Dyas <[email protected]> Signed-off-by: Bogdan Dobrelya <[email protected]>
map multiple DNS records with the same name/type into the external-dns which models such records as a single Endpoint with multiple entries in the Targets attribute. Solution: Generalize the solution introduced to the DigitalOcean provider by kubernetes-sigs#1595 by refactoring the mergeEndpointsByNameType function into the endpoint module. Then use that function in the RFC2136 provider. Authored-by: Tom Dyas <[email protected]> Signed-off-by: Bogdan Dobrelya <[email protected]>
This PR teaches the DigialOcean provider how to support multiple targets per endpoint. (The DigitalOcean provider currently only supports one endpoint per target which other providers do support.)
The Problem
I am running nginx-ingress in DaemonSet mode with host networking enabled on my Kubernetes cluster. I want the IPs for every node running nginx-ingress to appear as
A
records in DNS. First, because the DigitalOcean provider only supports one endpoint per ingress currently, only one of the A records is created which means the additional nginx-ingress pods will not receive traffic.Moreover, because
external-dns
believes that there should be multiple A records for the endpoint in question, the reconciliation loop never converges and external-dns continually sends update API calls every minute. This is not how external-dns seems intended to operate. (Indeed, with this PR, the reconciliation loop does converge and avoids sending an update every minute.)Solution
If the DigitalOcean API were like the AWS or GCP APIs, then the API representation of a DNS record would have an attribute that is a list of RR datas, and supporting multiple targets per endpoint would be as simple as setting that attribute to the list of targets. The DigitalOcean API is not like that though because it represents multiple A records as multiple "domain record" instances.
This representation is actually quite similar to the Linode API. The Linode provider models updates by expanding an endpoint with multiple targets into multiple domain records to be sent to the Linode API. I have taken that approach with this PR: The DigitalOcean provider now expands an endpoint with multiple targets into multiple
godo.DomainRecord
instances.Overview of the changes:
The provider's
Records
method uses the newmergeEndpointsByNameType
function to combine multiplegodo.DomainRecord
s for the same DNS name into a singleendpoint.Endpoint
with multiple targets. This maps the DigitalOcean representation to theexternal-dns
data modelThe provider's
ApplyChanges
method has been rewritten to compute a set ofdigitalOceanChangeCreate
,digitalOceanChangeUpdate
, anddigitalOceanChangeDelete
instances representing how to modify thegodo.DomainRecord
instances associated with agodo.Domain
. Computation of each type of change has been put into theprocessCreateActions
,processUpdateActions
, andprocessDeleteActions
functions.Tests: Lots more testing of individual functions. I added go-cmp to the project so I could use its Equal and Diff functions. These handle structs with nested pointers to other structs much better than the testify package. I did that so I could actually compare the *godo.DomainRecordEditRequest struct contained in the change structs. (Added a TODO to try and see if testify would be willing to allow custom matching functions.)
Upgraded godo to the latest just to keep it current.
go
bumped the version of two other packages in the go.mod as well, not sure why it did that.This is currently in production for my cluster. Seems to be working nicely. I did some basic tests against production by deleting and adding some records and external-dns figures out what changed and fixes it. And the reconciliation loop actually converges.