New to KubeDB? Please start here.
Running Weaviate
This tutorial will show you how to use KubeDB to run a Weaviate vector database.
Before You Begin
At first, you need to have a Kubernetes cluster, and the
kubectlcommand-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using kind.Now, install KubeDB operator in your cluster following the steps here and make sure to include the Weaviate feature gate during installation.
To keep things isolated, this tutorial uses a separate namespace called
demothroughout this tutorial.
$ kubectl create ns demo
namespace/demo created
Note: YAML files used in this tutorial are stored in docs/examples/weaviate/quickstart folder in GitHub repository kubedb/docs.
Find Available StorageClass
We will need to provide a StorageClass in the Weaviate CR specification. Check the available StorageClass in your cluster using the following command:
$ kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
local-path (default) rancher.io/local-path Delete WaitForFirstConsumer false 38h
longhorn driver.longhorn.io Delete Immediate true 6m27s
longhorn-static driver.longhorn.io Delete Immediate true 6m23s
Here, we have the longhorn StorageClass in our cluster. It supports volume expansion, which is required by some of the day-2 operations (such as Volume Expansion and Storage Autoscaling) shown in later guides.
Find Available WeaviateVersion
When you install KubeDB, it creates a WeaviateVersion CR for each supported Weaviate version. Let’s check the available WeaviateVersions:
$ kubectl get weaviateversions
NAME VERSION DB_IMAGE DEPRECATED AGE
1.33.1 1.33.1 ghcr.io/appscode-images/weaviate:1.33.1 34h
Notice the DEPRECATED column. true means that the WeaviateVersion is deprecated for the current KubeDB version and KubeDB will not work for that version.
In this tutorial, we will use the 1.33.1 WeaviateVersion CR to create a Weaviate cluster.
Create a Weaviate Database
KubeDB implements a Weaviate CRD to define the specification of a Weaviate database.
Below is the Weaviate object created in this tutorial:
apiVersion: kubedb.com/v1alpha2
kind: Weaviate
metadata:
name: weaviate-sample
namespace: demo
spec:
version: 1.33.1
replicas: 3
storageType: Durable
storage:
storageClassName: longhorn
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
podTemplate:
spec:
containers:
- name: weaviate
securityContext:
runAsNonRoot: false
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 500m
memory: 1Gi
deletionPolicy: WipeOut
healthChecker:
periodSeconds: 10
timeoutSeconds: 10
failureThreshold: 3
$ kubectl create -f https://github.com/kubedb/docs/raw/v2026.7.10/docs/examples/weaviate/quickstart/weaviate-sample.yaml
weaviate.kubedb.com/weaviate-sample created
Here,
spec.versionis the name of theWeaviateVersionCR where the Docker images are specified. In this tutorial, a Weaviate1.33.1cluster is created.spec.replicasspecifies the number of Weaviate nodes that form the cluster. A multi-node cluster lets Weaviate replicate collections across nodes for high availability.spec.storageTypecan beDurableorEphemeral.Durableuses a PersistentVolumeClaim;Ephemeraluses anemptyDir.spec.storagespecifies the size and StorageClass of the PVC that will be dynamically allocated to store data for each Weaviate pod. This storage spec will be passed to the PetSet created by the KubeDB operator to run database pods.spec.deletionPolicyspecifies what KubeDB should do when a user tries to delete theWeaviateCR. Deletion policyDoNotTerminateprevents deletion of this object if the admission webhook is enabled.
Note:
spec.storagesection is used to create PVC for the database pods. Specify onlyrequests, notlimits— a PVC does not resize automatically.
Now, let’s watch the progress of creating the Weaviate cluster:
$ kubectl get weaviate -n demo weaviate-sample -w
NAME TYPE VERSION STATUS AGE
weaviate-sample kubedb.com/v1alpha2 1.33.1 Provisioning 6s
weaviate-sample kubedb.com/v1alpha2 1.33.1 Provisioning 2m
weaviate-sample kubedb.com/v1alpha2 1.33.1 Ready 5m21s
Describe Weaviate
Let’s describe the Weaviate object to see its current state:
$ kubectl describe weaviate -n demo weaviate-sample
Name: weaviate-sample
Namespace: demo
Labels: <none>
Annotations: <none>
API Version: kubedb.com/v1alpha2
Kind: Weaviate
Metadata:
Creation Timestamp: 2026-06-30T17:23:54Z
Finalizers:
kubedb.com/weaviate
Generation: 3
Resource Version: 61772
UID: ac548e5a-1d08-4ca6-946e-cdd0a34a2d92
Spec:
Auth Secret:
Active From: 2026-06-30T17:23:54Z
API Group:
Kind:
Name: weaviate-sample-auth
Deletion Policy: WipeOut
Health Checker:
Failure Threshold: 3
Period Seconds: 10
Timeout Seconds: 10
Pod Template:
Controller:
Metadata:
Spec:
Containers:
Name: weaviate
Resources:
Limits:
Cpu: 500m
Memory: 1Gi
Requests:
Cpu: 500m
Memory: 1Gi
Security Context:
Allow Privilege Escalation: false
Capabilities:
Drop:
ALL
Run As Non Root: false
Seccomp Profile:
Type: RuntimeDefault
Pod Placement Policy:
Name: default
Security Context:
Replicas: 3
Storage:
Access Modes:
ReadWriteOnce
Resources:
Requests:
Storage: 1Gi
Storage Class Name: longhorn
Storage Type: Durable
Version: 1.33.1
Status:
Conditions:
Last Transition Time: 2026-06-30T17:23:54Z
Message: The KubeDB operator has started the provisioning of Weaviate demo/weaviate-sample
Observed Generation: 1
Reason: DatabaseProvisioningStartedSuccessfully
Status: True
Type: ProvisioningStarted
Last Transition Time: 2026-06-30T17:28:43Z
Message: All replicas are ready
Observed Generation: 3
Reason: AllReplicasReady
Status: True
Type: ReplicaReady
Last Transition Time: 2026-06-30T17:28:54Z
Message: The Weaviate: demo/weaviate-sample is accepting client requests
Observed Generation: 3
Reason: DatabaseAcceptingConnectionRequest
Status: True
Type: AcceptingConnection
Last Transition Time: 2026-06-30T17:28:55Z
Message: The Weaviate: demo/weaviate-sample is ready.
Observed Generation: 3
Reason: ReadinessCheckSucceeded
Status: True
Type: Ready
Last Transition Time: 2026-06-30T17:28:55Z
Message: The Weaviate demo/weaviate-sample is successfully provisioned.
Observed Generation: 3
Reason: DatabaseSuccessfullyProvisioned
Status: True
Type: Provisioned
Phase: Ready
Events: <none>
Find Underlying Kubernetes Resources
KubeDB operator creates a PetSet, PVCs, Services, and Secrets for the Weaviate database. Let’s check them:
$ kubectl get petset -n demo weaviate-sample
NAME AGE
weaviate-sample 5m19s
$ kubectl get pods -n demo -l app.kubernetes.io/instance=weaviate-sample
NAME READY STATUS RESTARTS AGE
weaviate-sample-0 1/1 Running 0 62s
weaviate-sample-1 1/1 Running 0 55s
weaviate-sample-2 1/1 Running 0 44s
$ kubectl get pvc -n demo
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
data-weaviate-sample-0 Bound pvc-b8b6d9e6-634f-4ead-b1fd-1bfe549976e4 1Gi RWO longhorn <unset> 5m18s
data-weaviate-sample-1 Bound pvc-4e9329c0-8a3d-4402-919c-afa4fe2144c9 1Gi RWO longhorn <unset> 56s
data-weaviate-sample-2 Bound pvc-a846947c-212f-4aea-92a7-c8f88ae7f463 1Gi RWO longhorn <unset> 45s
$ kubectl get service -n demo
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
weaviate-sample ClusterIP 10.43.98.199 <none> 8080/TCP,50051/TCP,7102/TCP,7103/TCP,8300/TCP 5m23s
weaviate-sample-pods ClusterIP None <none> 8080/TCP,50051/TCP,7102/TCP,7103/TCP,8300/TCP 5m23s
KubeDB creates two services for a Weaviate cluster:
weaviate-sample— the primaryClusterIPservice used by clients. It exposes the REST API (8080, or8443when TLS is enabled), the gRPC API (50051), and the internal cluster ports.weaviate-sample-pods— a headless (governing) service used for stable per-pod DNS within the cluster.
The internal ports are: 8080 (HTTP REST), 50051 (gRPC), 8300 (raft consensus), 7102 (gossip), and 7103 (cluster data).
Verify Weaviate YAML Output
KubeDB operator sets the status.phase to Ready once the database is successfully created and is able to accept client connections. Run the following command to see the modified Weaviate object:
$ kubectl get weaviate -n demo weaviate-sample -o yaml
apiVersion: kubedb.com/v1alpha2
kind: Weaviate
metadata:
creationTimestamp: "2026-06-30T17:23:54Z"
finalizers:
- kubedb.com/weaviate
generation: 3
name: weaviate-sample
namespace: demo
resourceVersion: "61772"
uid: ac548e5a-1d08-4ca6-946e-cdd0a34a2d92
spec:
authSecret:
activeFrom: "2026-06-30T17:23:54Z"
apiGroup: ""
kind: ""
name: weaviate-sample-auth
deletionPolicy: WipeOut
healthChecker:
failureThreshold: 3
periodSeconds: 10
timeoutSeconds: 10
podTemplate:
controller: {}
metadata: {}
spec:
containers:
- name: weaviate
resources:
limits:
cpu: 500m
memory: 1Gi
requests:
cpu: 500m
memory: 1Gi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
runAsNonRoot: false
seccompProfile:
type: RuntimeDefault
podPlacementPolicy:
name: default
securityContext: {}
replicas: 3
storage:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: longhorn
storageType: Durable
version: 1.33.1
status:
conditions:
- lastTransitionTime: "2026-06-30T17:23:54Z"
message: The KubeDB operator has started the provisioning of Weaviate demo/weaviate-sample
observedGeneration: 1
reason: DatabaseProvisioningStartedSuccessfully
status: "True"
type: ProvisioningStarted
- lastTransitionTime: "2026-06-30T17:28:43Z"
message: All replicas are ready
observedGeneration: 3
reason: AllReplicasReady
status: "True"
type: ReplicaReady
- lastTransitionTime: "2026-06-30T17:28:54Z"
message: 'The Weaviate: demo/weaviate-sample is accepting client requests'
observedGeneration: 3
reason: DatabaseAcceptingConnectionRequest
status: "True"
type: AcceptingConnection
- lastTransitionTime: "2026-06-30T17:28:55Z"
message: 'The Weaviate: demo/weaviate-sample is ready.'
observedGeneration: 3
reason: ReadinessCheckSucceeded
status: "True"
type: Ready
- lastTransitionTime: "2026-06-30T17:28:55Z"
message: The Weaviate demo/weaviate-sample is successfully provisioned.
observedGeneration: 3
reason: DatabaseSuccessfullyProvisioned
status: "True"
type: Provisioned
phase: Ready
Connect to Weaviate
By default, KubeDB enables API-key authentication for the Weaviate cluster and stores the generated key in a Secret named <database-name>-auth. Let’s check it:
$ kubectl get secret -n demo weaviate-sample-auth -o yaml
apiVersion: v1
data:
AUTHENTICATION_APIKEY_ALLOWED_KEYS: dnpXU2ppUkdOTkVaRXl0Ug==
AUTHENTICATION_APIKEY_ENABLED: dHJ1ZQ==
AUTHENTICATION_APIKEY_USERS: YWRtaW4=
kind: Secret
metadata:
annotations:
kubedb.com/auth-active-from: "2026-06-30T17:23:54Z"
creationTimestamp: "2026-06-30T17:23:54Z"
labels:
app.kubernetes.io/component: database
app.kubernetes.io/instance: weaviate-sample
app.kubernetes.io/managed-by: kubedb.com
app.kubernetes.io/name: weaviates.kubedb.com
name: weaviate-sample-auth
namespace: demo
ownerReferences:
- apiVersion: kubedb.com/v1alpha2
blockOwnerDeletion: true
controller: true
kind: Weaviate
name: weaviate-sample
uid: ac548e5a-1d08-4ca6-946e-cdd0a34a2d92
resourceVersion: "60964"
uid: ca1779b9-b1ba-4635-a769-6cee4f998384
type: Opaque
The Secret stores the standard Weaviate API-key environment variables: AUTHENTICATION_APIKEY_ENABLED, AUTHENTICATION_APIKEY_ALLOWED_KEYS (the API key itself), and AUTHENTICATION_APIKEY_USERS (the bound user, admin).
Now, let’s connect to the Weaviate cluster using port forwarding. In one terminal, start the port-forward:
$ kubectl port-forward -n demo svc/weaviate-sample 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
In another terminal, export the API key and call the REST API:
$ export WEAVIATE_API_KEY=$(kubectl get secret -n demo weaviate-sample-auth -o jsonpath='{.data.AUTHENTICATION_APIKEY_ALLOWED_KEYS}' | base64 -d)
$ curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/v1/.well-known/ready \
-H "Authorization: Bearer $WEAVIATE_API_KEY"
200
Check the cluster nodes — all three should report HEALTHY:
$ curl -s http://localhost:8080/v1/nodes -H "Authorization: Bearer $WEAVIATE_API_KEY" | jq
{
"nodes": [
{"name": "weaviate-sample-0", "status": "HEALTHY", "version": "1.33.1", "gitHash": "c87f308", "batchStats": {"queueLength": 0, "ratePerSecond": 0}, "shards": null},
{"name": "weaviate-sample-1", "status": "HEALTHY", "version": "1.33.1", "gitHash": "c87f308", "batchStats": {"queueLength": 0, "ratePerSecond": 0}, "shards": null},
{"name": "weaviate-sample-2", "status": "HEALTHY", "version": "1.33.1", "gitHash": "c87f308", "batchStats": {"queueLength": 0, "ratePerSecond": 0}, "shards": null}
]
}
Let’s create a collection (class) and then read the schema back:
$ curl -s -X POST http://localhost:8080/v1/schema \
-H "Authorization: Bearer $WEAVIATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"class":"Article","vectorizer":"none"}'
{"class":"Article","invertedIndexConfig":{...},"multiTenancyConfig":{"enabled":false},...}
$ curl -s http://localhost:8080/v1/schema -H "Authorization: Bearer $WEAVIATE_API_KEY" | jq '.classes[].class'
"Article"
The collection was created and is served by the cluster.
AppBinding
KubeDB creates an AppBinding CR that holds the necessary information to connect with the database.
$ kubectl get appbinding -n demo
NAME TYPE VERSION AGE
weaviate-sample kubedb.com/weaviate 1.33.1 5m20s
$ kubectl get appbinding -n demo weaviate-sample -o yaml
apiVersion: appcatalog.appscode.com/v1alpha1
kind: AppBinding
metadata:
creationTimestamp: "2026-06-30T17:23:57Z"
generation: 1
labels:
app.kubernetes.io/component: database
app.kubernetes.io/instance: weaviate-sample
app.kubernetes.io/managed-by: kubedb.com
app.kubernetes.io/name: weaviates.kubedb.com
name: weaviate-sample
namespace: demo
ownerReferences:
- apiVersion: kubedb.com/v1alpha2
blockOwnerDeletion: true
controller: true
kind: Weaviate
name: weaviate-sample
uid: ac548e5a-1d08-4ca6-946e-cdd0a34a2d92
resourceVersion: "60960"
uid: 73731c82-f346-4424-be73-05e2ea6e3ebd
spec:
appRef:
apiGroup: kubedb.com
kind: Weaviate
name: weaviate-sample
namespace: demo
clientConfig:
service:
name: weaviate-sample
port: 8080
scheme: http
secret:
name: weaviate-sample-auth
type: kubedb.com/weaviate
version: 1.33.1
You can use this AppBinding to connect with the Weaviate cluster from external applications, including KubeStash for backup and restore.
Database DeletionPolicy
This field regulates the deletion process of the related resources when the Weaviate object is deleted. The available options are:
DoNotTerminate:
When deletionPolicy is set to DoNotTerminate, KubeDB prevents deletion of the database using admission webhooks. If you try to delete it, you will get an error:
$ kubectl patch -n demo weaviate/weaviate-sample -p '{"spec":{"deletionPolicy":"DoNotTerminate"}}' --type="merge"
weaviate.kubedb.com/weaviate-sample patched
$ kubectl delete weaviate -n demo weaviate-sample
The Weaviate "weaviate-sample" is invalid: spec.deletionPolicy: Invalid value: "weaviate-sample": Can not delete as deletionPolicy is set to "DoNotTerminate"
Halt:
When deletionPolicy is set to Halt, KubeDB deletes the Weaviate object and its pods but keeps the PVCs and Secrets intact. This allows you to recreate the database later using the same data.
Delete:
When deletionPolicy is set to Delete, KubeDB deletes the Weaviate object, pods, and PVCs but keeps the Secrets. This allows you to restore the database from a previously taken backup.
WipeOut:
When deletionPolicy is set to WipeOut, KubeDB deletes all resources of this database (pods, PVCs, Secrets, snapshots, etc.). There is no option to recreate the database once deleted with this policy.
$ kubectl patch -n demo weaviate/weaviate-sample -p '{"spec":{"deletionPolicy":"WipeOut"}}' --type="merge"
weaviate.kubedb.com/weaviate-sample patched
Be careful when using
WipeOut— there is no way to recover the database after deletion.
Next Steps
- Use custom configuration for your Weaviate cluster.
- Encrypt traffic with TLS.
- Run day-2 operations: Restart, Reconfigure, Volume Expansion, Vertical Scaling, Horizontal Scaling, Rotate Authentication, and Storage Migration.
- Automatically scale your cluster with the Compute Autoscaler and Storage Autoscaler.
- Want to hack on KubeDB? Check our contribution guidelines.
Cleaning up
To clean up the Kubernetes resources created by this tutorial, run:
kubectl delete weaviate -n demo weaviate-sample
kubectl delete ns demo































