diff --git a/docs/examples/neo4j/migration/sample-neo4j.yaml b/docs/examples/neo4j/migration/sample-neo4j.yaml new file mode 100644 index 000000000..4c733a52e --- /dev/null +++ b/docs/examples/neo4j/migration/sample-neo4j.yaml @@ -0,0 +1,17 @@ +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + replicas: 3 + deletionPolicy: WipeOut + version: "2025.12.1" + storage: + storageClassName: "local-path" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + diff --git a/docs/examples/neo4j/migration/storage-migration.yaml b/docs/examples/neo4j/migration/storage-migration.yaml new file mode 100644 index 000000000..095e7e826 --- /dev/null +++ b/docs/examples/neo4j/migration/storage-migration.yaml @@ -0,0 +1,14 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: storage-migration + namespace: demo +spec: + type: StorageMigration + databaseRef: + name: neo4j-test + migration: + storageClassName: custom-longhorn + oldPVReclaimPolicy: Delete + timeout: 3000s + diff --git a/docs/examples/neo4j/quickstart/neo4j.yaml b/docs/examples/neo4j/quickstart/neo4j.yaml new file mode 100644 index 000000000..ee7f1493b --- /dev/null +++ b/docs/examples/neo4j/quickstart/neo4j.yaml @@ -0,0 +1,16 @@ +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + replicas: 3 + deletionPolicy: WipeOut + version: "2025.11.2" + storage: + storageClassName: local-path + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi diff --git a/docs/examples/neo4j/reconfigure-tls/ops-request.yaml b/docs/examples/neo4j/reconfigure-tls/ops-request.yaml new file mode 100644 index 000000000..9e67db2fb --- /dev/null +++ b/docs/examples/neo4j/reconfigure-tls/ops-request.yaml @@ -0,0 +1,13 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-reconfigure-tls + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: tls-neo4j + tls: + rotateCertificates: true + bolt: + mode: mTLS diff --git a/docs/examples/neo4j/reconfigure/ops-request.yaml b/docs/examples/neo4j/reconfigure/ops-request.yaml new file mode 100644 index 000000000..70254d681 --- /dev/null +++ b/docs/examples/neo4j/reconfigure/ops-request.yaml @@ -0,0 +1,17 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-reconfigure + namespace: demo +spec: + type: Reconfigure + databaseRef: + name: neo4j-test + configuration: + configSecret: + name: new-custom-config + removeCustomConfig: true + applyConfig: + server.metrics.csv.interval: "40s" + timeout: 5m + apply: IfReady diff --git a/docs/examples/neo4j/restart/ops-request.yaml b/docs/examples/neo4j/restart/ops-request.yaml new file mode 100644 index 000000000..546894d0a --- /dev/null +++ b/docs/examples/neo4j/restart/ops-request.yaml @@ -0,0 +1,11 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-restart + namespace: demo +spec: + type: Restart + databaseRef: + name: neo4j-test + timeout: 5m + apply: Always diff --git a/docs/examples/neo4j/rotate-auth/ops-request.yaml b/docs/examples/neo4j/rotate-auth/ops-request.yaml new file mode 100644 index 000000000..c9281dcde --- /dev/null +++ b/docs/examples/neo4j/rotate-auth/ops-request.yaml @@ -0,0 +1,11 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-rotate-auth + namespace: demo +spec: + type: RotateAuth + databaseRef: + name: neo4j-test + timeout: 5m + apply: IfReady diff --git a/docs/examples/neo4j/scaling/horizontal-scaling/ops-request-scale-down.yaml b/docs/examples/neo4j/scaling/horizontal-scaling/ops-request-scale-down.yaml new file mode 100644 index 000000000..6699ff8f8 --- /dev/null +++ b/docs/examples/neo4j/scaling/horizontal-scaling/ops-request-scale-down.yaml @@ -0,0 +1,15 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-horizontal-scale-down + namespace: demo +spec: + type: HorizontalScaling + databaseRef: + name: neo4j-test + horizontalScaling: + server: 4 + reallocate: + strategy: "incremental" + batchSize: 1 + diff --git a/docs/examples/neo4j/scaling/horizontal-scaling/ops-request-scale-up.yaml b/docs/examples/neo4j/scaling/horizontal-scaling/ops-request-scale-up.yaml new file mode 100644 index 000000000..f8cf8cdca --- /dev/null +++ b/docs/examples/neo4j/scaling/horizontal-scaling/ops-request-scale-up.yaml @@ -0,0 +1,15 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-horizontal-scale-up + namespace: demo +spec: + type: HorizontalScaling + databaseRef: + name: neo4j-test + horizontalScaling: + server: 5 + reallocate: + strategy: "incremental" + batchSize: 1 + diff --git a/docs/examples/neo4j/scaling/horizontal-scaling/ops-request.yaml b/docs/examples/neo4j/scaling/horizontal-scaling/ops-request.yaml new file mode 100644 index 000000000..13fcc47bf --- /dev/null +++ b/docs/examples/neo4j/scaling/horizontal-scaling/ops-request.yaml @@ -0,0 +1,14 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-horizontal-scale + namespace: demo +spec: + type: HorizontalScaling + databaseRef: + name: neo4j-test + horizontalScaling: + server: 5 + reallocate: + strategy: "incremental" + batchSize: 1 diff --git a/docs/examples/neo4j/scaling/vertical-scaling/ops-request.yaml b/docs/examples/neo4j/scaling/vertical-scaling/ops-request.yaml new file mode 100644 index 000000000..de0391a60 --- /dev/null +++ b/docs/examples/neo4j/scaling/vertical-scaling/ops-request.yaml @@ -0,0 +1,18 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-vertical-scale + namespace: demo +spec: + type: VerticalScaling + databaseRef: + name: neo4j-test + verticalScaling: + server: + resources: + limits: + cpu: 1500m + memory: 4Gi + requests: + cpu: 700m + memory: 4Gi \ No newline at end of file diff --git a/docs/examples/neo4j/update-version/ops-request.yaml b/docs/examples/neo4j/update-version/ops-request.yaml new file mode 100644 index 000000000..84c6e0712 --- /dev/null +++ b/docs/examples/neo4j/update-version/ops-request.yaml @@ -0,0 +1,11 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-update-version + namespace: demo +spec: + type: UpdateVersion + databaseRef: + name: neo4j-test + updateVersion: + targetVersion: "2025.12.1" diff --git a/docs/examples/neo4j/volume-expansion/ops-request.yaml b/docs/examples/neo4j/volume-expansion/ops-request.yaml new file mode 100644 index 000000000..2fc1f023f --- /dev/null +++ b/docs/examples/neo4j/volume-expansion/ops-request.yaml @@ -0,0 +1,12 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-volume-expand + namespace: demo +spec: + type: VolumeExpansion + databaseRef: + name: neo4j-test + volumeExpansion: + mode: "Online" + server: 4Gi \ No newline at end of file diff --git a/docs/guides/neo4j/README.md b/docs/guides/neo4j/README.md new file mode 100644 index 000000000..59ecaa927 --- /dev/null +++ b/docs/guides/neo4j/README.md @@ -0,0 +1,97 @@ +--- +title: Neo4j +menu: + docs_{{ .version }}: + identifier: neo4j-readme + name: Neo4j + parent: neo4j-guides + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +url: /docs/{{ .version }}/guides/neo4j/ +aliases: + - /docs/{{ .version }}/guides/neo4j/README/ +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Overview + +KubeDB supports graph database deployment with Neo4j using the `Neo4j` CRD. + +## Supported Neo4j Features + +| Features | Availability | +|----------------------------------|:------------:| +| Standalone provisioning | ✓ | +| Cluster provisioning | ✓ | +| Monitoring | ✓ | +| TLS | ✓ | +| Ops Requests | ✓ | + +## Supported Ops Requests + +- Reconfigure +- HorizontalScaling +- VerticalScaling +- VolumeExpansion +- StorageMigration +- UpdateVersion +- ReconfigureTLS +- RotateAuth +- Restart + +## Example Neo4j Manifest + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + replicas: 3 + deletionPolicy: WipeOut + version: "2025.12.1" + storage: + storageClassName: local-path + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi +``` + +## User Guide + +- [Quickstart Neo4j](/docs/guides/neo4j/quickstart/quickstart.md) with KubeDB operator. +- [Cluster Architecture Overview](/docs/guides/neo4j/clustering/architecture-overview.md) +- [Neo4j CRD Concept](/docs/guides/neo4j/concepts/neo4j.md). +- [Neo4jVersion CRD Concept](/docs/guides/neo4j/concepts/catalog.md). +- [Neo4jOpsRequest CRD Concept](/docs/guides/neo4j/concepts/opsrequest.md). +- [Private Registry](/docs/guides/neo4j/private-registry/using-private-registry.md) +- [Custom RBAC](/docs/guides/neo4j/custom-rbac/using-custom-rbac.md) +- [Custom Configuration](/docs/guides/neo4j/configuration/using-config-file.md) +- [Monitoring](/docs/guides/neo4j/monitoring/overview.md) for metrics collection guidance. +- [Builtin Prometheus Monitoring](/docs/guides/neo4j/monitoring/using-builtin-prometheus.md) +- [Prometheus Operator Monitoring](/docs/guides/neo4j/monitoring/using-prometheus-operator.md) +- [TLS](/docs/guides/neo4j/tls/overview/) for protocol-level TLS guidance. +- [Configure TLS](/docs/guides/neo4j/tls/configure/) +- [Ops Request](/docs/guides/neo4j/ops-request/overview.md) for supported operational changes. +- [Reconfigure](/docs/guides/neo4j/reconfigure/overview.md) +- [Reconfigure Details](/docs/guides/neo4j/reconfigure/reconfigure.md) +- [Reconfigure TLS](/docs/guides/neo4j/reconfigure-tls/overview.md) +- [Reconfigure TLS Details](/docs/guides/neo4j/reconfigure-tls/reconfigure-tls.md) +- [Restart](/docs/guides/neo4j/restart/restart.md) +- [Rotate Auth](/docs/guides/neo4j/rotate-auth/overview.md) +- [Rotate Auth Details](/docs/guides/neo4j/rotate-auth/rotateauth.md) +- [Update Version](/docs/guides/neo4j/update-version/overview.md) +- [Update Version Details](/docs/guides/neo4j/update-version/versionupgrading/) +- [Volume Expansion](/docs/guides/neo4j/volume-expansion/overview.md) +- [Volume Expansion Details](/docs/guides/neo4j/volume-expansion/volume-expansion.md) +- [Migration](/docs/guides/neo4j/migration/) +- [StorageClass Migration](/docs/guides/neo4j/migration/storageMigration.md) +- [Horizontal Scaling](/docs/guides/neo4j/scaling/horizontal-scaling/overview.md) +- [Horizontal Scaling Details](/docs/guides/neo4j/scaling/horizontal-scaling/scale-horizontally/) +- [Vertical Scaling](/docs/guides/neo4j/scaling/vertical-scaling/overview.md) +- [Vertical Scaling Details](/docs/guides/neo4j/scaling/vertical-scaling/scale-vertically/) \ No newline at end of file diff --git a/docs/guides/neo4j/_index.md b/docs/guides/neo4j/_index.md new file mode 100644 index 000000000..d57050e9c --- /dev/null +++ b/docs/guides/neo4j/_index.md @@ -0,0 +1,10 @@ +--- +title: Neo4j +menu: + docs_{{ .version }}: + identifier: neo4j-guides + name: Neo4j + parent: guides + weight: 16 +menu_name: docs_{{ .version }} +--- \ No newline at end of file diff --git a/docs/guides/neo4j/clustering/_index.md b/docs/guides/neo4j/clustering/_index.md new file mode 100644 index 000000000..0a417e89f --- /dev/null +++ b/docs/guides/neo4j/clustering/_index.md @@ -0,0 +1,11 @@ +--- +title: Neo4j Clustering +menu: + docs_{{ .version }}: + identifier: neo4j-clustering + name: Clustering + parent: neo4j-guides + weight: 20 +menu_name: docs_{{ .version }} +--- + diff --git a/docs/guides/neo4j/clustering/architecture-overview.md b/docs/guides/neo4j/clustering/architecture-overview.md new file mode 100644 index 000000000..f19e85f03 --- /dev/null +++ b/docs/guides/neo4j/clustering/architecture-overview.md @@ -0,0 +1,166 @@ +--- +title: Neo4j Cluster Architecture +menu: + docs_{{ .version }}: + identifier: neo4j-cluster-architecture + name: Architecture Overview + parent: neo4j-clustering + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Neo4j Cluster Architecture + +## Overview + +KubeDB provisions Neo4j in **cluster mode** using the [Neo4j Cluster](https://neo4j.com/docs/operations-manual/current/clustering/) topology. Each `Neo4j` cluster is a set of server instances that cooperate to provide a fully connected, highly available, and scalable graph database. KubeDB strictly follows the `modeConstraint: NONE` server operating mode, which allows any server in the cluster to perform any role the cluster topology requires. + +## Cluster Mode: `NONE` Constraint + +Neo4j servers can be constrained to specific roles in the cluster (primary-only, secondary-only). KubeDB does not apply any such restriction, every server is started with: + +``` +server.cluster.mode.constraint=NONE +``` + +This means: + +- Each server can operate as a **primary** server (hosting a database copy that accepts writes and participates in Raft consensus). +- Each server can also operate as a **secondary** server (hosting read replicas for scale-out). +- The cluster topology engine assigns roles dynamically based on placement policies and the number of servers available. +- No server is permanently locked to a specific role, which gives maximum flexibility during scaling, version updates, and pod failures. + +## Operational View +

+ + operational-view + +

+ +The diagram above shows the operational view of a KubeDB-managed `Neo4j` cluster. Each pod runs a single Neo4j server instance. Kubernetes services route: + +- `Bolt traffic` (`7687`) to the cluster-level ClusterIP Service `{neo4j-name}`. +- `HTTP Browser traffic` (`7474`) to the same ClusterIP Service. +- `Intra-cluster communication` (`7000` discovery, `6000` transaction, `7688` intra-Bolt) through per-pod headless Services. + +## Cluster Components + +### Server Instances + +Every Neo4j pod in a KubeDB-managed cluster is an independent server member. The cluster is formed when a quorum of servers successfully complete the **discovery and Raft election** phases on startup. + +With `spec.replicas: 3`, KubeDB creates: + +| Resource | Count | Purpose | +|---|---|---| +| Neo4j pods | 3 | One server process per pod | +| PVCs | 3 | Independent persistent volume per pod | +| Per-pod headless Service | 3 | Intra-cluster communication per member | +| Cluster ClusterIP Service | 1 | Client Bolt/HTTP entry point | + +### Discovery + +Neo4j servers find each other using the per-pod headless Services (`{neo4j-name}-0`, `{neo4j-name}-1`, `{neo4j-name}-2`). These Services expose discovery port `6000` and transaction port `7000`, which the Neo4j cluster engine uses to build its routing table. + +### Raft Consensus + +Neo4j uses the [Raft protocol](https://neo4j.com/docs/operations-manual/current/clustering/internals/) to elect a leader for each database hosted in the cluster. With `modeConstraint: NONE`, any server is eligible to become the Raft leader for a given database. A minimum quorum of โŒŠN/2โŒ‹ + 1 servers must be available for the cluster to accept writes. + +| Replicas | Fault tolerance | Write quorum needed | +|---|---|---| +| 3 | 1 server failure | 2 | +| 5 | 2 server failures | 3 | +| 7 | 3 server failures | 4 | + +### Database Hosting + +Each logical database inside Neo4j (for example `neo4j`, `system`) has its own Raft group and its own elected leader. A 3-server cluster can host multiple databases, each with independent leaders โ€” a server may be the write leader for one database and a follower for another. + +## Example: 3-Server Cluster + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + replicas: 3 + version: "2025.12.1" + storage: + storageClassName: local-path + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + deletionPolicy: WipeOut +``` + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/examples/neo4j/quickstart/neo4j.yaml +``` + +When applied: + +1. KubeDB creates a PetSet with 3 replicas. +2. Each pod gets its own PVC and a dedicated headless Service. +3. All three Neo4j processes start, exchange discovery packets, and elect a Raft leader per database. +4. Once the quorum is established, `status.phase` moves to `Ready`. + +```bash +$ kubectl get neo4j -n demo neo4j-test +NAME VERSION STATUS AGE +neo4j-test 2025.12.1 Ready 3m + +$ kubectl get pods -n demo -l app.kubernetes.io/instance=neo4j-test +NAME READY STATUS RESTARTS AGE +neo4j-test-0 1/1 Running 0 3m +neo4j-test-1 1/1 Running 0 2m +neo4j-test-2 1/1 Running 0 2m +``` + +## Verify Cluster Health + +Once the cluster is ready, connect via `cypher-shell` and inspect the cluster topology: + +```bash +$ PASS=$(kubectl get secret -n demo neo4j-test-auth -o jsonpath='{.data.password}' | base64 -d) + +$ kubectl exec -n demo neo4j-test-0 -- \ + cypher-shell -u neo4j -p "$PASS" \ + "SHOW SERVERS YIELD serverId, name, address, state, health, hosting + RETURN serverId, name, address, state, health, hosting;" +``` + +Expected output (3-server cluster, all `Enabled` and `Available`): + +``` ++----------------------------------------------------------------------------------------+ +| serverId | name | address | state | health | hosting | ++----------------------------------------------------------------------------------------+ +| "abc..." | "neo4j-test-0" | "neo4j-test-0.demo.svc...:7100" | Enabled | Available | ["neo4j"] | +| "def..." | "neo4j-test-1" | "neo4j-test-1.demo.svc...:7100" | Enabled | Available | ["neo4j"] | +| "ghi..." | "neo4j-test-2" | "neo4j-test-2.demo.svc...:7100" | Enabled | Available | ["neo4j"] | ++----------------------------------------------------------------------------------------+ +``` + +Check database allocation and current leaders: + +```bash +$ kubectl exec -n demo neo4j-test-0 -- \ + cypher-shell -u neo4j -p "$PASS" \ + "SHOW DATABASES YIELD name, role, writer, currentStatus, address + RETURN name, role, writer, currentStatus, address + ORDER BY name, role;" +``` + +## Next Steps + +- Follow the [Neo4j quickstart](/docs/guides/neo4j/quickstart/quickstart.md) to provision your first cluster. +- Learn about [horizontal scaling](/docs/guides/neo4j/scaling/horizontal-scaling/overview.md) to add or remove cluster members. +- Learn about [vertical scaling](/docs/guides/neo4j/scaling/vertical-scaling/overview.md) to adjust pod resources. +- Learn about [TLS configuration](/docs/guides/neo4j/tls/overview/) for securing cluster communication. diff --git a/docs/guides/neo4j/concepts/_index.md b/docs/guides/neo4j/concepts/_index.md new file mode 100644 index 000000000..7ec3f5844 --- /dev/null +++ b/docs/guides/neo4j/concepts/_index.md @@ -0,0 +1,10 @@ +--- +title: Neo4j Concepts +menu: + docs_{{ .version }}: + identifier: neo4j-concepts + name: Concepts + parent: neo4j-guides + weight: 15 +menu_name: docs_{{ .version }} +--- \ No newline at end of file diff --git a/docs/guides/neo4j/concepts/appbinding.md b/docs/guides/neo4j/concepts/appbinding.md new file mode 100644 index 000000000..3a8bb9d9c --- /dev/null +++ b/docs/guides/neo4j/concepts/appbinding.md @@ -0,0 +1,118 @@ +--- +title: AppBinding CRD +menu: + docs_{{ .version }}: + identifier: neo4j-appbinding-concepts + name: AppBinding + parent: neo4j-concepts-neo4j + weight: 20 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# AppBinding + +## What is AppBinding + +An `AppBinding` is a Kubernetes `CustomResourceDefinition` (CRD) that points to an application endpoint and its access credentials. + +If you deploy a Neo4j database using KubeDB, KubeDB automatically creates an `AppBinding` for that database. This object is used by tools like KubeStash to discover connection information and database credentials. + +## AppBinding CRD Specification + +Like other Kubernetes resources, an `AppBinding` has `TypeMeta`, `ObjectMeta`, and `Spec` sections. It does not have a `Status` section. + +An `AppBinding` created by KubeDB for a Neo4j database looks like this: + +```yaml +apiVersion: appcatalog.appscode.com/v1alpha1 +kind: AppBinding +metadata: + name: neo4j-test + namespace: demo + labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: neo4j-test + app.kubernetes.io/managed-by: kubedb.com + app.kubernetes.io/name: neo4js.kubedb.com +spec: + appRef: + apiGroup: kubedb.com + kind: Neo4j + name: neo4j-test + namespace: demo + clientConfig: + service: + name: neo4j-test + port: 7687 + scheme: neo4j + secret: + apiGroup: "" + kind: Secret + name: neo4j-test-auth + type: kubedb.com/Neo4j + version: 2025.12.1-enterprise +``` + +Here, we describe the important sections of this AppBinding. + +### spec.type + +`spec.type` identifies the app type represented by this AppBinding. + +Format: `/`. + +For Neo4j managed by KubeDB, it is typically: + +- `kubedb.com/Neo4j` + +### spec.appRef + +`spec.appRef` points back to the source database object that owns this binding. + +For Neo4j, this includes: + +- `apiGroup: kubedb.com` +- `kind: Neo4j` +- `name: ` +- `namespace: ` + +### spec.secret + +`spec.secret` references the Secret that stores credentials required to connect to the database. The Secret must be in the same namespace. + +For Neo4j, KubeDB-generated auth secret typically contains: + +| Key | Usage | +|-----|-------| +| `username` | Neo4j user name | +| `password` | Password for that user | + +### spec.clientConfig + +`spec.clientConfig` defines how clients should connect to the target database. + +For in-cluster Neo4j deployments, KubeDB sets `spec.clientConfig.service`. + +#### spec.clientConfig.service + +- `name`: Kubernetes Service name for the database. +- `port`: Service port used for client connection (Neo4j Bolt is commonly `7687`). +- `scheme`: Connection scheme (for example, `neo4j`). + +## Verify AppBinding + +You can inspect the generated AppBinding with: + +```bash +$ kubectl get appbinding -n demo neo4j-test -o yaml +``` + +## Next Steps + +- Read the [Neo4j CRD concept](/docs/guides/neo4j/concepts/neo4j.md). +- Learn Neo4j operations from [Neo4j OpsRequest](/docs/guides/neo4j/concepts/opsrequest.md). +- Run the [Neo4j quickstart](/docs/guides/neo4j/quickstart/quickstart.md). + diff --git a/docs/guides/neo4j/concepts/catalog.md b/docs/guides/neo4j/concepts/catalog.md new file mode 100644 index 000000000..84b861b4e --- /dev/null +++ b/docs/guides/neo4j/concepts/catalog.md @@ -0,0 +1,48 @@ +--- +title: Neo4jVersion CRD +menu: + docs_{{ .version }}: + identifier: neo4j-catalog-concepts + name: Neo4jVersion + parent: neo4j-concepts-neo4j + weight: 15 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Neo4jVersion + +## What is Neo4jVersion + +`Neo4jVersion` is the catalog CRD that provides image and version metadata for KubeDB-managed Neo4j. + +The value of `Neo4j.spec.version` must correspond to a valid `Neo4jVersion` resource. + +## Neo4jVersion Specification + +```yaml +apiVersion: catalog.kubedb.com/v1alpha1 +kind: Neo4jVersion +metadata: + name: 2025.11.2 +spec: + db: + image: docker.io/library/neo4j:2025.11.2-enterprise + securityContext: + runAsUser: 7474 + version: 2025.11.2-enterprise +``` + +## Key fields + +- `metadata.name` is used in `Neo4j.spec.version`. +- `spec.version` identifies the Neo4j release represented. +- `spec.db.image` defines the image for Neo4j pods. +- `spec.deprecated` signals if the version should be avoided. + +## Next Steps + +- Read the [Neo4j CRD concept](/docs/guides/neo4j/concepts/neo4j.md). +- Run the [Neo4j quickstart](/docs/guides/neo4j/quickstart/quickstart.md). \ No newline at end of file diff --git a/docs/guides/neo4j/concepts/neo4j.md b/docs/guides/neo4j/concepts/neo4j.md new file mode 100644 index 000000000..992b533d9 --- /dev/null +++ b/docs/guides/neo4j/concepts/neo4j.md @@ -0,0 +1,165 @@ +--- +title: Neo4j CRD +menu: + docs_{{ .version }}: + identifier: neo4j-concepts-neo4j + name: Neo4j + parent: neo4j-concepts + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Neo4j + +## What is Neo4j + +`Neo4j` is a Kubernetes `CustomResourceDefinition` (CRD) managed by KubeDB. It provides declarative configuration for Neo4j in a Kubernetes-native way. You define the desired state in a `Neo4j` object, and KubeDB provisions and reconciles the database resources. + +## Neo4j Spec + +As with all other Kubernetes objects, a Neo4j needs `apiVersion`, `kind`, and `metadata` fields. It also needs a `.spec` section. + +Below is an example Neo4j object. + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + version: "2025.12.1" + replicas: 3 + storageType: Durable + configuration: + secretName: neo4j-custom-config + monitor: + agent: prometheus.io/operator + prometheus: + serviceMonitor: + labels: + release: prometheus + interval: 10s + tls: + issuerRef: + apiGroup: cert-manager.io + kind: Issuer + name: neo4j-ca-issuer + bolt: + mode: mTLS + cluster: + mode: mTLS + podTemplate: + spec: + serviceAccountName: neo4j-test + imagePullSecrets: + - name: myregistrykey + storage: + storageClassName: local-path + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + deletionPolicy: WipeOut +``` + +### spec.version + +`spec.version` is a required field that specifies the name of the [Neo4jVersion](/docs/guides/neo4j/concepts/catalog.md) CRD where database image and version metadata are defined. + +To see available versions in your cluster: + +```bash +$ kubectl get neo4jversions +NAME VERSION DB_IMAGE DEPRECATED AGE +2025.10.1 2025.10.1-enterprise docker.io/library/neo4j:2025.10.1-enterprise 12d +2025.11.2 2025.11.2-enterprise docker.io/library/neo4j:2025.11.2-enterprise 12d +2025.12.1 2025.12.1-enterprise docker.io/library/neo4j:2025.12.1-enterprise 12d +``` + +### spec.replicas + +`spec.replicas` specifies the number of Neo4j server pods in the cluster. + +For production deployments, use multiple replicas so the cluster can continue serving traffic during node or pod disruptions. + +### spec.storageType + +`spec.storageType` is an optional field that specifies the storage mode. It can be `Durable` or `Ephemeral`. + +- `Durable`: Uses persistent volumes and keeps data across pod restarts. +- `Ephemeral`: Uses temporary storage and is mainly suitable for testing. + +### spec.storage + +If `spec.storageType` is `Durable` (or not explicitly set), `spec.storage` is required. This field defines PVC settings used by Neo4j pods. + +- `spec.storage.storageClassName` is the StorageClass used to provision PVCs. +- `spec.storage.accessModes` defines how volumes are mounted (for example, `ReadWriteOnce`). +- `spec.storage.resources.requests.storage` defines the requested volume size. + +To check available StorageClass resources: + +```bash +$ kubectl get storageclass +``` + +### spec.configuration + +`spec.configuration` is an optional field used to provide custom Neo4j configuration. + +- `spec.configuration.secretName` references a Secret containing Neo4j key-value settings. + +KubeDB merges the provided settings into Neo4j configuration and reconciles the cluster accordingly. See the [configuration guide](/docs/guides/neo4j/configuration/using-config-file.md). + +### spec.monitor + +`spec.monitor` is an optional field that enables monitoring integration for Neo4j. + +In the example above, KubeDB is configured for Prometheus Operator (`prometheus.io/operator`) with a `ServiceMonitor` definition. + +See [monitoring overview](/docs/guides/neo4j/monitoring/overview.md) for setup and verification. + +### spec.tls + +`spec.tls` is an optional field for enabling and configuring TLS for Neo4j protocols. + +- `spec.tls.issuerRef` tells KubeDB which cert-manager issuer to use for certificates. +- Protocol-specific TLS behavior (for example Bolt/HTTP) is configured under `spec.tls`. + +See [TLS overview](/docs/guides/neo4j/tls/overview/) and [Reconfigure TLS](/docs/guides/neo4j/reconfigure-tls/overview.md). + +### spec.podTemplate + +`spec.podTemplate` is an optional field for customizing Neo4j pods. + +Common examples: + +- `spec.podTemplate.spec.serviceAccountName` to use custom RBAC resources. +- `spec.podTemplate.spec.imagePullSecrets` to pull images from a private registry. +- `spec.podTemplate.spec.resources` to set CPU and memory requests/limits. + +To learn more: + +- [Custom RBAC for Neo4j](/docs/guides/neo4j/custom-rbac/using-custom-rbac.md) +- [Private Registry for Neo4j](/docs/guides/neo4j/private-registry/using-private-registry.md) + +### spec.deletionPolicy + +`spec.deletionPolicy` controls what KubeDB does when a `Neo4j` object is deleted. + +KubeDB supports standard database termination policies such as `DoNotTerminate`, `Halt`, `Delete`, and `WipeOut`. + +Use `WipeOut` when you want full cleanup, including data and generated secrets. Use safer policies in production when you need to preserve data for recovery. +For more details visit [HERE](https://appscode.com/blog/post/deletion-policy/) + +## Next Steps + +- Learn about [Neo4jVersion CRD](/docs/guides/neo4j/concepts/catalog.md). +- Learn about [AppBinding CRD](/docs/guides/neo4j/concepts/appbinding.md). +- Explore [Neo4j OpsRequest](/docs/guides/neo4j/concepts/opsrequest.md). +- Follow the [Neo4j quickstart](/docs/guides/neo4j/quickstart/quickstart.md) diff --git a/docs/guides/neo4j/concepts/opsrequest.md b/docs/guides/neo4j/concepts/opsrequest.md new file mode 100644 index 000000000..7bc3611f2 --- /dev/null +++ b/docs/guides/neo4j/concepts/opsrequest.md @@ -0,0 +1,388 @@ +--- +title: Neo4jOpsRequest CRD +menu: + docs_{{ .version }}: + identifier: neo4j-opsrequest-concepts + name: Neo4jOpsRequest + parent: neo4j-concepts-neo4j + weight: 25 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Neo4jOpsRequest + +## What is Neo4jOpsRequest + +`Neo4jOpsRequest` is the CRD for day-2 operational workflows for KubeDB-managed Neo4j databases. + +## Neo4jOpsRequest CRD Specifications + +Like any Kubernetes resource, a `Neo4jOpsRequest` contains `TypeMeta`, `ObjectMeta`, `Spec`, and `Status` sections. The `spec.type` field determines which operation KubeDB should perform on the target Neo4j database. + +## Supported operation types + +- `Reconfigure` +- `ReconfigureTLS` +- `Restart` +- `RotateAuth` +- `UpdateVersion` +- `HorizontalScaling` +- `VerticalScaling` +- `VolumeExpansion` +- `StorageMigration` + +## Sample Neo4jOpsRequest manifests + +**Sample `Neo4jOpsRequest` for updating database version:** + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-update-version + namespace: demo +spec: + type: UpdateVersion + databaseRef: + name: neo4j-test + updateVersion: + targetVersion: 2025.12.1 +``` + +**Sample `Neo4jOpsRequest` for vertical scaling:** + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: vscale + namespace: demo +spec: + type: VerticalScaling + databaseRef: + name: neo4j-test + verticalScaling: + server: + resources: + limits: + cpu: 1500m + memory: 4Gi + requests: + cpu: 700m + memory: 4Gi +``` + +**Sample `Neo4jOpsRequest` objects for volume expansion:** + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-volumeexpansion + namespace: demo +spec: + type: VolumeExpansion + databaseRef: + name: neo4j + volumeExpansion: + mode: "Offline" + server: 4Gi +``` + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-volumeexpansiononline + namespace: demo +spec: + type: VolumeExpansion + databaseRef: + name: neo4j + volumeExpansion: + mode: "Online" + server: 6Gi +``` + +**Sample `Neo4jOpsRequest` for horizontal scaling:** + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neoops-hscale + namespace: demo +spec: + type: HorizontalScaling + databaseRef: + name: neo4j-test + horizontalScaling: + server: 5 + reallocate: + strategy: "incremental" + batchSize: 1 +``` + +**Sample `Neo4jOpsRequest` objects for rotating auth credentials:** + +Rotate authentication without a user-provided Secret: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: rotate-auth-generated + namespace: demo +spec: + type: RotateAuth + databaseRef: + name: neo4j-test + timeout: 5m + apply: IfReady +``` + +Rotate authentication using a user-provided Secret: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neoops-rotate-auth-user + namespace: demo +spec: + type: RotateAuth + databaseRef: + name: neo4j + authentication: + secretRef: + kind: Secret + name: external-neo4j-auth + timeout: 5m + apply: IfReady +``` + +**Sample `Neo4jOpsRequest` objects for reconfiguring Neo4j:** + +Reconfigure using a new custom configuration Secret and inline overrides: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: reconfigure + namespace: demo +spec: + type: Reconfigure + databaseRef: + name: neo4j + configuration: + configSecret: + name: new-custom-config + removeCustomConfig: true + applyConfig: + server.metrics.csv.interval: "40s" + timeout: 5m + apply: IfReady +``` + +Reconfigure using inline `applyConfig` values: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: reconfigure-apply + namespace: demo +spec: + type: Reconfigure + databaseRef: + name: neo4j + configuration: + configSecret: + name: new-custom-config + applyConfig: + server.metrics.enabled: "false" + timeout: 5m + apply: IfReady +``` + +**Sample `Neo4jOpsRequest` for restart:** + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: restart + namespace: demo +spec: + type: Restart + databaseRef: + name: neo4j + timeout: 5m + apply: Always +``` + +**Sample `Neo4jOpsRequest` objects for TLS reconfiguration:** + +Rotate TLS certificates and update Bolt mode: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: rotate + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: neo4j-tls + tls: + rotateCertificates: true + bolt: + mode: mTLS +``` + +Remove TLS from the database: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: remove + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: neo4j-tls + tls: + remove: true +``` + +Add or replace TLS using a cert-manager issuer: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: add-tls + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: neo4j-tls + tls: + issuerRef: + apiGroup: "cert-manager.io" + kind: Issuer + name: neo4j-ca-issuer +``` + +**Sample `Neo4jOpsRequest` for storage class migration:** + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: storage-migration + namespace: demo +spec: + type: StorageMigration + databaseRef: + name: neo4j-test + migration: + storageClassName: custom-longhorn + oldPVReclaimPolicy: Delete + timeout: 3000s +``` + +## Key fields + +- `spec.databaseRef.name` identifies the target `Neo4j` object. +- `spec.type` selects the operation category. Valid values are `Restart`, `ReconfigureTLS`, `RotateAuth`, `Reconfigure`, `HorizontalScaling`, `VerticalScaling`, `VolumeExpansion`, `StorageMigration`, and `UpdateVersion`. +- Set the operation-specific section that matches `spec.type`, such as `spec.updateVersion`, `spec.verticalScaling`, `spec.volumeExpansion`, `spec.horizontalScaling`, `spec.migration`, `spec.authentication`, `spec.configuration`, or `spec.tls`. +- `spec.updateVersion.targetVersion` selects the target `Neo4jVersion` for an `UpdateVersion` request. +- `spec.verticalScaling.server.resources` defines the new CPU and memory requests and limits for Neo4j server Pods. +- `spec.volumeExpansion.mode` chooses whether storage expansion runs in `Online` or `Offline` mode, and `spec.volumeExpansion.server` sets the new PVC size for the server volume. +- `spec.migration.storageClassName` selects the destination StorageClass for `StorageMigration`, and `spec.migration.oldPVReclaimPolicy` controls old PV reclaim behavior (`Delete` or `Retain`). +- `spec.horizontalScaling.server` sets the desired number of Neo4j servers. `spec.horizontalScaling.reallocate.strategy` controls post-scaling reallocation, and `spec.horizontalScaling.reallocate.batchSize` is used with the `incremental` strategy. +- `spec.authentication.secretRef` optionally points to a user-managed Secret for `RotateAuth`. If it is omitted, KubeDB can rotate credentials using an operator-managed Secret. +- `spec.configuration.configSecret.name` points to a Secret containing new custom configuration, `spec.configuration.removeCustomConfig` removes the existing custom config, and `spec.configuration.applyConfig` applies inline configuration changes. +- `spec.tls.rotateCertificates`, `spec.tls.remove`, and `spec.tls.issuerRef` control TLS certificate rotation, removal, and issuer-based TLS configuration. Protocol-specific settings such as `spec.tls.bolt.mode` can also be updated there. +- `spec.timeout` sets the timeout for each step of the operation. +- `spec.apply` controls when KubeDB should execute the OpsRequest, and `spec.maxRetries` controls how many times the operator retries a failed step. + +### Neo4jOpsRequest `Status` + +`.status` describes the current state and progress of the `Neo4jOpsRequest` operation. It has the following fields: + +#### status.phase + +`status.phase` indicates the overall phase of the operation for this `Neo4jOpsRequest`. + +| Phase | Meaning | +|--------------|-----------------------------------------------------------------------------------| +| `Progressing` | KubeDB has started processing the requested operation | +| `Successful` | KubeDB has successfully completed the requested operation | +| `Failed` | KubeDB has failed to complete the requested operation | +| `Denied` | KubeDB has denied the requested operation | + +#### status.observedGeneration + +`status.observedGeneration` shows the most recent generation observed by the `Neo4jOpsRequest` controller. + +#### status.conditions + +`status.conditions` is an array that tracks step-by-step state transitions during `Neo4jOpsRequest` processing. Each condition entry includes: + +- `type`: category of the condition transition. +- `status`: one of `True`, `False`, or `Unknown`. +- `reason`: machine-readable reason for the latest transition. +- `message`: human-readable details for the transition. +- `lastTransitionTime`: timestamp for the latest state transition. +- `observedGeneration`: generation observed for that condition update. + +Common `type` values: + +| Type | Meaning | +|-----------------------|-------------------------------------------------------------------------| +| `UpdateVersion` | Version update step has completed | +| `VerticalScaling` | Vertical scaling step has completed | +| `HorizontalScaling` | Horizontal scaling step has completed | +| `VolumeExpansion` | Volume expansion step has completed | +| `StorageMigration` | Storage class migration step has completed | +| `Reconfigure` | Reconfiguration step has completed | +| `ReconfigureTLS` | TLS reconfiguration step has completed | +| `Restart` | Restart step has completed | +| `RotateAuth` | Auth rotation step has completed | + +Common `reason` values: + +| Reason | Meaning | +|-----------------------------------------|-------------------------------------------------------------------------| +| `OpsRequestProgressingStarted` | Operator has started processing the OpsRequest | +| `OpsRequestFailedToProgressing` | Operator failed to start processing | +| `OpsRequestProcessedSuccessfully` | Operator has completed the requested operation | +| `DatabaseVersionUpdatingStarted` | Version update has started | +| `SuccessfullyUpdatedDatabaseVersion` | Version update has completed successfully | +| `FailedToUpdateDatabaseVersion` | Version update has failed | +| `VerticalScalingStarted` | Vertical scaling has started | +| `SuccessfullyPerformedVerticalScaling` | Vertical scaling has completed successfully | +| `FailedToPerformVerticalScaling` | Vertical scaling has failed | +| `HorizontalScalingStarted` | Horizontal scaling has started | +| `SuccessfullyPerformedHorizontalScaling`| Horizontal scaling has completed successfully | +| `FailedToPerformHorizontalScaling` | Horizontal scaling has failed | +| `StorageMigrationStarted` | Storage migration has started | +| `SuccessfullyPerformedStorageMigration` | Storage migration has completed successfully | +| `FailedToPerformStorageMigration` | Storage migration has failed | + +## Next Steps + +- See [Neo4j ops overview](/docs/guides/neo4j/ops-request/overview.md) for operation links. +- Read the [Reconfigure guide](/docs/guides/neo4j/reconfigure/overview.md) for configuration changes. +- Read the [Reconfigure TLS guide](/docs/guides/neo4j/reconfigure-tls/overview.md) for certificate rotation, removal, or issuer updates. +- Read the [Restart guide](/docs/guides/neo4j/restart/restart.md), [Rotate Auth guide](/docs/guides/neo4j/rotate-auth/overview.md), and [Update Version guide](/docs/guides/neo4j/update-version/overview.md). +- Read the [Horizontal Scaling guide](/docs/guides/neo4j/scaling/horizontal-scaling/overview.md), [Vertical Scaling guide](/docs/guides/neo4j/scaling/vertical-scaling/overview.md), and [Volume Expansion guide](/docs/guides/neo4j/volume-expansion/overview.md). +- Read the [Storage Migration guide](/docs/guides/neo4j/migration/storageMigration.md) for persistent volume and storage class migration. diff --git a/docs/guides/neo4j/configuration/_index.md b/docs/guides/neo4j/configuration/_index.md new file mode 100644 index 000000000..4f808e3fe --- /dev/null +++ b/docs/guides/neo4j/configuration/_index.md @@ -0,0 +1,10 @@ +--- +title: Run Neo4j with Custom Configuration +menu: + docs_{{ .version }}: + identifier: neo4j-configuration + name: Custom Configuration + parent: neo4j-guides + weight: 30 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/neo4j/configuration/using-config-file.md b/docs/guides/neo4j/configuration/using-config-file.md new file mode 100644 index 000000000..fe36a4be3 --- /dev/null +++ b/docs/guides/neo4j/configuration/using-config-file.md @@ -0,0 +1,193 @@ +--- +title: Run Neo4j with Custom Configuration +menu: + docs_{{ .version }}: + identifier: neo4j-using-config-file + name: Config File + parent: neo4j-configuration + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Using Custom Configuration File + +KubeDB supports providing custom configuration for Neo4j. This tutorial will show you how to use KubeDB to run Neo4j with custom configuration. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the kubectl command-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](https://kind.sigs.k8s.io/docs/user/quick-start/). + +- Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/README.md). + +- To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +## Overview + +Neo4j supports configuration via key-value pairs. KubeDB uses `spec.configuration.secretName` to allow users to provide a custom configuration Secret. The operator merges these key-value entries into the Neo4j configuration and restarts the cluster automatically. + +In this tutorial, we will configure `dbms.logs.query.enabled`, `dbms.logs.query.parameter_logging`, and JVM options via `server.jvm.additional`. + +## Custom Configuration + +KubeDB expects the custom configuration Secret to use `stringData` where each key is a Neo4j configuration property name and the corresponding value is its setting. Create the Secret: + +```yaml +apiVersion: v1 +stringData: + dbms.logs.query.enabled: "INFO" + dbms.logs.query.parameter_logging: "true" + server.jvm.additional: |- + -XX:+UseG1GC + -XX:-OmitStackTraceInFastThrow + -XX:+AlwaysPreTouch + -XX:+UnlockExperimentalVMOptions + -XX:+TrustFinalNonStaticFields + -XX:+DisableExplicitGC + -Djdk.nio.maxCachedBufferSize=1024 + -Dio.netty.tryReflectionSetAccessible=true + -Djdk.tls.ephemeralDHKeySize=2048 + -Djdk.tls.rejectClientInitiatedRenegotiation=true + -XX:FlightRecorderOptions=stackdepth=256 + -XX:+UnlockDiagnosticVMOptions + -XX:+DebugNonSafepoints + --add-opens=java.base/java.nio=ALL-UNNAMED + --add-opens=java.base/java.io=ALL-UNNAMED + --add-opens=java.base/sun.nio.ch=ALL-UNNAMED + -Dlog4j2.disable.jmx=true +kind: Secret +metadata: + name: neo4j-configuration + namespace: demo +``` + +```bash +$ kubectl apply -f neo4j-configuration-secret.yaml +secret/neo4j-configuration created +``` + +Verify the Secret was created: + +```bash +$ kubectl get secret -n demo neo4j-configuration +NAME TYPE DATA AGE +neo4j-configuration Opaque 3 10s +``` + +Now, create the Neo4j CRD specifying `spec.configuration.secretName`: + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: custom-neo4j + namespace: demo +spec: + version: "2025.12.1" + replicas: 3 + configuration: + secretName: neo4j-configuration + storageType: Durable + storage: + storageClassName: "local-path" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + deletionPolicy: WipeOut +``` + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/neo4j/configuration/neo4j-configuration.yaml +neo4j.kubedb.com/custom-neo4j created +``` + +Now, wait for the Neo4j cluster to be ready: + +```bash +$ kubectl get neo4j -n demo custom-neo4j -w +NAME VERSION STATUS AGE +custom-neo4j 2025.12.1 Ready 3m +``` + +## Verify the Applied Configuration + +To confirm the settings are active, connect to Neo4j via `cypher-shell` and run a `SHOW SETTINGS` query. First, get the default auth credentials: + +```bash +$ kubectl get secret -n demo custom-neo4j-auth \ + -o jsonpath='{.data.password}' | base64 -d + +``` + +Then exec into a Neo4j pod and run `cypher-shell`: + +```bash +$ kubectl exec -it -n demo custom-neo4j-0 -- \ + cypher-shell -u neo4j -p \ + "SHOW SETTINGS + YIELD name, value + WHERE name STARTS WITH 'dbms.logs.query' + RETURN name, value + ORDER BY name;" +``` + +Expected output: + +``` ++-----------------------------------------------------------+ +| name | value | ++-----------------------------------------------------------+ +| "dbms.logs.query.enabled" | "INFO" | +| "dbms.logs.query.parameter_logging" | "true" | ++-----------------------------------------------------------+ + +2 rows +``` + +You can also query other setting groups. For example, to check the Neo4j data directory paths: + +```bash +$ kubectl exec -it -n demo custom-neo4j-0 -- \ + cypher-shell -u neo4j -p \ + "SHOW SETTINGS + YIELD name, value + WHERE name STARTS WITH 'server.directories' + RETURN name, value + ORDER BY name + LIMIT 3;" +``` + +Expected output: + +``` ++---------------------------------------------------------------------+ +| name | value | ++---------------------------------------------------------------------+ +| "server.directories.data" | "/var/lib/neo4j/data" | +| "server.directories.import" | "/var/lib/neo4j/import" | +| "server.directories.logs" | "/var/lib/neo4j/logs" | ++---------------------------------------------------------------------+ + +3 rows +``` + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +kubectl patch -n demo neo4j/custom-neo4j -p '{"spec":{"deletionPolicy":"WipeOut"}}' --type="merge" +kubectl delete -n demo neo4j/custom-neo4j + +kubectl delete -n demo secret neo4j-configuration +kubectl delete ns demo +``` diff --git a/docs/guides/neo4j/custom-rbac/_index.md b/docs/guides/neo4j/custom-rbac/_index.md new file mode 100644 index 000000000..b4cee8dd9 --- /dev/null +++ b/docs/guides/neo4j/custom-rbac/_index.md @@ -0,0 +1,10 @@ +--- +title: Run Neo4j with Custom RBAC resources +menu: + docs_{{ .version }}: + identifier: neo4j-custom-rbac + name: Custom RBAC + parent: neo4j-guides + weight: 70 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/neo4j/custom-rbac/using-custom-rbac.md b/docs/guides/neo4j/custom-rbac/using-custom-rbac.md new file mode 100644 index 000000000..f6c900a11 --- /dev/null +++ b/docs/guides/neo4j/custom-rbac/using-custom-rbac.md @@ -0,0 +1,158 @@ +--- +title: Run Neo4j with Custom RBAC resources +menu: + docs_{{ .version }}: + identifier: neo4j-custom-rbac-quickstart + name: Custom RBAC + parent: neo4j-custom-rbac + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Using Custom RBAC Resources + +KubeDB supports finer user control over role based access permissions provided to a Neo4j instance. This tutorial will show you how to use KubeDB to run Neo4j instance with custom RBAC resources. + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-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](https://kind.sigs.k8s.io/docs/user/quick-start/). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/README.md). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +## Overview + +KubeDB allows users to provide custom RBAC resources, namely, `ServiceAccount`, `Role`, and `RoleBinding` for Neo4j. This is provided via the `spec.podTemplate.spec.serviceAccountName` field in Neo4j CRD. + +## Custom RBAC for Neo4j + +At first, let's create a `Service Account` in `demo` namespace. + +```bash +$ kubectl create serviceaccount -n demo my-custom-serviceaccount +serviceaccount/my-custom-serviceaccount created +``` + +Now, we need to create a role that has necessary access permissions for the Neo4j database named `quick-neo4j`. + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: my-custom-role + namespace: demo +rules: +- apiGroups: + - apps + resourceNames: + - quick-neo4j + resources: + - petsets + verbs: + - get +- apiGroups: + - kubedb.com + resourceNames: + - quick-neo4j + resources: + - neo4js + verbs: + - get +- apiGroups: + - "" + resources: + - pods + verbs: + - list + - patch +- apiGroups: + - "" + resources: + - pods/exec + verbs: + - create +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - create + - update +``` + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/neo4j/custom-rbac/neo4j-custom-role.yaml +role.rbac.authorization.k8s.io/my-custom-role created +``` + +Now create a `RoleBinding` to bind this `Role` with the already created service account. + +```bash +$ kubectl create rolebinding my-custom-rolebinding \ + --role=my-custom-role \ + --serviceaccount=demo:my-custom-serviceaccount \ + --namespace=demo +rolebinding.rbac.authorization.k8s.io/my-custom-rolebinding created +``` + +Now, create a Neo4j CRD specifying `spec.podTemplate.spec.serviceAccountName` field to `my-custom-serviceaccount`. + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: quick-neo4j + namespace: demo +spec: + version: "2025.12.1" + replicas: 3 + storageType: Durable + podTemplate: + spec: + serviceAccountName: my-custom-serviceaccount + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + deletionPolicy: WipeOut +``` + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/neo4j/custom-rbac/neo4j-custom-db.yaml +neo4j.kubedb.com/quick-neo4j created +``` + +Check that the pod is running: + +```bash +$ kubectl get pod -n demo quick-neo4j-0 +NAME READY STATUS RESTARTS AGE +quick-neo4j-0 1/1 Running 0 3m +``` + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +kubectl patch -n demo neo4j/quick-neo4j -p '{"spec":{"deletionPolicy":"WipeOut"}}' --type="merge" +kubectl delete -n demo neo4j/quick-neo4j + +kubectl delete -n demo serviceaccount my-custom-serviceaccount +kubectl delete -n demo role my-custom-role +kubectl delete -n demo rolebinding my-custom-rolebinding +kubectl delete ns demo +``` diff --git a/docs/guides/neo4j/migration/_index.md b/docs/guides/neo4j/migration/_index.md new file mode 100644 index 000000000..f77652010 --- /dev/null +++ b/docs/guides/neo4j/migration/_index.md @@ -0,0 +1,11 @@ +--- +title: Migration +menu: + docs_{{ .version }}: + identifier: neo4j-migration + name: Migration + parent: neo4j-guides + weight: 65 +menu_name: docs_{{ .version }} +--- + diff --git a/docs/guides/neo4j/migration/storageMigration.md b/docs/guides/neo4j/migration/storageMigration.md new file mode 100644 index 000000000..19b49414e --- /dev/null +++ b/docs/guides/neo4j/migration/storageMigration.md @@ -0,0 +1,142 @@ +--- +title: Neo4j StorageClass Migration Guide +menu: + docs_{{ .version }}: + identifier: neo4j-migration-storageclass + name: StorageClass Migration + parent: neo4j-migration + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Neo4j StorageClass Migration + +This guide shows how to migrate the `StorageClass` of a KubeDB-managed Neo4j cluster using `Neo4jOpsRequest` with `type: StorageMigration`. + +## Before You Begin + +- You need a Kubernetes cluster and `kubectl` configured. +- Install KubeDB operator following [setup guide](/docs/setup/README.md). +- Ensure at least two `StorageClass` resources are available in your cluster. + +Use a dedicated namespace for this walkthrough: + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +## Prepare Neo4j Database + +First, verify available storage classes: + +```bash +$ kubectl get sc +NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE +custom-longhorn driver.longhorn.io Delete WaitForFirstConsumer true 3h38m +local-path (default) rancher.io/local-path Delete WaitForFirstConsumer false 4h26m +longhorn (default) driver.longhorn.io Delete Immediate true 3h43m +longhorn-static driver.longhorn.io Delete Immediate true 3h43m +``` + +We will deploy Neo4j with `local-path`, then migrate to `custom-longhorn`. + +> Both old and new PVCs should stay on the same node. If the old class uses `WaitForFirstConsumer`, use a new class with `WaitForFirstConsumer` as well. + +Apply the Neo4j database manifest: + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + replicas: 3 + deletionPolicy: WipeOut + version: "2025.12.1" + storage: + storageClassName: "local-path" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi +EOF +neo4j.kubedb.com/neo4j-test created + +$ kubectl get neo4j,pvc -n demo +NAME VERSION STATUS AGE +neo4j.kubedb.com/neo4j-test 2025.12.1 Ready 2m + +NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE +persistentvolumeclaim/data-neo4j-test-0 Bound ... 2Gi RWO local-path 2m +persistentvolumeclaim/data-neo4j-test-1 Bound ... 2Gi RWO local-path 2m +persistentvolumeclaim/data-neo4j-test-2 Bound ... 2Gi RWO local-path 2m +``` + +## Apply StorageMigration OpsRequest + +To migrate `StorageClass`, create a `Neo4jOpsRequest`: + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: storage-migration + namespace: demo +spec: + type: StorageMigration + databaseRef: + name: neo4j-test + migration: + storageClassName: custom-longhorn + oldPVReclaimPolicy: Delete + timeout: 3000s +EOF +neo4jopsrequest.ops.kubedb.com/storage-migration created +``` + +Here, + +- `spec.type` must be `StorageMigration`. +- `spec.databaseRef.name` points to target Neo4j database. +- `spec.migration.storageClassName` is the destination `StorageClass`. +- `spec.migration.oldPVReclaimPolicy` controls old PV reclaim policy. + +> To retain old PVs after migration, use `oldPVReclaimPolicy: Retain`. + +## Verify StorageClass Migration + +Watch the OpsRequest status: + +```bash +$ kubectl get neo4jopsrequest -n demo -w +NAME TYPE STATUS AGE +storage-migration StorageMigration Successful 8m +``` + +Check PVC storage class after migration: + +```bash +$ kubectl get pvc -n demo +NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE +data-neo4j-test-0 Bound ... 2Gi RWO custom-longhorn 14m +data-neo4j-test-1 Bound ... 2Gi RWO custom-longhorn 14m +data-neo4j-test-2 Bound ... 2Gi RWO custom-longhorn 14m +``` + +The PVCs now use `custom-longhorn`, which confirms successful StorageClass migration. + +## Cleanup + +```bash +$ kubectl delete neo4jopsrequest -n demo storage-migration +$ kubectl delete neo4j -n demo neo4j-test +$ kubectl delete ns demo +``` diff --git a/docs/guides/neo4j/monitoring/_index.md b/docs/guides/neo4j/monitoring/_index.md new file mode 100644 index 000000000..6c73adcdf --- /dev/null +++ b/docs/guides/neo4j/monitoring/_index.md @@ -0,0 +1,10 @@ +--- +title: Neo4j Monitoring +menu: + docs_{{ .version }}: + identifier: neo4j-monitoring + name: Monitoring + parent: neo4j-guides + weight: 90 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/neo4j/monitoring/overview.md b/docs/guides/neo4j/monitoring/overview.md new file mode 100644 index 000000000..63b7f40a6 --- /dev/null +++ b/docs/guides/neo4j/monitoring/overview.md @@ -0,0 +1,76 @@ +--- +title: Neo4j Monitoring Overview +description: Neo4j Monitoring Overview +menu: + docs_{{ .version }}: + identifier: neo4j-monitoring-overview + name: Overview + parent: neo4j-monitoring + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Monitoring Neo4j with KubeDB + +KubeDB has native support for monitoring via [Prometheus](https://prometheus.io/). You can use builtin [Prometheus](https://github.com/prometheus/prometheus) scraper or [Prometheus operator](https://github.com/prometheus-operator/prometheus-operator) to monitor KubeDB-managed Neo4j clusters. This guide shows how Neo4j monitoring works with KubeDB and how to configure `Neo4j` CR to enable monitoring. + +## Overview + +KubeDB uses an exporter sidecar to expose Prometheus metrics from Neo4j pods. The following diagram shows the logical monitoring flow for Neo4j with KubeDB. + +

+ Database Monitoring Flow +

+ +When a user creates a `Neo4j` CR with `spec.monitor` configured, KubeDB provisions the database and creates a dedicated stats service named `{neo4j-name}-stats` for monitoring. Prometheus scrapes metrics from this stats service. + +## Configure Monitoring + +To enable monitoring for Neo4j, configure the `spec.monitor` section. KubeDB provides the following options: + +| Field | Type | Uses | +| --- | --- | --- | +| `spec.monitor.agent` | `Required` | Type of monitoring agent. Supported values: `prometheus.io/builtin` or `prometheus.io/operator`. | +| `spec.monitor.prometheus.serviceMonitor.labels` | `Optional` | Labels for `ServiceMonitor` object. | +| `spec.monitor.prometheus.serviceMonitor.interval` | `Optional` | Metrics scraping interval. | + +## Sample Configuration + +A sample YAML for a Neo4j cluster with monitoring enabled using Prometheus operator is shown below. + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: sample-neo4j + namespace: demo +spec: + version: "2025.12.1" + replicas: 3 + deletionPolicy: WipeOut + storage: + storageClassName: local-path + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + monitor: + agent: prometheus.io/operator + prometheus: + serviceMonitor: + labels: + release: prometheus + interval: 10s +``` + +Here, `spec.monitor.agent: prometheus.io/operator` tells KubeDB to create monitoring resources for Prometheus operator. KubeDB creates a `ServiceMonitor` object with the configured labels, and the Prometheus server discovers and scrapes Neo4j metrics through `{neo4j-name}-stats` service. + +## Next Steps + +- Monitor Neo4j using [Builtin Prometheus](/docs/guides/neo4j/monitoring/using-builtin-prometheus.md). +- Monitor Neo4j using [Prometheus Operator](/docs/guides/neo4j/monitoring/using-prometheus-operator.md). +- Configure alerting and dashboards from scraped metrics in Prometheus/Grafana. diff --git a/docs/guides/neo4j/monitoring/using-builtin-prometheus.md b/docs/guides/neo4j/monitoring/using-builtin-prometheus.md new file mode 100644 index 000000000..698c4f869 --- /dev/null +++ b/docs/guides/neo4j/monitoring/using-builtin-prometheus.md @@ -0,0 +1,365 @@ +--- +title: Monitor Neo4j using Builtin Prometheus Discovery +menu: + docs_{{ .version }}: + identifier: neo4j-using-builtin-prometheus-monitoring + name: Builtin Prometheus + parent: neo4j-monitoring + weight: 20 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Monitoring Neo4j with Builtin Prometheus + +This tutorial will show you how to monitor a Neo4j database using builtin [Prometheus](https://github.com/prometheus/prometheus) scraper. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the `kubectl` command-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](https://kind.sigs.k8s.io/docs/user/quick-start/). + +- Install KubeDB operator in your cluster following the steps [here](/docs/setup/README.md). + +- If you are not familiar with how to configure Prometheus to scrape metrics from various Kubernetes resources, please read the tutorial from [here](https://github.com/appscode/third-party-tools/tree/master/monitoring/prometheus/builtin). + +- To learn how Prometheus monitoring works with KubeDB in general, please visit [here](/docs/guides/neo4j/monitoring/overview.md). + +- To keep Prometheus resources isolated, we are going to use a separate namespace called `monitoring` to deploy respective monitoring resources. We are going to deploy the database in the `demo` namespace. + + ```bash + $ kubectl create ns monitoring + namespace/monitoring created + + $ kubectl create ns demo + namespace/demo created + ``` + +> Note: YAML files used in this tutorial are stored in the [docs/examples/neo4j](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/examples/neo4j) folder in the GitHub repository [kubedb/docs](https://github.com/kubedb/docs). + +## Deploy Neo4j with Monitoring Enabled + +Let's deploy a Neo4j database with monitoring enabled. Below is the Neo4j object that we are going to create. + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: builtin-prom-neo4j + namespace: demo +spec: + version: "2025.12.1" + replicas: 3 + deletionPolicy: WipeOut + storage: + storageClassName: "local-path" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + monitor: + agent: prometheus.io/builtin +``` + +Here, + +- `spec.monitor.agent: prometheus.io/builtin` specifies that we are going to monitor this server using the builtin Prometheus scraper. + +Let's create the Neo4j CR: + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/neo4j/monitoring/builtin-prom-neo4j.yaml +neo4j.kubedb.com/builtin-prom-neo4j created +``` + +Now, wait for the database to go into `Ready` state. + +```bash +$ kubectl get neo4j -n demo builtin-prom-neo4j +NAME VERSION STATUS AGE +builtin-prom-neo4j 2025.12.1 Ready 2m +``` + +KubeDB will create a separate stats service with the name `{Neo4j CR name}-stats` for monitoring purposes. + +```bash +$ kubectl get svc -n demo +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +builtin-prom-neo4j ClusterIP 10.43.110.23 6362/TCP,7687/TCP,7474/TCP 4m12s +builtin-prom-neo4j-0 ClusterIP None 6362/TCP,7687/TCP,7474/TCP,7688/TCP,7000/TCP,6000/TCP 4m12s +builtin-prom-neo4j-1 ClusterIP None 6362/TCP,7687/TCP,7474/TCP,7688/TCP,7000/TCP,6000/TCP 4m12s +builtin-prom-neo4j-2 ClusterIP None 6362/TCP,7687/TCP,7474/TCP,7688/TCP,7000/TCP,6000/TCP 4m12s +builtin-prom-neo4j-stats ClusterIP 10.43.245.51 2004/TCP 4m12s +``` + +Here, `builtin-prom-neo4j-stats` service has been created for monitoring purposes. Let's describe this stats service: + +```bash +$ kubectl get svc -n demo builtin-prom-neo4j-stats -o yaml +``` + +```yaml +apiVersion: v1 +kind: Service +metadata: + annotations: + monitoring.appscode.com/agent: prometheus.io/builtin + prometheus.io/path: /metrics + prometheus.io/port: "2004" + prometheus.io/scheme: http + prometheus.io/scrape: "true" + labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: builtin-prom-neo4j + app.kubernetes.io/managed-by: kubedb.com + app.kubernetes.io/name: neo4js.kubedb.com + kubedb.com/role: stats + name: builtin-prom-neo4j-stats + namespace: demo +spec: + clusterIP: 10.43.245.51 + ports: + - name: metrics + port: 2004 + protocol: TCP + targetPort: metrics + selector: + app.kubernetes.io/instance: builtin-prom-neo4j + app.kubernetes.io/managed-by: kubedb.com + app.kubernetes.io/name: neo4js.kubedb.com + type: ClusterIP +``` + +You can see that the service contains following annotations: + +```yaml +prometheus.io/path: /metrics +prometheus.io/port: "2004" +prometheus.io/scrape: "true" +``` + +The Prometheus server will discover the service endpoint using these specifications and will scrape metrics from the exporter. + +## Configure Prometheus Server + +Now, we have to configure a Prometheus scraping job to scrape the metrics using this service. We are going to configure a scraping job similar to this [kubernetes-service-endpoints](https://github.com/appscode/third-party-tools/tree/master/monitoring/prometheus/builtin#kubernetes-service-endpoints) job that scrapes metrics from endpoints of a service. + +Let's configure a Prometheus scraping job to collect metrics from this service: + +```yaml +- job_name: 'kubedb-databases' + honor_labels: true + scheme: http + kubernetes_sd_configs: + - role: endpoints + # by default Prometheus server select all Kubernetes services as possible target. + # relabel_config is used to filter only desired endpoints + relabel_configs: + # keep only those services that has "prometheus.io/scrape","prometheus.io/path" and "prometheus.io/port" annotations + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_service_annotation_prometheus_io_port] + separator: ; + regex: true;(.*) + action: keep + # currently KubeDB supported databases uses only "http" scheme to export metrics. so, drop any service that uses "https" scheme. + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: drop + regex: https + # only keep the stats services created by KubeDB for monitoring purpose which has "-stats" suffix + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*-stats) + action: keep + # service created by KubeDB will have "app.kubernetes.io/name" and "app.kubernetes.io/instance" labels. keep only those services that have these labels. + - source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_name] + separator: ; + regex: (.*) + action: keep + # read the metric path from "prometheus.io/path: " annotation + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + # read the port from "prometheus.io/port: " annotation and update scraping address accordingly + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + # add service namespace as label to the scraped metrics + - source_labels: [__meta_kubernetes_namespace] + separator: ; + regex: (.*) + target_label: namespace + replacement: $1 + action: replace + # add service name as a label to the scraped metrics + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*) + target_label: service + replacement: $1 + action: replace + # add stats service's labels to the scraped metrics + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) +``` + +### Configure Existing Prometheus Server + +If you already have a Prometheus server running, you have to add the above scraping job in the `ConfigMap` used to configure the Prometheus server. Then, you have to restart it for the updated configuration to take effect. + +> If you don't use a persistent volume for Prometheus storage, you will lose your previously scraped data on restart. + +### Deploy New Prometheus Server + +If you don't have any existing Prometheus server running, you have to deploy one. In this section, we are going to deploy a Prometheus server in the `monitoring` namespace to collect metrics using this stats service. + +**Create ConfigMap:** + +At first, create a ConfigMap with the scraping configuration. Below is the YAML of the ConfigMap that we are going to create: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-config + labels: + app: prometheus-demo + namespace: monitoring +data: + prometheus.yml: | + global: + scrape_interval: 5s + evaluation_interval: 5s + scrape_configs: + - job_name: 'kubedb-databases' + honor_labels: true + scheme: http + kubernetes_sd_configs: + - role: endpoints + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_service_annotation_prometheus_io_port] + separator: ; + regex: true;(.*) + action: keep + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: drop + regex: https + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*-stats) + action: keep + - source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_name] + separator: ; + regex: (.*) + action: keep + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - source_labels: [__meta_kubernetes_namespace] + separator: ; + regex: (.*) + target_label: namespace + replacement: $1 + action: replace + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*) + target_label: service + replacement: $1 + action: replace + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) +``` + +Let's create the ConfigMap: + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/monitoring/builtin-prometheus/prom-config.yaml +configmap/prometheus-config created +``` + +**Create RBAC:** + +If you are using an RBAC enabled cluster, you have to give necessary RBAC permissions for Prometheus. Let's create necessary RBAC resources for Prometheus: + +```bash +$ kubectl apply -f https://github.com/appscode/third-party-tools/raw/master/monitoring/prometheus/builtin/artifacts/rbac.yaml +clusterrole.rbac.authorization.k8s.io/prometheus created +serviceaccount/prometheus created +clusterrolebinding.rbac.authorization.k8s.io/prometheus created +``` + +> YAML for the RBAC resources created above can be found [here](https://github.com/appscode/third-party-tools/blob/master/monitoring/prometheus/builtin/artifacts/rbac.yaml). + +**Deploy Prometheus:** + +Now, we are ready to deploy the Prometheus server. Let's deploy it using the following deployment: + +```bash +$ kubectl apply -f https://github.com/appscode/third-party-tools/raw/master/monitoring/prometheus/builtin/artifacts/deployment.yaml +deployment.apps/prometheus created +``` + +### Verify Monitoring Metrics + +The Prometheus server is listening on port `9090`. We are going to use [port forwarding](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) to access the Prometheus dashboard. + +At first, let's check if the Prometheus pod is in `Running` state: + +```bash +$ kubectl get pod -n monitoring -l=app=prometheus +NAME READY STATUS RESTARTS AGE +prometheus-8597f664fd-2sl48 1/1 Running 0 6m58s +``` + +Now, run the following command in a separate terminal to forward port 9090: + +```bash +$ kubectl port-forward -n monitoring prometheus-8597f664fd-2sl48 9090 +Forwarding from 127.0.0.1:9090 -> 9090 +Forwarding from [::1]:9090 -> 9090 +``` + +Now, we can access the dashboard at `localhost:9090`. Open [http://localhost:9090](http://localhost:9090) in your browser. Navigate to **Status โ†’ Targets** and you should see the endpoint of `builtin-prom-neo4j-stats` service as one of the active targets. + +

+ Prometheus Target +

+ +The labels marked in the image confirm that the metrics are coming from the Neo4j database `builtin-prom-neo4j` through the stats service `builtin-prom-neo4j-stats`. + +Now, you can view the collected metrics and create graphs from the Prometheus homepage. You can also use this Prometheus server as a data source for [Grafana](https://grafana.com/) and create beautiful dashboards with collected metrics. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl patch -n demo neo4j/builtin-prom-neo4j -p '{"spec":{"deletionPolicy":"WipeOut"}}' --type="merge" +$ kubectl delete -n demo neo4j/builtin-prom-neo4j + +$ kubectl delete -n monitoring deployment.apps/prometheus + +$ kubectl delete -n monitoring clusterrole.rbac.authorization.k8s.io/prometheus +$ kubectl delete -n monitoring serviceaccount/prometheus +$ kubectl delete -n monitoring clusterrolebinding.rbac.authorization.k8s.io/prometheus + +$ kubectl delete ns demo +$ kubectl delete ns monitoring +``` + +## Next Steps + +- Learn about [backup and restore](/docs/guides/neo4j/backup/overview.md) Neo4j databases using Stash. +- Monitor your Neo4j database with KubeDB using [`Prometheus operator`](/docs/guides/neo4j/monitoring/using-prometheus-operator.md). +- Use [private Docker registry](/docs/guides/neo4j/private-registry/using-private-registry.md) to deploy Neo4j with KubeDB. +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/neo4j/monitoring/using-prometheus-operator.md b/docs/guides/neo4j/monitoring/using-prometheus-operator.md new file mode 100644 index 000000000..67b2dfb10 --- /dev/null +++ b/docs/guides/neo4j/monitoring/using-prometheus-operator.md @@ -0,0 +1,247 @@ +--- +title: Monitor Neo4j using Prometheus Operator +menu: + docs_{{ .version }}: + identifier: neo4j-using-prometheus-operator-monitoring + name: Prometheus Operator + parent: neo4j-monitoring + weight: 30 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Monitoring Neo4j Using Prometheus Operator + +[Prometheus operator](https://github.com/prometheus-operator/prometheus-operator) provides a simple and Kubernetes-native way to deploy and configure Prometheus server. This tutorial will show you how to use the Prometheus operator to monitor a Neo4j database deployed with KubeDB. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the `kubectl` command-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](https://kind.sigs.k8s.io/docs/user/quick-start/). + +- To learn how Prometheus monitoring works with KubeDB in general, please visit [here](/docs/guides/neo4j/monitoring/overview.md). + +- To keep Prometheus resources isolated, we are going to use a separate namespace called `monitoring` to deploy respective monitoring resources. We are going to deploy the database in the `demo` namespace. + + ```bash + $ kubectl create ns monitoring + namespace/monitoring created + + $ kubectl create ns demo + namespace/demo created + ``` + +- We need a [Prometheus operator](https://github.com/prometheus-operator/prometheus-operator) instance running. If you don't already have one, deploy it following the docs from [here](https://github.com/appscode/third-party-tools/blob/master/monitoring/prometheus/operator/README.md). + +- If you don't already have a Prometheus server running, deploy one following the tutorial from [here](https://github.com/appscode/third-party-tools/blob/master/monitoring/prometheus/operator/README.md#deploy-prometheus-server). + +> Note: YAML files used in this tutorial are stored in the [docs/examples/neo4j](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/examples/neo4j) folder in the GitHub repository [kubedb/docs](https://github.com/kubedb/docs). + +## Find out Required Labels for ServiceMonitor + +We need to know the labels used to select `ServiceMonitor` by a `Prometheus` CR. We will provide these labels in `spec.monitor.prometheus.labels` field of the Neo4j CR so that KubeDB creates a `ServiceMonitor` object accordingly. + +Let's find out the available Prometheus server in our cluster. + +```bash +$ kubectl get prometheus --all-namespaces +NAMESPACE NAME VERSION DESIRED READY RECONCILED AVAILABLE AGE +monitoring prometheus-kube-prometheus-prometheus v3.11.3-distroless 1 1 True True 10m +``` + +> If you don't have any Prometheus server running in your cluster, deploy one following the guide specified in the **Before You Begin** section. + +Now, let's view the YAML of the available Prometheus server in `monitoring` namespace. + +```bash +$ kubectl get prometheus -n monitoring prometheus-kube-prometheus-prometheus -o yaml +``` + +```yaml +apiVersion: monitoring.coreos.com/v1 +kind: Prometheus +metadata: + name: prometheus-kube-prometheus-prometheus + namespace: monitoring + labels: + app: kube-prometheus-stack-prometheus + release: prometheus +spec: + replicas: 1 + serviceMonitorSelector: + matchLabels: + release: prometheus + serviceMonitorNamespaceSelector: {} + ... +``` + +Notice the `spec.serviceMonitorSelector` section. Here, `release: prometheus` label is used to select `ServiceMonitor` CRs. So, we are going to use this label in `spec.monitor.prometheus.labels` field of the Neo4j CR. + +## Deploy Neo4j with Monitoring Enabled + +Below is the Neo4j object that we are going to create with monitoring enabled. + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: coreos-prom-neo4j + namespace: demo +spec: + replicas: 3 + deletionPolicy: WipeOut + version: "2025.11.2" + storage: + storageClassName: local-path + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + monitor: + agent: prometheus.io/operator + prometheus: + serviceMonitor: + labels: + release: prometheus + interval: 10s +``` + +Here, + +- `monitor.agent: prometheus.io/operator` indicates that we are going to monitor this server using Prometheus operator. +- `monitor.prometheus.serviceMonitor.labels` specifies that KubeDB should create a `ServiceMonitor` with these labels. We use `release: prometheus` to match the `serviceMonitorSelector` configured in the Prometheus CR above. +- `monitor.prometheus.interval` indicates that the Prometheus server should scrape metrics from this database at a 10-second interval. + +Let's create the Neo4j object: + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/neo4j/monitoring/coreos-prom-neo4j.yaml +neo4j.kubedb.com/coreos-prom-neo4j created +``` + +Now, wait for the database to go into `Ready` state. + +```bash +$ kubectl get neo4j -n demo coreos-prom-neo4j +NAME VERSION STATUS AGE +coreos-prom-neo4j 2025.11.2 Ready 3m +``` + +KubeDB will create a separate stats service with the name `{Neo4j CR name}-stats` for monitoring purposes. + +```bash +$ kubectl get svc -n demo --selector="app.kubernetes.io/instance=coreos-prom-neo4j" +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +coreos-prom-neo4j ClusterIP 10.43.124.250 6362/TCP,7687/TCP,7474/TCP 3m55s +coreos-prom-neo4j-0 ClusterIP None 6362/TCP,7687/TCP,7474/TCP,7688/TCP,7000/TCP,6000/TCP 3m55s +coreos-prom-neo4j-1 ClusterIP None 6362/TCP,7687/TCP,7474/TCP,7688/TCP,7000/TCP,6000/TCP 3m55s +coreos-prom-neo4j-2 ClusterIP None 6362/TCP,7687/TCP,7474/TCP,7688/TCP,7000/TCP,6000/TCP 3m55s +coreos-prom-neo4j-stats ClusterIP 10.43.214.74 2004/TCP 3m55s +``` + +Here, `coreos-prom-neo4j-stats` service has been created for monitoring purposes. It exposes metrics on port `2004`. + +## Verify ServiceMonitor Creation + +KubeDB will also create a `ServiceMonitor` CR in the `demo` namespace that selects the endpoints of `coreos-prom-neo4j-stats` service. Verify that the `ServiceMonitor` has been created. + +```bash +$ kubectl get servicemonitor -n demo +NAME AGE +coreos-prom-neo4j-stats 6m8s +``` + +Let's verify the `ServiceMonitor` YAML. + +```bash +$ kubectl get servicemonitor -n demo coreos-prom-neo4j-stats -o yaml +``` + +```yaml +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: coreos-prom-neo4j + app.kubernetes.io/managed-by: kubedb.com + app.kubernetes.io/name: neo4js.kubedb.com + release: prometheus + name: coreos-prom-neo4j-stats + namespace: demo +spec: + endpoints: + - honorLabels: true + interval: 10s + path: /metrics + port: metrics + relabelings: + - action: replace + sourceLabels: + - __meta_kubernetes_endpoint_address_target_name + targetLabel: pod + scheme: http + namespaceSelector: + matchNames: + - demo + selector: + matchLabels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: coreos-prom-neo4j + app.kubernetes.io/managed-by: kubedb.com + app.kubernetes.io/name: neo4js.kubedb.com + kubedb.com/role: stats +``` + +Notice that the `ServiceMonitor` carries the `release: prometheus` label that we specified in the Neo4j CR โ€” this is exactly what the Prometheus server's `serviceMonitorSelector` looks for. + +The `ServiceMonitor` selects the `coreos-prom-neo4j-stats` service by matching its labels and scrapes the `metrics` port (`2004`) every 10 seconds. + +## Verify Monitoring Metrics + +Let's find out the Prometheus pod for our Prometheus server. + +```bash +$ kubectl get pod -n monitoring -l app.kubernetes.io/name=prometheus +NAME READY STATUS RESTARTS AGE +prometheus-prometheus-kube-prometheus-prometheus-0 2/2 Running 0 15m +``` + +The Prometheus server is listening on port `9090`. We are going to use [port forwarding](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) to access the Prometheus dashboard. + +Run the following command in a separate terminal to forward port 9090: + +```bash +$ kubectl port-forward -n monitoring prometheus-prometheus-kube-prometheus-prometheus-0 9090 +Forwarding from 127.0.0.1:9090 -> 9090 +Forwarding from [::1]:9090 -> 9090 +``` + +Now, open [http://localhost:9090](http://localhost:9090) in your browser. Navigate to **Status โ†’ Targets** and you should see the `coreos-prom-neo4j-stats` endpoint listed as an active scrape target. + +

+ Prometheus Target +

+ +The `endpoint` and `service` labels confirm the target is our Neo4j database. You can now browse collected metrics from the Prometheus homepage and create graphs, or use this Prometheus server as a data source for [Grafana](https://grafana.com/) to build dashboards. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +# delete the Neo4j database +kubectl patch -n demo neo4j/coreos-prom-neo4j -p '{"spec":{"deletionPolicy":"WipeOut"}}' --type="merge" +kubectl delete -n demo neo4j/coreos-prom-neo4j + +# delete namespaces +kubectl delete ns demo +kubectl delete ns monitoring +``` + +## Next Steps + +- Monitor your Neo4j database with KubeDB using [built-in Prometheus](/docs/guides/neo4j/monitoring/using-builtin-prometheus.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/neo4j/private-registry/_index.md b/docs/guides/neo4j/private-registry/_index.md new file mode 100644 index 000000000..b38cc887c --- /dev/null +++ b/docs/guides/neo4j/private-registry/_index.md @@ -0,0 +1,10 @@ +--- +title: Run Neo4j using Private Registry +menu: + docs_{{ .version }}: + identifier: neo4j-private-registry + name: Private Registry + parent: neo4j-guides + weight: 80 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/neo4j/private-registry/using-private-registry.md b/docs/guides/neo4j/private-registry/using-private-registry.md new file mode 100644 index 000000000..0a6dadec1 --- /dev/null +++ b/docs/guides/neo4j/private-registry/using-private-registry.md @@ -0,0 +1,126 @@ +--- +title: Run Neo4j using Private Registry +menu: + docs_{{ .version }}: + identifier: neo4j-using-private-registry + name: Quickstart + parent: neo4j-private-registry + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Using Private Docker Registry + +KubeDB supports using private Docker registries. This tutorial will show you how to run KubeDB managed Neo4j database using private Docker images. + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-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](https://kind.sigs.k8s.io/docs/user/quick-start/). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +## Prepare Private Docker Registry + +- You will also need a docker private [registry](https://docs.docker.com/registry/) or [private repository](https://docs.docker.com/docker-hub/repos/#private-repositories). + +- Push the required images from KubeDB's [Docker hub account](https://hub.docker.com/r/kubedb/) into your private registry. For Neo4j, push the `DB_IMAGE` of the following Neo4jVersions, where `deprecated` is not true. + + ```bash + $ kubectl get neo4jversions -o=custom-columns=NAME:.metadata.name,VERSION:.spec.version,DB_IMAGE:.spec.db.image,DEPRECATED:.spec.deprecated + NAME VERSION DB_IMAGE DEPRECATED + 2025.11.2 2025.11.2 kubedb/neo4j:2025.11.2 + ``` + +## Create ImagePullSecret + +Run the following command to create an image pull secret for your private Docker registry: + +```bash +$ kubectl create secret docker-registry -n demo myregistrykey \ + --docker-server=DOCKER_REGISTRY_SERVER \ + --docker-username=DOCKER_USER \ + --docker-email=DOCKER_EMAIL \ + --docker-password=DOCKER_PASSWORD +secret/myregistrykey created +``` + +## Install KubeDB Operator + +Follow the steps to [install KubeDB operator](/docs/setup/README.md) properly in cluster so that it points to the `DOCKER_REGISTRY` you wish to pull images from. + +## Create Neo4jVersion CRD + +Create a Neo4jVersion CRD specifying images from your private registry. Replace `PRIVATE_REGISTRY` with your private registry. + +```yaml +apiVersion: catalog.kubedb.com/v1alpha1 +kind: Neo4jVersion +metadata: + name: "2025.11.2" +spec: + db: + image: PRIVATE_REGISTRY/neo4j:2025.11.2 + version: "2025.11.2" +``` + +```bash +$ kubectl apply -f pvt-neo4jversion.yaml +neo4jversion.catalog.kubedb.com/2025.11.2 created +``` + +## Deploy Neo4j from Private Registry + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: pvt-reg-neo4j + namespace: demo +spec: + version: "2025.11.2" + replicas: 3 + storageType: Durable + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + podTemplate: + spec: + imagePullSecrets: + - name: myregistrykey + deletionPolicy: WipeOut +``` + +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/neo4j/private-registry/pvt-reg-neo4j.yaml +neo4j.kubedb.com/pvt-reg-neo4j created +``` + +Check that the Neo4j is in Running state: + +```bash +$ kubectl get pods -n demo --selector="app.kubernetes.io/instance=pvt-reg-neo4j" +NAME READY STATUS RESTARTS AGE +pvt-reg-neo4j-0 1/1 Running 0 3m +``` + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +kubectl patch -n demo neo4j/pvt-reg-neo4j -p '{"spec":{"deletionPolicy":"WipeOut"}}' --type="merge" +kubectl delete -n demo neo4j/pvt-reg-neo4j +kubectl delete ns demo +``` diff --git a/docs/guides/neo4j/quickstart/_index.md b/docs/guides/neo4j/quickstart/_index.md new file mode 100644 index 000000000..51511d996 --- /dev/null +++ b/docs/guides/neo4j/quickstart/_index.md @@ -0,0 +1,10 @@ +--- +title: Neo4j Quickstart +menu: + docs_{{ .version }}: + identifier: neo4j-quickstart + name: Quickstart + parent: neo4j-guides + weight: 10 +menu_name: docs_{{ .version }} +--- \ No newline at end of file diff --git a/docs/guides/neo4j/quickstart/quickstart.md b/docs/guides/neo4j/quickstart/quickstart.md new file mode 100644 index 000000000..83221663b --- /dev/null +++ b/docs/guides/neo4j/quickstart/quickstart.md @@ -0,0 +1,225 @@ +--- +title: Neo4j Quickstart +menu: + docs_{{ .version }}: + identifier: neo4j-quickstart-overview + name: Overview + parent: neo4j-quickstart + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Running Neo4j + +This tutorial will show you how to use KubeDB to run a Neo4j database on Kubernetes. + +

+ lifecycle +

+ +> Note: YAML files used in this tutorial are stored in [docs/examples/neo4j/quickstart](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/examples/neo4j/quickstart) folder in GitHub repository [kubedb/docs](https://github.com/kubedb/docs). + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the `kubectl` command-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](https://kind.sigs.k8s.io/docs/user/quick-start/). + +Now, install KubeDB CLI on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/README.md). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +## Find Available StorageClass + +You will need to provide a `StorageClass` in the Neo4j CR specification. Check the available `StorageClass` in your cluster using the following command: + +```bash +$ kubectl get storageclass +NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE +local-path (default) rancher.io/local-path Delete WaitForFirstConsumer false 12d +``` + +Here, we have `local-path` as the default StorageClass in our cluster. + +## Find Available Neo4jVersion + +When KubeDB is installed, it creates `Neo4jVersion` CRDs for all supported Neo4j versions. Check the available versions by running: + +```bash +$ kubectl get neo4jversions +NAME VERSION DB_IMAGE DEPRECATED AGE +2025.10.1 2025.10.1-enterprise docker.io/library/neo4j:2025.10.1-enterprise 12d +2025.11.2 2025.11.2-enterprise docker.io/library/neo4j:2025.11.2-enterprise 12d +2025.12.1 2025.12.1-enterprise docker.io/library/neo4j:2025.12.1-enterprise 12d +``` + +Notice the `DEPRECATED` column. A `true` value means that version is deprecated for the current KubeDB release and should be avoided. In this tutorial, we will use `2025.12.1`. + +## Create a Neo4j Database + +KubeDB implements a `Neo4j` CRD to define the specification of a Neo4j database. Below is the `Neo4j` object used in this tutorial: + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + replicas: 3 + version: "2025.12.1" + storage: + storageClassName: local-path + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + deletionPolicy: WipeOut +``` + +Here, + +- `spec.version` is the name of the `Neo4jVersion` CR specifying the Docker image for each database pod. In this tutorial, Neo4j `2025.12.1` Enterprise is used. +- `spec.replicas` sets the number of Neo4j instances in the cluster. Here, a 3-member cluster is created. +- `spec.storage` specifies the `StorageClass` and size of the PVC that KubeDB will dynamically allocate for each pod. This field is required when `spec.storageType` is `Durable` (the default). +- `spec.deletionPolicy` controls what KubeDB does when the `Neo4j` CR is deleted. `WipeOut` removes all related resources including PVCs and Secrets. + +Now apply the manifest and watch the cluster come up: + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/neo4j/quickstart/neo4j.yaml +neo4j.kubedb.com/neo4j-test created + +$ kubectl get neo4j -n demo neo4j-test -w +NAME VERSION STATUS AGE +neo4j-test 2025.12.1 Provisioning 10s +neo4j-test 2025.12.1 Ready 2m +``` + +KubeDB operator watches for `Neo4j` objects using the Kubernetes API. When a `Neo4j` object is created, KubeDB provisions a PetSet, one PVC per replica, a ClusterIP Service for client access, and a headless governing Service for pod-to-pod communication. It also auto-generates an auth Secret for the `neo4j` superuser. + +## Verify Neo4j Database + +Once `status.phase` is `Ready`, all three pods are running and the cluster has formed. Let's verify: + +```bash +$ kubectl get neo4j -n demo +NAME VERSION STATUS AGE +neo4j-test 2025.12.1 Ready 3m + +$ kubectl get pods -n demo -l app.kubernetes.io/instance=neo4j-test +NAME READY STATUS RESTARTS AGE +neo4j-test-0 1/1 Running 0 3m +neo4j-test-1 1/1 Running 0 2m +neo4j-test-2 1/1 Running 0 2m +``` + +KubeDB also creates two Services for the Neo4j cluster: + +```bash +$ kubectl get service -n demo -l app.kubernetes.io/instance=neo4j-test +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +neo4j-test ClusterIP 10.43.86.203 6362/TCP,7687/TCP,7474/TCP 11m +neo4j-test-0 ClusterIP None 6362/TCP,7687/TCP,7474/TCP,7688/TCP,7000/TCP,6000/TCP 11m +neo4j-test-1 ClusterIP None 6362/TCP,7687/TCP,7474/TCP,7688/TCP,7000/TCP,6000/TCP 11m +neo4j-test-2 ClusterIP None 6362/TCP,7687/TCP,7474/TCP,7688/TCP,7000/TCP,6000/TCP 11m +``` + +- **`neo4j-test`** โ€” the primary ClusterIP Service exposing HTTP (`7474`), Bolt (`7687`), and backup (`6362`) for client access. +- **`neo4j-test-0`, `neo4j-test-1`, `neo4j-test-2`** โ€” per-pod headless Services exposing all cluster-internal ports including inter-node communication (`7000`), cluster discovery (`6000`), and intra-cluster Bolt (`7688`). + +## Connect with Neo4j + +KubeDB creates a Secret named `{neo4j-name}-auth` containing the `neo4j` superuser credentials. Retrieve them: + +```bash +$ kubectl get secret -n demo neo4j-test-auth -o jsonpath='{.data.username}' | base64 -d +neo4j + +$ kubectl get secret -n demo neo4j-test-auth -o jsonpath='{.data.password}' | base64 -d +Xk9mR2qLpTz3vYwB +``` + +> Note: Auth Secret name format: `{neo4j-name}-auth`. The password is randomly generated on first provisioning. + +### Connect via cypher-shell + +Exec into any pod and use `cypher-shell` to verify the cluster is accepting queries: + +```bash +$ PASS=$(kubectl get secret -n demo neo4j-test-auth -o jsonpath='{.data.password}' | base64 -d) + +$ kubectl exec -n demo neo4j-test-0 -- cypher-shell -u neo4j -p "$PASS" "RETURN 'connected' AS status" ++-------------+ +| status | ++-------------+ +| "connected" | ++-------------+ +``` + +### Connect via Neo4j Browser + +You can access the Neo4j Browser UI from your local machine by port-forwarding the cluster service: + +```bash +$ kubectl port-forward -n demo svc/neo4j-test 7474:7474 7687:7687 +Forwarding from 127.0.0.1:7474 -> 7474 +Forwarding from 127.0.0.1:7687 -> 7687 +``` + +Now open your browser and navigate to: + +``` +http://localhost:7474 +``` + +On the login screen, enter the following connection details: + +| Field | Value | +|----------------|------------------------------| +| Protocol | `neo4j://` | +| Connection URL | `localhost:7687` | +| Database user | `neo4j` | +| Password | _(from the Secret above)_ | + +

+ + neo4j-browser-login + +

+ +After a successful login, you will land on the Neo4j Browser home. You can run Cypher queries directly โ€” for example, `SHOW DATABASE` lists all databases in the cluster along with their host addresses, roles, and status: + +

+ + neo4j-browser-connected + +

+ +## Cleaning up + +To remove all resources created by this tutorial: + +```bash +$ kubectl delete neo4j -n demo neo4j-test +neo4j.kubedb.com "neo4j-test" deleted + +$ kubectl delete ns demo +namespace "demo" deleted +``` + +> Note: Since `deletionPolicy` is set to `WipeOut`, deleting the `Neo4j` CR also removes all associated PVCs and the auth Secret. + +## Next Steps + +- If your cluster enforces RBAC, review required permissions in [RBAC for Neo4j](/docs/guides/neo4j/quickstart/rbac.md). +- Learn how to perform day-2 operations such as version upgrades, scaling, volume expansion, TLS configuration, and more using the [Neo4j OpsRequest overview](/docs/guides/neo4j/ops-request/overview.md). +- Detail concepts of the [Neo4j CRD](/docs/guides/neo4j/concepts/neo4j.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/neo4j/quickstart/rbac.md b/docs/guides/neo4j/quickstart/rbac.md new file mode 100644 index 000000000..47fc53e45 --- /dev/null +++ b/docs/guides/neo4j/quickstart/rbac.md @@ -0,0 +1,191 @@ +--- +title: RBAC for Neo4j +menu: + docs_{{ .version }}: + identifier: neo4j-rbac-quickstart + name: RBAC + parent: neo4j-quickstart + weight: 15 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# RBAC Permissions for Neo4j + +If RBAC is enabled in your cluster, KubeDB creates Neo4j-specific RBAC resources so Neo4j pods can discover Services and Endpoints during cluster operations. + +Here are the additional permissions used by Neo4j pods: + +| Kubernetes Resource | Resource Names | Permission required | +|---------------------|----------------|---------------------| +| services | | get, list, watch | +| endpoints | | get, list, watch | + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the `kubectl` command-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](https://kind.sigs.k8s.io/docs/user/quick-start/). + +Now, install KubeDB CLI on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/README.md). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: YAML files used in this tutorial are stored in [docs/examples/neo4j/quickstart](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/examples/neo4j/quickstart) folder in GitHub repository [kubedb/docs](https://github.com/kubedb/docs). + +## Create a Neo4j Database + +Below is the Neo4j object used in this tutorial. + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + replicas: 3 + version: "2025.12.1" + storage: + storageClassName: local-path + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + deletionPolicy: WipeOut +``` + +Create the above Neo4j object with the following command: + +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/neo4j/quickstart/neo4j.yaml +neo4j.kubedb.com/neo4j-test created +``` + +When this `Neo4j` object is created, KubeDB operator creates a `Role`, `ServiceAccount`, and `RoleBinding` with matching names and uses that ServiceAccount in the Neo4j pods. + +Let's inspect what KubeDB creates. + +### Role + +KubeDB operator creates a Role object `neo4j-test-role` in the same namespace as the Neo4j object. + +```yaml +$ kubectl get role -n demo neo4j-test-role -o yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + creationTimestamp: "2026-05-14T06:54:08Z" + labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: neo4j-test + app.kubernetes.io/managed-by: kubedb.com + app.kubernetes.io/name: neo4js.kubedb.com + name: neo4j-test-role + namespace: demo + ownerReferences: + - apiVersion: kubedb.com/v1alpha2 + blockOwnerDeletion: true + controller: true + kind: Neo4j + name: neo4j-test + uid: 0034a30c-d33d-4596-a6d8-7cf47aa3d9e6 + resourceVersion: "1461745" + uid: 1f3850bc-4d28-4780-88ad-b31e9c7fa21e +rules: + - apiGroups: + - "" + resources: + - services + - endpoints + verbs: + - get + - list + - watch +``` + +### ServiceAccount + +KubeDB operator creates a ServiceAccount object `neo4j-test` in the same namespace as the Neo4j object. + +```yaml +$ kubectl get serviceaccount -n demo neo4j-test -o yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + creationTimestamp: "2026-05-14T06:54:08Z" + labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: neo4j-test + app.kubernetes.io/managed-by: kubedb.com + app.kubernetes.io/name: neo4js.kubedb.com + name: neo4j-test + namespace: demo + ownerReferences: + - apiVersion: kubedb.com/v1alpha2 + blockOwnerDeletion: true + controller: true + kind: Neo4j + name: neo4j-test + uid: 0034a30c-d33d-4596-a6d8-7cf47aa3d9e6 + resourceVersion: "1461744" + uid: 8bb16bdc-2a76-454c-8a58-284f0cc33da3 +``` + +This ServiceAccount is used by Neo4j pods created for the `neo4j-test` database. + +### RoleBinding + +KubeDB operator creates a RoleBinding object `neo4j-test-rolebinding` in the same namespace as the Neo4j object. + +```yaml +$ kubectl get rolebinding -n demo neo4j-test-rolebinding -o yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + creationTimestamp: "2026-05-14T06:54:09Z" + labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: neo4j-test + app.kubernetes.io/managed-by: kubedb.com + app.kubernetes.io/name: neo4js.kubedb.com + name: neo4j-test-rolebinding + namespace: demo + ownerReferences: + - apiVersion: kubedb.com/v1alpha2 + blockOwnerDeletion: true + controller: true + kind: Neo4j + name: neo4j-test + uid: 0034a30c-d33d-4596-a6d8-7cf47aa3d9e6 + resourceVersion: "1461748" + uid: f5e8ae7f-62a9-4390-bae0-918f4d5b54d1 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: neo4j-test-role +subjects: + - kind: ServiceAccount + name: neo4j-test +``` + +This object binds Role `neo4j-test-role` with ServiceAccount `neo4j-test`. + +## Cleaning up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +$ kubectl delete -n demo neo4j/neo4j-test +neo4j.kubedb.com "neo4j-test" deleted + +$ kubectl delete ns demo +namespace "demo" deleted +``` + diff --git a/docs/guides/neo4j/reconfigure-tls/_index.md b/docs/guides/neo4j/reconfigure-tls/_index.md new file mode 100644 index 000000000..adddea805 --- /dev/null +++ b/docs/guides/neo4j/reconfigure-tls/_index.md @@ -0,0 +1,10 @@ +--- +title: Reconfigure TLS +menu: + docs_{{ .version }}: + identifier: neo4j-reconfigure-tls + name: Reconfigure TLS + parent: neo4j-guides + weight: 55 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/neo4j/reconfigure-tls/overview.md b/docs/guides/neo4j/reconfigure-tls/overview.md new file mode 100644 index 000000000..eb0377be0 --- /dev/null +++ b/docs/guides/neo4j/reconfigure-tls/overview.md @@ -0,0 +1,48 @@ +--- +title: Reconfiguring Neo4j TLS +menu: + docs_{{ .version }}: + identifier: neo4j-reconfigure-tls-overview + name: Overview + parent: neo4j-reconfigure-tls + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Reconfiguring TLS of Neo4j Database + +This guide gives an overview of how KubeDB Ops-manager reconfigures TLS for a `Neo4j` database, including adding TLS, rotating certificates, updating issuer reference, and removing TLS through `Neo4jOpsRequest`. + +## Before You Begin + +- You should be familiar with [Neo4j](/docs/guides/neo4j/concepts/neo4j.md). +- You should be familiar with [Neo4jOpsRequest](/docs/guides/neo4j/concepts/opsrequest.md). + +## How Reconfiguring Neo4j TLS Works + +The following diagram shows the TLS reconfiguration flow for a `Neo4j` database. Open the image in a new tab to see the enlarged version. + +
+ Reconfiguring TLS process of Neo4j +
Fig: Reconfiguring TLS process of Neo4j
+
+ +The process consists of the following steps: + +1. A user creates a `Neo4j` Custom Resource. +2. KubeDB Provisioner reconciles the database and creates required workloads and secrets. +3. To update TLS settings, the user creates a `Neo4jOpsRequest` with `spec.type: ReconfigureTLS`. +4. KubeDB Ops-manager watches the `Neo4jOpsRequest` and validates the `spec.tls` fields. +5. Ops-manager temporarily pauses conflicting reconciliation for the target database. +6. It applies the requested TLS action (add/update via `issuerRef`, rotate via `rotateCertificates`, or disable via `remove`). +7. It rolls/restarts the required pods so updated TLS configuration is picked up. +8. After successful checks, Ops-manager marks the request `Successful` and resumes normal reconciliation. + +In the next guide, we show the step-by-step workflow for each TLS reconfiguration operation. + +## Next Step + +- Follow: [Reconfigure TLS in Neo4j](/docs/guides/neo4j/reconfigure-tls/reconfigure-tls.md). diff --git a/docs/guides/neo4j/reconfigure-tls/reconfigure-tls.md b/docs/guides/neo4j/reconfigure-tls/reconfigure-tls.md new file mode 100644 index 000000000..337840576 --- /dev/null +++ b/docs/guides/neo4j/reconfigure-tls/reconfigure-tls.md @@ -0,0 +1,357 @@ +--- +title: Reconfigure TLS of Neo4j +menu: + docs_{{ .version }}: + identifier: neo4j-reconfigure-tls-cluster + name: Cluster + parent: neo4j-reconfigure-tls + weight: 30 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Reconfigure TLS in Neo4j + +KubeDB supports TLS reconfiguration for existing `Neo4j` databases through `Neo4jOpsRequest`. You can add TLS, rotate certificates, change issuer, and remove TLS without recreating the database. + +## Before You Begin + +- You need a Kubernetes cluster and `kubectl` configured to communicate with the cluster. +- Install `cert-manager` to manage certificates. +- Install KubeDB operator following [the setup guide](/docs/setup/README.md). +- This guide uses namespace `demo`. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +This guide assumes a running Neo4j database named `tls-neo4j` in namespace `demo`. + +## Create Issuer for TLS Certificates + +If you already have an `Issuer`/`ClusterIssuer`, you can skip this section. + +Generate a CA certificate and private key: + +```bash +$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ca.key -out ca.crt -subj "/CN=neo4j-ca/O=kubedb" +Generating a RSA private key +...+++++ +...+++++ +writing new private key to 'ca.key' +----- +``` + +Create a TLS secret from the generated CA files: + +```bash +$ kubectl create secret tls neo4j-ca --cert=ca.crt --key=ca.key -n demo +secret/neo4j-ca created +``` + +Create an `Issuer` using that secret: + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: neo4j-ca-issuer + namespace: demo +spec: + ca: + secretName: neo4j-ca +EOF +issuer.cert-manager.io/neo4j-ca-issuer created + +$ kubectl get issuer -n demo neo4j-ca-issuer +NAME READY AGE +neo4j-ca-issuer True 10s +``` + +## Add TLS to Neo4j + +Use this `Neo4jOpsRequest` to add TLS (or replace issuer settings) for the target database: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-add-tls + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: tls-neo4j + tls: + issuerRef: + apiGroup: cert-manager.io + kind: Issuer + name: neo4j-ca-issuer +``` + +Here, + +- `spec.type: ReconfigureTLS` selects TLS reconfiguration operation. +- `spec.databaseRef.name` selects the target `Neo4j` database. +- `spec.tls.issuerRef` defines which issuer should sign/re-issue certificates. + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-add-tls + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: tls-neo4j + tls: + issuerRef: + apiGroup: cert-manager.io + kind: Issuer + name: neo4j-ca-issuer +EOF +neo4jopsrequest.ops.kubedb.com/neo4j-add-tls created + +$ kubectl wait --for=jsonpath='{.status.phase}'=Successful neo4jopsrequest/neo4j-add-tls -n demo --timeout=600s +neo4jopsrequest.ops.kubedb.com/neo4j-add-tls condition met +``` + +Verify request status, generated certs, and encrypted connection via `neo4j+s`: + +```bash +$ kubectl get neo4jopsrequest -n demo neo4j-add-tls +NAME TYPE STATUS AGE +neo4j-add-tls ReconfigureTLS Successful 2m + +$ kubectl get secret -n demo tls-neo4j-server-cert +NAME TYPE DATA AGE +tls-neo4j-server-cert kubernetes.io/tls 3 2m + +$ kubectl get secret -n demo tls-neo4j-server-cert -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -dates +notBefore=May 15 07:10:28 2026 GMT +notAfter=Aug 13 07:10:28 2026 GMT + +$ kubectl get secret -n demo tls-neo4j-auth -o jsonpath='{.data.password}' | base64 -d && echo +8pyn3zno7QbX4iQn + +$ kubectl exec -it -n demo tls-neo4j-0 -- cypher-shell -a neo4j+s://tls-neo4j-0.demo.svc.cluster.local:7687 -u neo4j -p '8pyn3zno7QbX4iQn' +Connected to Neo4j using Bolt protocol version 6.0 at neo4j+s://tls-neo4j-0.demo.svc.cluster.local:7687 as user neo4j. +Type :help for a list of available commands or :exit to exit the shell. +Note that Cypher queries must end with a semicolon. +``` + +## Rotate TLS Certificates + +Before rotation, check current certificate validity window: + +```bash +$ kubectl get secret -n demo tls-neo4j-server-cert -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -dates +notBefore=May 15 07:10:28 2026 GMT +notAfter=Aug 13 07:10:28 2026 GMT +``` + +Now rotate certificates and update Bolt TLS mode: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-reconfigure-tls + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: tls-neo4j + tls: + rotateCertificates: true + bolt: + mode: mTLS +``` + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-reconfigure-tls + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: tls-neo4j + tls: + rotateCertificates: true + bolt: + mode: mTLS +EOF +neo4jopsrequest.ops.kubedb.com/neo4j-reconfigure-tls created + +$ kubectl wait --for=jsonpath='{.status.phase}'=Successful neo4jopsrequest/neo4j-reconfigure-tls -n demo --timeout=600s +neo4jopsrequest.ops.kubedb.com/neo4j-reconfigure-tls condition met + +$ kubectl get neo4jopsrequest -n demo neo4j-reconfigure-tls +NAME TYPE STATUS AGE +neo4j-reconfigure-tls ReconfigureTLS Successful 2m + +$ kubectl get secret -n demo tls-neo4j-server-cert -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -dates +notBefore=May 15 07:24:11 2026 GMT +notAfter=Aug 13 07:24:11 2026 GMT +``` + +The changed certificate timestamp confirms rotation happened successfully. + +## Change Issuer for Existing TLS + +Create a new CA and issuer: + +```bash +$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout new-ca.key -out new-ca.crt -subj "/CN=neo4j-ca-updated/O=kubedb-updated" +Generating a RSA private key +...+++++ +...+++++ +writing new private key to 'new-ca.key' +----- + +$ kubectl create secret tls neo4j-new-ca --cert=new-ca.crt --key=new-ca.key -n demo +secret/neo4j-new-ca created + +$ cat <<'EOF' | kubectl apply -f - +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: neo4j-new-ca-issuer + namespace: demo +spec: + ca: + secretName: neo4j-new-ca +EOF +issuer.cert-manager.io/neo4j-new-ca-issuer created +``` + +Apply an OpsRequest that points to the new issuer: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-change-issuer + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: tls-neo4j + tls: + issuerRef: + apiGroup: cert-manager.io + kind: Issuer + name: neo4j-new-ca-issuer +``` + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-change-issuer + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: tls-neo4j + tls: + issuerRef: + apiGroup: cert-manager.io + kind: Issuer + name: neo4j-new-ca-issuer +EOF +neo4jopsrequest.ops.kubedb.com/neo4j-change-issuer created + +$ kubectl wait --for=jsonpath='{.status.phase}'=Successful neo4jopsrequest/neo4j-change-issuer -n demo --timeout=600s +neo4jopsrequest.ops.kubedb.com/neo4j-change-issuer condition met + +$ kubectl get secret -n demo tls-neo4j-server-cert -o jsonpath='{.data.ca\.crt}' | base64 -d | openssl x509 -noout -subject +subject=CN = neo4j-ca-updated, O = kubedb-updated +``` + +## Remove TLS from Neo4j + +Use this request to disable TLS from the target database: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-remove-tls + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: tls-neo4j + tls: + remove: true +``` + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-remove-tls + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: tls-neo4j + tls: + remove: true +EOF +neo4jopsrequest.ops.kubedb.com/neo4j-remove-tls created + +$ kubectl wait --for=jsonpath='{.status.phase}'=Successful neo4jopsrequest/neo4j-remove-tls -n demo --timeout=600s +neo4jopsrequest.ops.kubedb.com/neo4j-remove-tls condition met + +$ kubectl get neo4jopsrequest -n demo neo4j-remove-tls +NAME TYPE STATUS AGE +neo4j-remove-tls ReconfigureTLS Successful 1m +``` + +## Verify All Requests + +```bash +$ kubectl get neo4jopsrequest -n demo neo4j-reconfigure-tls +NAME TYPE STATUS AGE +neo4j-reconfigure-tls ReconfigureTLS Successful 2m + +$ kubectl get neo4jopsrequest -n demo neo4j-remove-tls +NAME TYPE STATUS AGE +neo4j-remove-tls ReconfigureTLS Successful 1m + +$ kubectl get neo4jopsrequest -n demo neo4j-add-tls +NAME TYPE STATUS AGE +neo4j-add-tls ReconfigureTLS Successful 1m + +$ kubectl get neo4jopsrequest -n demo neo4j-change-issuer +NAME TYPE STATUS AGE +neo4j-change-issuer ReconfigureTLS Successful 1m +``` + +## Cleaning up + +```bash +$ kubectl delete neo4jopsrequest -n demo neo4j-add-tls neo4j-reconfigure-tls neo4j-change-issuer neo4j-remove-tls +neo4jopsrequest.ops.kubedb.com "neo4j-add-tls" deleted +neo4jopsrequest.ops.kubedb.com "neo4j-reconfigure-tls" deleted +neo4jopsrequest.ops.kubedb.com "neo4j-change-issuer" deleted +neo4jopsrequest.ops.kubedb.com "neo4j-remove-tls" deleted +``` + +## Next Steps + +- Learn `Neo4jOpsRequest` fields in detail from [Neo4j OpsRequest concept](/docs/guides/neo4j/concepts/opsrequest.md). + diff --git a/docs/guides/neo4j/reconfigure/_index.md b/docs/guides/neo4j/reconfigure/_index.md new file mode 100644 index 000000000..263409d70 --- /dev/null +++ b/docs/guides/neo4j/reconfigure/_index.md @@ -0,0 +1,10 @@ +--- +title: Reconfigure +menu: + docs_{{ .version }}: + identifier: neo4j-reconfigure + name: Reconfigure + parent: neo4j-guides + weight: 50 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/neo4j/reconfigure/overview.md b/docs/guides/neo4j/reconfigure/overview.md new file mode 100644 index 000000000..2631caf41 --- /dev/null +++ b/docs/guides/neo4j/reconfigure/overview.md @@ -0,0 +1,46 @@ +--- +title: Reconfiguring Neo4j +menu: + docs_{{ .version }}: + identifier: neo4j-reconfigure-overview + name: Overview + parent: neo4j-reconfigure + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Reconfiguring Neo4j + +This guide gives an overview of how KubeDB Ops-manager reconfigures `Neo4j` database components. + +## Before You Begin + +- You should be familiar with [Neo4j](/docs/guides/neo4j/concepts/neo4j.md). +- You should be familiar with [Neo4jOpsRequest](/docs/guides/neo4j/concepts/opsrequest.md). + +## How Reconfiguring Neo4j Process Works + +The following diagram shows how KubeDB Ops-manager reconfigures `Neo4j` database components. Open the image in a new tab to see the enlarged version. + +
+ Reconfiguring process of Neo4j +
Fig: Reconfiguring process of Neo4j
+
+ +The reconfigure process consists of the following steps: + +For a `Neo4jOpsRequest` with `spec.type: Reconfigure`, KubeDB Ops-manager: + +1. Validates configuration inputs from `spec.configuration`. +2. Resolves custom config secret and inline `applyConfig` values. +3. Pauses conflicting reconciliations. +4. Merges or replaces Neo4j config based on request fields. +5. Restarts relevant pods to apply new configuration. +6. Verifies pod/database health and marks the request `Successful`. + +## Next Step + +Follow the detailed guide: [Reconfigure Neo4j Cluster](/docs/guides/neo4j/reconfigure/reconfigure.md). diff --git a/docs/guides/neo4j/reconfigure/reconfigure.md b/docs/guides/neo4j/reconfigure/reconfigure.md new file mode 100644 index 000000000..54ea0b233 --- /dev/null +++ b/docs/guides/neo4j/reconfigure/reconfigure.md @@ -0,0 +1,347 @@ +--- +title: Reconfigure Neo4j +menu: + docs_{{ .version }}: + identifier: neo4j-reconfigure-cluster + name: Cluster + parent: neo4j-reconfigure + weight: 30 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Reconfigure Neo4j + +This guide shows how to reconfigure a Neo4j database using `Neo4jOpsRequest`. +We will: + +1. Deploy Neo4j with default configuration. +2. Check current values from Neo4j using `cypher-shell`. +3. Create a custom config secret. +4. Apply a `Reconfigure` OpsRequest. +5. Verify changed values and show `applyConfig` precedence over `configSecret`. + +## Before You Begin + +- You need a Kubernetes cluster and `kubectl` configured. +- Install KubeDB Community and Enterprise operators following [the setup guide](/docs/setup/README.md). +- Review [Neo4j](/docs/guides/neo4j/concepts/neo4j.md), [OpsRequest](/docs/guides/neo4j/concepts/opsrequest.md), and [Reconfigure Overview](/docs/guides/neo4j/reconfigure/overview.md). + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +## Prepare Database + +First, deploy Neo4j with default configuration (no custom config secret): + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + version: "2025.12.1" + replicas: 3 + storageType: Durable + storage: + storageClassName: standard + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + deletionPolicy: WipeOut +``` + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + version: "2025.12.1" + replicas: 3 + storageType: Durable + storage: + storageClassName: standard + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + deletionPolicy: WipeOut +EOF +neo4j.kubedb.com/neo4j-test created + +$ kubectl wait --for=condition=Ready neo4j/neo4j-test -n demo --timeout=600s +neo4j.kubedb.com/neo4j-test condition met +``` + +## Check Current Settings (Before Reconfigure) + +Before applying the reconfigure request, connect with `cypher-shell` and check current values: + +```bash +$ PASS=$(kubectl get secret -n demo neo4j-test-auth -o jsonpath='{.data.password}' | base64 -d) +$ kubectl exec -it -n demo neo4j-test-0 -- cypher-shell -u neo4j -p "$PASS" +``` + +These are the current values before running the reconfigure OpsRequest. + +Check `db.query` settings: + +```bash +neo4j@neo4j> SHOW SETTINGS + YIELD name, value + WHERE name STARTS WITH 'db.query' + RETURN name, value + ORDER BY name + LIMIT 10; ++-------------------------------------------+ +| name | value | ++-------------------------------------------+ +| "db.query.default_language" | "CYPHER_25" | ++-------------------------------------------+ + +1 row +ready to start consuming query after 12 ms, results consumed after another 1 ms +``` + +Check `db.checkpoint` settings: + +```bash +neo4j@neo4j> SHOW SETTINGS + YIELD name, value + WHERE name STARTS WITH 'db' + RETURN name, value + ORDER BY name + LIMIT 3; ++--------------------------------------------+ +| name | value | ++--------------------------------------------+ +| "db.checkpoint" | "PERIODIC" | +| "db.checkpoint.interval.time" | "15m" | +| "db.checkpoint.interval.tx" | "100000" | ++--------------------------------------------+ + +3 rows +ready to start consuming query after 11 ms, results consumed after another 1 ms +``` + +Check `server.jvm` settings: + +```bash +neo4j@neo4j> SHOW SETTINGS + YIELD name, value + WHERE name STARTS WITH 'server.jvm' + RETURN name, value + ORDER BY name + LIMIT 3; ++---------------------------------+ +| name | value | ++---------------------------------+ +| "server.jvm.additional" | NULL | ++---------------------------------+ + +1 row +ready to start consuming query after 13 ms, results consumed after another 2 ms +``` + +## Create Custom Configuration Secret + +Create `custom-config` with your provided values: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: custom-config + namespace: demo +stringData: + db.query.default_language: "CYPHER_5" + db.checkpoint.interval.time: "20m" + server.jvm.additional: |- + -XX:+UseG1GC + -XX:-OmitStackTraceInFastThrow +``` + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: v1 +kind: Secret +metadata: + name: custom-config + namespace: demo +stringData: + db.query.default_language: "CYPHER_5" + db.checkpoint.interval.time: "20m" + server.jvm.additional: |- + -XX:+UseG1GC + -XX:-OmitStackTraceInFastThrow +EOF +secret/custom-config created +``` + +## Reconfigure Request + +Now apply this `Neo4jOpsRequest` exactly: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: reconfigure + namespace: demo +spec: + type: Reconfigure + databaseRef: + name: neo4j-test + configuration: + configSecret: + name: custom-config + applyConfig: + db.checkpoint.interval.time: "25m" + timeout: 5m + apply: IfReady +``` + +Here, + +- `configSecret` provides base custom settings. +- `applyConfig` applies inline overrides. +- If the same key exists in both places, `applyConfig` takes precedence. + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: reconfigure + namespace: demo +spec: + type: Reconfigure + databaseRef: + name: neo4j-test + configuration: + configSecret: + name: custom-config + applyConfig: + db.checkpoint.interval.time: "25m" + timeout: 5m + apply: IfReady +EOF +neo4jopsrequest.ops.kubedb.com/reconfigure created + +$ kubectl wait --for=jsonpath='{.status.phase}'=Successful neo4jopsrequest/reconfigure -n demo --timeout=600s +neo4jopsrequest.ops.kubedb.com/reconfigure condition met +``` + +## Verify Reconfiguration + +Check OpsRequest status: + +```bash +$ kubectl get neo4jopsrequest -n demo reconfigure +NAME TYPE STATUS AGE +reconfigure Reconfigure Successful 2m5s +``` + +Now run the same three queries again and confirm updated values: + +```bash +$ PASS=$(kubectl get secret -n demo neo4j-test-auth -o jsonpath='{.data.password}' | base64 -d) +$ kubectl exec -it -n demo neo4j-test-0 -- cypher-shell -u neo4j -p "$PASS" +``` + +Check `db.query` settings: + +```bash +neo4j@neo4j> SHOW SETTINGS + YIELD name, value + WHERE name STARTS WITH 'db.query' + RETURN name, value + ORDER BY name + LIMIT 10; ++-------------------------------------------+ +| name | value | ++-------------------------------------------+ +| "db.query.default_language" | "CYPHER_5" | ++-------------------------------------------+ + +1 row +ready to start consuming query after 12 ms, results consumed after another 1 ms +``` + +Check `db.checkpoint` settings (updated): + +```bash +neo4j@neo4j> SHOW SETTINGS + YIELD name, value + WHERE name STARTS WITH 'db' + RETURN name, value + ORDER BY name + LIMIT 3; ++--------------------------------------------+ +| name | value | ++--------------------------------------------+ +| "db.checkpoint" | "PERIODIC" | +| "db.checkpoint.interval.time" | "25m" | +| "db.checkpoint.interval.tx" | "100000" | ++--------------------------------------------+ + +3 rows +ready to start consuming query after 11 ms, results consumed after another 1 ms +``` + +Check `server.jvm` settings (updated): + +```bash +neo4j@neo4j> SHOW SETTINGS + YIELD name, value + WHERE name STARTS WITH 'server.jvm' + RETURN name, value + ORDER BY name + LIMIT 3; ++-----------------------------------------------------------+ +| name | value | ++-----------------------------------------------------------+ +| "server.jvm.additional" | "-XX:+UseG1GC | +| \ -XX:-OmitStackTraceInFastThrow" | ++-----------------------------------------------------------+ + +1 row +ready to start consuming query after 80 ms, results consumed after another 7 ms +``` + +From the output: + +- `db.query.default_language` comes from `custom-config` secret. +- `db.checkpoint.interval.time` is `25m` from `applyConfig`, not `20m` from secret. +- `server.jvm.additional` is now set from `custom-config` (it was `NULL` before reconfigure). +- This confirms `applyConfig` has higher precedence than `configSecret` for overlapping keys. + +## Cleaning up + +```bash +$ kubectl delete neo4jopsrequest -n demo reconfigure +neo4jopsrequest.ops.kubedb.com "reconfigure" deleted + +$ kubectl delete secret -n demo custom-config +secret "custom-config" deleted + +$ kubectl patch -n demo neo4j/neo4j-test -p '{"spec":{"deletionPolicy":"WipeOut"}}' --type="merge" +neo4j.kubedb.com/neo4j-test patched + +$ kubectl delete -n demo neo4j/neo4j-test +neo4j.kubedb.com "neo4j-test" deleted + +$ kubectl delete ns demo +namespace "demo" deleted +``` diff --git a/docs/guides/neo4j/restart/_index.md b/docs/guides/neo4j/restart/_index.md new file mode 100644 index 000000000..6ad237efe --- /dev/null +++ b/docs/guides/neo4j/restart/_index.md @@ -0,0 +1,10 @@ +--- +title: Restart Neo4j +menu: + docs_{{ .version }}: + identifier: neo4j-restart + name: Restart + parent: neo4j-guides + weight: 30 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/neo4j/restart/restart.md b/docs/guides/neo4j/restart/restart.md new file mode 100644 index 000000000..9f16fea2f --- /dev/null +++ b/docs/guides/neo4j/restart/restart.md @@ -0,0 +1,136 @@ +--- +title: Restart Neo4j +menu: + docs_{{ .version }}: + identifier: neo4j-restart-overview + name: Restart Neo4j + parent: neo4j-restart + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Restart Neo4j + +This guide shows how to restart Neo4j pods using `Neo4jOpsRequest`. + +## Before You Begin + +- You need a Kubernetes cluster and `kubectl` configured. +- Install KubeDB and Ops-manager from [here](/docs/setup/README.md). +- Create an isolated namespace: + +```bash +kubectl create ns demo +``` + +## Deploy Neo4j + +Save this as `neo4j.yaml`: + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + version: "2025.10.1" + replicas: 3 + storage: + resources: + requests: + storage: 2Gi + storageClassName: standard + accessModes: + - ReadWriteOnce + deletionPolicy: WipeOut +``` + +Apply it and wait for the cluster to become ready: + +```bash +$ kubectl apply -f neo4j.yaml + +$ kubectl get neo4j -n demo neo4j-test -w +``` + +Wait until `STATUS` shows `Ready` before proceeding. + +``` +NAME VERSION STATUS AGE +neo4j-test 2025.10.1 Ready 3m +``` + +## Apply Restart OpsRequest + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-restart + namespace: demo +spec: + type: Restart + databaseRef: + name: neo4j-test + timeout: 5m + apply: Always +``` + +`apply: Always` tells KubeDB to execute the restart even if the database is not currently in the ready state. + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-restart + namespace: demo +spec: + type: Restart + databaseRef: + name: neo4j-test + timeout: 5m + apply: Always +EOF +neo4jopsrequest.ops.kubedb.com/neo4j-restart created + +$ kubectl wait --for=jsonpath='{.status.phase}'=Successful neo4jopsrequest/neo4j-restart -n demo --timeout=600s +neo4jopsrequest.ops.kubedb.com/neo4j-restart condition met +``` + +## Verify + +```bash +$ kubectl get neo4jopsrequest -n demo neo4j-restart +NAME TYPE STATUS AGE +neo4j-restart Restart Successful 1m + +$ kubectl describe neo4jopsrequest -n demo neo4j-restart +Name: neo4j-restart +Namespace: demo +Labels: +Annotations: +API Version: ops.kubedb.com/v1alpha1 +Kind: Neo4jOpsRequest +Metadata: + ... +Spec: + Type: Restart + Database Ref: + Name: neo4j-test + Apply: Always +Status: + Phase: Successful +``` + +## Cleaning up + +```bash +kubectl delete neo4jopsrequest -n demo neo4j-restart +kubectl delete neo4j -n demo neo4j-test +kubectl delete ns demo +``` \ No newline at end of file diff --git a/docs/guides/neo4j/rotate-auth/_index.md b/docs/guides/neo4j/rotate-auth/_index.md new file mode 100644 index 000000000..3f3f266f0 --- /dev/null +++ b/docs/guides/neo4j/rotate-auth/_index.md @@ -0,0 +1,10 @@ +--- +title: Rotate Auth +menu: + docs_{{ .version }}: + identifier: neo4j-rotate-auth + name: Rotate Auth + parent: neo4j-guides + weight: 60 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/neo4j/rotate-auth/overview.md b/docs/guides/neo4j/rotate-auth/overview.md new file mode 100644 index 000000000..5cb1828f8 --- /dev/null +++ b/docs/guides/neo4j/rotate-auth/overview.md @@ -0,0 +1,39 @@ +--- +title: Rotating Neo4j Credentials +menu: + docs_{{ .version }}: + identifier: neo4j-rotate-auth-overview + name: Overview + parent: neo4j-rotate-auth + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Rotate Auth for Neo4j Overview + +This page explains how KubeDB Ops-manager rotates Neo4j credentials using `Neo4jOpsRequest`. + +## Before You Begin + +- You should be familiar with [Neo4j](/docs/guides/neo4j/concepts/neo4j.md). +- You should be familiar with [Neo4jOpsRequest](/docs/guides/neo4j/concepts/opsrequest.md). + +## How RotateAuth Works + +For a `Neo4jOpsRequest` with `spec.type: RotateAuth`, KubeDB Ops-manager: + +1. Validates rotate-auth request and target database. +2. Uses one of the supported credential sources: + - operator-managed generated secret, + - user-provided secret from `spec.authentication.secretRef`. +3. Rotates credentials in Neo4j and updates auth secret state. +4. Ensures database authentication remains healthy. +5. Marks the request `Successful` when rotation completes. + + +## Next Step + +Follow the detailed guide: [Rotate Auth for Neo4j](/docs/guides/neo4j/rotate-auth/rotateauth.md). diff --git a/docs/guides/neo4j/rotate-auth/rotateauth.md b/docs/guides/neo4j/rotate-auth/rotateauth.md new file mode 100644 index 000000000..3f8c4adac --- /dev/null +++ b/docs/guides/neo4j/rotate-auth/rotateauth.md @@ -0,0 +1,268 @@ +--- +title: Rotate Auth of Neo4j +menu: + docs_{{ .version }}: + identifier: neo4j-rotate-auth-cluster + name: Cluster + parent: neo4j-rotate-auth + weight: 30 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> ๐Ÿ†• New to KubeDB? Start with the [quickstart guide](/docs/README.md) before continuing here. + +# Neo4j Auth Rotation with KubeDB + +Auth rotation replaces the Neo4j admin password without downtime. KubeDB updates the Kubernetes Secret and rotates the credential inside the running cluster automatically through `Neo4jOpsRequest`. + +This guide covers two rotation modes: + +| Mode | When to use | +|---|---| +| **KubeDB-generated** | Let KubeDB create a new random password | +| **User-provided** | Supply your own password via a Kubernetes Secret | + +--- + +## How It Works + +KubeDB uses `Neo4jOpsRequest` with `type: RotateAuth` to rotate credentials. Under the hood it: + +1. Generates a new password or reads one from `spec.authentication.secretRef` +2. Updates the Kubernetes auth Secret +3. Calls the Neo4j password-change API on the running cluster +4. Marks the operation `Successful` once all pods accept the new credential + +--- + +## Prerequisites + +| Requirement | Details | +|---|---| +| KubeDB installed | Provisioner and Ops-manager operators running | +| Neo4j instance | `neo4j-test` in namespace `demo`, `status.phase=Ready` | +| `kubectl` configured | With permissions to the `demo` namespace | + +--- + +## Step 2 โ€” Deploy Neo4j + +Save this as `neo4j.yaml`: + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + version: "2025.10.1" + replicas: 3 + storage: + resources: + requests: + storage: 2Gi + storageClassName: standard + accessModes: + - ReadWriteOnce + deletionPolicy: WipeOut +``` + +Apply it and wait for the cluster to become ready: + +```bash +kubectl apply -f neo4j.yaml + +kubectl get neo4j -n demo neo4j-test -w +``` + +Wait until `STATUS` shows `Ready` before proceeding. + +``` +NAME VERSION STATUS AGE +neo4j-test 2025.10.1 Ready 3m +``` + +--- + +## Mode 1 โ€” KubeDB-Generated Password + +In this mode, KubeDB generates a new random password and stores it back in the auth Secret. + +### Step 1 โ€” Record the Current Password Hash + +Capture the current base64-encoded password so you can confirm it changes after rotation. + +```bash +BEFORE_B64=$(kubectl get secret -n demo neo4j-test-auth -o jsonpath='{.data.password}') +echo "Before: $BEFORE_B64" +``` + +### Step 2 โ€” Apply the RotateAuth Request + +Save this as `neo4j-rotate-auth.yaml`: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-rotate-auth + namespace: demo +spec: + type: RotateAuth + databaseRef: + name: neo4j-test + timeout: 5m + apply: IfReady +``` + +Apply it and wait for completion: + +```bash +$ kubectl apply -f neo4j-rotate-auth.yaml + +$ kubectl wait --for=jsonpath='{.status.phase}'=Successful \ + neo4jopsrequest/neo4j-rotate-auth \ + -n demo --timeout=900s +``` + +Expected output: + +``` +neo4jopsrequest.ops.kubedb.com/neo4j-rotate-auth condition met +``` + +### Step 3 โ€” Verify the Password Changed + +```bash +$ kubectl get neo4jopsrequest -n demo neo4j-rotate-auth + +AFTER_B64=$(kubectl get secret -n demo neo4j-test-auth -o jsonpath='{.data.password}') +[ "$BEFORE_B64" != "$AFTER_B64" ] && echo "password_changed=true" || echo "password_changed=false" + +NEW_PASS=$(kubectl get secret -n demo neo4j-test-auth -o jsonpath='{.data.password}' | base64 -d) +$ kubectl exec -n demo neo4j-test-0 -- cypher-shell -u neo4j -p "$NEW_PASS" "RETURN 'auth-ok' AS status" +``` + +Expected output: + +```bash +NAME TYPE STATUS AGE +neo4j-rotate-auth RotateAuth Successful 37s + +password_changed=true + +status +"auth-ok" +``` + +> โœ… The password in the Secret has changed and Neo4j accepts the new credential. + +--- + +## Mode 2 โ€” User-Provided Password + +In this mode, you supply a Kubernetes Secret containing your chosen password. KubeDB reads it and rotates Neo4j to use it. + +### Step 1 โ€” Create the Auth Secret + +```bash +$ kubectl create secret generic external-neo4j-auth \ + -n demo \ + --from-literal=username=neo4j \ + --from-literal=password='Neo4j@12345' \ + --dry-run=client -o yaml | kubectl apply -f - +``` + +> **Password requirements:** Neo4j requires the password to differ from the username and be at least 8 characters. + +### Step 2 โ€” Apply the RotateAuth Request + +Save this as `neo4j-rotate-auth-user.yaml`: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-rotate-auth-user + namespace: demo +spec: + type: RotateAuth + databaseRef: + name: neo4j-test + authentication: + secretRef: + kind: Secret + name: external-neo4j-auth + timeout: 5m + apply: IfReady +``` + +Apply it and wait for completion: + +```bash +$ kubectl apply -f neo4j-rotate-auth-user.yaml + +$ kubectl wait --for=jsonpath='{.status.phase}'=Successful \ + neo4jopsrequest/neo4j-rotate-auth-user \ + -n demo --timeout=900s +``` + +Expected output: + +``` +neo4jopsrequest.ops.kubedb.com/neo4j-rotate-auth-user condition met +``` + +### Step 3 โ€” Verify Login with the New Password + +```bash +$ kubectl get neo4jopsrequest -n demo neo4j-rotate-auth-user + +$ kubectl exec -n demo neo4j-test-0 -- \ + cypher-shell -u neo4j -p 'Neo4j@12345' "RETURN 'user-auth-ok' AS status" +``` + +Expected output: + +```bash +NAME TYPE STATUS AGE +neo4j-rotate-auth-user RotateAuth Successful 33s + +status +"user-auth-ok" +``` + +> โœ… Neo4j now accepts the password from `external-neo4j-auth`. + +--- + +## Understanding the OpsRequest Fields + +| Field | Description | +|---|---| +| `spec.type` | `RotateAuth` โ€” identifies this as a credential rotation operation | +| `spec.databaseRef.name` | Name of the target `Neo4j` resource | +| `spec.authentication.secretRef` | *(Optional)* Secret with `username` and `password` keys. Omit to let KubeDB generate a password. | +| `spec.timeout` | How long KubeDB waits before marking the operation failed | +| `spec.apply` | `IfReady` โ€” only proceed if the database is in a healthy state | + +--- + +## Cleanup + +```bash +kubectl delete neo4jopsrequest -n demo neo4j-rotate-auth neo4j-rotate-auth-user +kubectl delete secret -n demo external-neo4j-auth +kubectl delete neo4j -n demo neo4j-test +kubectl delete ns demo +``` + +--- + +## Next Steps + +- [Neo4j TLS Configuration](/docs/guides/neo4j/tls/) โ€” encrypt traffic between clients and the cluster +- [Neo4j Vertical Scaling](/docs/guides/neo4j/scaling/vertical-scaling/) โ€” adjust CPU and memory +- [Neo4j Version Upgrade](/docs/guides/neo4j/update-version/) โ€” roll to a newer Neo4j release \ No newline at end of file diff --git a/docs/guides/neo4j/scaling/_index.md b/docs/guides/neo4j/scaling/_index.md new file mode 100644 index 000000000..b0a15e8db --- /dev/null +++ b/docs/guides/neo4j/scaling/_index.md @@ -0,0 +1,10 @@ +--- +title: Scaling +menu: + docs_{{ .version }}: + identifier: neo4j-scaling + name: Scaling + parent: neo4j-guides + weight: 35 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/neo4j/scaling/horizontal-scaling/_index.md b/docs/guides/neo4j/scaling/horizontal-scaling/_index.md new file mode 100644 index 000000000..14d412a81 --- /dev/null +++ b/docs/guides/neo4j/scaling/horizontal-scaling/_index.md @@ -0,0 +1,10 @@ +--- +-title: Horizontal Scaling +-menu: +- docs_{{ .version }}: +- identifier: neo4j-horizontal-scaling +- name: Horizontal Scaling +- parent: neo4j-scaling +- weight: 10 +-menu_name: docs_{{ .version }} +--- \ No newline at end of file diff --git a/docs/guides/neo4j/scaling/horizontal-scaling/overview.md b/docs/guides/neo4j/scaling/horizontal-scaling/overview.md new file mode 100644 index 000000000..88aca9799 --- /dev/null +++ b/docs/guides/neo4j/scaling/horizontal-scaling/overview.md @@ -0,0 +1,51 @@ +--- +title: Neo4j Horizontal Scaling +menu: + docs_{{ .version }}: + identifier: neo4j-horizontal-scaling-overview + name: Overview + parent: neo4j-horizontal-scaling + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Neo4j Horizontal Scaling Overview + +This page explains how KubeDB Ops-manager performs horizontal scaling for Neo4j using `Neo4jOpsRequest`. + +## Before You Begin + +- You should be familiar with [Neo4j](/docs/guides/neo4j/concepts/neo4j.md). +- You should be familiar with [Neo4jOpsRequest](/docs/guides/neo4j/concepts/opsrequest.md). + +## How Horizontal Scaling Works + +The following diagram shows how KubeDB Ops-manager performs horizontal scaling for a `Neo4j` database. Open the image in a new tab to see the enlarged version. + +
+ Horizontal scaling process of Neo4j +
Fig: Horizontal scaling process of Neo4j
+
+ +The horizontal scaling process consists of the following steps: + +For a `Neo4jOpsRequest` with `spec.type: HorizontalScaling`, KubeDB Ops-manager: + +1. Validates the requested server count in `spec.horizontalScaling.server`. +2. Pauses conflicting reconciliations for safe scale execution. +3. Updates the target Neo4j server replica count. +4. Applies reallocation policy from `spec.horizontalScaling.reallocate`. +5. Waits for members and database hosting to reach a healthy state. +6. Marks the operation `Successful` and resumes normal reconciliation. + +Use Cypher views to verify topology and allocation after scaling: + +- `SHOW DATABASE ` for allocation status. +- `SHOW SERVERS` for hosting distribution. + +## Next Step + +Follow the detailed guide: [Scale Neo4j Horizontally](/docs/guides/neo4j/scaling/horizontal-scaling/scale-horizontally/index.md). diff --git a/docs/guides/neo4j/scaling/horizontal-scaling/scale-horizontally/index.md b/docs/guides/neo4j/scaling/horizontal-scaling/scale-horizontally/index.md new file mode 100644 index 000000000..0aa004568 --- /dev/null +++ b/docs/guides/neo4j/scaling/horizontal-scaling/scale-horizontally/index.md @@ -0,0 +1,376 @@ +--- +title: Scale Neo4j Horizontally +menu: + docs_{{ .version }}: + identifier: neo4j-scale-horizontally + name: Scale Horizontally + parent: neo4j-horizontal-scaling + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> ๐Ÿ†• New to KubeDB? Start with the [quickstart guide](/docs/README.md) before continuing here. + +# Neo4j Horizontal Scaling with KubeDB + +Horizontally scaling a Neo4j cluster means adding or removing cluster members (pods) at runtime โ€” without downtime and without data loss. KubeDB handles the orchestration automatically through `Neo4jOpsRequest`. + +This guide walks you through: +- Seeding a user database with test data +- Scaling **up** from 3 โ†’ 5 members +- Scaling **down** from 5 โ†’ 4 members +- Verifying cluster topology and data integrity at each step + +--- + +## How It Works + +KubeDB uses the `Neo4jOpsRequest` custom resource to perform horizontal scaling operations. Under the hood it: + +1. Adds (or drains) StatefulSet replicas +2. Enables / deallocates the new/removed Neo4j server in the cluster +3. Waits for database reallocation to complete before marking the operation `Successful` + +You verify the result using two complementary Cypher views: + +| Cypher View | What It Shows | +|---|---| +| `SHOW DATABASE ` | Database allocation status, primary/secondary count | +| `SHOW SERVERS` | Which servers host which databases | + +> **Tip (Neo4j 2025.x):** Always use **both** views together for a reliable picture of cluster topology after a scale event. + +--- + +## Prerequisites + +| Requirement | Details | +|---|---| +| KubeDB installed | Operator running in your cluster | +| Neo4j instance | `status.phase=Ready` | +| `kubectl` access | With permissions to the `demo` namespace | + +--- + +## Step 1 โ€” Set Up the Namespace + +```bash +$ kubectl create ns demo +``` + +--- + +## Step 2 โ€” Deploy Neo4j + +Apply the example manifest and wait for the cluster to become ready: + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/neo4j/quickstart/neo4j.yaml + +$ kubectl get neo4j -n demo neo4j-test -w +``` + +Wait until `STATUS` shows `Ready` before proceeding. + +--- + +## Step 3 โ€” Create a Database and Seed Data + +Open a shell into pod `neo4j-test-0` and run the following Cypher commands to: +- Create a new database called `appdb` +- Insert 2,000 test `User` nodes +- Verify the count + +```bash +# Retrieve the admin password +PASS=$(kubectl get secret -n demo neo4j-test-auth \ + -o jsonpath='{.data.password}' | base64 -d) + +# Create the database +$ kubectl exec -n demo neo4j-test-0 -- \ + cypher-shell -u neo4j -p "$PASS" \ + "CREATE DATABASE appdb IF NOT EXISTS WAIT" + +# Seed 2,000 User nodes +$ kubectl exec -n demo neo4j-test-0 -- \ + cypher-shell -d appdb -u neo4j -p "$PASS" \ + "UNWIND range(1,2000) AS i CREATE (:User {id:i, name:'user-'+toString(i)})" + +# Confirm the count +$ kubectl exec -n demo neo4j-test-0 -- \ + cypher-shell -d appdb -u neo4j -p "$PASS" \ + "MATCH (u:User) RETURN count(u) AS totalUsers" +``` + +Expected output: + +``` +totalUsers +2000 +``` + +--- + +## Step 4 โ€” Scale Up (3 โ†’ 5 Members) + +Apply the scale-up ops request: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-horizontal-scale-up + namespace: demo +spec: + type: HorizontalScaling + databaseRef: + name: neo4j-test + horizontalScaling: + server: 5 + reallocate: + strategy: "incremental" + batchSize: 1 +``` + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-horizontal-scale-up + namespace: demo +spec: + type: HorizontalScaling + databaseRef: + name: neo4j-test + horizontalScaling: + server: 5 + reallocate: + strategy: "incremental" + batchSize: 1 +EOF +neo4jopsrequest.ops.kubedb.com/neo4j-horizontal-scale-up created + +$ kubectl wait \ + --for=jsonpath='{.status.phase}'=Successful \ + neo4jopsrequest/neo4j-horizontal-scale-up \ + -n demo --timeout=900s +neo4jopsrequest.ops.kubedb.com/neo4j-horizontal-scale-up condition met +``` + +### Verify the Scale-Up + +Run these commands to confirm the cluster now has 5 members and that databases have been reallocated: + +```bash +$ kubectl get neo4jopsrequest -n demo neo4j-horizontal-scale-up +NAME TYPE STATUS AGE +neo4j-horizontal-scale-up HorizontalScaling Successful 16s + +$ kubectl get neo4j -n demo neo4j-test -o jsonpath='{.spec.replicas}{"\n"}' +5 + +$ kubectl get pods -n demo -l app.kubernetes.io/instance=neo4j-test +NAME READY STATUS RESTARTS AGE +neo4j-test-0 1/1 Running 0 ... +neo4j-test-1 1/1 Running 0 ... +neo4j-test-2 1/1 Running 0 ... +neo4j-test-3 1/1 Running 0 ... +neo4j-test-4 1/1 Running 0 ... + +$ PASS=$(kubectl get secret -n demo neo4j-test-auth -o jsonpath='{.data.password}' | base64 -d) + +$ kubectl exec -n demo neo4j-test-0 -- cypher-shell -u neo4j -p "$PASS" \ + "SHOW DATABASE appdb YIELD name, currentStatus, currentPrimariesCount, currentSecondariesCount RETURN name, currentStatus, currentPrimariesCount, currentSecondariesCount" +name, currentStatus, currentPrimariesCount, currentSecondariesCount +"appdb", "online", 2, 0 +"appdb", "online", 2, 0 + +$ kubectl exec -n demo neo4j-test-0 -- cypher-shell -u neo4j -p "$PASS" \ + "SHOW SERVERS YIELD name, state, health, hosting RETURN name, state, health, hosting ORDER BY name" +name, state, health, hosting +"neo4j-test-0", "Enabled", "Available", ["neo4j", "system"] +"neo4j-test-1", "Enabled", "Available", ["neo4j", "system"] +"neo4j-test-2", "Enabled", "Available", ["appdb", "system"] +"neo4j-test-3", "Enabled", "Available", ["appdb", "system"] +"neo4j-test-4", "Enabled", "Available", ["system"] +``` + +> **What to look for:** +> - All 5 pods are `Running` +> - `appdb` shows `currentStatus: online` +> - `SHOW SERVERS` shows new servers hosting databases (reallocation is complete) + +--- + +## Step 5 โ€” Scale Down (5 โ†’ 3 Members) + +Apply the scale-down ops request: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-horizontal-scale-down + namespace: demo +spec: + type: HorizontalScaling + databaseRef: + name: neo4j-test + horizontalScaling: + server: 3 + reallocate: + strategy: "full" +``` + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-horizontal-scale-down + namespace: demo +spec: + type: HorizontalScaling + databaseRef: + name: neo4j-test + horizontalScaling: + server: 3 + reallocate: + strategy: "full" +EOF +neo4jopsrequest.ops.kubedb.com/neo4j-horizontal-scale-down created + +$ kubectl wait \ + --for=jsonpath='{.status.phase}'=Successful \ + neo4jopsrequest/neo4j-horizontal-scale-down \ + -n demo --timeout=900s +neo4jopsrequest.ops.kubedb.com/neo4j-horizontal-scale-down condition met +``` + +### Verify the Scale-Down + +```bash +$ kubectl get neo4jopsrequest -n demo neo4j-horizontal-scale-down +NAME TYPE STATUS AGE +neo4j-horizontal-scale-down HorizontalScaling Successful 37s + +$ kubectl get neo4j -n demo neo4j-test -o jsonpath='{.spec.replicas}{"\n"}' +3 + +$ kubectl get pods -n demo -l app.kubernetes.io/instance=neo4j-test +NAME READY STATUS RESTARTS AGE +neo4j-test-0 1/1 Running 0 ... +neo4j-test-1 1/1 Running 0 ... +neo4j-test-2 1/1 Running 0 ... + +$ PASS=$(kubectl get secret -n demo neo4j-test-auth -o jsonpath='{.data.password}' | base64 -d) + +$ kubectl exec -n demo neo4j-test-0 -- \ + cypher-shell -d appdb -u neo4j -p "$PASS" \ + "MATCH (u:User) RETURN count(u) AS totalUsers" +totalUsers +2000 + +$ kubectl exec -n demo neo4j-test-0 -- cypher-shell -u neo4j -p "$PASS" \ + "SHOW DATABASE appdb YIELD name, currentStatus, currentPrimariesCount, currentSecondariesCount RETURN name, currentStatus, currentPrimariesCount, currentSecondariesCount" +name, currentStatus, currentPrimariesCount, currentSecondariesCount +"appdb", "online", 2, 0 +"appdb", "online", 2, 0 + + +$ kubectl exec -n demo neo4j-test-0 -- cypher-shell -u neo4j -p "$PASS" \ + "SHOW SERVERS YIELD name, state, health, hosting RETURN name, state, health, hosting ORDER BY name" +name, state, health, hosting +"neo4j-test-0", "Enabled", "Available", ["neo4j", "system"] +"neo4j-test-1", "Enabled", "Available", ["appdb", "neo4j", "system"] +"neo4j-test-2", "Enabled", "Available", ["appdb", "system"] +``` + +> โœ… The `totalUsers: 2000` result confirms **no data was lost** during the scale-down. The database remained online and queryable throughout. + +--- + +## Understanding the Output + +### `SHOW DATABASE` Fields + +| Field | Description | +|---|---| +| `name` | Database name | +| `currentStatus` | `online` means the database is healthy and accepting queries | +| `currentPrimariesCount` | Number of primary copies currently allocated | +| `currentSecondariesCount` | Number of secondary (read replica) copies | + +> One row appears per server that hosts the database. Seeing `"appdb", "online", 2, 0` twice means two servers each confirm they hold a primary copy. + +### `SHOW SERVERS` Fields + +| Field | Description | +|---|---| +| `name` | Pod name (maps directly to Kubernetes pod) | +| `state` | `Enabled` = active cluster member | +| `health` | `Available` = healthy and reachable | +| `hosting` | List of databases currently allocated to this server | + +--- + +## Troubleshooting + +If this OpsRequest does not finish, first inspect the affected pod and then check the `kubedb-ops-manager` operator logs for the exact error. For a shared checklist, see the [Neo4j Ops Request Overview](/docs/guides/neo4j/ops-request/overview.md#troubleshooting). + +**Ops request stuck in `Progressing`** + +Check the OpsRequest status, the pod events, and cluster allocation: + +```bash +$ kubectl describe neo4jopsrequest -n demo +$ kubectl get pods -n demo -l app.kubernetes.io/instance=neo4j-test +$ kubectl describe pod -n demo neo4j-test-0 +``` + +If the node is full, the new server count may not be schedulable. Check node capacity: + +```bash +$ kubectl describe node | grep -A 10 "Allocated resources" +``` + +**Database shows `offline` after scaling** + +Neo4j may need time to reallocate. Wait a few seconds and re-run `SHOW DATABASE`. If it persists, check the `kubedb-ops-manager` logs and pod readiness: + +```bash +$ kubectl logs -n -l app.kubernetes.io/name=kubedb-ops-manager --tail=50 +$ kubectl get pods -n demo -l app.kubernetes.io/instance=neo4j-test +``` + +**OpsRequest moves to `Failed`** + +Read the failure condition and then inspect the `kubedb-ops-manager` logs: + +```bash +$ kubectl get neo4jopsrequest -n demo -o jsonpath='{.status.conditions}' | jq . +$ kubectl logs -n -l app.kubernetes.io/name=kubedb-ops-manager --tail=50 +``` + +--- + +## Cleanup + +Remove all resources created in this guide: + +```bash +$ kubectl delete neo4jopsrequest -n demo \ + neo4j-horizontal-scale-up \ + neo4j-horizontal-scale-down +$ kubectl delete neo4j -n demo neo4j-test +$ kubectl delete ns demo +``` + +--- + +## Next Steps + +- [Neo4j Vertical Scaling](/docs/guides/neo4j/scaling/vertical-scaling/) โ€” adjust CPU and memory +- [Neo4j TLS Configuration](/docs/guides/neo4j/tls/) โ€” enable encrypted connections diff --git a/docs/guides/neo4j/scaling/vertical-scaling/_index.md b/docs/guides/neo4j/scaling/vertical-scaling/_index.md new file mode 100644 index 000000000..6d16b404a --- /dev/null +++ b/docs/guides/neo4j/scaling/vertical-scaling/_index.md @@ -0,0 +1,10 @@ +--- +-title: Vertical Scaling +-menu: +- docs_{{ .version }}: +- identifier: neo4j-vertical-scaling +- name: Vertical Scaling +- parent: neo4j-scaling +- weight: 20 +-menu_name: docs_{{ .version }} +--- \ No newline at end of file diff --git a/docs/guides/neo4j/scaling/vertical-scaling/overview.md b/docs/guides/neo4j/scaling/vertical-scaling/overview.md new file mode 100644 index 000000000..2e76f27c7 --- /dev/null +++ b/docs/guides/neo4j/scaling/vertical-scaling/overview.md @@ -0,0 +1,46 @@ +--- +title: Neo4j Vertical Scaling Overview +menu: + docs_{{ .version }}: + identifier: neo4j-vertical-scaling-overview + name: Overview + parent: neo4j-vertical-scaling + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Neo4j Vertical Scaling Overview + +This page explains how KubeDB Ops-manager updates Neo4j pod resources using `Neo4jOpsRequest`. + +## Before You Begin + +- You should be familiar with [Neo4j](/docs/guides/neo4j/concepts/neo4j.md). +- You should be familiar with [Neo4jOpsRequest](/docs/guides/neo4j/concepts/opsrequest.md). + +## How Vertical Scaling Works + +The following diagram shows how KubeDB Ops-manager performs vertical scaling for a `Neo4j` database. Open the image in a new tab to see the enlarged version. + +
+ Vertical scaling process of Neo4j +
Fig: Vertical scaling process of Neo4j
+
+ +The vertical scaling process consists of the following steps: + +For a `Neo4jOpsRequest` with `spec.type: VerticalScaling`, KubeDB Ops-manager: + +1. Validates CPU/memory values from `spec.verticalScaling.server.resources`. +2. Pauses conflicting reconciliations. +3. Applies updated requests/limits to Neo4j server pods. +4. Performs controlled restarts where necessary. +5. Waits for pods to become healthy with new resources. +6. Marks the request `Successful` after reconciliation. + +## Next Step + +Follow the detailed guide: [Scale Neo4j Vertically](/docs/guides/neo4j/scaling/vertical-scaling/scale-vertically/index.md). diff --git a/docs/guides/neo4j/scaling/vertical-scaling/scale-vertically/index.md b/docs/guides/neo4j/scaling/vertical-scaling/scale-vertically/index.md new file mode 100644 index 000000000..8653600df --- /dev/null +++ b/docs/guides/neo4j/scaling/vertical-scaling/scale-vertically/index.md @@ -0,0 +1,278 @@ +--- +title: Scale Neo4j Vertically +menu: + docs_{{ .version }}: + identifier: neo4j-scale-vertically + name: Scale Vertically + parent: neo4j-vertical-scaling + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> ๐Ÿ†• New to KubeDB? Start with the [quickstart guide](/docs/README.md) before continuing here. + +# Neo4j Vertical Scaling with KubeDB + +Vertical scaling adjusts the CPU and memory **requests and limits** on running Neo4j pods without recreating the database or losing data. KubeDB handles the rollout automatically through `Neo4jOpsRequest`. + +This guide walks you through: +- Deploying a Neo4j cluster +- Checking current pod resource allocation +- Applying a vertical scale-up +- Verifying the new resources are live + +--- + +## How It Works + +KubeDB uses `Neo4jOpsRequest` with `type: VerticalScaling` to update pod resources. Under the hood it: + +1. Patches the StatefulSet container spec with the new CPU/memory values +2. Performs a rolling restart of Neo4j pods one at a time +3. Marks the operation `Successful` once all pods are running with the new resources + +--- + +## Prerequisites + +| Requirement | Details | +|---|---| +| KubeDB installed | Provisioner and Ops-manager operators running | +| `kubectl` configured | With permissions to create namespaces and resources | + +See also: [Neo4j](/docs/guides/neo4j/concepts/neo4j.md) ยท [Neo4jOpsRequest](/docs/guides/neo4j/concepts/opsrequest.md) ยท [Vertical Scaling Overview](/docs/guides/neo4j/scaling/vertical-scaling/overview.md) + +--- + +## Step 1 โ€” Set Up the Namespace + +```bash +$ kubectl create ns demo +``` + +--- + +## Step 2 โ€” Deploy Neo4j + +Save this as `neo4j.yaml`: + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + version: "2025.12.1" + replicas: 3 + storage: + resources: + requests: + storage: 2Gi + storageClassName: standard + accessModes: + - ReadWriteOnce + podTemplate: + spec: + resources: + requests: + cpu: "250m" + memory: "1Gi" + limits: + cpu: "500m" + memory: "1Gi" + deletionPolicy: WipeOut +``` + +Apply it and wait for the cluster to become ready: + +```bash +$ kubectl apply -f neo4j.yaml + +$ kubectl get neo4j -n demo neo4j-test -w +``` + +Wait until `STATUS` shows `Ready` before proceeding. + +```bash +NAME VERSION STATUS AGE +neo4j-test 2025.12.1 Ready 3m +``` + +--- + +## Step 3 โ€” Check Current Pod Resources + +Before scaling, record the existing CPU and memory values so you can confirm the change later. + +```bash +$ kubectl get pod -n demo neo4j-test-0 \ + -o jsonpath='{.spec.containers[0].resources}' | jq . +``` + +Expected output: + +```json +{ + "limits": { "cpu": "500m", "memory": "1Gi" }, + "requests": { "cpu": "250m", "memory": "1Gi" } +} +``` + +--- + +## Step 4 โ€” Apply the Vertical Scaling OpsRequest + +The `Neo4jOpsRequest` below raises the CPU limit to `1500m` and memory to `4Gi`. + +Save this as `neo4j-vertical-scale.yaml`: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-vertical-scale + namespace: demo +spec: + type: VerticalScaling + databaseRef: + name: neo4j-test + verticalScaling: + server: + resources: + requests: + cpu: "700m" + memory: "4Gi" + limits: + cpu: "1500m" + memory: "4Gi" +``` + +Apply it and wait for completion: + +```bash +$ kubectl apply -f neo4j-vertical-scale.yaml + +$ kubectl wait --for=jsonpath='{.status.phase}'=Successful \ + neo4jopsrequest/neo4j-vertical-scale \ + -n demo --timeout=600s +``` + +Expected output: + +```bash +neo4jopsrequest.ops.kubedb.com/neo4j-vertical-scale condition met +``` + +### What Happens During This Step + +Once you apply the OpsRequest, KubeDB Ops-manager picks it up and begins the scaling process: + +1. The OpsRequest moves to `Progressing` phase +2. KubeDB patches the StatefulSet with the new resource values +3. Pods are restarted one at a time โ€” each must reach `Running` before the next restarts +4. Once all pods are up with the new resources, the OpsRequest moves to `Successful` + +You can watch the live status with: + +```bash +$ kubectl get neo4jopsrequest -n demo neo4j-vertical-scale -w +``` + +--- + +## Step 5 โ€” Verify the New Resources + +```bash +$ kubectl get neo4jopsrequest -n demo neo4j-vertical-scale + +$ kubectl get pod -n demo neo4j-test-0 \ + -o jsonpath='{.spec.containers[0].resources}' | jq . +``` + +Expected output: + +``` +NAME TYPE STATUS AGE +neo4j-vertical-scale VerticalScaling Successful 101s + +{ + "limits": { "cpu": "1500m", "memory": "4Gi" }, + "requests": { "cpu": "700m", "memory": "4Gi" } +} +``` + +> โœ… The values now match `spec.verticalScaling.server.resources` โ€” the scaling is complete. + +--- + +## Understanding the OpsRequest Fields + +| Field | Description | +|---|---| +| `spec.type` | `VerticalScaling` โ€” identifies this as a resource update operation | +| `spec.databaseRef.name` | Name of the target `Neo4j` resource | +| `spec.verticalScaling.server.resources.requests` | Minimum CPU/memory guaranteed to the pod | +| `spec.verticalScaling.server.resources.limits` | Maximum CPU/memory the pod is allowed to use | + +> **Tip:** Always set `requests` equal to `limits` for Neo4j in production. This gives the pod a [Guaranteed QoS class](https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/), preventing it from being evicted under memory pressure. + +--- + +## Troubleshooting + +If this OpsRequest does not finish, first inspect the affected pod and then check the `kubedb-ops-manager` operator logs for the exact error. For a shared checklist, see the [Neo4j Ops Request Overview](/docs/guides/neo4j/ops-request/overview.md#troubleshooting). + +**OpsRequest stays in `Progressing` and never completes** + +Check the pod that is being restarted and look for scheduling or resource issues: + +```bash +$ kubectl get pods -n demo -l app.kubernetes.io/instance=neo4j-test +$ kubectl describe pod -n demo neo4j-test-0 +$ kubectl describe node | grep -A 10 "Allocated resources" +``` + +**OpsRequest moves to `Failed`** + +Read the failure condition and then inspect the `kubedb-ops-manager` logs: + +```bash +kubectl get neo4jopsrequest -n demo neo4j-vertical-scale -o jsonpath='{.status.conditions}' | jq . +kubectl logs -n -l app.kubernetes.io/name=kubedb-ops-manager --tail=50 +``` + +**Pod restarts repeatedly after scaling (`CrashLoopBackOff`)** + +If Neo4j does not start with the new memory values, inspect the previous pod logs: + +```bash +kubectl logs -n demo neo4j-test-0 --previous +``` + +**`jq` not installed** + +Use jsonpath directly: + +```bash +kubectl get neo4jopsrequest -n demo neo4j-vertical-scale -o jsonpath='{.status.conditions}' +``` + +--- + +## Cleanup + +```bash +kubectl delete neo4jopsrequest -n demo neo4j-vertical-scale +kubectl delete neo4j -n demo neo4j-test +kubectl delete ns demo +``` + +--- + +## Next Steps + +- [Neo4j Horizontal Scaling](/docs/guides/neo4j/scaling/horizontal-scaling/) โ€” add or remove cluster members +- [Neo4j Version Upgrade](/docs/guides/neo4j/update-version/) โ€” roll to a newer Neo4j release +- [Neo4j Volume Expansion](/docs/guides/neo4j/volume-expansion/) โ€” increase persistent storage \ No newline at end of file diff --git a/docs/guides/neo4j/tls/_index.md b/docs/guides/neo4j/tls/_index.md new file mode 100644 index 000000000..7d36651ea --- /dev/null +++ b/docs/guides/neo4j/tls/_index.md @@ -0,0 +1,10 @@ +--- +title: TLS/SSL Encryption +menu: + docs_{{ .version }}: + identifier: neo4j-tls + name: TLS/SSL Encryption + parent: neo4j-guides + weight: 25 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/neo4j/tls/configure/index.md b/docs/guides/neo4j/tls/configure/index.md new file mode 100644 index 000000000..4ffc104ca --- /dev/null +++ b/docs/guides/neo4j/tls/configure/index.md @@ -0,0 +1,177 @@ +--- +title: TLS/SSL (Transport Encryption) +menu: + docs_{{ .version }}: + identifier: neo4j-tls-configure + name: Neo4j TLS/SSL Configuration + parent: neo4j-tls + weight: 20 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Configure TLS/SSL in Neo4j + +`KubeDB` supports TLS/SSL for Neo4j client and intra-cluster communication. This guide shows how to deploy a TLS-enabled Neo4j cluster and verify encrypted connection using `neo4j+s`. + +## Before You Begin + +- You need a Kubernetes cluster and `kubectl` configured to talk to it. +- Install [`cert-manager`](https://cert-manager.io/docs/installation/) v1.4.0 or later. +- Install KubeDB following [the setup guide](/docs/setup/README.md). + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +### Create Issuer + +Create a CA secret and an `Issuer` that KubeDB will use to generate Neo4j certificates. + +```bash +$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ca.key -out ca.crt -subj "/CN=neo4j/O=kubedb" + +$ kubectl create secret tls neo4j-ca --cert=ca.crt --key=ca.key -n demo +secret/neo4j-ca created + +$ cat <<'EOF' | kubectl apply -f - +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: neo4j-ca-issuer + namespace: demo +spec: + ca: + secretName: neo4j-ca +EOF +issuer.cert-manager.io/neo4j-ca-issuer created +``` + +## Deploy Neo4j with TLS + +Now apply a `Neo4j` object with TLS configuration: + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: tls-neo4j + namespace: demo +spec: + version: "2025.12.1" + replicas: 3 + storageType: Durable + storage: + storageClassName: standard + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + tls: + issuerRef: + apiGroup: cert-manager.io + kind: Issuer + name: neo4j-ca-issuer + bolt: + mode: TLS + cluster: + mode: mTLS + deletionPolicy: WipeOut +``` + +Here, + +- `spec.tls.issuerRef` points to the certificate issuer. +- `spec.tls.bolt.mode: TLS` enables encrypted Bolt client traffic. +- `spec.tls.cluster.mode: mTLS` enables mutual TLS for inter-server traffic. + +Apply the CR: + +```bash +$ cat <<'EOF' | kubectl apply -f - +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: tls-neo4j + namespace: demo +spec: + version: "2025.12.1" + replicas: 3 + storageType: Durable + storage: + storageClassName: standard + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + tls: + issuerRef: + apiGroup: cert-manager.io + kind: Issuer + name: neo4j-ca-issuer + bolt: + mode: TLS + cluster: + mode: mTLS + deletionPolicy: WipeOut +EOF +neo4j.kubedb.com/tls-neo4j created +``` + +## Verify TLS + +Check database readiness and generated TLS secret: + +```bash +$ kubectl wait --for=condition=Ready neo4j/tls-neo4j -n demo --timeout=600s +neo4j.kubedb.com/tls-neo4j condition met + +$ kubectl get secret -n demo tls-neo4j-server-cert +NAME TYPE DATA AGE +tls-neo4j-server-cert kubernetes.io/tls 3 2m +``` + +Get Neo4j credentials: + +```bash +$ kubectl get secret -n demo tls-neo4j-auth -o jsonpath='{.data.username}' | base64 -d && echo +neo4j + +$ kubectl get secret -n demo tls-neo4j-auth -o jsonpath='{.data.password}' | base64 -d && echo +8pyn3zno7QbX4iQn +``` + +Connect using `neo4j+s` and verify TLS session: + +```bash +$ kubectl exec -it -n demo tls-neo4j-0 -- bash +neo4j@tls-neo4j-0:~$ cypher-shell -a neo4j+s://tls-neo4j-0.demo.svc.cluster.local:7687 -u neo4j -p '8pyn3zno7QbX4iQn' +Connected to Neo4j using Bolt protocol version 6.0 at neo4j+s://tls-neo4j-0.demo.svc.cluster.local:7687 as user neo4j. +Type :help for a list of available commands or :exit to exit the shell. +Note that Cypher queries must end with a semicolon. +``` + +The successful `neo4j+s` connection confirms the cluster is accepting encrypted, certificate-validated Bolt traffic. + +## Cleaning up + +```bash +$ kubectl patch -n demo neo4j/tls-neo4j -p '{"spec":{"deletionPolicy":"WipeOut"}}' --type="merge" +neo4j.kubedb.com/tls-neo4j patched + +$ kubectl delete -n demo neo4j/tls-neo4j +neo4j.kubedb.com "tls-neo4j" deleted + +$ kubectl delete ns demo +namespace "demo" deleted +``` + +## Next Steps + +- Learn Neo4j CR fields from [Neo4j concept doc](/docs/guides/neo4j/concepts/neo4j.md). + diff --git a/docs/guides/neo4j/tls/overview/index.md b/docs/guides/neo4j/tls/overview/index.md new file mode 100644 index 000000000..904fabcdc --- /dev/null +++ b/docs/guides/neo4j/tls/overview/index.md @@ -0,0 +1,52 @@ +--- +title: Neo4j TLS/SSL Encryption Overview +menu: + docs_{{ .version }}: + identifier: neo4j-tls-overview + name: Overview + parent: neo4j-tls + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Neo4j TLS/SSL Encryption + +**Prerequisite:** To configure TLS/SSL in `Neo4j`, KubeDB uses `cert-manager` to issue certificates. Make sure `cert-manager` is installed in your cluster. You can install it by following the official guide [here](https://cert-manager.io/docs/installation/kubernetes/). + +To issue certificates, the following cert-manager CRDs are used: + +- `Issuer/ClusterIssuer`: Represents the certificate authority used to sign certificate requests. +- `Certificate`: Describes the desired X.509 certificate that cert-manager keeps renewed. + +**Neo4j CRD Specification:** + +KubeDB uses `spec.tls` in the `Neo4j` CR to enable transport encryption. + +- `spec.tls.issuerRef` +- protocol-specific TLS settings under `spec.tls` (for example `bolt`, `https`, and cluster channels) + +Read field details in [Neo4j concept](/docs/guides/neo4j/concepts/neo4j.md). + +## How TLS/SSL is configured in Neo4j + +The following figure shows the operational flow used by KubeDB to configure TLS/SSL in Neo4j. + +
+ Neo4j with TLS/SSL Flow +
Fig: Deploy Neo4j with TLS/SSL
+
+ +Deploying Neo4j with TLS/SSL configuration consists of the following steps: + +1. User creates an `Issuer/ClusterIssuer`. +2. User creates a `Neo4j` CR with `spec.tls`. +3. KubeDB operator watches the `Neo4j` CR and creates required resources. +4. KubeDB Ops Manager detects required resources and creates `Certificate` resources. +5. cert-manager watches `Certificate` resources and issues certificate Secrets. +6. KubeDB reconciles Neo4j pods with issued TLS certificates mounted. +7. Neo4j cluster becomes ready with encrypted transport enabled for configured protocols. + +In the next document, we show a step-by-step guide for configuring a `Neo4j` database with TLS/SSL. diff --git a/docs/guides/neo4j/update-version/_index.md b/docs/guides/neo4j/update-version/_index.md new file mode 100644 index 000000000..b9a7327ad --- /dev/null +++ b/docs/guides/neo4j/update-version/_index.md @@ -0,0 +1,10 @@ +--- +title: Update Version +menu: + docs_{{ .version }}: + identifier: neo4j-update-version + name: Update Version + parent: neo4j-guides + weight: 45 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/neo4j/update-version/overview.md b/docs/guides/neo4j/update-version/overview.md new file mode 100644 index 000000000..f8ed1598e --- /dev/null +++ b/docs/guides/neo4j/update-version/overview.md @@ -0,0 +1,46 @@ +--- +title: Updating Neo4j Version +menu: + docs_{{ .version }}: + identifier: neo4j-update-version-overview + name: Overview + parent: neo4j-update-version + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Neo4j Update Version Overview + +This page explains how KubeDB Ops-manager upgrades Neo4j using `Neo4jOpsRequest`. + +## Before You Begin + +- You should be familiar with [Neo4j](/docs/guides/neo4j/concepts/neo4j.md). +- You should be familiar with [Neo4jOpsRequest](/docs/guides/neo4j/concepts/opsrequest.md). + +## How Update Version Works + +The following diagram shows how KubeDB Ops-manager updates the version of a `Neo4j` database. Open the image in a new tab to see the enlarged version. + +
+ Update version process of Neo4j +
Fig: Update version process of Neo4j
+
+ +The update version process consists of the following steps: + +For a `Neo4jOpsRequest` with `spec.type: UpdateVersion`, KubeDB Ops-manager: + +1. Validates target version from `spec.updateVersion.targetVersion`. +2. Pauses conflicting reconciliations for safe upgrade. +3. Updates Neo4j image/version references. +4. Performs controlled rolling update of Neo4j members. +5. Waits for all pods and cluster status to become healthy. +6. Marks the request `Successful` and resumes reconciliation. + +## Next Step + +Follow the detailed guide: [Upgrade Neo4j Version](/docs/guides/neo4j/update-version/versionupgrading/index.md). diff --git a/docs/guides/neo4j/update-version/versionupgrading/index.md b/docs/guides/neo4j/update-version/versionupgrading/index.md new file mode 100644 index 000000000..d9727766e --- /dev/null +++ b/docs/guides/neo4j/update-version/versionupgrading/index.md @@ -0,0 +1,248 @@ +--- +title: Upgrade Neo4j Version +menu: + docs_{{ .version }}: + identifier: neo4j-version-upgrading + name: Version Upgrading + parent: neo4j-update-version + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> ๐Ÿ†• New to KubeDB? Start with the [quickstart guide](/docs/README.md) before continuing here. + +# Neo4j Version Upgrade with KubeDB + +Upgrading Neo4j involves restarting pods with an updated container image. KubeDB handles the rolling upgrade automatically through `Neo4jOpsRequest`, ensuring the cluster stays available throughout. + +This guide walks you through: +- Deploying a Neo4j cluster +- Checking the current version +- Applying a version upgrade request +- Verifying the cluster is running the new version + +--- + +## How It Works + +KubeDB uses `Neo4jOpsRequest` with `type: UpdateVersion` to upgrade Neo4j. Under the hood it: + +1. Resolves the target image from the `Neo4jVersion` catalog +2. Performs a rolling restart, updating one pod at a time +3. Waits for each pod to become ready before proceeding to the next +4. Marks the operation `Successful` once all pods are on the new version + +> **Note:** During the rollout, Neo4j may briefly show a `Critical` status before converging back to `Ready`. This is expected โ€” the cluster remains available because only one pod restarts at a time. + +--- + +## Prerequisites + +| Requirement | Details | +|---|---| +| KubeDB installed | Provisioner and Ops-manager operators running | +| `kubectl` configured | With permissions to create namespaces and resources | + +--- + +## Step 1 โ€” Set Up the Namespace + +```bash +kubectl create ns demo +``` + +--- + +## Step 2 โ€” Deploy Neo4j + +Save this as `neo4j.yaml`: + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + version: "2025.10.1" + replicas: 3 + storage: + resources: + requests: + storage: 2Gi + storageClassName: standard + accessModes: + - ReadWriteOnce + deletionPolicy: WipeOut +``` + +Apply it and wait for the cluster to become ready: + +```bash +kubectl apply -f neo4j.yaml + +kubectl get neo4j -n demo neo4j-test -w +``` + +Wait until `STATUS` shows `Ready` before proceeding. + +``` +NAME VERSION STATUS AGE +neo4j-test 2025.10.1 Ready 3m +``` + +To see all available upgrade targets before proceeding: + +```bash +kubectl get neo4jversions +``` + +--- + +## Step 3 โ€” Apply the Version Upgrade OpsRequest + +Save this as `neo4j-update-version.yaml`, setting `targetVersion` to the version you want: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-update-version + namespace: demo +spec: + type: UpdateVersion + databaseRef: + name: neo4j-test + updateVersion: + targetVersion: "2025.12.1" +``` + +Apply it and wait for completion: + +```bash +kubectl apply -f neo4j-update-version.yaml + +kubectl wait --for=jsonpath='{.status.phase}'=Successful \ + neo4jopsrequest/neo4j-update-version \ + -n demo --timeout=600s +``` + +Expected output: + +``` +neo4jopsrequest.ops.kubedb.com/neo4j-update-version condition met +``` + +### What Happens During This Step + +Once you apply the OpsRequest, KubeDB Ops-manager begins the upgrade: + +1. The OpsRequest moves to `Progressing` phase +2. KubeDB resolves the new container image from the `Neo4jVersion` catalog +3. Pods are updated one at a time โ€” the cluster stays available throughout +4. Neo4j may briefly report `Critical` status between pod restarts โ€” this is normal +5. Once all pods are running the new image and are healthy, the OpsRequest moves to `Successful` + +You can watch live progress with: + +```bash +kubectl get neo4jopsrequest -n demo neo4j-update-version -w +``` + +--- + +## Step 4 โ€” Verify the Upgrade + +```bash +kubectl get neo4jopsrequest -n demo neo4j-update-version + +kubectl get neo4j -n demo neo4j-test +``` + +Expected output: + +``` +NAME TYPE STATUS AGE +neo4j-update-version UpdateVersion Successful 2m57s + +NAME VERSION STATUS AGE +neo4j-test 2025.12.1 Ready 21m +``` + +> โœ… The `VERSION` column now shows `2025.12.1` and `STATUS` is `Ready` โ€” the upgrade is complete. + +--- + +## Understanding the OpsRequest Fields + +| Field | Description | +|---|---| +| `spec.type` | `UpdateVersion` โ€” identifies this as a version upgrade operation | +| `spec.databaseRef.name` | Name of the target `Neo4j` resource | +| `spec.updateVersion.targetVersion` | The `Neo4jVersion` name to upgrade to (must exist in the catalog) | + +--- + +## Troubleshooting + +If this OpsRequest does not finish, first inspect the affected pod and then check the `kubedb-ops-manager` operator logs for the exact error. For a shared checklist, see the [Neo4j Ops Request Overview](/docs/guides/neo4j/ops-request/overview.md#troubleshooting). + +**OpsRequest stays in `Progressing` and never completes** + +A pod is likely not becoming ready after its image was updated. Find which pod is stuck and inspect its events and logs: + +```bash +kubectl get pods -n demo -l app.kubernetes.io/instance=neo4j-test +kubectl describe pod -n demo neo4j-test-0 +kubectl logs -n demo neo4j-test-0 +``` + +Common causes include image pull failures, insufficient node resources, or a version mismatch. + +**`targetVersion` not found** + +The version must exist as a `Neo4jVersion` catalog entry in your cluster. If the version you want is missing from the list, your KubeDB catalog is outdated: + +```bash +kubectl get neo4jversions | grep 2025 +``` + +Update your KubeDB operator to get the latest catalog, or check the [supported versions list](/docs/guides/neo4j/README.md). + +**Neo4j stuck in `Critical` and does not recover** + +If the new version fails to start cleanly, inspect the pod logs for startup errors and then check the `kubedb-ops-manager` logs: + +```bash +kubectl logs -n demo neo4j-test-0 +kubectl logs -n demo neo4j-test-1 +kubectl logs -n -l app.kubernetes.io/name=kubedb-ops-manager --tail=50 +``` + +**OpsRequest moves to `Failed`** + +Read the failure condition directly, then use the operator logs for the detailed message: + +```bash +kubectl get neo4jopsrequest -n demo neo4j-update-version -o jsonpath='{.status.conditions}' | jq . +kubectl logs -n -l app.kubernetes.io/name=kubedb-ops-manager --tail=50 +``` + +--- + +## Cleanup + +```bash +kubectl delete neo4jopsrequest -n demo neo4j-update-version +kubectl delete neo4j -n demo neo4j-test +kubectl delete ns demo +``` + +--- + +## Next Steps + +- [Neo4j Vertical Scaling](/docs/guides/neo4j/scaling/vertical-scaling/) โ€” adjust CPU and memory +- [Neo4j Horizontal Scaling](/docs/guides/neo4j/scaling/horizontal-scaling/) โ€” add or remove cluster members +- [Neo4j Volume Expansion](/docs/guides/neo4j/volume-expansion/) โ€” increase persistent storage \ No newline at end of file diff --git a/docs/guides/neo4j/volume-expansion/_index.md b/docs/guides/neo4j/volume-expansion/_index.md new file mode 100644 index 000000000..c29684c35 --- /dev/null +++ b/docs/guides/neo4j/volume-expansion/_index.md @@ -0,0 +1,10 @@ +--- +title: Volume Expansion +menu: + docs_{{ .version }}: + identifier: neo4j-volume-expansion + name: Volume Expansion + parent: neo4j-guides + weight: 40 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/neo4j/volume-expansion/overview.md b/docs/guides/neo4j/volume-expansion/overview.md new file mode 100644 index 000000000..ee11b43ed --- /dev/null +++ b/docs/guides/neo4j/volume-expansion/overview.md @@ -0,0 +1,47 @@ +--- +title: Expanding Neo4j Storage +menu: + docs_{{ .version }}: + identifier: neo4j-volume-expansion-overview + name: Overview + parent: neo4j-volume-expansion + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Neo4j Volume Expansion Overview + +This page explains how KubeDB Ops-manager expands Neo4j data volumes using `Neo4jOpsRequest`. + +## Before You Begin + +- You should be familiar with [Neo4j](/docs/guides/neo4j/concepts/neo4j.md). +- You should be familiar with [Neo4jOpsRequest](/docs/guides/neo4j/concepts/opsrequest.md). +- Your StorageClass must support `allowVolumeExpansion: true`. + +## How Volume Expansion Works + +The following diagram shows how KubeDB Ops-manager expands volume for a `Neo4j` database. Open the image in a new tab to see the enlarged version. + +
+ Volume expansion process of Neo4j +
Fig: Volume expansion process of Neo4j
+
+ +The volume expansion process consists of the following steps: + +For a `Neo4jOpsRequest` with `spec.type: VolumeExpansion`, KubeDB Ops-manager: + +1. Validates requested size from `spec.volumeExpansion.server`. +2. Validates expansion mode from `spec.volumeExpansion.mode`. +3. Pauses conflicting reconciliations. +4. Expands the target PVCs to the requested size. +5. Reconciles Neo4j state based on online/offline mode requirements. +6. Marks request `Successful` after PVC and pod health checks. + +## Next Step + +Follow the detailed guide: [Expand Neo4j Volume](/docs/guides/neo4j/volume-expansion/volume-expansion.md). diff --git a/docs/guides/neo4j/volume-expansion/volume-expansion.md b/docs/guides/neo4j/volume-expansion/volume-expansion.md new file mode 100644 index 000000000..d60a4ea8a --- /dev/null +++ b/docs/guides/neo4j/volume-expansion/volume-expansion.md @@ -0,0 +1,288 @@ +--- +title: Expand Neo4j Volume +menu: + docs_{{ .version }}: + identifier: neo4j-volume-expansion-cluster + name: Cluster + parent: neo4j-volume-expansion + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> ๐Ÿ†• New to KubeDB? Start with the [quickstart guide](/docs/README.md) before continuing here. + +# Neo4j Volume Expansion with KubeDB + +Volume expansion increases the persistent storage size allocated to Neo4j pods without downtime. KubeDB delegates the resize to your storage provisioner through `Neo4jOpsRequest`. + +This guide walks you through: +- Deploying a Neo4j cluster with Longhorn storage +- Checking current PVC sizes +- Applying an online volume expansion +- Verifying the new disk size is available to the database + +> **Longhorn requirement:** This guide uses the [Longhorn](https://longhorn.io/) storage class, which supports online volume expansion out of the box. Ensure Longhorn is installed in your cluster before proceeding: +> ```bash +> kubectl get storageclass longhorn +> ``` + +--- + +## How It Works + +KubeDB uses `Neo4jOpsRequest` with `type: VolumeExpansion` to resize persistent volumes. Under the hood it: + +1. Patches the `PersistentVolumeClaim` size on each pod +2. Signals Longhorn to perform the resize online โ€” no pod restart needed +3. Verifies the new capacity is reflected inside the pod +4. Marks the operation `Successful` once all PVCs match the target size + +**Online vs Offline mode:** + +| Mode | When to use | +|---|---| +| `Online` | Pod keeps running during resize. Longhorn and most cloud CSI drivers support this. | +| `Offline` | Pod is stopped, volume is resized, then pod restarts. Use when your storage class does not support online expansion. | + +> **Important:** Volume expansion is **irreversible** โ€” you cannot shrink a PVC after expanding it. + +--- + +## Prerequisites + +| Requirement | Details | +|---|---| +| KubeDB installed | Provisioner and Ops-manager operators running | +| Longhorn installed | Storage class `longhorn` available in the cluster | +| `kubectl` configured | With permissions to create namespaces and resources | + +--- + +## Step 1 โ€” Set Up the Namespace + +```bash +kubectl create ns demo +``` + +--- + +## Step 2 โ€” Deploy Neo4j with Longhorn Storage + +Save this as `neo4j.yaml`. Note that `storageClassName: longhorn` is set so that PVCs are provisioned by Longhorn and support online expansion: + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: Neo4j +metadata: + name: neo4j-test + namespace: demo +spec: + version: "2025.12.1" + replicas: 3 + storage: + resources: + requests: + storage: 2Gi + storageClassName: longhorn + accessModes: + - ReadWriteOnce + deletionPolicy: WipeOut +``` + +Apply it and wait for the cluster to become ready: + +```bash +kubectl apply -f neo4j.yaml + +kubectl get neo4j -n demo neo4j-test -w +``` + +Wait until `STATUS` shows `Ready` before proceeding. + +``` +NAME VERSION STATUS AGE +neo4j-test 2025.12.1 Ready 3m +``` + +--- + +## Step 3 โ€” Check Current PVC Size + +Confirm each pod has a `2Gi` volume provisioned by Longhorn: + +```bash +kubectl get pvc -n demo -l app.kubernetes.io/instance=neo4j-test +``` + +Expected output: + +```bash +NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE +data-neo4j-test-0 Bound ... 2Gi RWO longhorn 3m +data-neo4j-test-1 Bound ... 2Gi RWO longhorn 3m +data-neo4j-test-2 Bound ... 2Gi RWO longhorn 3m +``` + +--- + +## Step 4 โ€” Apply the Volume Expansion OpsRequest + +Save this as `neo4j-volume-expansion.yaml`: + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: Neo4jOpsRequest +metadata: + name: neo4j-volume-expansion + namespace: demo +spec: + type: VolumeExpansion + databaseRef: + name: neo4j-test + volumeExpansion: + mode: "Online" + server: "4Gi" +``` + +Apply it and wait for completion: + +```bash +kubectl apply -f neo4j-volume-expansion.yaml + +kubectl wait --for=jsonpath='{.status.phase}'=Successful \ + neo4jopsrequest/neo4j-volume-expansion \ + -n demo --timeout=600s +``` + +Expected output: + +``` +neo4jopsrequest.ops.kubedb.com/neo4j-volume-expansion condition met +``` + +### What Happens During This Step + +Once you apply the OpsRequest, KubeDB Ops-manager begins the expansion: + +1. The OpsRequest moves to `Progressing` phase +2. KubeDB patches each PVC's `spec.resources.requests.storage` to `4Gi` +3. Longhorn detects the PVC change and resizes the volume online โ€” pods keep running +4. KubeDB verifies the new capacity is visible inside each container +5. Once all PVCs reflect the new size, the OpsRequest moves to `Successful` + +You can watch live progress with: + +```bash +kubectl get neo4jopsrequest -n demo neo4j-volume-expansion -w +``` + +--- + +## Step 5 โ€” Verify the New Volume Size + +```bash +kubectl get neo4jopsrequest -n demo neo4j-volume-expansion + +kubectl get pvc -n demo -l app.kubernetes.io/instance=neo4j-test +``` + +Expected output: + +``` +NAME TYPE STATUS AGE +neo4j-volume-expansion VolumeExpansion Successful 2m10s + +NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE +data-neo4j-test-0 Bound ... 4Gi RWO longhorn 8m +data-neo4j-test-1 Bound ... 4Gi RWO longhorn 8m +data-neo4j-test-2 Bound ... 4Gi RWO longhorn 8m +``` + +> โœ… All PVCs now show `4Gi` โ€” the expansion is complete. + +You can also verify the available disk from inside a container: + +```bash +kubectl exec -n demo neo4j-test-0 -- df -h /data +``` + +--- + +## Understanding the OpsRequest Fields + +| Field | Description | +|---|---| +| `spec.type` | `VolumeExpansion` โ€” identifies this as a storage resize operation | +| `spec.databaseRef.name` | Name of the target `Neo4j` resource | +| `spec.volumeExpansion.mode` | `Online` (no restart) or `Offline` (pod stopped during resize) | +| `spec.volumeExpansion.server` | Target size for each Neo4j server PVC โ€” must be larger than the current size | + +--- + +## Troubleshooting + +If this OpsRequest does not finish, first inspect the affected PVC and then check the `kubedb-ops-manager` operator logs for the exact error. For a shared checklist, see the [Neo4j Ops Request Overview](/docs/guides/neo4j/ops-request/overview.md#troubleshooting). + +**OpsRequest stays in `Progressing` โ€” PVC capacity does not change** + +First, confirm the PVC resize was actually sent: + +```bash +kubectl describe pvc -n demo data-neo4j-test-0 +``` + +Look for a `FileSystemResizePending` condition. If it is there, the volume backend accepted the resize but the filesystem inside the pod has not updated yet. If it has not happened after a few minutes, restart the pod: + +```bash +kubectl delete pod -n demo neo4j-test-0 +``` + +**`Longhorn volume driver not found` or PVC stays in `Pending`** + +Verify the storage backend and the storage class: + +```bash +kubectl get storageclass longhorn +kubectl get pods -n longhorn-system +``` + +If the storage class is missing, install Longhorn and re-deploy the Neo4j cluster. + +**OpsRequest moves to `Failed` with error `volume expansion not supported`** + +This means the storage class does not have `allowVolumeExpansion: true`. Check it and patch the storage class if needed: + +```bash +kubectl get storageclass longhorn -o jsonpath='{.allowVolumeExpansion}' +kubectl patch storageclass longhorn -p '{"allowVolumeExpansion": true}' +``` + +Then re-apply the OpsRequest. + +**OpsRequest moves to `Failed` โ€” read the exact reason** + +Use the OpsRequest status and the `kubedb-ops-manager` logs together: + +```bash +kubectl get neo4jopsrequest -n demo neo4j-volume-expansion -o jsonpath='{.status.conditions}' | jq . +kubectl logs -n -l app.kubernetes.io/name=kubedb-ops-manager --tail=50 +``` + +--- + +## Cleanup + +```bash +kubectl delete neo4jopsrequest -n demo neo4j-volume-expansion +kubectl delete neo4j -n demo neo4j-test +kubectl delete ns demo +``` + +--- + +## Next Steps + +- [Neo4j Vertical Scaling](/docs/guides/neo4j/scaling/vertical-scaling/) โ€” adjust CPU and memory +- [Neo4j Horizontal Scaling](/docs/guides/neo4j/scaling/horizontal-scaling/) โ€” add or remove cluster members +- [Neo4j Version Upgrade](/docs/guides/neo4j/update-version/) โ€” roll to a newer Neo4j release \ No newline at end of file diff --git a/docs/images/neo4j/HorizontalScalling.png b/docs/images/neo4j/HorizontalScalling.png new file mode 100644 index 000000000..abf68294b Binary files /dev/null and b/docs/images/neo4j/HorizontalScalling.png differ diff --git a/docs/images/neo4j/Reconfigure.png b/docs/images/neo4j/Reconfigure.png new file mode 100644 index 000000000..ac07169f9 Binary files /dev/null and b/docs/images/neo4j/Reconfigure.png differ diff --git a/docs/images/neo4j/TLS.png b/docs/images/neo4j/TLS.png new file mode 100644 index 000000000..353daae03 Binary files /dev/null and b/docs/images/neo4j/TLS.png differ diff --git a/docs/images/neo4j/UpdateVersion.png b/docs/images/neo4j/UpdateVersion.png new file mode 100644 index 000000000..beeaef5ce Binary files /dev/null and b/docs/images/neo4j/UpdateVersion.png differ diff --git a/docs/images/neo4j/VerticalScaling.png b/docs/images/neo4j/VerticalScaling.png new file mode 100644 index 000000000..75b2a4381 Binary files /dev/null and b/docs/images/neo4j/VerticalScaling.png differ diff --git a/docs/images/neo4j/VolumeExpanison.png b/docs/images/neo4j/VolumeExpanison.png new file mode 100644 index 000000000..000502be0 Binary files /dev/null and b/docs/images/neo4j/VolumeExpanison.png differ diff --git a/docs/images/neo4j/compute-autoscaling.png b/docs/images/neo4j/compute-autoscaling.png new file mode 100644 index 000000000..b35533b61 Binary files /dev/null and b/docs/images/neo4j/compute-autoscaling.png differ diff --git a/docs/images/neo4j/lifecycle.png b/docs/images/neo4j/lifecycle.png new file mode 100644 index 000000000..e00a26244 Binary files /dev/null and b/docs/images/neo4j/lifecycle.png differ diff --git a/docs/images/neo4j/neo4j-browser-connected.png b/docs/images/neo4j/neo4j-browser-connected.png new file mode 100644 index 000000000..2bcb109b9 Binary files /dev/null and b/docs/images/neo4j/neo4j-browser-connected.png differ diff --git a/docs/images/neo4j/neo4j-browser-login.png b/docs/images/neo4j/neo4j-browser-login.png new file mode 100644 index 000000000..9d223a697 Binary files /dev/null and b/docs/images/neo4j/neo4j-browser-login.png differ diff --git a/docs/images/neo4j/operational-view.png b/docs/images/neo4j/operational-view.png new file mode 100644 index 000000000..c0bd083b8 Binary files /dev/null and b/docs/images/neo4j/operational-view.png differ diff --git a/docs/images/neo4j/prometheus-builtin.png b/docs/images/neo4j/prometheus-builtin.png new file mode 100644 index 000000000..4332bfeec Binary files /dev/null and b/docs/images/neo4j/prometheus-builtin.png differ diff --git a/docs/images/neo4j/prometheus.png b/docs/images/neo4j/prometheus.png new file mode 100644 index 000000000..cae02237f Binary files /dev/null and b/docs/images/neo4j/prometheus.png differ diff --git a/docs/images/neo4j/reconfigureTLS.png b/docs/images/neo4j/reconfigureTLS.png new file mode 100644 index 000000000..fe1ddd72b Binary files /dev/null and b/docs/images/neo4j/reconfigureTLS.png differ diff --git a/docs/images/neo4j/storage-autoscaling.png b/docs/images/neo4j/storage-autoscaling.png new file mode 100644 index 000000000..61765f195 Binary files /dev/null and b/docs/images/neo4j/storage-autoscaling.png differ