<p>I want to connect multiple microservices hosted on Google Kubernetes Engine to a MongoDB Atlas database.</p>
<p>All Deployments and Services inside the cluster are on the <code>gitlab-managed-apps</code> namespace.</p>
<p>I have created the following ExternalName Service:</p>
<p><strong>mongo-external-name.yaml</strong></p>
<pre class="lang-sh prettyprint-override"><code>kind: Service
apiVersion: v1
metadata:
  name: mongo
  namespace: gitlab-managed-apps
spec:
  type: ExternalName
  externalName: db_name.mrud5.mongodb.net
</code></pre>
<p>To connect to MongoDB Atlas I tried to use the ExternalName since using <em>db_name.mrud5.mongodb.net</em> would try to resolve to an internal service:</p>
<pre class="lang-js prettyprint-override"><code>//connect.js
mongoose.connect(`mongodb+srv://${ global.DB_USER }:${ global.DB_PASSWORD }@mongo.gitlab-managed-apps.svc.cluster.local/${ global.DB_NAME }?retryWrites=true&amp;w=majority`, {
        useNewUrlParser: true,
        useCreateIndex: true,
        useUnifiedTopology: true,
        useFindAndModify: false
    });
</code></pre>
<p>As per the deployments, I have them inside a couple of Helm Charts. I thought it had something to do with the <code>dnsPolicy: ClusterFirst</code> and I attempted to set it to <code>dnsPolicy: Default</code>, but that made no difference.</p>
<p>Upon executing bash on one of the pods, I have tried <code>nslookup</code> as suggested by many other issues, this is the result:</p>
<pre class="lang-sh prettyprint-override"><code>bash-5.0# nslookup mongo.gitlab-managed-apps.svc.cluster.local
Server:         10.1.0.10
Address:        10.1.0.10:53

    mongo.gitlab-managed-apps.svc.cluster.local     canonical name = db_name.mrud5.mongodb.net

    mongo.gitlab-managed-apps.svc.cluster.local     canonical name = db_name.mrud5.mongodb.net
</code></pre>
<p>I figured that if the pod can see the CNAME records there must be something else that I am not doing right.</p>
<p>I was unable to <code>ping mongo.gitlab-managed-apps.svc.cluster.local</code></p>
<pre class="lang-sh prettyprint-override"><code>bash-5.0# ping mongo.gitlab-managed-apps.svc.cluster.local
ping: bad address 'mongo.gitlab-managed-apps.svc.cluster.local'
</code></pre>
<p>My cluster's master version is <code>1.15.11-gke.15</code>. I did not create the cluster with this version, upon creation, Gitlab automatically chose <code>1.14.10</code>. After reading multiple issues on GitHub, I understood that there were some issues with <code>kube-dns</code> on version <code>1.14.9</code>. I, therefore, ran the command below to try to fix this.</p>
<pre class="lang-sh prettyprint-override"><code>kubectl set image deployment/kube-dns -n kube-system \
  kubedns=gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.14.10 \
  dnsmasq=gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:1.14.10 \
  sidecar=gcr.io/google_containers/k8s-dns-sidecar-amd64:1.14.10
</code></pre>
<p>As I thought, this was not the solution either. Desperate, I upgraded the cluster to <code>1.15.11-gke.15</code> and kube-dns with the above command. That was not the solution either.</p>
<p>I don't think it causes this problem but I have posted below my Ingress controller:</p>
<p><strong>ingress-service.yaml</strong></p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    nginx.ingress.kubernetes.io/proxy-body-size: &quot;100m&quot;
    certmanager.k8s.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/proxy-connect-timeout: &quot;7200&quot;
    nginx.ingress.kubernetes.io/proxy-read-timeout: &quot;7200&quot;
    nginx.ingress.kubernetes.io/proxy-send-timeout: &quot;7200&quot;
  name: ingress-service
  namespace: gitlab-managed-apps
spec:
  tls:
    - hosts:
        - my.host
      secretName: letsencrypt-prod
  rules:
    - host: my.host
      http:
        paths:
          - backend:
              serviceName: my-cluster-ip-service
              servicePort: 3000
            path: /?(.*)
</code></pre>
<p>Any suggestion is very much appreciated!</p>

<p>Well, the <code>ExternalName</code> configuration is correct ✅. Your cluster pods are giving you the right canonical name. However, <code>db_name.mrud5.mongodb.net</code> is not even pingable nor reachable. It's basically a TXT DNS record. I say this because I tried it myself with my DB👇:</p>
<pre class="lang-sh prettyprint-override"><code>dig txt mycluster.vvcme.mongodb.net

; &lt;&lt;&gt;&gt; DiG 9.10.6 &lt;&lt;&gt;&gt; txt cluster0.vvcme.mongodb.net
;; global options: +cmd
;; Got answer:
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 18012
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;cluster0.vvcme.mongodb.net.    IN  TXT

;; ANSWER SECTION:
mycluster.vvcme.mongodb.net. 60 IN  TXT &quot;authSource=admin&amp;replicaSet=atlas-xxxxxx-shard-0&quot;

;; Query time: 127 msec
;; SERVER: 10.240.246.53#53(10.240.246.53)
;; WHEN: Fri Jul 17 19:26:52 PDT 2020
;; MSG SIZE  rcvd: 105
</code></pre>
<p>This is used by the client to get all the shards but in essence, you can find the shards directly👇:</p>
<pre class="lang-sh prettyprint-override"><code>dig srv _mongodb._tcp.mycluster.vvcme.mongodb.net

; &lt;&lt;&gt;&gt; DiG 9.10.6 &lt;&lt;&gt;&gt; srv _mongodb._tcp.mycluster.vvcme.mongodb.net
;; global options: +cmd
;; Got answer:
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 5089
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;_mongodb._tcp.mycluster.vvcme.mongodb.net. IN SRV

;; ANSWER SECTION:
_mongodb._tcp.cluster0.vvcme.mongodb.net. 60 IN SRV 0 0 27017 mycluster-shard-00-00.vvcme.mongodb.net. 👈
_mongodb._tcp.cluster0.vvcme.mongodb.net. 60 IN SRV 0 0 27017 mycluster-shard-00-01.vvcme.mongodb.net. 👈
_mongodb._tcp.cluster0.vvcme.mongodb.net. 60 IN SRV 0 0 27017 mycluster-shard-00-02.vvcme.mongodb.net. 👈

...
</code></pre>
<p>Those shards are actually pingable and DNS resolvable👇:</p>
<pre class="lang-sh prettyprint-override"><code>dig cluster0-shard-00-00.vvcme.mongodb.net

; &lt;&lt;&gt;&gt; DiG 9.10.6 &lt;&lt;&gt;&gt; cluster0-shard-00-00.vvcme.mongodb.net
;; global options: +cmd
;; Got answer:
;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 41225
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;cluster0-shard-00-00.vvcme.mongodb.net.    IN A

;; ANSWER SECTION:
mycluster-shard-00-00.vvcme.mongodb.net.    60 IN CNAME mtm-aws-use1-22-m0-14-shard-00-00.5yapb.mongodb.net.
mtm-aws-use1-22-m0-14-shard-00-00.5yapb.mongodb.net. 60 IN CNAME ec2-xx-xx-xx-xx.compute-1.amazonaws.com.
ec2-xx-xx-xx-xx.compute-1.amazonaws.com. 86400 IN A xx.xxx.xx.xx 👈

...
</code></pre>
<p>All this stuff is available on the open internet and it's <a href="https://docs.mongodb.com/manual/reference/connection-string/" rel="nofollow noreferrer">documented here</a>. So you don't even need your <code>ExternalName</code> Kubernetes service. Unless for some reason you are running Atlas in your private VPC in which case you would have to configure/ping the appropriate records. ✌️</p>
