I wrote a blog post in the past about a generic approach on how to expose databases in Kubernetes with Ingress controllers. Today, we will dive deeper into PostgreSQL with ingress and also review two different ways that can be taken to expose the TCP service. The goal is to expose multiple PostgreSQL clusters through a single ingress using different TCP ports:

Prepare the PostgreSQL cluster

We are going to use Percona Operator for PostgreSQL to deploy the cluster. Deploy the Operator first. We will use Helm for that:

  • Add the Percona’s Helm charts repository and make your Helm client up to date with it:

  • Install the Percona Operator for PostgreSQL:

Now, we are ready to deploy the database. The default configuration is fine for this example:

Connecting to PostgreSQL

There are two ways how you can connect to the PostgreSQL cluster deployed with the Percona Operator:

  1. Connect through pgBouncer (recommended)
  2. Connect directly to Primary and Replicas

Connecting to PostgreSQL

We recommend connecting through pgBouncer, as it provides connection pooling. Keep in mind, though, that when you connect through pgBouner, all your reads and writes go to a primary node. In that case, your replicas are sitting idle and needed for high availability only. In this blog post, we will be connecting to pgBouncer through Ingress. 

Get the connection string

We need to get the pgBouncer URI to configure ingress and test the connection later on. 

Ingress time

We are going to use the most popular ingress controlleringress-nginx. To be consistent, we will deploy it using Helm.

There are two ways somebody can expose additional TCP ports through ingress.

  1. Put TCP configuration into values.yaml 
  2. Put TCP settings into the ConfigMap 

We will show how to do it and explain the differences between approaches below.

Expose with values.yaml

You can simply list the TCP ports and services that you want to have exposed. To expose my PostgreSQL cluster with pgBouncer on port 30001 with ingress my values manifest would look like this:

Note the last line:

  • 30001  – is the TCP port we are going to use to connect to the cluster
  • default  – namespace where PostgreSQL cluster is
  • my-db-pg-db-pgbouncer:5432 – Service name and the port of the pgBouncer. Get it with kubectl get services if unsure.

Deploy the controller:

Expose with ConfigMap

With this approach, we define ports that we want to be exposed in the values.yaml of ingress, but the specific Service endpoint will be in the ConfigMap.

  • tcp-services-configmap – defines the location of a ConfigMap with Services configuration
  • tcp:  section lists the ports that we want to be exposed. I specifically added multiple ports as an example.

The tcp-services-cm ConfigMap looks like this:

Create the ConfigMap and deploy the ingress with helm:

Using a ConfigMap to expose your PostgreSQL cluster on port 30001 offers greater flexibility and control. Your teams can easily add new services without needing to redeploy the Ingress controller, saving time and effort. It also enhances security by allowing Kubernetes administrators to define which ports are exposed while developers maintain control over service exposure.

Connect to PostgreSQL

To connect to PostgreSQL, you need the following:

  1. pgBouncer uri that we got above. For me, it is:

  1. The IP-address of the ingress LoadBalancer:

We will connect to the IP-address of the ingress controller and the port we defined – 30001. postgresql connection string for me looks like this:

What can go wrong

Port overlap

Choosing ports is manual. So when your developers are going to create ConfigMaps to expose services, ports must not overlap. So, you can’t have two services exposed on the same TCP port. You can maintain the list of ports used or introduce additional validation webhooks that are going to check if a port is in use already.

Port limits

Public clouds have limits on the number of TCP ports that can be exposed through a load balancer. For AWS, it is 50 TCP ports, and for Google Cloud, it is 100. Keep that in mind when you plan to use Ingresses to expose services.

Firewalls

Exposing a port through a LoadBalancer Service in Kubernetes does not guarantee that this port is going to be reachable. There might be various firewalls or network restrictions that you need to consider (for example, Access Lists on the cloud provider). Keep that in mind when troubleshooting the connection.

Conclusion

Ingresses are widely popular for exposing HTTP and HTTPS services, but they can also be used for TCP exposure. That way, you simplify your network and minimize the attack surface. This approach empowers development teams while maintaining robust security and control for Kubernetes administrators. However, it’s crucial to be mindful of potential challenges like port overlaps and cloud provider limits. By carefully planning your Ingress strategy and considering the potential pitfalls, you can ensure seamless and secure access to your PostgreSQL databases in Kubernetes.

Percona offers various software options to run PostgreSQL:

And, of course, if you are looking for help, support, or professional support – let our team know: https://www.percona.com/about/contact

Our community and Perconians are always ready to help you on Percona Forums.

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments