<p>So I'm working on a project that involves managing many postgres instances inside of a k8s cluster. Each instance is managed using a <code>Stateful Set</code> with a <code>Service</code> for network communication. I need to expose each <code>Service</code> to the public internet via DNS on port 5432. </p>

<p>The most natural approach here is to use the k8s <code>Load Balancer</code> resource and something like <a href="https://github.com/kubernetes-incubator/external-dns" rel="noreferrer">external dns</a> to dynamically map a DNS name to a load balancer endpoint. This is great for many types of services, but for databases there is one massive limitation: the <a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/config-idle-timeout.html" rel="noreferrer">idle connection timeout</a>. AWS ELBs have a maximum idle timeout limit of 4000 seconds. There are many long running analytical queries/transactions that easily exceed that amount of time, not to mention potentially long-running operations like <code>pg_restore</code>. </p>

<p>So I need some kind of solution that allows me to work around the limitations of Load Balancers. <code>Node IPs</code> are out of the question since I will need port <code>5432</code> exposed for every single postgres instance in the cluster. <code>Ingress</code> also seems less than ideal since it's a layer 7 proxy that only supports HTTP/HTTPS. I've seen workarounds with nginx-ingress involving some configmap chicanery, but I'm a little worried about committing to hacks like that for a large project. <code>ExternalName</code> is intriguing but even if I can find better documentation on it I think it may end up having similar limitations as <code>NodeIP</code>. </p>

<p>Any suggestions would be greatly appreciated. </p>

<p>The Kubernetes ingress controller implementation <a href="https://github.com/heptio/contour" rel="nofollow noreferrer">Contour</a> from Heptio can <a href="https://github.com/heptio/contour/blob/master/docs/ingressroute.md#tcp-proxying" rel="nofollow noreferrer">proxy <code>TCP</code> streams</a> when they are encapsulated in <code>TLS</code>. This is required to use the <code>SNI</code> handshake message to direct the connection to the correct backend service.</p>

<p>Contour can handle <code>ingresses</code>, but introduces additionally a new ingress API <a href="https://github.com/heptio/contour/blob/master/docs/ingressroute.md" rel="nofollow noreferrer">IngressRoute</a> which is implemented via a <a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions" rel="nofollow noreferrer"><code>CRD</code></a>. The TLS connection can be <a href="https://github.com/heptio/contour/blob/master/docs/ingressroute.md#tls-passthrough-to-the-backend-service" rel="nofollow noreferrer">terminated at your backend</a> service. An <code>IngressRoute</code> might look like this:</p>

<pre><code>apiVersion: contour.heptio.com/v1beta1
kind: IngressRoute
metadata:
  name: postgres
  namespace: postgres-one
spec:
  virtualhost:
    fqdn: postgres-one.example.com
    tls:
      passthrough: true
  tcpproxy:
    services:
    - name: postgres
      port: 5432
  routes:
  - match: /
    services:
    - name: dummy
      port: 80
</code></pre>
