Skip to main content

Your submission was sent successfully! Close

Thank you for signing up for our newsletter!
In these regular emails you will find the latest updates from Canonical and upcoming events where you can meet our team.Close

Thank you for contacting us. A member of our team will be in touch shortly. Close

Deploy for external TLS VIP access

This guide goes over an example deployment of PostgreSQL, PgBouncer and HAcluster that require external TLS/SSL access via Virtual IP (VIP).

It combines the following guides, where you can find more detailed information:

Summary


Requirements

Although Canonical does not prescribe how you should set up your environment, we can provide recommendations. Consider contacting us for support with your use-case.

The basic requirements to follow along with this example setup are the following:

Design

This setup applicable for VM/machine charms only. Do NOT use it for K8s deployments!

PostgreSQL TLS VIP

This setup deploys the following components:

Deploy components

Create a Juju model if you haven’t already:

juju add-model my-external-tls-db

Deploy postgresql and self-signed-certificates:

juju deploy postgresql -n 3
juju deploy self-signed-certificates
juju integrate postgresql self-signed-certificates

Deploy pgbouncer from the 1/stable channel and configure it with your VIP:

juju deploy pgbouncer --channel 1/stable --config vip=10.20.30.40
juju integrate pgbouncer postgresql
juju integrate pgbouncer self-signed-certificates

Deploy data-integrator with 3 units and configure the database name of your choice. In this example, we use mytestdb:

juju deploy data-integrator -n 3 --config database-name=mytestdb
juju integrate data-integrator pgbouncer

Deploy hacluster:

juju deploy hacluster
juju integrate hacluster pgbouncer
juju integrate hacluster:juju-info data-integrator

Example juju status output:

Model               Controller  Cloud/Region         Version  SLA          Timestamp
my-external-tls-db  lxd         localhost/localhost  3.5.5    unsupported  12:53:35+01:00

App                       Version  Status  Scale  Charm                     Channel        Rev  Exposed  Message
data-integrator                    active      3  data-integrator           latest/stable   78  no       
hacluster                 2.1.2    active      3  hacluster                 2.4/stable     131  no       Unit is ready and clustered
pgbouncer                 1.21.0   active      3  pgbouncer                 1/stable       396  no       VIP: 10.78.217.100
postgresql                14.12    active      3  postgresql                14/stable      468  no       
self-signed-certificates           active      1  self-signed-certificates  latest/stable  155  no       

Unit                         Workload  Agent  Machine  Public address  Ports     Message
data-integrator/0            active    idle   4        10.78.217.30              
  hacluster/3                active    idle            10.78.217.30              Unit is ready and clustered
  pgbouncer/0*               active    idle            10.78.217.30    6432/tcp  VIP: 10.78.217.100
data-integrator/1            active    idle   5        10.78.217.132             
  hacluster/2                active    idle            10.78.217.132             Unit is ready and clustered
  pgbouncer/1                active    idle            10.78.217.132   6432/tcp  
data-integrator/2*           active    idle   6        10.78.217.93              
  hacluster/1*               active    idle            10.78.217.93              Unit is ready and clustered
  pgbouncer/2                active    idle            10.78.217.93    6432/tcp  
postgresql/0                 active    idle   0        10.78.217.254   5432/tcp  
postgresql/1                 active    idle   1        10.78.217.245   5432/tcp  
postgresql/2*                active    idle   2        10.78.217.192   5432/tcp  Primary
self-signed-certificates/0*  active    idle   3        10.78.217.79              

Machine  State    Address        Inst id        Base          AZ  Message
0        started  10.78.217.254  juju-318984-0  [email protected]      Running
1        started  10.78.217.245  juju-318984-1  [email protected]      Running
2        started  10.78.217.192  juju-318984-2  [email protected]      Running
3        started  10.78.217.79   juju-318984-3  [email protected]      Running
4        started  10.78.217.30   juju-318984-4  [email protected]      Running
5        started  10.78.217.132  juju-318984-5  [email protected]      Running
6        started  10.78.217.93   juju-318984-6  [email protected]      Running

Check connectivity

To test the connection to PostgreSQL via TLS, first get the credentials via data-integrator:

juju run data-integrator/leader get-credentials
...
postgresql:                                                                                                                                                                                                                                             
  data: '{"database": "mytestdb", "external-node-connectivity": "true", "requested-secrets":                                                                                                                                                            
    "[\"username\", \"password\", \"tls\", \"tls-ca\", \"uris\"]"}'                                                                                                                                                                                     
  database: mytestdb                                                                                                                                                                                                                                    
  endpoints: 10.78.217.100:6432                                                                                                                                                                                                                         
  password: V7kHqHyapIphkUS0cHoOtP3j                                                                                                                                                                                                                    
  subordinated: "true"                                                                                                                                                                                                                                  
  uris: postgresql://relation_id_9:[email protected]:6432/mytestdb                                                                                                                                                                 
  username: relation_id_9                                                                                                                                                                                                                               
  version: "14.12"     

Now use the received credentials (uris) to connect PostgreSQL (via TLS/SSL):

> psql postgresql://relation_id_9:[email protected]:6432/mytestdb
psql (14.15 (Ubuntu 14.15-0ubuntu0.22.04.1), server 14.12 (Ubuntu 14.12-0ubuntu0.22.04.1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

mytestdb=> select now();
              now              
-------------------------------
 2025-01-14 11:51:04.646245+00
(1 row)

Ensure your DNS records points to the virtual IP and that it is routable/reachable from outside of your network to connect using DNS:

psql postgresql://relation_id_9:[email protected]:6432/mytestdb

(Optional) Add monitoring

Consider adding the Canonical Observability Stack (COS) to your setup for monitoring, alert rules, logs, and tracing.

See: PostgreSQL | How to enable monitoring, PgBouncer | How to enable monitoring.

High availability

In production environments, deploy different units into separate availability zones (AZ).

See: How to deploy > Multi-AZ

At this point, Juju is responsible for the health of the clusters/applications:

  • The PostgreSQL charm will restart the workload if PostgreSQL is not healthy.
  • The Juju agent will restart the unit/vm/container if it is no longer reachable/healthy (in the same AZ).
  • The Juju controller will make sure Juju agent is up and running and charm is healthy.
  • The HACluster charm will make sure the VIP is always reachable and routes to a single PgBouncer.
  • PgBouncer will balance incoming connections and makes sure write traffic goes to the primary PostgreSQL unit.
  • The TLS operator (in this example, the self-signed-certificates charm) is responsible for providing all components with signed ready-to-use TLS artifacts.

Troubleshooting

Contact us if you have any issues with this setup or would like help with a different use-case.

Last updated 5 hours ago. Help improve this document in the forum.