Announcing KubeDB v2025.8.31

KubeDB v2025.8.31 introduces new features like storage migration, TLS reconfiguration, authentication rotation, Git-Sync initialization support, and version updates across various databases. This release enhances operational efficiency, security, and flexibility for managing databases in Kubernetes environments.

Key Changes

  • Storage Migration Support: Added storage migration for Postgres and MySQL to change StorageClass seamlessly.
  • TLS and Authentication Enhancements: Introduced ReconfigureTLS and RotateAuth OpsRequests for ClickHouse and Hazelcast.
  • Git-Sync Initialization: New support for initializing databases from public/private Git repositories in MariaDB, Redis, Pgpool, and Pgbouncer.
  • Recommendation Engine: Added recommendations for Pgpool, Hazelcast, and Pgbouncer, including version updates, TLS rotation, and auth secret rotation.
  • Version Updates: New version for Postgres (16.10).
  • Distributed Database Enhancements: Improvements in PodPlacementPolicy, OpsRequest support for TLS reconfiguration, version upgrades, volume expansion, and auth rotation in distributed MariaDB Galera Cluster mode, with fixed full cluster disaster recovery.

ClickHouse

This release introduces ReconfigureTLS, RotateAuth OpsRequests for ClickHouse

ReconfigureTLS

To configure TLS in Ignite using a ClickHouseOpsRequest, we have introduced ReconfigureTLS. You can enable TLS in ClickHouse by simply deploying a YAML configuration:

apiVersion: ops.kubedb.com/v1alpha1
kind: ClickHouseOpsRequest
metadata:
  name: chops-add-tls
  namespace: demo
spec:
  type: ReconfigureTLS
  databaseRef:
    name: clickhouse-prod
  tls:
    sslVerificationMode: "relaxed"
    issuerRef:
      apiGroup: cert-manager.io
      kind: Issuer
      name: clickhouse-ca-issuer
    certificates:
      - alias: server
        subject:
          organizations:
            - kubedb:server
        dnsNames:
          - localhost
        ipAddresses:
          - "127.0.0.1"
  timeout: 10m
  apply: IfReady

RotateAuth

To modify the credentials in ClickHouse, you can use RotateAuth. This ClickHouseOpsRequest will update the credential.

apiVersion: ops.kubedb.com/v1alpha1
kind: ClickHouseOpsRequest
metadata:
  name: chops-rotate-auth-generated
  namespace: demo
spec:
  type: RotateAuth
  databaseRef:
    name: clickhouse-prod
  timeout: 5m
  apply: IfReady

Hazelcast

Recommendation Engine

KubeDB now supports recommendations for Hazelcast, including Version Update, TLS Certificate Rotation, and Authentication Secret Rotation. Recommendations are generated if .spec.authSecret.rotateAfter is set, based on:

AuthSecret lifespan > 1 month with < 1 month remaining. AuthSecret lifespan < 1 month with < 1/3 lifespan remaining. Example recommendation:

apiVersion: supervisor.appscode.com/v1alpha1
kind: Recommendation
metadata:
  annotations:
    kubedb.com/recommendation-for-version: 5.5.2
  creationTimestamp: "2025-09-01T11:07:26Z"
  generation: 1
  labels:
    app.kubernetes.io/instance: hazelcast
    app.kubernetes.io/managed-by: kubedb.com
    app.kubernetes.io/type: version-update
  name: hazelcast-x-hazelcast-x-update-version-yln1o1
  namespace: demo
  resourceVersion: "8102465"
  uid: 8fa1d430-a94d-4bed-819f-216ea659b7c3
spec:
  backoffLimit: 10
  description: Latest patch version is available. Recommending version Update from
    5.5.2 to 5.5.6.
  operation:
    apiVersion: ops.kubedb.com/v1alpha1
    kind: HazelcastOpsRequest
    metadata:
      name: update-version
      namespace: demo
    spec:
      databaseRef:
        name: hazelcast
      type: UpdateVersion
      updateVersion:
        targetVersion: 5.5.6
    status: {}
  recommender:
    name: kubedb-ops-manager
  requireExplicitApproval: true
  rules:
    failed: has(self.status) && has(self.status.phase) && self.status.phase == 'Failed'
    inProgress: has(self.status) && has(self.status.phase) && self.status.phase ==
      'Progressing'
    success: has(self.status) && has(self.status.phase) && self.status.phase == 'Successful'
  target:
    apiGroup: kubedb.com
    kind: Hazelcast
    name: hazelcast
  vulnerabilityReport:
    message: no matches for kind "ImageScanReport" in version "scanner.appscode.com/v1alpha1"
    status: Failure
status:
  approvalStatus: Pending
  failedAttempt: 0
  outdated: false
  parallelism: Namespace
  phase: Pending
  reason: WaitingForApproval

This release introduces multiple OpsRequests for Hazelcast, including Rotate-Authentication, Reconfigure-TLS To configure TLS in Hazelcast using a HazelcastOpsRequest, we have introduced ReconfigureTLS. You can enable TLS in Hazelast by simply deploying a YAML configuration:

apiVersion: ops.kubedb.com/v1alpha1
kind: HazelcastOpsRequest
metadata:
  name: hzops-add-tls
  namespace: demo
spec:
  type: ReconfigureTLS
  databaseRef:
    name: hz
  tls:
    issuerRef:
      name: hz-issuer
      kind: Issuer
      apiGroup: "cert-manager.io"
    certificates:
      - alias: client
        subject:
          organizations:
            - hazelcast
          organizationalUnits:
            - client
  timeout: 5m
  apply: IfReady

Rotate-Authentication

To modify the credential in Hazelcast you can use RotateAuth. This HazelcastOpsRequest will update the credential.

apiVersion: ops.kubedb.com/v1alpha1
kind: HazelcastOpsRequest
metadata:
  name: hzops-rotate-auth-generated
  namespace: demo
spec:
  type: RotateAuth
  databaseRef:
    name: hz
  apply: IfReady

MariaDB

In this release, Ops-Request now supports TLS reconfiguration, version upgrades, volume expansion, and authentication rotation for distributed MariaDB in Galera Cluster mode. Additionally, full cluster disaster recovery support has been fixed.

Git-Sync

We have added a new feature now you can initialize MariaDB from the public/private git repository. Here’s a quick example of how to configure it.

From Public Repository

apiVersion: kubedb.com/v1
kind: MariaDB
metadata:
  name: sample-mariadb
  namespace: demo
spec:
  init:
   script:
     scriptPath: "current"
     git:
       args:
       - --repo=https://github.com/kubedb/mysql-init-scripts
       - --depth=1
       - --period=60s
       - --link=current
       - --root=/my-path
       # terminate after successful sync
       - --one-time 
  version: "10.5.23"
  storage:
    accessModes:
    - ReadWriteOnce
    resources:
      requests:
        storage: 1Gi
  deletionPolicy: WipeOut

From Private Repository

Create a kubernetes secret containing your SSH keys:

ssh-keyscan $YOUR_GIT_HOST > /tmp/known_hosts
kubectl create secret generic -n demo git-creds \
   --from-file=ssh=$HOME/.ssh/id_rsa \
   --from-file=known_hosts=/tmp/known_hosts

Apply the following yaml:

apiVersion: kubedb.com/v1
kind: MariaDB
metadata:
  name: sample-mariadb
  namespace: demo
spec:
  init:
   script:
     scriptPath: "current"
     git:
       args:
       # update with your private repository    
       - --repo=git@github.com:refat75/mysql-init-scripts.git
       - --depth=1
       - --period=60s
       - --link=current
       - --root=/my-path
       # terminate after successful sync
       - --one-time 
       authSecret:
         name: git-creds
       # run as git sync user 
       securityContext:
         runAsUser: 65533
  version: "10.5.23"
  storage:
    accessModes:
    - ReadWriteOnce
    resources:
      requests:
        storage: 1Gi
  deletionPolicy: WipeOut

This example refers to initialization from a private git repository .spec.init.git.args represents the arguments required to represent the git repository and its actions. You can find details at git_syc_docs

.spec.init.git.authSecret holds the necessary information to pull from the private repository. You have to provide a secret with the id_rsa and github knwonhosts. You can find detailed information at git_sync_docs .

If you are using a different authentication mechanism for your git repository, please consult the documentation for git-sync project.

MySQL

In this release, a new OpsRequest called StorageMigration has been introduced. It allows you to change your database’s StorageClass seamlessly.

First deploy a standalone MySQL:

apiVersion: kubedb.com/v1
kind: MySQL
metadata:
  name: sample-mysql
  namespace: demo
spec:
  version: "8.0.35"
  storageType: Durable
  storage:
    storageClassName: longhorn
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 16Gi
  deletionPolicy: WipeOut

Then apply the following StorageMigration ops-request:

apiVersion: ops.kubedb.com/v1alpha1
kind: MySQLOpsRequest
metadata:
  name: storage-migration
  namespace: demo
spec:
  type: StorageMigration
  databaseRef:
    name: sample-mysql
  migration:
    storageClassName: local-path
    oldPVReclaimPolicy: Retain

Note: If you don’t want to keep the old PersistentVolume set spec.migration.oldPVReclaimPolicy to Delete

Pgbouncer

KubeDB now supports Recommandation for PgBouncer. For more details follow kubedb docs

Git-Sync

We have added a new feature now you can initialize Redis from the public/private git repository. Here’s a quick example of how to configure it.

From Public Repository

apiVersion: kubedb.com/v1
kind: PgBouncer
metadata:
  name: pb-demo
  namespace: demo
spec:
  version: "1.24.0"
  replicas: 1
  database:
    syncUsers: true
    databaseName: "postgres"
    databaseRef:
      name: "postgres-demo"
      namespace: demo
  connectionPool:
    maxClientConnections: 20
    reservePoolSize: 5
  init:
    script:
      scriptPath: "sync-test"
      git:
        args:
        - --repo=<desired repo>
        - --depth=1
        - --add-user=true
        - --period=60s
        - --one-time
        securityContext:
          runAsUser: 999

From Private Repository

apiVersion: kubedb.com/v1
kind: PgBouncer
metadata:
  name: pb-demo
  namespace: demo
spec:
  version: "1.24.0"
  replicas: 1
  database:
    syncUsers: true
    databaseName: "postgres"
    databaseRef:
      name: "postgres-demo"
      namespace: demo
  connectionPool:
    maxClientConnections: 20
    reservePoolSize: 5
  init:
  script:
    scriptPath: "current"
    git:
      args:
      # use --ssh for private repository
      - --ssh
      - --repo=<desired repo>
      - --depth=1
      - --period=60s
      - --link=current
      - --root=/init-script-from-git
      # terminate after successful sync
      - --one-time
      authSecret:
        name: git-creds
      # run as git sync user
        securityContext:
          runAsUser: 999

This example refers to initialization from a private git repository .spec.init.git.args represents the arguments required to represent the git repository and its actions.

.spec.init.git.authSecret holds the necessary information to pull from the private repository. You have to provide a secret with the id_rsa and github knwonhosts . If you are using a different authentication mechanism for your git repository, please consult the documentation for the git-sync project. .spec.init.git.securityContext.runAsUser the init container git_sync runs with user 999. .spec.podTemplate.Spec.securityContext.fsGroup In order to read the ssh key the fsGroup also should be 999.

Pgpool

KubeDB now supports Recommandation for Pgpool. For more details follow kubedb docs

Git-Sync

We have added a new feature now you can initialize Redis from the public/private git repository. Here’s a quick example of how to configure it.

From Public Repository

apiVersion: kubedb.com/v1alpha2
kind: Pgpool
metadata:
  name: pgpool-demo
  namespace: demo
spec:
  version: "4.4.5"
  replicas: 1
  postgresRef:
    name: <postgres-ref>
    namespace: demo
  initConfig:
    pgpoolConfig:
      num_init_children : 6
      max_pool : 65
      child_life_time : 400
  deletionPolicy: WipeOut
  init:
    script:
      scriptPath: "sync-test"
      git:
        args:
        - --repo=<desired repo>
        - --depth=1
        - --add-user=true
        - --period=60s
        - --one-time
        securityContext:
          runAsUser: 999

From Private Repository

apiVersion: kubedb.com/v1alpha2
kind: Pgpool
metadata:
  name: pgpool-demo
  namespace: demo
spec:
  version: "4.4.5"
  replicas: 1
  postgresRef:
    name: <postgres-ref>
    namespace: demo
  initConfig:
    pgpoolConfig:
      num_init_children : 6
      max_pool : 65
      child_life_time : 400
  deletionPolicy: WipeOut
  init:
  script:
    scriptPath: "current"
    git:
      args:
      # use --ssh for private repository
      - --ssh
      - --repo=<desired repo>
      - --depth=1
      - --period=60s
      - --link=current
      - --root=/init-script-from-git
      # terminate after successful sync
      - --one-time
      authSecret:
        name: git-creds
      # run as git sync user
        securityContext:
          runAsUser: 999

This example refers to initialization from a private git repository .spec.init.git.args represents the arguments required to represent the git repository and its actions.

.spec.init.git.authSecret holds the necessary information to pull from the private repository. You have to provide a secret with the id_rsa and github knwonhosts. If you are using a different authentication mechanism for your git repository, please consult the documentation for the git-sync project. .spec.init.git.securityContext.runAsUser the init container git_sync runs with user 999. .spec.podTemplate.Spec.securityContext.fsGroup In order to read the ssh key the fsGroup also should be 999.

Postgres

A new OpsRequest called StorageMigration has been introduced. It allows you to change your database’s StorageClass seamlessly.

First deploy a standalone PostgreSQL:

apiVersion: kubedb.com/v1
kind: Postgres
metadata:
  name: sample-postgres
  namespace: demo
spec:
  version: "13.13"
  storageType: Durable
  storage:
    storageClassName: "longhorn"
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 1Gi
  deletionPolicy: WipeOut

Then apply the following StorageMigration ops-request:

apiVersion: ops.kubedb.com/v1alpha1
kind: PostgresOpsRequest
metadata:
  name: storage-migration
  namespace: demo
spec:
  type: StorageMigration
  databaseRef:
    name: sample-postgres
  migration:
    storageClassName: local-path
    oldPVReclaimPolicy: Retain

Note: If you don’t want to keep the old PersistentVolume set spec.migration.oldPVReclaimPolicy to Delete

Redis

Git-Sync

We have added a new feature now you can initialize Redis from the public/private git repository. Here’s a quick example of how to configure it.

From Public Repository

apiVersion: kubedb.com/v1
kind: Redis
metadata:
  name: redis-demo
  namespace: demo
spec:
  version: 7.2.4
  mode: Cluster
  init:
    script:
      scriptPath: "sync-test"
      git:
        args:
        - --repo=<desired git repository>
        - --depth=1
        - --add-user=true
        - --period=60s
        - --one-time
        securityContext:
          runAsUser: 999
  cluster:
    shards: 3
    replicas: 2
  storageType: Durable
  storage:
    resources:
      requests:
        storage: 20M
    storageClassName: "standard"
    accessModes:
    - ReadWriteOnce
  deletionPolicy: WipeOut

From Private Repository

apiVersion: kubedb.com/v1
kind: Redis
metadata:
  name: redis-demo
  namespace: demo
spec:
  version: 7.2.4
  mode: Cluster
  init:
  script:
    scriptPath: "current"
    git:
      args:
      # use --ssh for private repository
      - --ssh
      - --repo=<desired repo>
      - --depth=1
      - --period=60s
      - --link=current
      - --root=/init-script-from-git
      # terminate after successful sync
      - --one-time
      authSecret:
        name: git-creds
      # run as git sync user
        securityContext:
          runAsUser: 999
  cluster:
    shards: 3
    replicas: 2
  storageType: Durable
  storage:
    resources:
      requests:
        storage: 20M
    storageClassName: "standard"
    accessModes:
    - ReadWriteOnce
  deletionPolicy: WipeOut

This example refers to initialization from a private git repository .spec.init.git.args represents the arguments required to represent the git repository and its actions.

.spec.init.git.authSecret holds the necessary information to pull from the private repository. You have to provide a secret with the id_rsa and github knwonhosts. If you are using a different authentication mechanism for your git repository, please consult the documentation for the git-sync project. .spec.init.git.securityContext.runAsUser the init container git_sync run with user 999. .spec.podTemplate.Spec.securityContext.fsGroup In order to read the ssh key the fsGroup also should be 999.

Common Changes

PlacementPolicy for PetSet

We have updated the api of PlacementPolicy for Distributed PetSet.

Previous api:

apiVersion: apps.k8s.appscode.com/v1
kind: PlacementPolicy
metadata:
  labels:
    app.kubernetes.io/managed-by: Helm
  name: distributed-postgres
spec:
  nodeSpreadConstraint:
    maxSkew: 1
    whenUnsatisfiable: ScheduleAnyway
  ocm:
    distributionRules:
      - clusterName: demo-controller
        replicas:
          - 0
          - 2
      - clusterName: demo-worker
        replicas:
          - 1
    sliceName: demo-slice
  zoneSpreadConstraint:
    maxSkew: 1
    whenUnsatisfiable: ScheduleAnyway

New Api:

apiVersion: apps.k8s.appscode.com/v1
kind: PlacementPolicy
metadata:
   labels:
      app.kubernetes.io/managed-by: Helm
   name: distributed-postgres
spec:
   clusterSpreadConstraint:
      distributionRules:
         - clusterName: demo-controller
           replicaIndices:
              - 0
              - 2
         - clusterName: demo-worker
           replicaIndices:
              - 1
      slice:
         projectNamespace: kubeslice-demo-distributed-mariadb
         sliceName: demo-slice
   nodeSpreadConstraint:
      maxSkew: 1
      whenUnsatisfiable: ScheduleAnyway
   zoneSpreadConstraint:
      maxSkew: 1
      whenUnsatisfiable: ScheduleAnyway

you can see changes were introduced under spec.clusterSpreadConstraint section. spec.ocm is replaced with spec.clusterSpreadConstraint.distributionRules and spec.clusterSpreadConstraint.slice.

New field spec.clusterSpreadConstraint.slice.projectNamespace is added to specify the project namespace of the slice.

Find domain

In all the previous releases, communications inside the k8s cluster happened using <>.<namespace>.svc.cluster.local (aka pod dns). In this release, we added support for different domains where “cluster.local” is even not resolvable. So, the pod dns will be <>.<namespace>.svc.<domain>. This is helpful when users created the kubernetes cluster with their custom domain.

Support


TAGS

Get Up and Running Quickly

Deploy, manage, upgrade Kubernetes on any cloud and automate deployment, scaling, and management of containerized applications.