<p>I have a scenario where I have multiple mysql servers running in different namespaces in single kubernetes cluster. All mysql servers belong to different departments.</p>

<p>My requirement is I should be able to connect to different mysql servers using hostname, i.e.,</p>

<p>mysqlServerA running in ServerA namespace should be reachable from outside the cluster using:</p>

<pre><code>mysql -h mysqlServerA.mydomain.com -A
</code></pre>

<p>mysqlServerB running in ServerB namespace should be reachable from outside the cluster using:</p>

<pre><code>mysql -h mysqlServerB.mydomain.com -A
</code></pre>

<p>and so on.</p>

<p>I have tried TCP based routing using config maps of Nginx Ingress controller, where I am routing traffic from clients to different mysql servers by assigning different port numbers:</p>

<p>for mysqlServerA:</p>

<pre><code>mysql -h mysqlServer.mydomain.com -A -P 3301
</code></pre>

<p>for mysqlServerB:</p>

<pre><code>mysql -h mysqlServer.mydomain.com -A -P 3302
</code></pre>

<p>this works perfectly. But I want to know if hostname based routing is possible or not, because I don't want separate load balancer for each mysql service.</p>

<p>Thanks</p>

Ammar Taj
<p><strong>General info</strong></p>

<blockquote>
  <p>I  routing traffic by  different port numbers</p>
</blockquote>

<p>You are right, the reason for that is that connection to Mysql is done via TCP. That is why it is definitely not possible to have two simultaneous connections to two servers on the same <code>IP:port</code>.</p>

<p>Unlike HTTP, the TCP don't have headers that allows distinguishing the host the traffic shall be routed to. However, still there are at least two ways to achieve the functionality you'd like to achieve :) I'll describe that later.</p>

<blockquote>
  <p>I want to know if hostname based routing is possible or not
  I don't want separate load balancer for each mysql service.</p>
</blockquote>

<p>K8s allows <a href="http://alesnosek.com/blog/2017/02/14/accessing-kubernetes-pods-from-outside-of-the-cluster/" rel="nofollow noreferrer">a few methods</a> for service to be reachable outside the cluster (namely  <code>hostNetwork</code>, <code>hostPort</code>, <code>NodePort</code> , <code>LoadBalancer</code>, <code>Ingress</code>   )</p>

<p>The <code>LoadBalancer</code> is the simplest way to serve traffic on LoadBalancerIP:port ; however, due to TCP nature of connection you'll have to use one <code>LoadBalancer</code> per one mysql instance.</p>

<pre><code>kind: Service 
apiVersion: v1 
metadata: 
  name: mysql 
spec: 
  type: LoadBalancer 
  ports: 
    - port: 3306 
  selector: 
    name: my-mysql
</code></pre>

<p>The <code>NodePort</code> looks good, but it allows you connecting only when you know port (which can be tedious work for clients)</p>

<p><strong>Proposed solutions</strong></p>

<ul>
<li><a href="https://kubernetes.io/docs/concepts/services-networking/service/#external-ips" rel="nofollow noreferrer"><strong>External IPs</strong></a></li>
</ul>

<p>If there are external IPs that route to one or more cluster nodes, Kubernetes Services can be exposed on those  <code>externalIPs</code>. Traffic that ingresses into the cluster with the external IP (as destination IP), on the Service port, will be routed to one of the Service endpoints.  <code>externalIPs</code>  are not managed by Kubernetes and are the responsibility of the cluster administrator.</p>

<p>In the Service spec,  <code>externalIPs</code>  can be specified along with any of the  <code>ServiceTypes</code>. In the example below, <code>mysql-1</code> can be accessed by clients on <code>1.2.3.4:3306</code> (<code>externalIP:port</code>) and <code>mysql-2</code> can be accessed by clients on <code>4.3.2.1:3306</code> </p>

<pre><code>$ cat stereo-mysql-3306.yaml 
apiVersion: v1
kind: Service
metadata:
  name: mysql-1234-inst-1
spec:
  selector:
    app: mysql-prod
  ports:
    - name: mysql
      protocol: TCP
      port: 3306
      targetPort: 3306
  externalIPs:
    - 1.2.3.4 
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-4321-inst-1
spec:
  selector:
    app: mysql-repl
  ports:
    - name: mysql
      protocol: TCP
      port: 3306
      targetPort: 3306
  externalIPs:
    - 4.3.2.1
</code></pre>

<p>Note: you need to have <code>1.2.3.4</code> and <code>4.3.2.1</code> assigned to your Nodes (and resolve <code>mysqlServerA</code> / <code>mysqlserverB</code> at <code>mydomain.com</code>to these IPs as well). I've tested that solution on my GKE cluster and it works :). </p>

<p>With that config all the requests for <code>mysqlServerA.mydomain.com:3306</code> that resolves to <code>1.2.3.4</code> are going to be routed to the <code>Endpoints</code> for service <code>mysql-1234-inst-1</code> with the <code>app: mysql-prod</code> selector, and <code>mysqlServerA.mydomain.com:3306</code> will be served by <code>app: mysql-repl</code>.</p>

<p>Of course it is possible to split that config for 2 namespaces (one namespace - one mysql - one service per one namespace).</p>

<ul>
<li><a href="https://itnext.io/use-helm-to-deploy-openvpn-in-kubernetes-to-access-pods-and-services-217dec344f13" rel="nofollow noreferrer"><strong>ClusterIP+OpenVPN</strong></a></li>
</ul>

<p>Taking into consideration that your mysql pods have ClusterIPs, it is possible to spawn additional VPN pod in cluster and connect to mysqls through it. </p>

<p>As a result, you can establish VPN connection and have access to all the cluster resources. That is very limited solution which requires establishing the VPN connection for anyone who needs access to mysql. </p>

<p>Good practice is to add a bastion server on top of that solution. That server will be responsible for providing access to cluster services via VPN.</p>

<p>Hope that helps. </p>
