From documentation
CloudNativePG is an open-source operator designed to manage PostgreSQL workloads on any supported Kubernetes cluster running in private, public, hybrid, or multi-cloud environments. CloudNativePG adheres to DevOps principles and concepts such as declarative configuration and immutable infrastructure.
Now let’s try to understand some key concepts used in the above definition
Open source means that the software’s source code is freely available for anyone to view, use, modify, and distribute.
Kubernetes, often called K8s due to the eight letters between “K” and “S,” is an open-source platform that automates the management of Linux containers. It simplifies the manual tasks of deploying and scaling containerized applications. Essentially, Kubernetes allows you to group hosts running Linux containers into clusters and efficiently manage them.
Kubernetes cluster Is a collection of computers (nodes) that work together to run and manage applications in containers. Kubernetes coordinates the deployment, scaling, and management of these applications across the cluster.
Operator Is a custom automation tool that helps manage and run specific applications on Kubernetes. It automates tasks like setup and maintenance, similar to how an administrator would manually manage software, but more efficiently. Just as a PostgreSQL extension adds features to PostgreSQL, a Kubernetes operator automates and manages applications, enhancing the system’s ability to handle specific tasks.
Declarative configuration In this approach, we define the desired state of our system, and the system automatically adjusts to reach that state. We focus on what we want, rather than detailing how to achieve it.
Immutable infrastructure In this approach, once a component (such as a server or container) is deployed, it remains unchanged. If updates are needed, a new instance with the desired changes is created, and the old one is decommissioned.
What Issues Does Cloud Native Postgres Address?
CloudNativePG addresses the challenges of managing PostgreSQL databases in Kubernetes environments by automating deployment, scaling, and high availability. It simplifies:
Management
- By automating setup and maintenance of PostgreSQL clusters, reducing manual work.
Scaling
- Easily scales PostgreSQL clusters up or down based on demand.
High Availability
- Ensures continuous database operation and failover in case of node failures.
Consistency
- Handles configuration changes and updates across the cluster consistently.
Setting Up Your First Local Kubernetes Cluster
A Kubernetes cluster consists of a group of computers (nodes) that include a control plane (master) and worker nodes. The control plane oversees and manages container scheduling, while the worker nodes execute the containers. This setup provides an efficient and automated environment for deploying, managing, and scaling containerized applications.
Pre Requirements
First, let’s install the kind utility, a tool designed to create and manage local Kubernetes clusters using Docker containers as nodes. It’s mainly used for testing and developing Kubernetes clusters locally, without requiring a full cloud environment.
Install kind
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.24.0/kind-linux-amd64 chmod +x ./kind sudo mv ./kind /usr/local/bin/kind kind --version kind version 0.24.0
Install docker
Docker must be installed on our system to use kind because kind sets up a local Kubernetes cluster by running Kubernetes nodes as Docker containers. Both the control plane and worker nodes are essentially Docker containers managed by kind. Since kind depends on Docker to handle these containers, Docker needs to be installed and running for kind to work correctly.
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
Install kubectl
After setting up the cluster, we use kubectl to interact with it. It lets you run commands to deploy applications, manage resources, and monitor the cluster.
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg sudo chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo chmod 644 /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubectl
We can now create the local Kubernetes cluster using the following command
sudo kind create cluster --name local-cnpg Creating cluster "local-cnpg" ... ✓ Ensuring node image (kindest/node:v1.31.0) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 Set kubectl context to "kind-local-cnpg" You can now use your cluster with: kubectl cluster-info --context kind-local-cnpg root@ip-172-31-93-185:~# kubectl cluster-info --context kind-local-cnpg Kubernetes control plane is running at https://127.0.0.1:44337 CoreDNS is running at https://127.0.0.1:44337/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
When we create a Kubernetes cluster with Kind, it sets up nodes (virtual machines) that need an operating system and essential software to operate properly. Kindest/node: This is a Docker image that provides the essential components for a Kubernetes node.
We can verify that the command has created a Docker container on our system, which serves as the primary node (control-plane).
docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 702cfaffaca4 kindest/node:v1.31.0 "/usr/local/bin/entr…" 3 minutes ago Up 2 minutes 127.0.0.1:41739->6443/tcp local-cnpg-control-plane
Installing the Cloud Native Postgres
Now, we’ll install Cloud Native Postgres on our deployed cluster. To do this, we applied a YAML configuration file to the Kubernetes cluster. This file manages the creation and updating of various resources, such as namespaces, Custom Resource Definitions (CRDs), service accounts, roles, and deployments. The term “serverside-applied” indicates that these changes were made directly on the server side of the Kubernetes cluster.
kubectl apply --server-side -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/main/releases/cnpg-1.24.0.yaml namespace/cnpg-system serverside-applied customresourcedefinition.apiextensions.k8s.io/backups.postgresql.cnpg.io serverside-applied customresourcedefinition.apiextensions.k8s.io/clusterimagecatalogs.postgresql.cnpg.io serverside-applied customresourcedefinition.apiextensions.k8s.io/clusters.postgresql.cnpg.io serverside-applied customresourcedefinition.apiextensions.k8s.io/imagecatalogs.postgresql.cnpg.io serverside-applied customresourcedefinition.apiextensions.k8s.io/poolers.postgresql.cnpg.io serverside-applied customresourcedefinition.apiextensions.k8s.io/scheduledbackups.postgresql.cnpg.io serverside-applied serviceaccount/cnpg-manager serverside-applied clusterrole.rbac.authorization.k8s.io/cnpg-manager serverside-applied clusterrolebinding.rbac.authorization.k8s.io/cnpg-manager-rolebinding serverside-applied configmap/cnpg-default-monitoring serverside-applied service/cnpg-webhook-service serverside-applied deployment.apps/cnpg-controller-manager serverside-applied mutatingwebhookconfiguration.admissionregistration.k8s.io/cnpg-mutating-webhook-configuration serverside-applied validatingwebhookconfiguration.admissionregistration.k8s.io/cnpg-validating-webhook-configuration serverside-applied
After successfully installing Cloud Native Postgres, we can now proceed to deploy the PostgreSQL cluster using the CNPG operator.
Creating the 3-node PostgreSQL cluster
Create a local file named configure-PostgreSQL.yml and add the following content:
apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: cluster-example spec: instances: 3 storage: size: 3Gi
apiVersion: postgresql.cnpg.io/v1: This defines the API version provided by the CNPG operator. The postgresql.cnpg.io is a custom API group created by the CNPG operator when installed in your Kubernetes cluster, and /v1 specifies the API version.
kind: Cluster: This indicates that the resource being created is a Cluster object, which is a custom resource type managed by the CNPG operator. The operator recognizes and manages this type to deploy a PostgreSQL cluster.
These fields tell the CNPG operator how to interpret and manage the configuration.
When you apply this YAML file with kubectl, the CNPG operator in your Kubernetes cluster will
- Create the Necessary Pods: Deploy 3 PostgreSQL instances as defined in the spec section.
- Manage the Storage: Allocate 3Gi of storage for each instance as specified.
- Ensure High Availability and Manage Lifecycle: Handle replication, failover, updates, and other aspects of running the PostgreSQL cluster.
If the CNPG operator is not installed, the custom resource definitions (CRDs) like Cluster in apiVersion: postgresql.cnpg.io/v1 won’t be recognized, and the cluster creation will not occur.
Apply the configuration file to set up the 3-node PostgreSQL cluster
kubectl apply -f configure-PostgreSQL.yml cluster.postgresql.cnpg.io/cluster-example created
Get information about the pods
kubectl get pods NAME READY STATUS RESTARTS AGE cluster-example-1 1/1 Running 0 2m30s cluster-example-2 1/1 Running 0 2m9s cluster-example-3 1/1 Running 0 108s
To see the containers running within your Kubernetes pods, you should use the following Kubernetes commands which give more details about the containers inside each pod.
kubectl describe pod cluster-example-1
We can also access the running pod and connect to PostgreSQL from within it.
kubectl exec -it cluster-example-1 -- /bin/bash Defaulted container "postgres" out of: postgres, bootstrap-controller (init) postgres@cluster-example-1:/$ postgres@cluster-example-1:/$ psql psql (16.4 (Debian 16.4-1.pgdg110+1)) Type "help" for help. postgres=#
Get details about a specific cluster (cluster-example) within a Kubernetes environment.
kubectl get cluster cluster-example NAME AGE INSTANCES READY STATUS PRIMARY cluster-example 6m54s 3 3 Cluster in healthy state cluster-example-1
CNPG Plugin
A CNPG plugin is a specialized extension that enhances the functionality of the CNPG operator. It offers additional features or integrates with external systems, enabling you to customize and improve your PostgreSQL deployments in Kubernetes.
Install CNPG using the installation script
curl -sSfL \ https://github.com/cloudnative-pg/cloudnative-pg/raw/main/hack/install-cnpg-plugin.sh | \ sudo sh -s -- -b /usr/local/bin cloudnative-pg/cloudnative-pg info checking GitHub for latest tag cloudnative-pg/cloudnative-pg info found version: 1.24.0 for v1.24.0/linux/x86_64 cloudnative-pg/cloudnative-pg info installed /usr/local/bin/kubectl-cnpg
Display the current status and health of the PostgreSQL cluster
kubectl cnpg status cluster-example Cluster Summary Name: cluster-example Namespace: default System ID: 7409746140750782489 PostgreSQL Image: ghcr.io/cloudnative-pg/postgresql:16.4 Primary instance: cluster-example-1 Primary start time: 2024-09-01 18:39:32 +0000 UTC (uptime 12h30m6s) Status: Cluster in healthy state Instances: 3 Ready instances: 3 Current Write LSN: 0/8008870 (Timeline: 1 - WAL File: 000000010000000000000008) Certificates Status Certificate Name Expiration Date Days Left Until Expiration ---------------- --------------- -------------------------- cluster-example-ca 2024-11-30 18:34:05 +0000 UTC 89.48 cluster-example-replication 2024-11-30 18:34:05 +0000 UTC 89.48 cluster-example-server 2024-11-30 18:34:05 +0000 UTC 89.48 Continuous Backup status Not configured Physical backups No running physical backups found Streaming Replication status Replication Slots Enabled Name Sent LSN Write LSN Flush LSN Replay LSN Write Lag Flush Lag Replay Lag State Sync State Sync Priority Replication Slot ---- -------- --------- --------- ---------- --------- --------- ---------- ----- ---------- ------------- ---------------- cluster-example-2 0/8008870 0/8008870 0/8008870 0/8008870 00:00:00 00:00:00 00:00:00 streaming async 0 active cluster-example-3 0/8008870 0/8008870 0/8008870 0/8008870 00:00:00 00:00:00 00:00:00 streaming async 0 active Unmanaged Replication Slot Status No unmanaged replication slots found Managed roles status No roles managed Tablespaces status No managed tablespaces Pod Disruption Budgets status Name Role Expected Pods Current Healthy Minimum Desired Healthy Disruptions Allowed ---- ---- ------------- --------------- ----------------------- ------------------- cluster-example replica 2 2 1 1 cluster-example-primary primary 1 1 1 0 Instances status Name Database Size Current LSN Replication role Status QoS Manager Version Node ---- ------------- ----------- ---------------- ------ --- --------------- ---- cluster-example-1 29 MB 0/8008870 Primary OK BestEffort 1.24.0 local-cnpg-control-plane cluster-example-2 29 MB 0/8008870 Standby (async) OK BestEffort 1.24.0 local-cnpg-control-plane cluster-example-3 29 MB 0/8008870 Standby (async) OK BestEffort 1.24.0 local-cnpg-control-plane
In conclusion, Cloud Native Postgres offers a flexible solution for managing PostgreSQL clusters in Kubernetes, making it ideal for modern database environments. In upcoming blogs, we will explore how to use Cloud Native Postgres for production systems.