Deploy PgBouncer using Kubernetes PgBouncer Operator

Kubernetes PgBouncer

As businesses increasingly integrate containerization and orchestration technologies, the management of databases in dynamic and scalable environments presents a significant challenge. Kubernetes, a prevalent container orchestration technology, offers robust features for automating the deployment, scaling, and maintenance of containerized applications. However, effectively managing databases within a Kubernetes cluster requires careful consideration to ensure peak performance and scalability.

This article covers the importance of PgBouncer in the area of database management within a Kubernetes environment. We will explore the basics of PgBouncer, highlighting its significance in effective database management, and offering best practices for the deployment and configuration of PgBouncer on Kubernetes. By the end of this article, you will have acquired a thorough understanding of how the integration of Kubernetes PgBouncer elevates your strategy for database management within the Kubernetes ecosystem.

Advantage of PgBouncer in Kubernetes

PgBouncer is a high-performance open-source connection pooler for PostgreSQL databases, specifically designed to manage database connections efficiently. Operating as an intermediary layer between applications and databases, PgBouncer optimizes connection pooling and query handling. With PgBouncer, you can achieve load balancing of queries across multiple PostgreSQL database instances, route read and write operations to replicas, and ensure failover support.

A compelling reason to opt for PgBouncer is its capability to enhance database performance and scalability. Through efficient connection pooling and query distribution, PgBouncer effectively manages the database workload, preventing any single instance from becoming a bottleneck. This load distribution becomes particularly crucial in a Kubernetes environment, where applications dynamically scale, requiring the database to adapt to fluctuating demand.

PgBouncer, in addition to connection pooling, offers transaction pooling, which can be advantageous in scenarios with a high number of short-lived connections. This feature contributes to resource optimization and efficient handling of connection requests in Kubernetes deployments.

Moreover, PgBouncer facilitates connection pooling, resulting in minimized overhead and improved resource utilization, making it well-suited for dynamic and scalable Kubernetes environments. Its ability to handle connections and queries efficiently makes PgBouncer an essential component for optimizing PostgreSQL database performance in Kubernetes deployments.

Deploying PgBouncer on Kubernetes

Pre-requisites

We have to set up the environment to deploy PgBouncer on Kubernetes using a Kubernetes PgBouncer operator. You requires to have a running Kubernetes cluster and a basic understanding of PgBouncer. Here we are using Kind to create our Kubernetes cluster. Additionally, you should install Helm to your Kubernetes cluster.

In this tutorial, We will use the Kubernetes PgBouncer operator KubeDB to deploy PgBouncer on Kubernetes. First, We must install KubeDB in our Kubernetes cluster. It requires a license to setup KubeDB in our Kubernetes cluster. We can obtain a free license via the AppsCode License Server. To obtain the license we must provide our Kubernetes cluster ID. Run the following command to get the cluster ID.

$ kubectl get ns kube-system -o jsonpath='{.metadata.uid}'
6c08dcb8-8440-4388-849f-1f2b590b731e

After providing the required information, we will receive an email from the license server including a license.txt file. To install KubeDB, use the following helm commands.

$ helm install kubedb oci://ghcr.io/appscode-charts/kubedb \
  --version v2023.12.28 \
  --namespace kubedb --create-namespace \
  --set-file global.license=/path/to/the/license.txt \
  --wait --burst-limit=10000 --debug

Verify the KubeDB installation by the following command,

$ kubectl get pods --all-namespaces -l "app.kubernetes.io/instance=kubedb"
NAMESPACE   NAME                                           READY   STATUS    RESTARTS        AGE
kubedb      kubedb-kubedb-autoscaler-6d6ffb847c-bpb9c      1/1     Running   0               3m57s
kubedb      kubedb-kubedb-dashboard-65cd5f6ddf-l72vc       1/1     Running   0               3m57s
kubedb      kubedb-kubedb-ops-manager-9665f8666-2qnbb      1/1     Running   0               3m57s
kubedb      kubedb-kubedb-provisioner-7984979d86-xphhz     1/1     Running   0               3m57s
kubedb      kubedb-kubedb-webhook-server-95989684b-jdsj4   1/1     Running   0               3m57s

If all of the pod status is running, we can move to the next step.

Create a Namespace

We will now create a new namespace and deploy the server. The following command can be used to create a namespace:

$ kubectl create namespace pgdemo
namespace/pgdemo created

Deploy PostgreSQL Cluster

We need to create a yaml manifest to Deploy PostgreSQL on Kubernetes. Here is the yaml manifest we’ll be using,

apiVersion: kubedb.com/v1alpha2 
kind: Postgres
metadata:
  name: postgres
  namespace: pgdemo
spec:
  version: "15.1"
  replicas: 3 
  standbyMode: Hot 
  storageType: Durable 
  storage:
    storageClassName: "standard" 
    accessModes:
    - ReadWriteOnce
    resources:
      requests:
        storage: 1Gi 
  terminationPolicy: WipeOut

You can see the detailed yaml specifications in the Kubernetes PostgreSQL documentation.

We will save this yaml configuration to postgres.yaml. Then create the above PostgreSQL object.

$ kubectl create -f postgres.yaml
postgres.kubedb.com/postgres created

Let’s check if the server is ready to use,

$ kubectl get postgres -n pgdemo postgres
NAME       VERSION   STATUS   AGE
postgres   15.1      Ready    2m50s

Create Database, User & Grant Privileges

Here, we are going to create a database with user and grant them all privileges to the database.

$ kubectl exec -it postgres-0 -n pgdemo -- bash
Defaulted container "postgres" out of: postgres, pg-coordinator, postgres-init-container (init)

postgres-0:/$ psql -c "create database test"
CREATE DATABASE

postgres-0:/$ psql -c "create role roy with login password '12345'"
CREATE ROLE

postgres-0:/$ psql -c "grant all privileges on database test to roy"
GRANT

postgres-0:/$ psql test
psql (15.1)
Type "help" for help.

test=# GRANT ALL ON SCHEMA public TO roy;
GRANT

test=# exit

postgres-0:/$ exit
exit

Create Secret

Now, we’ll create a secret that includes the User and Password that we created as Postgres roles above.

apiVersion: v1
stringData:
  password: "12345"
  username: roy
kind: Secret
metadata:
  name: db-user-pass
  namespace: pgdemo
type: kubernetes.io/basic-auth

Let’s save this yaml configuration into db-user-pass.yaml, Then create the above Secret

$ kubectl apply -f db-user-pass.yaml 
secret/db-user-pass created

Create AppBinding

Now, we are going to create a AppBinding which we will connect as a database reference to PgBouncer,

apiVersion: appcatalog.appscode.com/v1alpha1
kind: AppBinding
metadata:
  name: pg-appbinding
  namespace: pgdemo
  labels:
    app.kubernetes.io/component: database
    app.kubernetes.io/instance: pg-appbinding
    app.kubernetes.io/managed-by: kubedb.com
    app.kubernetes.io/name: postgreses.kubedb.com
spec:
  appRef:
    apiGroup: kubedb.com
    kind: Postgres
    name: postgres
    namespace: pgdemo
  clientConfig:
    service:
      name: postgres
      path: /
      port: 5432
      query: sslmode=disable
      scheme: postgresql
  parameters:
    apiVersion: appcatalog.appscode.com/v1alpha1
    kind: StashAddon
    stash:
      addon:
        backupTask:
          name: postgres-backup-15.1
        restoreTask:
          name: postgres-restore-15.1
  secret:
    name: db-user-pass
  type: kubedb.com/postgres
  version: "15.1"

Let’s save this yaml configuration into pg-appbinding.yaml, Then create the above AppBinding

You can see the detailed yaml specifications in the Kubernetes PgBouncer AppBinding documentation.

Deploy PgBouncer Cluster

We will use KubeDB to deploy the PgBouncer cluster. Here is the yaml manifest that will be used.

apiVersion: kubedb.com/v1alpha2
kind: PgBouncer
metadata:
  name: pgbouncer
  namespace: pgdemo
spec:
  version: "1.18.0"
  replicas: 3
  databases:
  - alias: "testdb"
    databaseName: "test"
    databaseRef:
      name: "pg-appbinding"
      namespace: pgdemo
  connectionPool:
    port: 5432
    poolMode: session
    authType: md5
  terminationPolicy: WipeOut

You can see the detailed yaml specifications in the Kubernetes PgBouncer documentation.

Let’s save this yaml configuration into pgbouncer.yaml Then create the above PgBouncer CRO,

$ kubectl apply -f pgbouncer.yaml
pgbouncer.kubedb.com/pgbouncer created

If all of the previous steps are followed correctly, and PostgreSQL and PgBouncer are deployed, the following objects will be created:

$ kubectl get all -n pgdemo
NAME              READY   STATUS    RESTARTS   AGE
pod/pgbouncer-0   1/1     Running   0          2m29s
pod/pgbouncer-1   1/1     Running   0          2m17s
pod/pgbouncer-2   1/1     Running   0          2m11s
pod/postgres-0    2/2     Running   0          6m29s
pod/postgres-1    2/2     Running   0          7m11s
pod/postgres-2    2/2     Running   0          7m59s

NAME                       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                      AGE
service/pgbouncer          ClusterIP   10.8.6.63    <none>        5432/TCP                     3m7s
service/pgbouncer-pods     ClusterIP   None         <none>        5432/TCP                     3m7s
service/postgres           ClusterIP   10.8.6.135   <none>        5432/TCP,2379/TCP            7m32s
service/postgres-pods      ClusterIP   None         <none>        5432/TCP,2380/TCP,2379/TCP   7m32s
service/postgres-standby   ClusterIP   10.8.0.37    <none>        5432/TCP                     7m32s

NAME                         READY   AGE
statefulset.apps/pgbouncer   3/3     2m3s
statefulset.apps/postgres    3/3     8m34s

NAME                                               TYPE                   VERSION   AGE
appbinding.appcatalog.appscode.com/pg-appbinding   kubedb.com/postgres    15.1      2m52s
appbinding.appcatalog.appscode.com/pgbouncer       kubedb.com/pgbouncer   1.18.0    2m7s
appbinding.appcatalog.appscode.com/postgres        kubedb.com/postgres    15.1      7m58s

NAME                           VERSION   STATUS   AGE
postgres.kubedb.com/postgres   15.1      Ready    8m

NAME                             VERSION   STATUS   AGE
pgbouncer.kubedb.com/pgbouncer   1.18.0    Ready    2m27s

We have successfully deployed PgBouncer to Kubernetes via the Kubernetes PgBouncer operator. Now, we will connect to the PostgreSQL database through PgBouncer to insert some sample data to verify the deployed PgBouncer is working.

Insert Sample Data

Let’s exec to the PgBouncer Pod to enter into PostgreSQL server using previously created user credentials to write and read some sample data to the database,

$ kubectl exec -it -n pgdemo pgbouncer-0 -- sh
Defaulted container "pgbouncer" out of: pgbouncer, pgbouncer-init-container (init)

$ psql -d "host=localhost user=roy password=12345 dbname=testdb"
psql (15.1)
Type "help" for help.

testdb=> create table music(id int, artist varchar, name varchar);
CREATE TABLE

testdb=> insert into music values(1, 'John Denver', 'Country Roads');
INSERT 0 1

testdb=> select * from music;
 id |   artist     |  name        
----+--------------+---------------
  1 |  John Denver | Country Roads
(1 row)

testdb=> exit
$ exit

Verify Data in PostgreSQL

Here, we are going to exec into PostgreSQL pod to verify the inserted data through PgBouncer.

$ kubectl exec -it -n pgdemo postgres-0 -- bash
Defaulted container "postgres" out of: postgres, pg-coordinator, postgres-init-container (init)

$ psql
psql (15.1)
Type "help" for help.

postgres=# \l
                                   List of databases
     Name      |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges   
---------------+----------+----------+------------+------------+-----------------------
 kubedb_system | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 postgres      | postgres | UTF8     | en_US.utf8 | en_US.utf8 | 
 template0     | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
               |          |          |            |            | postgres=CTc/postgres
 template1     | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
               |          |          |            |            | postgres=CTc/postgres
 test          | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =Tc/postgres         +
               |          |          |            |            | postgres=CTc/postgres+
               |          |          |            |            | roy=CTc/postgres
(5 rows)

postgres=# \c test
You are now connected to database "test" as user "postgres".

test=# \dt
       List of relations
 Schema | Name  | Type  | Owner 
--------+-------+-------+-------
 public | music | table | roy
(1 row)

test=# select * from music;
 id |   artist     |  name        
----+--------------+---------------
  1 |  John Denver | Country Roads
(1 row)

test=# exit
$ exit

We’ve successfully deployed PgBouncer to Kubernetes via Kubernetes PgBouncer operator KubeDB. Also, we use PgBouncer to connect to the PostgreSQL database and insert some sample data into it.

PgBouncer on Kubernetes: Best Practices

To ensure the stability of your application when using PgBouncer on Kubernetes, there are some best practices that you should follow:

  • Utilizing the Kubernetes PgBouncer Operator: Streamlining the deployment and management of PgBouncer in a Kubernetes environment is best achieved by leveraging the Kubernetes PgBouncer Operator. This operator encapsulates operational knowledge, automates administrative tasks, and simplifies the configuration and scaling of PgBouncer instances. By adopting the Kubernetes PgBouncer Operator, database administrators can efficiently manage and deploy PgBouncer instances, optimizing performance with minimal effort.

  • Ensuring High Availability: High availability remains a paramount consideration in a production-grade database setup. When deploying PgBouncer on Kubernetes, the scalability option becomes instrumental in meeting dynamic demands and ensuring optimal performance. This flexibility allows swift resource allocation to handle expanding workloads in real-time, contributing to a highly available architecture.

  • Configuring Connection Pooling: Efficiently managing the connections between PgBouncer and the database backends is achieved through proper configuration of connection pooling. Striking the right balance ensures resource efficiency and prevents the database from being overloaded with excessive connections. Configuring connection pooling is pivotal to providing a maximum number of connections while also keeping some connections open to meet varying demand.

  • Monitoring & Security: Implementing robust monitoring practices is essential for identifying performance issues, optimizing resource utilization, and ensuring seamless operations. Monitoring key metrics such as connection rate, query cache hit rate, and backend server status enables proactive responses to changes in the database workload. Enabling TLS/SSL Support in the database ensures secure communication, protecting sensitive data from unauthorized access or interception. Establishing an encrypted connection between the client and the database not only enhances data privacy but also upholds high-security standards.

Conclusion

In conclusion, PgBouncer emerges as a highly effective solution for enhancing database management within a Kubernetes framework. PgBouncer proves instrumental in optimizing database performance and scalability by efficiently managing connections, employing proper pooling configurations, and providing valuable transaction pooling support. Here, you have successfully deployed PgBouncer on Kubernetes using the Kubernetes PgBouncer operator, which is suitable for various scenarios. For more detailed information on implementing PgBouncer in Kubernetes, you can visit the official PgBouncer documentation. Achieving peak efficiency and availability in database operations necessitates a deep understanding of PgBouncer-specific best practices and a commitment to continuous improvement. Leveraging KubeDB’s extensive support services ensures that your database management aligns consistently with rigorous performance and operational standards. Whether your database infrastructure is on-premises, spans multiple geographical locations, or relies on cloud services and database-as-a-service providers, KubeDB offers comprehensive support to manage the entire process within a robust production-grade environment.

Share on social media

What They Are Talking About us

Trusted by top engineers at the most ambitious companies

faq-image

frequently asked questions

Here are a few of the questions we get the most. If you don't see what's on your mind, contact us anytime.

Can I manage multiple Databases via KubeDB?

Yes, you can manage as many databases as you want within a single subscription to KubeDB, and there is no extra charge for that!

Can I use KubeDB in any cloud?

Yes, of course! KubeDB is platform-independent. You can use KubeDB in any cloud or on-premises.

My cluster is running on bare metal. Will it be safe to use KubeDB?

KubeDB is running in production by multiple Governments and large organizations. Your data is always safe within KubeDB.

Do you have offer technical support?

We offer 24x7 technical system and maintain SLA to provide 100% reliability to our customers.

Is Stash complementary with KubeDB?

Yes, Stash is seemingly integrated with KubeDB. There is no extra charge for using Stash. It is complimentary with KubeDB.

Can we try KubeDB?

Of course! We offer a 30 days license free of cost to try fully featured KubeDB.

Is there any cancellation fee?

There is no cancellation fee. But plans are subject to minimum duration (1 year) as stated above.

What types of payment do you accept?

We prefer ACH transfer for US based customers and international wire transfer for everyone else. We can also accept all popular credit/debit cards such as Visa, Mastercard, American Express, Discover, etc.

Is my payment information safe?

Yes! For ACH transfer and wire transfer you work with your bank for payment. Our credit card processing is powerd by Stripe. You credit card data never touches our servers. For more information, please visit stripe.com.

Run and Manage your Database on Kubernetes FREE !

KubeDB is FREE to use on any supported Kubernetes engines. You can deploy and manage your database in Kubernetes using KubeDB. There is no up-front investment required. We offer a 30 days license FREE of cost to try KubeDB.