Skip to main content

Kubernetes: Adding CloudnativePG Databases

Kubernetes - This article is part of a series.
Part 7: This Article

Deploying postgres databases using CloudnativePG
#

CloudnativePG provides an easy to use API to deploy postgres databases on our cluster drawing from a single image pool with easy backups and configuration.

Deploying the cloudnativePG Helm chart and image catalog
#

Before using the cloudnativePG API we must deploy the official helm chart. We must also define a postgres image catalog for database deployments to use:

{
  inputs,
  ...
}:
{
  flake.modules.nixos.postgres =
    {
      config,
      lib,
      pkgs,
      ...
    }:
    let
      chart = {
        name = "cloudnative-pg";
        repo = "https://cloudnative-pg.github.io/charts";
        version = "0.28.0";
        hash = "sha256-gdN4lPNgbfm9kcVRkFP0GnnoM9KKyiUv+zkpTLnLGa4=";
      };
      image = pkgs.dockerTools.pullImage {
        imageName = "ghcr.io/cloudnative-pg/cloudnative-pg";
        imageDigest = "sha256:68074486205a33ed41928761e22ad48278c690feebe8316727a1c6b3380f9e5e";
        sha256 = "sha256-UWieKoPlh4RvK73QJcOC9+76kYzKruSsh5+uZZELVnU=";
        finalImageTag = "1.29.0";
        arch = "amd64";
      };
      postgresImage = pkgs.dockerTools.pullImage {
        imageName = "ghcr.io/cloudnative-pg/postgresql";
        imageDigest = "sha256:d879dfab951cb0eef9beac367f259d08ea1c04ae84699526854ff9ae478656be";
        sha256 = "sha256-ngZW2rMlOaGm/VbSR2AHGCQis88zt+S2I++Oi6hqcKE=";
        finalImageTag = "18.3-standard-trixie";
        arch = "amd64";
      };
    in
    {
      options = {
        postgres.enable = lib.mkEnableOption "Cloudnative-pg helm chart on k3s";
      };

      config = lib.mkIf config.postgres.enable {
        services.k3s = {
          images = [
            image
            postgresImage
          ];
          autoDeployCharts = {
            cloudnative-pg = chart // {
              targetNamespace = "database";
              createNamespace = true;
              values = {
                image = {
                  repository = image.imageName;
                  tag = image.imageTag;
                };
                resources = {
                  requests.cpu = "100m";
                  requests.memory = "128Mi";
                  limits.cpu = "200m";
                  limits.memory = "256Mi";
                };
              };
              extraDeploy = [
                {
                  apiVersion = "postgresql.cnpg.io/v1";
                  kind = "ClusterImageCatalog";
                  metadata = {
                    name = "postgresql-global";
                  };
                  spec = {
                    images = [
                      {
                        major = 18;
                        image = "${postgresImage.imageName}:${postgresImage.imageTag}";
                      }
                    ];
                  };
                }
              ];
            };
          };
        };
      };
    };
}

Deploying postgres databases
#

Once installed, we can use CloudnativePG to define postgres databases for use in complex service deployments:

{
  self,
  inputs,
  ...
}:
{
  flake.modules.nixos.immich-postgres =
    {
      config,
      lib,
      pkgs,
      ...
    }:
    {
      config = lib.mkIf config.immich.enable {
        services.k3s.autoDeployCharts.immich.extraDeploy = [
          {
            apiVersion = "postgresql.cnpg.io/v1";
            kind = "Cluster";
            metadata = {
              namespace = "immich";
              name = "immich-postgres";
            };
            spec = {
              instances = 1;
              imageCatalogRef = {
                apiGroup = "postgresql.cnpg.io";
                kind = "ClusterImageCatalog";
                name = "postgresql-global";
                major = 18;
              };
              storage.size = "8Gi";
              managed.roles = [
                {
                  name = "immich";
                  passwordSecret.name = "immich-secrets";
                  superuser = true;
                  login = true;
                }
              ];
              bootstrap.initdb = {
                database = "immich";
                owner = "immich";
                secret.name = "immich-secrets";
              };
              resources = {
                requests.cpu = "200m";
                requests.memory = "256Mi";
                limits.cpu = "1000m";
                limits.memory = "1Gi";
              };
            };
          }
        ];
      };
    };
}

Kubernetes - This article is part of a series.
Part 7: This Article