diff --git a/middleware/kubernetes/README.md b/middleware/kubernetes/README.md
index b64a3b1d0..46237ab2c 100644
--- a/middleware/kubernetes/README.md
+++ b/middleware/kubernetes/README.md
@@ -128,4 +128,14 @@ all values.  The labels that accept wildcards are:
 * multiple wild cards are allowed in a single query.
    * e.g. `A` Request `*.*.svc.zone.` or `SRV` request `*.*.*.*.svc.zone.`
 
+## deploy.sh and coredns.yaml.sed
 
+A convenience script to generate a manifest for running CoreDNS on a cluster that is currently
+running standard kube-dns. It creates a ConfigMap and a CoreDNS deployment, then updates the
+Kube-DNS service selector to use the CoreDNS deployment. It doesn't delete the kube-dns
+deployment or replication controller - you'll have to do that manually.
+
+~~~
+$ ./deploy.sh 10.3.0.0/24 | kubectl apply -f -
+$ kubectl delete --namespace=kube-system deployment kube-dns
+~~~
diff --git a/middleware/kubernetes/coredns.yaml.sed b/middleware/kubernetes/coredns.yaml.sed
new file mode 100644
index 000000000..04f80d64c
--- /dev/null
+++ b/middleware/kubernetes/coredns.yaml.sed
@@ -0,0 +1,93 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: coredns
+  namespace: kube-system
+data:
+  Corefile: |
+    .:53 {
+        errors
+        log stdout
+        health
+        kubernetes CLUSTER_DOMAIN {
+          cidrs SERVICE_CIDR
+        }
+        proxy . /etc/resolv.conf
+        cache 30
+    }
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+  name: coredns
+  namespace: kube-system
+  labels:
+    k8s-app: coredns
+    kubernetes.io/cluster-service: "true"
+    kubernetes.io/name: "CoreDNS"
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      k8s-app: coredns
+  template:
+    metadata:
+      labels:
+        k8s-app: coredns
+      annotations:
+        scheduler.alpha.kubernetes.io/critical-pod: ''
+        scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]'
+    spec:
+      containers:
+      - name: coredns
+        image: infoblox/coredns:latest
+        imagePullPolicy: Always
+        args: [ "-conf", "/etc/coredns/Corefile" ]
+        volumeMounts:
+        - name: config-volume
+          mountPath: /etc/coredns
+        ports:
+        - containerPort: 53
+          name: dns
+          protocol: UDP
+        - containerPort: 53
+          name: dns-tcp
+          protocol: TCP
+        livenessProbe:
+          httpGet:
+            path: /health
+            port: 8080
+            scheme: HTTP
+          initialDelaySeconds: 60
+          timeoutSeconds: 5
+          successThreshold: 1
+          failureThreshold: 5
+      dnsPolicy: Default
+      volumes:
+        - name: config-volume
+          configMap:
+            name: coredns
+            items:
+            - key: Corefile
+              path: Corefile
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: kube-dns
+  namespace: kube-system
+  labels:
+    k8s-app: coredns
+    kubernetes.io/cluster-service: "true"
+    kubernetes.io/name: "CoreDNS"
+spec:
+  selector:
+    k8s-app: coredns
+  clusterIP: CLUSTER_DNS_IP
+  ports:
+  - name: dns
+    port: 53
+    protocol: UDP
+  - name: dns-tcp
+    port: 53
+    protocol: TCP
diff --git a/middleware/kubernetes/deploy.sh b/middleware/kubernetes/deploy.sh
new file mode 100755
index 000000000..d8aade328
--- /dev/null
+++ b/middleware/kubernetes/deploy.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# Deploys CoreDNS to a cluster currently running Kube-DNS.
+
+SERVICE_CIDR=$1
+CLUSTER_DOMAIN=${2:-cluster.local}
+YAML_TEMPLATE=${3:-`pwd`/coredns.yaml.sed}
+YAML=${4:-`pwd`/coredns.yaml}
+
+if [[ -z $SERVICE_CIDR ]]; then
+	echo "Usage: $0 SERVICE-CIDR [ CLUSTER-DOMAIN ] [ YAML-TEMPLATE ] [ YAML ]"
+	exit 1
+fi
+
+CLUSTER_DNS_IP=$(kubectl get service --namespace kube-system kube-dns -o jsonpath="{.spec.clusterIP}")
+
+sed -e s/CLUSTER_DNS_IP/$CLUSTER_DNS_IP/g -e s/CLUSTER_DOMAIN/$CLUSTER_DOMAIN/g -e s?SERVICE_CIDR?$SERVICE_CIDR?g $YAML_TEMPLATE
+
+