Skip to content

Alternative Datastores

Kamaji offers the possibility of having a different storage system than etcd thanks to kine integration.

Installing Drivers

The following make recipes help you to setup alternative Datastore resources. On the Management Cluster, you can use the following commands:

  • MySQL: $ make -C deploy/kine/mysql mariadb

  • PostgreSQL: $ make -C deploy/kine/postgresql postgresql

  • NATS: $ make -C deploy/kine/nats nats

Not for production

The default settings are not production grade: the following scripts are just used to test the Kamaji usage of different drivers.

Defining a default Datastore upon Kamaji installation

Use Helm to install the Kamaji Operator, making sure it uses a datastore with the proper driver datastore.driver=<MySQL|PostgreSQL|NATS>. Refer to the Chart's available values for more information on the supported options.

The following example shows how to install PostgreSQL as the alternative default datastore for Kamaji.

Use the makefiles under deploy/kine/postgresql to deploy the proper resources (e.g. deployment, certificates and secret). For the sake of this example, we'll override the variable NAME to create the resources so they match the sample manifest used in the next step.

make -C ./deploy/kine/postgresql/ postgresql NAME=gold

When all the resources are ready, apply the following sample chart:

kubectl apply -f ./config/samples/kamaji_v1alpha1_datastore_postgresql_gold.yaml 

Check the Datastore creation:

kubectl get datastores
NAME                 DRIVER       READY   AGE
postgresql-gold   PostgreSQL              18s

The Datastore stays not ready until the Kamaji chart is installed, since no operator is yet running to reconcile it. Install it with:

helm install kamaji ./charts/kamaji -n kamaji-system --create-namespace \
  --set kamaji-etcd.deploy=false \
  --set datastore.driver=PostgreSQL \
  --set datastore.endpoints[0]=postgres-gold-rw.postgres-system.svc:5432 \
  --set datastore.basicAuth.usernameSecret.name=postgres-gold-superuser \
  --set datastore.basicAuth.usernameSecret.namespace=postgres-system \
  --set datastore.basicAuth.usernameSecret.keyPath=username \
  --set datastore.basicAuth.passwordSecret.name=postgres-gold-superuser \
  --set datastore.basicAuth.passwordSecret.namespace=postgres-system \
  --set datastore.basicAuth.passwordSecret.keyPath=password \
  --set datastore.tlsConfig.certificateAuthority.certificate.name=postgres-gold-ca \
  --set datastore.tlsConfig.certificateAuthority.certificate.namespace=postgres-system \
  --set datastore.tlsConfig.certificateAuthority.certificate.keyPath=ca.crt \
  --set datastore.tlsConfig.certificateAuthority.privateKey.name=postgres-gold-ca \
  --set datastore.tlsConfig.certificateAuthority.privateKey.namespace=postgres-system \
  --set datastore.tlsConfig.certificateAuthority.privateKey.keyPath=ca.key \
  --set datastore.tlsConfig.clientCertificate.certificate.name=postgres-gold-root-cert \
  --set datastore.tlsConfig.clientCertificate.certificate.namespace=postgres-system \
  --set datastore.tlsConfig.clientCertificate.certificate.keyPath=tls.crt \
  --set datastore.tlsConfig.clientCertificate.privateKey.name=postgres-gold-root-cert \
  --set datastore.tlsConfig.clientCertificate.privateKey.namespace=postgres-system \
  --set datastore.tlsConfig.clientCertificate.privateKey.keyPath=tls.key

Once the operator is fully deployed, the Datastore resource should appear in a Ready state.

NAME                 DRIVER       READY   AGE
postgresql-gold   PostgreSQL   true    4m40s

Once the installation is complete, you can create Tenant Control Planes that use the alternative default datastore.

Apply a TenantControlPlane manifest:

cat > test-tenant-gold.yaml <<EOF 
apiVersion: kamaji.clastix.io/v1alpha1
kind: TenantControlPlane
metadata:
  name: k8s-133
  labels:
    tenant.clastix.io: k8s-133
spec:
  dataStore: postgresql-gold #this should match the Datastore's resource NAME
  controlPlane:
    deployment:
      replicas: 2
    service:
      serviceType: LoadBalancer
  kubernetes:
    version: "v1.33.0"
    kubelet:
      configurationJSONPatches:
        - op: add
          path: /featureGates
          value:
            KubeletCrashLoopBackOffMax: false
            KubeletEnsureSecretPulledImages: false
        - op: replace
          path: /cgroupDriver
          value: systemd
  networkProfile:
    port: 6443
  addons:
    coreDNS: {}
    kubeProxy: {}
    konnectivity:
      server:
        port: 8132
      agent:
        mode: DaemonSet
EOF

kubectl apply -f test-tenant-gold.yaml

Finally, clean up the resources:

kubectl delete -f test-tenant-gold.yaml
kubectl delete -f ./config/samples/kamaji_v1alpha1_datastore_postgresql_gold.yaml 
make -C ./deploy/kine/postgresql postgresql-destroy

Defining specific Datastore per Tenant Control Plane

Each TenantControlPlane can refer to a specific Datastore thanks to the /spec/dataStore field. This allows you to implement your preferred sharding or pooling strategy.

When this key is omitted, Kamaji will use the default datastore configured with its CLI argument --datastore.

The following example shows how to use MySQL as an alternative datastore for each TenantControlPlane.

Install Kamaji disabling the default datastore through:

helm install kamaji ./charts/kamaji -n kamaji-system --create-namespace --set kamaji-etcd.deploy=false

Use the makefiles under deploy/kine/mysql to deploy the proper resources (e.g. deployment, certificates and secret). For the sake of this example, we'll override the variable NAME to create the resources so they match the sample manifest used in the next step.

make -C ./deploy/kine/mysql mariadb NAME=gold

Then, apply the sample DataStore manifest:

kubectl apply -f ./config/samples/kamaji_v1alpha1_datastore_mysql_gold.yaml

Check the created datastore with:

kubectl get datastores

NAME         DRIVER   READY   AGE
mysql-gold   MySQL    true    30s

Apply the TenantControlPlane manifest:

cat > test-tenant-gold.yaml <<EOF 
apiVersion: kamaji.clastix.io/v1alpha1
kind: TenantControlPlane
metadata:
  name: k8s-133
  labels:
    tenant.clastix.io: k8s-133
spec:
  dataStore: mysql-gold #this should match the Datastore's resource NAME
  controlPlane:
    deployment:
      replicas: 2
    service:
      serviceType: LoadBalancer
  kubernetes:
    version: "v1.33.0"
    kubelet:
      configurationJSONPatches:
        - op: add
          path: /featureGates
          value:
            KubeletCrashLoopBackOffMax: false
            KubeletEnsureSecretPulledImages: false
        - op: replace
          path: /cgroupDriver
          value: systemd
  networkProfile:
    port: 6443
  addons:
    coreDNS: {}
    kubeProxy: {}
    konnectivity:
      server:
        port: 8132
      agent:
        mode: DaemonSet
EOF

kubectl apply -f test-tenant-gold.yaml

Check the TenantControlPlane through:

kubectl get tcp -A 
NAMESPACE   NAME      VERSION   INSTALLED VERSION   STATUS   CONTROL-PLANE ENDPOINT   KUBECONFIG                 DATASTORE    AGE
default     k8s-133   v1.33.0   v1.33.0             Ready    10.10.10.200:6443        k8s-133-admin-kubeconfig   mysql-gold   43s

Finally, cleanup the resources:

kubectl delete -f test-tenant-gold.yaml
kubectl delete -f ./config/samples/kamaji_v1alpha1_datastore_mysql_gold.yaml 
make -C ./deploy/kine/mysql mariadb-destroy NAME=gold

NATS considerations

The NATS support is still experimental, mostly because multi-tenancy is NOT supported.

A NATS based DataStore can host one and only one Tenant Control Plane. When a TenantControlPlane refers to a NATS DataStore already used by another instance, its reconciliation will fail and be blocked.