Support dns-controller compat mode for pod source

This commit is contained in:
Ole Markus With 2021-04-02 12:12:58 +02:00
parent 7a16ab46fa
commit 73469a0852
4 changed files with 111 additions and 12 deletions

View File

@ -284,7 +284,7 @@ Here's a rough outline on what is to come (subject to change):
- [ ] Ability to replace Kops' [DNS Controller](https://github.com/kubernetes/kops/tree/HEAD/dns-controller)
- [x] Add support for pod source
- [ ] Add support for DNS Controller annotations for pod, ingress, and service sources
- [x] Add support for DNS Controller annotations for pod and service sources
- [ ] Add support for kOps gossip provider
- [x] Ability to replace Zalando's [Mate](https://github.com/linki/mate)
- [x] Ability to replace Molecule Software's [route53-kubernetes](https://github.com/wearemolecule/route53-kubernetes)

View File

@ -38,10 +38,11 @@ type podSource struct {
namespace string
podInformer coreinformers.PodInformer
nodeInformer coreinformers.NodeInformer
compatibility string
}
// NewPodSource creates a new podSource with the given config.
func NewPodSource(kubeClient kubernetes.Interface, namespace string) (Source, error) {
func NewPodSource(kubeClient kubernetes.Interface, namespace string, compatibility string) (Source, error) {
informerFactory := kubeinformers.NewSharedInformerFactoryWithOptions(kubeClient, 0, kubeinformers.WithNamespace(namespace))
podInformer := informerFactory.Core().V1().Pods()
nodeInformer := informerFactory.Core().V1().Nodes()
@ -75,6 +76,7 @@ func NewPodSource(kubeClient kubernetes.Interface, namespace string) (Source, er
podInformer: podInformer,
nodeInformer: nodeInformer,
namespace: namespace,
compatibility: compatibility,
}, nil
}
@ -114,6 +116,28 @@ func (ps *podSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error
}
}
}
if ps.compatibility == "dns-controller" {
if domain, ok := pod.Annotations[dnsControllerInternalHostnameAnnotationKey]; ok {
if _, ok := domains[domain]; !ok {
domains[domain] = []string{}
}
domains[domain] = append(domains[domain], pod.Status.PodIP)
}
if domain, ok := pod.Annotations[dnsControllerHostnameAnnotationKey]; ok {
if _, ok := domains[domain]; !ok {
domains[domain] = []string{}
}
node, _ := ps.nodeInformer.Lister().Get(pod.Spec.NodeName)
for _, address := range node.Status.Addresses {
if address.Type == corev1.NodeExternalIP {
domains[domain] = append(domains[domain], address.Address)
}
}
}
}
}
endpoints := []*endpoint.Endpoint{}
for domain, targets := range domains {

View File

@ -32,6 +32,7 @@ func TestPodSource(t *testing.T) {
for _, tc := range []struct {
title string
targetNamespace string
compatibility string
expected []*endpoint.Endpoint
expectError bool
nodes []*corev1.Node
@ -40,6 +41,7 @@ func TestPodSource(t *testing.T) {
{
"create records based on pod's external and internal IPs",
"",
"",
[]*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},
@ -106,9 +108,80 @@ func TestPodSource(t *testing.T) {
},
},
},
{
"create records based on pod's external and internal IPs using DNS Controller annotations",
"",
"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},
},
false,
[]*corev1.Node{
{
ObjectMeta: metav1.ObjectMeta{
Name: "my-node1",
},
Status: corev1.NodeStatus{
Addresses: []corev1.NodeAddress{
{Type: corev1.NodeExternalIP, Address: "54.10.11.1"},
{Type: corev1.NodeInternalIP, Address: "10.0.1.1"},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "my-node2",
},
Status: corev1.NodeStatus{
Addresses: []corev1.NodeAddress{
{Type: corev1.NodeExternalIP, Address: "54.10.11.2"},
{Type: corev1.NodeInternalIP, Address: "10.0.1.2"},
},
},
},
},
[]*corev1.Pod{
{
ObjectMeta: metav1.ObjectMeta{
Name: "my-pod1",
Namespace: "kube-system",
Annotations: map[string]string{
dnsControllerInternalHostnameAnnotationKey: "internal.a.foo.example.org",
dnsControllerHostnameAnnotationKey: "a.foo.example.org",
},
},
Spec: corev1.PodSpec{
HostNetwork: true,
NodeName: "my-node1",
},
Status: corev1.PodStatus{
PodIP: "10.0.1.1",
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "my-pod2",
Namespace: "kube-system",
Annotations: map[string]string{
dnsControllerInternalHostnameAnnotationKey: "internal.a.foo.example.org",
dnsControllerHostnameAnnotationKey: "a.foo.example.org",
},
},
Spec: corev1.PodSpec{
HostNetwork: true,
NodeName: "my-node2",
},
Status: corev1.PodStatus{
PodIP: "10.0.1.2",
},
},
},
},
{
"create multiple records",
"",
"",
[]*endpoint.Endpoint{
{DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1"}, RecordType: endpoint.RecordTypeA},
{DNSName: "b.foo.example.org", Targets: endpoint.Targets{"54.10.11.2"}, RecordType: endpoint.RecordTypeA},
@ -176,6 +249,7 @@ func TestPodSource(t *testing.T) {
{
"pods with hostNetwore=false should be ignored",
"",
"",
[]*endpoint.Endpoint{
{DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1"}, RecordType: endpoint.RecordTypeA},
{DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1"}, RecordType: endpoint.RecordTypeA},
@ -245,6 +319,7 @@ func TestPodSource(t *testing.T) {
{
"only watch a given namespace",
"kube-system",
"",
[]*endpoint.Endpoint{
{DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1"}, RecordType: endpoint.RecordTypeA},
{DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1"}, RecordType: endpoint.RecordTypeA},
@ -332,7 +407,7 @@ func TestPodSource(t *testing.T) {
}
}
client, err := NewPodSource(kubernetes, tc.targetNamespace)
client, err := NewPodSource(kubernetes, tc.targetNamespace, tc.compatibility)
require.NoError(t, err)
endpoints, err := client.Endpoints(ctx)

View File

@ -193,7 +193,7 @@ func BuildWithConfig(source string, p ClientGenerator, cfg *Config) (Source, err
if err != nil {
return nil, err
}
return NewPodSource(client, cfg.Namespace)
return NewPodSource(client, cfg.Namespace, cfg.Compatibility)
case "istio-gateway":
kubernetesClient, err := p.KubeClient()
if err != nil {