Repository: containous/maesh (go)

Issue:
Maesh Corefile patch: upstream causing coredns to crash
<!-- PLEASE FOLLOW THE ISSUE TEMPLATE TO HELP TRIAGE AND SUPPORT! -->

## Bug Report

`upstream` in CoreDNS Corefile is causing it to end in a crash loop with the following error:

```
Error during parsing: unknown property 'upstream'
```

### What did you do?

Installed Maesh v1.3.2 with the official Helm chart.

<!--
HOW TO WRITE A GOOD BUG REPORT?

- Respect the issue template as much as possible.
- The title should be short and descriptive.
- Explain the conditions which led you to report this issue: the context.
- The context should lead to something, an idea or a problem that you’re facing.
- Remain clear and concise.
- Format your messages to help the reader focus on what matters and understand the structure of your message, use Markdown syntax https://help.github.com/articles/github-flavored-markdown
-->

### What did you expect to see?

CoreDNS pod functioning.

### What did you see instead?

CoreDNS pod in a crash loop, outputting the following logs:

```
$ kubectl logs deploy/coredns -n kube-system
plugin/kubernetes: /etc/coredns/Corefile:25 - Error during parsing: unknown property 'upstream'
```

But when I edit the `coredns` ConfigMap and remove `upstream`, the `coredns` pod runs appropriately.

### Output of controller log: (_What version of Maesh are you using?_)

<!---
`latest` is not considered as a valid version.
We need a release number!
-->

```
v1.3.2
```

### What is your environment & configuration (arguments, provider, platform, ...)?

N/A

### If applicable, please paste the yaml objects required to reproduce your issue

```
kind: ConfigMap
apiVersion: v1
metadata:
  name: coredns
  namespace: kube-system
  selfLink: /api/v1/namespaces/kube-system/configmaps/coredns
  uid: 0abbbf22-0f79-424e-a22c-e7eabf6d9465
  resourceVersion: '2842406969'
  creationTimestamp: '2020-06-10T11:24:47Z'
  labels:
    addonmanager.kubernetes.io/mode: EnsureExists
    k8s.scw.cloud/object: ConfigMap
    k8s.scw.cloud/system: coredns
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: >
      {"apiVersion":"v1","data":{"Corefile":".:53 {\n    errors\n    health\n   
      kubernetes cluster.local in-addr.arpa ip6.arpa {\n        pods
      insecure\n        fallthrough in-addr.arpa ip6.arpa\n    }\n    prometheus
      :9153\n    forward . /etc/resolv.conf\n    cache 30\n    loop\n   
      reload\n   
      loadbalance\n}\n"},"kind":"ConfigMap","metadata":{"annotations":{},"labels":{"addonmanager.kubernetes.io/mode":"EnsureExists","k8s.scw.cloud/object":"ConfigMap","k8s.scw.cloud/system":"coredns"},"name":"coredns","namespace":"kube-system"}}
  managedFields:
    - manager: kubectl
      operation: Update
      apiVersion: v1
      time: '2020-07-22T11:51:06Z'
      fieldsType: FieldsV1
      fieldsV1:error
        'f:data': {}
        'f:metadata':
          'f:annotations':
            .: {}
            'f:kubectl.kubernetes.io/last-applied-configuration': {}
          'f:labels':
            .: {}
            'f:addonmanager.kubernetes.io/mode': {}
            'f:k8s.scw.cloud/object': {}
            'f:k8s.scw.cloud/system': {}
    - manager: maesh
      operation: Update
      apiVersion: v1
      time: '2020-07-22T15:51:12Z'
      fieldsType: FieldsV1
      fieldsV1:
        'f:data':
          'f:Corefile': {}
data:
  Corefile: |
    .:53 {
        errors
        health
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    }

    #### Begin Maesh Block
    maesh:53 {
        errors
        rewrite continue {
            name regex ([a-zA-Z0-9-_]*)\.([a-zv0-9-_]*)\.maesh maesh-{1}-6d61657368-{2}.maesh.svc.cluster.local
            answer name maesh-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\.maesh\.svc\.cluster\.local {1}.{2}.maesh
        }
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            upstream
            fallthrough in-addr.arpa ip6.arpa
        }
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    }
    #### End Maesh Block
```

Pull request description:
Fix CoreDNS config if version is greater than or equal to 1.7
## What does this PR do?

This PR:

- Removes the `upstream` keyword in the CoreDNS config if version is greater than `1.7` 

Fixes #685 

<!-- A brief description of the change being made with this pull request. -->

### How to test it

* make test
* make test-integration

Patch:
diff --git a/pkg/dns/dns.go b/pkg/dns/dns.go
index 6f7166e..daa747d 100644
--- a/pkg/dns/dns.go
+++ b/pkg/dns/dns.go
@@ -10,6 +10,7 @@ import (
 	"github.com/cenkalti/backoff/v4"
 	"github.com/containous/traefik/v2/pkg/safe"
 	"github.com/google/uuid"
+	goversion "github.com/hashicorp/go-version"
 	"github.com/sirupsen/logrus"
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
@@ -31,15 +32,7 @@ const (
 	coreFileTrailer = "#### End Maesh Block"
 )
 
-var (
-	supportedCoreDNSVersions = []string{
-		"1.3",
-		"1.4",
-		"1.5",
-		"1.6",
-		"1.7",
-	}
-)
+var versionCoreDNS17 = goversion.Must(goversion.NewVersion("1.7"))
 
 // Client holds the client for interacting with the k8s DNS system.
 type Client struct {
@@ -84,6 +77,7 @@ func (c *Client) coreDNSMatch() (bool, error) {
 	c.logger.Info("Checking CoreDNS")
 
 	deployment, err := c.kubeClient.AppsV1().Deployments(metav1.NamespaceSystem).Get("coredns", metav1.GetOptions{})
+
 	if kerrors.IsNotFound(err) {
 		c.logger.Debugf("CoreDNS deployment does not exist in namespace %q", metav1.NamespaceSystem)
 		return false, nil
@@ -93,19 +87,18 @@ func (c *Client) coreDNSMatch() (bool, error) {
 		return false, fmt.Errorf("unable to get CoreDNS deployment in namespace %q: %w", metav1.NamespaceSystem, err)
 	}
 
-	var version string
-
-	for _, container := range deployment.Spec.Template.Spec.Containers {
-		if container.Name != "coredns" {
-			continue
-		}
+	version, err := c.getCoreDNSVersion(deployment)
+	if err != nil {
+		return false, err
+	}
 
-		sp := strings.Split(container.Image, ":")
-		version = sp[len(sp)-1]
+	versionConstraint, err := goversion.NewConstraint(">= 1.3, < 1.8")
+	if err != nil {
+		return false, err
 	}
 
-	if !isCoreDNSVersionSupported(version) {
-		return false, fmt.Errorf("unsupported CoreDNS version %q, (supported versions are: %s)", version, strings.Join(supportedCoreDNSVersions, ","))
+	if !versionConstraint.Check(version) {
+		return false, fmt.Errorf("unsupported CoreDNS version %q", version)
 	}
 
 	c.logger.Info("CoreDNS match")
@@ -113,16 +106,6 @@ func (c *Client) coreDNSMatch() (bool, error) {
 	return true, nil
 }
 
-func isCoreDNSVersionSupported(versionLine string) bool {
-	for _, v := range supportedCoreDNSVersions {
-		if strings.Contains(versionLine, v) {
-			return true
-		}
-	}
-
-	return false
-}
-
 func (c *Client) kubeDNSMatch() (bool, error) {
 	c.logger.Info("Checking KubeDNS")
 
@@ -169,6 +152,11 @@ func (c *Client) ConfigureCoreDNS(coreDNSNamespace, clusterDomain, maeshNamespac
 }
 
 func (c *Client) patchCoreDNSConfig(deployment *appsv1.Deployment, clusterDomain, maeshNamespace string) (*corev1.ConfigMap, error) {
+	coreDNSVersion, err := c.getCoreDNSVersion(deployment)
+	if err != nil {
+		return nil, err
+	}
+
 	customConfigMap, err := c.getConfigMap(deployment, "coredns-custom")
 
 	// For AKS the CoreDNS config have to be added to the coredns-custom ConfigMap.
@@ -178,6 +166,7 @@ func (c *Client) patchCoreDNSConfig(deployment *appsv1.Deployment, clusterDomain
 			clusterDomain,
 			maeshNamespace,
 			"",
+			coreDNSVersion,
 		)
 
 		return customConfigMap, nil
@@ -192,12 +181,18 @@ func (c *Client) patchCoreDNSConfig(deployment *appsv1.Deployment, clusterDomain
 		clusterDomain,
 		maeshNamespace,
 		coreDNSConfigMap.Data["Corefile"],
+		coreDNSVersion,
 	)
 
 	return coreDNSConfigMap, nil
 }
 
-func (c *Client) addMaeshStubDomain(clusterDomain, maeshNamespace, coreDNSConfig string) string {
+func (c *Client) addMaeshStubDomain(clusterDomain, maeshNamespace, coreDNSConfig string, coreDNSVersion *goversion.Version) string {
+	// config already contains the maesh block.
+	if strings.Contains(coreDNSConfig, coreFileHeader) {
+		return coreDNSConfig
+	}
+
 	stubDomainFormat := `
 %[4]s
 maesh:53 {
@@ -208,7 +203,7 @@ maesh:53 {
     }
     kubernetes %[1]s in-addr.arpa ip6.arpa {
         pods insecure
-        upstream
+        %[6]s
         fallthrough in-addr.arpa ip6.arpa
     }
     forward . /etc/resolv.conf
@@ -219,6 +214,11 @@ maesh:53 {
 }
 %[5]s
 `
+	upstream := ""
+
+	if coreDNSVersion.LessThan(versionCoreDNS17) {
+		upstream = "upstream"
+	}
 
 	stubDomain := fmt.Sprintf(stubDomainFormat,
 		clusterDomain,
@@ -226,14 +226,24 @@ maesh:53 {
 		maeshNamespace,
 		coreFileHeader,
 		coreFileTrailer,
+		upstream,
 	)
 
-	// CoreDNS config already contains the maesh block.
-	if strings.Contains(coreDNSConfig, coreFileHeader) {
-		return coreDNSConfig
+	return coreDNSConfig + stubDomain
+}
+
+func (c *Client) getCoreDNSVersion(deployment *appsv1.Deployment) (*goversion.Version, error) {
+	for _, container := range deployment.Spec.Template.Spec.Containers {
+		if container.Name != "coredns" {
+			continue
+		}
+
+		parts := strings.Split(container.Image, ":")
+
+		return goversion.NewVersion(parts[len(parts)-1])
 	}
 
-	return coreDNSConfig + stubDomain
+	return nil, fmt.Errorf("unable to get CoreDNS container in deployment %q/%q", deployment.Namespace, deployment.Name)
 }
 
 // ConfigureKubeDNS patches the KubeDNS configuration for Maesh.


Test patch:
diff --git a/integration/coredns_test.go b/integration/coredns_test.go
index 1d795ab..7266999 100644
--- a/integration/coredns_test.go
+++ b/integration/coredns_test.go
@@ -21,6 +21,7 @@ func (s *CoreDNSSuite) SetUpSuite(c *check.C) {
 		"coredns/coredns:1.7.0",
 		"giantswarm/tiny-tools:3.9",
 	}
+
 	s.startk3s(c, requiredImages)
 	s.startWhoami(c)
 	s.installTinyToolsMaesh(c)
@@ -54,12 +55,11 @@ func (s *CoreDNSSuite) TestCoreDNSVersionSafe(c *check.C) {
 		},
 	}
 
-	s.createResources(c, "testdata/coredns/corednssafe.yaml")
-	defer s.deleteResources(c, "testdata/coredns/corednssafe.yaml")
-
 	for _, test := range testCases {
+		s.createResources(c, "testdata/coredns/corednssafe.yaml")
 		s.WaitForCoreDNS(c)
-		c.Log("Testing compatibility with " + test.desc)
+
+		c.Logf("Testing compatibility with %s", test.desc)
 		s.setCoreDNSVersion(c, test.version)
 
 		cmd := s.maeshPrepareWithArgs()
@@ -73,6 +73,8 @@ func (s *CoreDNSSuite) TestCoreDNSVersionSafe(c *check.C) {
 		} else {
 			c.Assert(err, checker.IsNil)
 		}
+
+		s.deleteResources(c, "testdata/coredns/corednssafe.yaml")
 	}
 }
 
@@ -95,12 +97,11 @@ func (s *CoreDNSSuite) TestCoreDNSVersion(c *check.C) {
 		},
 	}
 
-	s.createResources(c, "testdata/coredns/coredns.yaml")
-	defer s.deleteResources(c, "testdata/coredns/coredns.yaml")
-
 	for _, test := range testCases {
+		s.createResources(c, "testdata/coredns/coredns.yaml")
 		s.WaitForCoreDNS(c)
-		c.Log("Testing compatibility with " + test.desc)
+
+		c.Logf("Testing compatibility with %s", test.desc)
 		s.setCoreDNSVersion(c, test.version)
 
 		cmd := s.maeshPrepareWithArgs()
@@ -109,22 +110,44 @@ func (s *CoreDNSSuite) TestCoreDNSVersion(c *check.C) {
 
 		c.Log(string(output))
 		c.Assert(err, checker.IsNil)
+
+		s.deleteResources(c, "testdata/coredns/coredns.yaml")
 	}
 }
 
 func (s *CoreDNSSuite) TestCoreDNSDig(c *check.C) {
-	s.createResources(c, "testdata/coredns/coredns.yaml")
-	defer s.deleteResources(c, "testdata/coredns/coredns.yaml")
-	s.WaitForCoreDNS(c)
+	testCases := []struct {
+		desc    string
+		version string
+	}{
+		{
+			desc:    "CoreDNS 1.6.3",
+			version: "1.6.3",
+		},
+		{
+			desc:    "CoreDNS 1.7.0",
+			version: "1.7.0",
+		},
+	}
+
+	for _, test := range testCases {
+		s.createResources(c, "testdata/coredns/coredns.yaml")
+		s.WaitForCoreDNS(c)
 
-	cmd := s.startMaeshBinaryCmd(c, false, false)
-	err := cmd.Start()
+		c.Logf("Testing dig with %s", test.desc)
+		s.setCoreDNSVersion(c, test.version)
 
-	c.Assert(err, checker.IsNil)
-	defer s.stopMaeshBinary(c, cmd.Process)
+		cmd := s.startMaeshBinaryCmd(c, false, false)
 
-	pod := s.getToolsPodMaesh(c)
-	c.Assert(pod, checker.NotNil)
+		err := cmd.Start()
+		c.Assert(err, checker.IsNil)
 
-	s.digHost(c, pod.Name, pod.Namespace, "whoami.whoami.maesh")
+		pod := s.getToolsPodMaesh(c)
+		c.Assert(pod, checker.NotNil)
+
+		s.digHost(c, pod.Name, pod.Namespace, "whoami.whoami.maesh")
+		s.stopMaeshBinary(c, cmd.Process)
+
+		s.deleteResources(c, "testdata/coredns/coredns.yaml")
+	}
 }
diff --git a/integration/testdata/coredns/coredns.yaml b/integration/testdata/coredns/coredns.yaml
index 625dd66..71604e5 100644
--- a/integration/testdata/coredns/coredns.yaml
+++ b/integration/testdata/coredns/coredns.yaml
@@ -58,7 +58,6 @@ data:
         ready
         kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
-          upstream
           fallthrough in-addr.arpa ip6.arpa
         }
         hosts /etc/coredns/NodeHosts {
diff --git a/integration/testdata/coredns/corednssafe.yaml b/integration/testdata/coredns/corednssafe.yaml
index 1df7192..046c283 100644
--- a/integration/testdata/coredns/corednssafe.yaml
+++ b/integration/testdata/coredns/corednssafe.yaml
@@ -57,7 +57,6 @@ data:
         health
         kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
-          upstream
           fallthrough in-addr.arpa ip6.arpa
         }
         hosts /etc/coredns/NodeHosts {
diff --git a/pkg/dns/dns_test.go b/pkg/dns/dns_test.go
index 276be9b..ac408fd 100644
--- a/pkg/dns/dns_test.go
+++ b/pkg/dns/dns_test.go
@@ -110,6 +110,12 @@ func TestConfigureCoreDNS(t *testing.T) {
 			expectedCorefile: ".:53 {\n    errors\n    health {\n        lameduck 5s\n    }\n    ready\n    kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {\n        pods insecure\n        fallthrough in-addr.arpa ip6.arpa\n        ttl 30\n    }\n    prometheus :9153\n    forward . /etc/resolv.conf\n    cache 30\n    loop\n    reload\n    loadbalance\n}\n",
 			expectedCustom:   "\n#### Begin Maesh Block\nmaesh:53 {\n    errors\n    rewrite continue {\n        name regex ([a-zA-Z0-9-_]*)\\.([a-zv0-9-_]*)\\.maesh toto-{1}-6d61657368-{2}.toto.svc.titi\n        answer name toto-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\\.toto\\.svc\\.titi {1}.{2}.maesh\n    }\n    kubernetes titi in-addr.arpa ip6.arpa {\n        pods insecure\n        upstream\n        fallthrough in-addr.arpa ip6.arpa\n    }\n    forward . /etc/resolv.conf\n    cache 30\n    loop\n    reload\n    loadbalance\n}\n#### End Maesh Block\n",
 		},
+		{
+			desc:             "Config of CoreDNS 1.7",
+			mockFile:         "configurecoredns_17.yaml",
+			expectedErr:      false,
+			expectedCorefile: ".:53 {\n    errors\n    health {\n        lameduck 5s\n    }\n    ready\n    kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {\n        pods insecure\n        fallthrough in-addr.arpa ip6.arpa\n        ttl 30\n    }\n    prometheus :9153\n    forward . /etc/resolv.conf\n    cache 30\n    loop\n    reload\n    loadbalance\n}\n\n#### Begin Maesh Block\nmaesh:53 {\n    errors\n    rewrite continue {\n        name regex ([a-zA-Z0-9-_]*)\\.([a-zv0-9-_]*)\\.maesh toto-{1}-6d61657368-{2}.toto.svc.titi\n        answer name toto-([a-zA-Z0-9-_]*)-6d61657368-([a-zA-Z0-9-_]*)\\.toto\\.svc\\.titi {1}.{2}.maesh\n    }\n    kubernetes titi in-addr.arpa ip6.arpa {\n        pods insecure\n        \n        fallthrough in-addr.arpa ip6.arpa\n    }\n    forward . /etc/resolv.conf\n    cache 30\n    loop\n    reload\n    loadbalance\n}\n#### End Maesh Block\n",
+		},
 		{
 			desc:        "Missing CoreDNS deployment",
 			mockFile:    "configurecoredns_missing_deployment.yaml",
diff --git a/pkg/dns/testdata/configurecoredns_17.yaml b/pkg/dns/testdata/configurecoredns_17.yaml
new file mode 100644
index 0000000..3a72c72
--- /dev/null
+++ b/pkg/dns/testdata/configurecoredns_17.yaml
@@ -0,0 +1,48 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: coredns
+  namespace: kube-system
+spec:
+  template:
+    spec:
+      containers:
+        - name: coredns
+          image: coredns:1.7.0
+      volumes:
+        - configMap:
+            name: "other-cfgmap"
+        - configMap:
+            name: "coredns"
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: other-cfgmap
+  namespace: kube-system
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: coredns
+  namespace: kube-system
+data:
+  Corefile: |
+    .:53 {
+        errors
+        health {
+            lameduck 5s
+        }
+        ready
+        kubernetes {{ pillar['dns_domain'] }} in-addr.arpa ip6.arpa {
+            pods insecure
+            fallthrough in-addr.arpa ip6.arpa
+            ttl 30
+        }
+        prometheus :9153
+        forward . /etc/resolv.conf
+        cache 30
+        loop
+        reload
+        loadbalance
+    }
diff --git a/pkg/dns/testdata/configurecoredns_already_patched.yaml b/pkg/dns/testdata/configurecoredns_already_patched.yaml
index 6575591..8a98c64 100644
--- a/pkg/dns/testdata/configurecoredns_already_patched.yaml
+++ b/pkg/dns/testdata/configurecoredns_already_patched.yaml
@@ -6,6 +6,9 @@ metadata:
 spec:
   template:
     spec:
+      containers:
+        - name: coredns
+          image: coredns:1.6.0
       volumes:
         - configMap:
             name: "other-cfgmap"
diff --git a/pkg/dns/testdata/configurecoredns_custom_already_patched.yaml b/pkg/dns/testdata/configurecoredns_custom_already_patched.yaml
index 3c4c750..f4cce8c 100644
--- a/pkg/dns/testdata/configurecoredns_custom_already_patched.yaml
+++ b/pkg/dns/testdata/configurecoredns_custom_already_patched.yaml
@@ -6,6 +6,9 @@ metadata:
 spec:
   template:
     spec:
+      containers:
+        - name: coredns
+          image: coredns:1.6.0
       volumes:
         - configMap:
             name: "coredns"
diff --git a/pkg/dns/testdata/configurecoredns_custom_not_patched.yaml b/pkg/dns/testdata/configurecoredns_custom_not_patched.yaml
index 2d92699..a2c7bf6 100644
--- a/pkg/dns/testdata/configurecoredns_custom_not_patched.yaml
+++ b/pkg/dns/testdata/configurecoredns_custom_not_patched.yaml
@@ -6,6 +6,9 @@ metadata:
 spec:
   template:
     spec:
+      containers:
+        - name: coredns
+          image: coredns:1.6.0
       volumes:
         - configMap:
             name: "coredns"
diff --git a/pkg/dns/testdata/configurecoredns_not_patched.yaml b/pkg/dns/testdata/configurecoredns_not_patched.yaml
index 85ce27c..38e402e 100644
--- a/pkg/dns/testdata/configurecoredns_not_patched.yaml
+++ b/pkg/dns/testdata/configurecoredns_not_patched.yaml
@@ -6,6 +6,9 @@ metadata:
 spec:
   template:
     spec:
+      containers:
+        - name: coredns
+          image: coredns:1.6.0
       volumes:
         - configMap:
             name: "other-cfgmap"
diff --git a/pkg/dns/testdata/configurekubedns_already_patched.yaml b/pkg/dns/testdata/configurekubedns_already_patched.yaml
index a525f3c..f620f7b 100644
--- a/pkg/dns/testdata/configurekubedns_already_patched.yaml
+++ b/pkg/dns/testdata/configurekubedns_already_patched.yaml
@@ -32,6 +32,9 @@ metadata:
 spec:
   template:
     spec:
+      containers:
+        - name: coredns
+          image: coredns:1.6.0
       volumes:
         - configMap:
             name: "other-cfgmap"
diff --git a/pkg/dns/testdata/configurekubedns_not_patched.yaml b/pkg/dns/testdata/configurekubedns_not_patched.yaml
index a525f3c..f620f7b 100644
--- a/pkg/dns/testdata/configurekubedns_not_patched.yaml
+++ b/pkg/dns/testdata/configurekubedns_not_patched.yaml
@@ -32,6 +32,9 @@ metadata:
 spec:
   template:
     spec:
+      containers:
+        - name: coredns
+          image: coredns:1.6.0
       volumes:
         - configMap:
             name: "other-cfgmap"
diff --git a/pkg/dns/testdata/configurekubedns_optional_configmap.yaml b/pkg/dns/testdata/configurekubedns_optional_configmap.yaml
index 9c5ac7a..76cee2c 100644
--- a/pkg/dns/testdata/configurekubedns_optional_configmap.yaml
+++ b/pkg/dns/testdata/configurekubedns_optional_configmap.yaml
@@ -27,6 +27,9 @@ metadata:
 spec:
   template:
     spec:
+      containers:
+        - name: coredns
+          image: coredns:1.6.0
       volumes:
         - configMap:
             name: "other-cfgmap"