You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@hugegraph.apache.org by "bitflicker64 (via GitHub)" <gi...@apache.org> on 2026/09/18 18:14:15 UTC

[PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

bitflicker64 opened a new pull request, #494:
URL: https://github.com/apache/hugegraph-doc/pull/494

   ## Purpose of the PR
   
   - link apache/hugegraph#3218 (the paired code PR that adds the chart)
   
   apache/hugegraph#3218 adds a Helm chart for the distributed deployment (PD + Store + Server, optional Hubble), and the site has no page for it yet. This adds that page in EN and CN under `docs/quickstart/hugegraph/` (weight 4, next to the Server/PD/Store install pages), following the same skeleton, heading numbering and mermaid usage as the sibling pages.
   
   What the page covers:
   
   - Install from the source tree with the three presets (`values.yaml`, `values-single.yaml`, `values-cluster.yaml`), `--wait` guidance, and the two defaults to know before production use: no resources are set, and image tags track `latest` until the next release publishes versioned images.
   - The auth model: the three chart-managed Secrets (`<release>-admin`, `<release>-auth-token`, `<release>-pd-auth`), the `existingSecret` bring-your-own paths, the value constraints, and the rotation caveats.
   - Why PD startup and liveness stay on `/v1/health` while readiness and the Store init-container wait use `/v1/ready`, and how the Server startup budget is derived from the startup probe.
   - Upgrade behavior: the one-time roll on the first upgrade after a fresh install, the `OnDelete` procedure for production Store image rolls, the PVC resize constraint, and the guard that rejects PD/Store scale-down below the live StatefulSet.
   - Uninstall behavior (PVCs and Secrets are kept on purpose) and the current limitations: no NetworkPolicy yet, `latest` tags, the cross-replica graph visibility window of apache/hugegraph#3137, and operator-triggered Store recovery.
   
   The full values reference stays in the chart README; the page links to its anchors instead of duplicating the tables, so the two cannot drift apart.
   
   Written against the chart at commit `05f3d9e0b` of the PR branch (2026-09-18). Verified locally: `scripts/hugo.sh build` passes and both pages render (nav placement, mermaid diagram, tables, details blocks) in EN and CN.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
bitflicker64 commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4166026864


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,282 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+Day-2 work (NetworkPolicy details, disaster recovery, scaling, safe Store
+rolls, running Hubble outside the cluster) is on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity, NetworkPolicy on |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. One of its numbers deserves a note: it requests 5Gi and limits at 8Gi of memory per Store, well above the
+1Gi heap, because the Store's RocksDB caches live outside the JVM heap (a 4Gi limit OOM-killed Stores after about
+1 GB of data). Scale both numbers with data size. The full parameter reference (every component, probe,
+scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions

Review Comment:
   Fixed in 686d3b930. Section 3.4 now starts the port-forward in its own block and terminal, then reads the password and runs `curl` from a second terminal. The operations page health check and its per-Pod Gremlin check got the same split, in EN and CN.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,282 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+Day-2 work (NetworkPolicy details, disaster recovery, scaling, safe Store
+rolls, running Hubble outside the cluster) is on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity, NetworkPolicy on |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. One of its numbers deserves a note: it requests 5Gi and limits at 8Gi of memory per Store, well above the
+1Gi heap, because the Store's RocksDB caches live outside the JVM heap (a 4Gi limit OOM-killed Stores after about
+1 GB of data). Scale both numbers with data size. The full parameter reference (every component, probe,
+scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable

Review Comment:
   Fixed in 5e4cbd25c. Section 4 now says the admin password must not start or end with whitespace, next to the newline, carriage-return and backslash rules, in EN and CN.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,483 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. For a production image roll, set
+`store.updateStrategy.type=OnDelete` and delete Store Pods one at a time,
+checking between deletions.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, term, and

Review Comment:
   Fixed in 795d5f835. Confirmed on apache/hugegraph master (176fb56dd): `PartitionAPI.getPartition()` sets role, leader and `logIndex` but never `term`, while the plural handler calls `setTerm`. Section 6 now lists role, leader and committed index (`logIndex`), compares only the index with a peer Store, and says `term` always reads 0 on that route. CN updated.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,483 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. For a production image roll, set
+`store.updateStrategy.type=OnDelete` and delete Store Pods one at a time,
+checking between deletions.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, term, and
+committed index that Store holds, and fails while the Store is down;
+compare term and index with a peer Store rather than reading them alone.
+The plural `GET :8520/v1/partitions` answers 500 on any Store that follows
+a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a
+group that is short a shard or has no leader as a stop. A real
+restoration-complete signal is upstream work, tracked in
+[apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229).
+
+### 7 Disaster recovery
+
+What PD automates on current builds is narrow: a 60-second patrol only
+marks Stores that stopped sending heartbeats as `Offline`. There is no
+automatic re-replication; re-placing the replicas of a lost Store,
+reconciling shard groups, and processing tombstoned Stores run only when a
+partition patrol is triggered explicitly.
+
+The task endpoints execute locally on the PD that receives them, and a
+follower answers with an empty success while doing nothing.
+Port-forwarding the client Service selects an arbitrary PD, so identify
+the leader first, then port-forward that Pod (two terminals: the forward
+runs in the foreground):
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-pd-client 8620:8620
+# Read .data.pdLeader.raftUrl; its host names the leader Pod.
+curl -su "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/members
+# Stop the Service forward, then forward the leader Pod instead.
+kubectl port-forward -n hugegraph pod/<leader-pod> 8620:8620
+# Reconcile shard groups and process tombstoned Stores.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/patrolPartitions
+# Spread Raft leaders, then partition data.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balanceLeaders

Review Comment:
   Fixed in 795d5f835. Confirmed in `TaskScheduleService.patrolPartitions()`: a shard group whose count differs from the configured shard count gets `reallocShards` and `BALANCE_SHARD_KEY` for 180 s. Section 7 now says both a reallocating patrol and `balancePartitions` set the flag, that inside the window `balanceLeaders` is refused and `balancePartitions` does nothing, and to wait 180 s after a patrol that repaired a group. The command block has a comment at that step. CN updated.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
bitflicker64 commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4192319417


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,523 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward. It runs in the foreground, so keep
+it in one terminal:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+```
+
+and call the API from a second terminal, with `PASSWORD` set as above:
+
+```bash
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry. An
+in-cluster Hubble in `pd` mode combined with `server.advertiseUrl` also
+fails the render until `networkPolicy.hubble.extraEgress` admits the
+advertised destination: PD hands Hubble that URL for discovery, and
+Hubble's egress policy otherwise reaches only the release's own Pods.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. `values-cluster.yaml` therefore sets
+`store.updateStrategy.type=OnDelete` (set it yourself on any other
+production values): an upgrade then updates the StatefulSet without
+replacing any Store Pod, and you delete Store Pods one at a time, checking
+between deletions. `OnDelete` only stops automatic advancement; deleting
+Pods without the checks below carries the same risk.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, leader, and
+committed index (`logIndex`) that Store holds, and fails while the Store
+is down; compare the index with a peer Store rather than reading it
+alone. This route never fills its `term` field, so `term` always reads 0
+there. The plural `GET :8520/v1/partitions` answers 500 on any Store that
+follows a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a
+group that is short a shard or has no leader as a stop. A real
+restoration-complete signal is upstream work, tracked in
+[apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229).
+
+### 7 Disaster recovery
+
+What PD automates on current builds is narrow: a 60-second patrol only
+marks Stores that stopped sending heartbeats as `Offline`. There is no
+automatic re-replication; re-placing the replicas of a lost Store,
+reconciling shard groups, and processing tombstoned Stores run only when a
+partition patrol is triggered explicitly.
+
+The task endpoints execute locally on the PD that receives them, and a
+follower answers with an empty success while doing nothing.
+Port-forwarding the client Service selects an arbitrary PD, so identify
+the leader first, then port-forward that Pod (two terminals: the forward
+runs in the foreground):
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-pd-client 8620:8620
+# Read .data.pdLeader.raftUrl; its host names the leader Pod.
+curl -su "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/members
+# Stop the Service forward, then forward the leader Pod instead.
+kubectl port-forward -n hugegraph pod/<leader-pod> 8620:8620
+# Reconcile shard groups and process tombstoned Stores.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/patrolPartitions
+# If the patrol repaired a shard group, wait 180 s first (see below).
+# Spread Raft leaders, then partition data.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balanceLeaders
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balancePartitions
+```
+
+Read `/v1/members` again after the tasks: if leadership moved mid-sequence,
+the later tasks ran on a follower and did nothing. PD sets a
+balance-shard flag for 180 s in two cases: `patrolPartitions` sets it
+whenever it reallocates a shard group whose shard count is wrong, and
+`balancePartitions` sets it even when it moves nothing. Inside that
+window `balanceLeaders` is refused and `balancePartitions` returns
+without doing anything, so wait at least 180 s after a patrol that
+repaired a group, and after `balancePartitions`, before the next
+balancing call. On images built before
+[apache/hugegraph#3233](https://github.com/apache/hugegraph/pull/3233)
+(merged 2026-09-24) the refusal is a bare HTTP 500 whose reason appears
+only in the PD log; after it, the reason comes back in the body as
+`{"status":1001,"error":"balance shard is processing, please try later!"}`.
+
+Telling a real run from a no-op takes the PD leader's log, because the
+responses do not: `patrolPartitions` answers the same empty success on the
+leader and on a follower, whether or not it repaired anything (look for
+`reallocShards`, `shardOffline` or `storeTurnoff` lines, or diff
+`/v1/shardGroups` before and after), and `balancePartitions` answers `{}`
+on the leader and an empty body on a follower. `balanceLeaders` is the one
+call whose body carries the work. Distinguishable task responses are
+upstream work, tracked in
+[apache/hugegraph#3231](https://github.com/apache/hugegraph/issues/3231).
+
+Run `patrolPartitions` after replacing a Store that is not coming back,
+`balancePartitions` once the cluster is stable again, and `balanceLeaders`
+after restarts that skewed leader placement.
+
+**Losing a Store volume.** A Store rebuilt with an empty PVC recovers in
+place on images carrying
+[apache/hugegraph#3234](https://github.com/apache/hugegraph/pull/3234)
+(merged 2026-09-24); on every earlier image, including all published
+release images, it does not. In both cases the replacement registers under
+a new Store ID while its Pod name, DNS name, and raft address are
+unchanged, so `/v1/stores` lists two IDs at one address.
+
+On post-#3234 images the retirement works: find the old ID in `/v1/stores`
+(the row at the replaced Pod's address that is not the newly registered
+one), `POST /v1/store/<oldId>` with `{"storeState":"Tombstone"}` on the PD
+leader, run `GET /v1/task/patrolPartitions`, and wait; verify every shard
+group is back to full shard count with one leader, no group names the old
+ID, and the replaced Store's own `:8520/v1/partition/<groupId>` answers
+200 for every group; then `DELETE /v1/store/<oldId>` to erase the retired
+record. Measured on a 3+3+3 install with images built from `master` at
+`dbb6663a`: the replacement was Ready in 156 s, all 12 groups converged
+onto the new ID 1 s after the Tombstone and patrol (the empty Store caught
+up by raft snapshot install), and a continuous writer lost 0 acknowledged
+writes.
+
+On images without #3234 the same retirement runs and does not repair the
+groups: PD fires the configuration change, but the group leader sees the
+address already in the group, so jraft has nothing to add and the group
+keeps the old ID. Measured: 20 minutes and three patrols later, all 12
+groups still listed the retired ID and the replacement Store held no
+partitions. Nothing in the health surface shows the failure; `/v1/stores`,
+cluster state, Hubble, and Pod readiness all read healthy while every
+shard group runs on two live replicas. The one check that shows it is the
+replaced Store's own `:8520/v1/partition/<groupId>`.
+
+So the default remains: replace a Store Pod, keep its PVC (the Store id
+lives in the data path, and the Pod comes back under the same id). Treat
+the empty-PVC procedure as recovery for post-#3234 images only; on a
+released image a genuinely lost volume leaves the cluster degraded, and
+expect to rebuild rather than to recover in place.
+
+Periodic leader balancing is tracked in
+[apache/hugegraph#3135](https://github.com/apache/hugegraph/issues/3135);
+disaster-recovery metrics in
+[apache/hugegraph#3136](https://github.com/apache/hugegraph/issues/3136).
+
+### 8 Scaling
+
+PD and Store reserve the maximum StatefulSet ordinal in their resource
+names, so scaling never renames a PersistentVolumeClaim or shifts a Pod
+identity; both are capped at 99 replicas. Server scales freely through
+`server.replicas` or `server.hpa` (with HPA on, the Deployment omits
+`spec.replicas` so upgrades do not overwrite the autoscaler).
+
+A staged rollout cannot be written in a values file (the schema requires
+one replica per component); stage it with `kubectl scale statefulset
+hugegraph-store --replicas=0` and scale back up when ready. The Servers
+wait, not ready, until Stores register, and the next `helm upgrade`
+restores the full topology from values.
+
+Changing PD or Store replicas on a live release is not a values change:
+raft and shard membership are persisted, and Pods alone do not reconfigure
+them. The chart rejects both directions for PD and a shrink for Store by
+reading the live StatefulSet, so fresh installs at any count are
+unaffected.
+
+**PD, either direction.** The rendered peer list reaches raft only as its
+bootstrap configuration, which an initialized group ignores; a 3-to-5
+upgrade leaves the voting configuration at three, and a 3-to-1 shrink
+loses quorum outright. Membership changes go through PD's peer-list
+change, which the PD client API and the PD REST route
+`POST /v1/members/change` both expose; the route needs the same Basic
+authentication as the other PD REST routes, and the chart wraps neither.
+Change the membership through PD, confirm it in `/v1/members`, scale the
+live StatefulSet, then `helm upgrade` with the matching value; until that
+sequence is verified on your own build, install the PD count you intend
+to keep.
+
+**Store, shrinking.** Draining is a state transition, not a balance:
+neither `patrolPartitions` nor `balancePartitions` retires a healthy
+Store. Retire the leaving Stores the way Disaster Recovery retires a
+replaced one:
+
+1. Check the remaining Stores still cover the persisted shard count
+   (`pd.partition.defaultShardCount`; empty derives 3 when
+   `store.replicas` is at least 3).
+2. Map the ordinals the shrink will delete (the highest ones) to Store
+   ids through `/v1/stores`, matching on the Pod address.
+3. `POST /v1/store/<id>` with `{"storeState":"Tombstone"}` for each

Review Comment:
   Important: Step 3 cannot succeed on a cluster this chart deployed. The chart sets `HG_PD_INITIAL_STORE_COUNT` to `store.replicas` ([pd-statefulset.yaml L123-124](https://github.com/apache/hugegraph/blob/8fd9841ebc6770df6119fdce07249fa9e558ae9e/helm/hugegraph/templates/pd-statefulset.yaml#L123-L124)), and that value is PD's `minStoreCount` ([PDConfig L63-64](https://github.com/apache/hugegraph/blob/8fd9841ebc6770df6119fdce07249fa9e558ae9e/hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/config/PDConfig.java#L63-L64)). `POST /v1/store/<id>` goes through `PDRestService.updateStore` into `StoreNodeService.updateStore`, which refuses a Tombstone for a Store whose last state is `Up` when `getStores().size() - 1 < minStoreCount` ([StoreNodeService L271-278](https://github.com/apache/hugegraph/blob/8fd9841ebc6770df6119fdce07249fa9e558ae9e/hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/StoreNodeService.java#L271-L278)). On a fresh 5-Store install, retiring a hea
 lthy Store gives 5 - 1 < 5, so PD returns `LESS_ACTIVE_STORE` ("The number of active stores is less then 5"). `StoreAPI.setStore` serializes that exception into the JSON body instead of failing the request, so an operator following the steps may not notice. Step 4 then never finishes. The Disaster Recovery retirement passes this check only because the replacement adds a second record at the same address. I traced this in the source at apache/hugegraph master 8fd9841eb and did not run it on a cluster. Please say that PD refuses to Tombstone an `Up` Store while the chart pins `pd.initial-store-count` to the current `store.replicas`. Then either document a path that works or mark Store shrink as unsupported for now, as the page already does for PD. Please make the same change in the Chinese page, section 8 step 3 (line 297).



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,523 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward. It runs in the foreground, so keep
+it in one terminal:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+```
+
+and call the API from a second terminal, with `PASSWORD` set as above:
+
+```bash
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry. An
+in-cluster Hubble in `pd` mode combined with `server.advertiseUrl` also
+fails the render until `networkPolicy.hubble.extraEgress` admits the
+advertised destination: PD hands Hubble that URL for discovery, and
+Hubble's egress policy otherwise reaches only the release's own Pods.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. `values-cluster.yaml` therefore sets
+`store.updateStrategy.type=OnDelete` (set it yourself on any other
+production values): an upgrade then updates the StatefulSet without
+replacing any Store Pod, and you delete Store Pods one at a time, checking
+between deletions. `OnDelete` only stops automatic advancement; deleting
+Pods without the checks below carries the same risk.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, leader, and
+committed index (`logIndex`) that Store holds, and fails while the Store
+is down; compare the index with a peer Store rather than reading it
+alone. This route never fills its `term` field, so `term` always reads 0
+there. The plural `GET :8520/v1/partitions` answers 500 on any Store that
+follows a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a
+group that is short a shard or has no leader as a stop. A real
+restoration-complete signal is upstream work, tracked in
+[apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229).
+
+### 7 Disaster recovery
+
+What PD automates on current builds is narrow: a 60-second patrol only
+marks Stores that stopped sending heartbeats as `Offline`. There is no
+automatic re-replication; re-placing the replicas of a lost Store,
+reconciling shard groups, and processing tombstoned Stores run only when a
+partition patrol is triggered explicitly.
+
+The task endpoints execute locally on the PD that receives them, and a
+follower answers with an empty success while doing nothing.
+Port-forwarding the client Service selects an arbitrary PD, so identify
+the leader first, then port-forward that Pod (two terminals: the forward
+runs in the foreground):
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-pd-client 8620:8620
+# Read .data.pdLeader.raftUrl; its host names the leader Pod.
+curl -su "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/members
+# Stop the Service forward, then forward the leader Pod instead.
+kubectl port-forward -n hugegraph pod/<leader-pod> 8620:8620
+# Reconcile shard groups and process tombstoned Stores.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/patrolPartitions
+# If the patrol repaired a shard group, wait 180 s first (see below).
+# Spread Raft leaders, then partition data.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balanceLeaders
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balancePartitions
+```
+
+Read `/v1/members` again after the tasks: if leadership moved mid-sequence,
+the later tasks ran on a follower and did nothing. PD sets a
+balance-shard flag for 180 s in two cases: `patrolPartitions` sets it
+whenever it reallocates a shard group whose shard count is wrong, and
+`balancePartitions` sets it even when it moves nothing. Inside that
+window `balanceLeaders` is refused and `balancePartitions` returns
+without doing anything, so wait at least 180 s after a patrol that
+repaired a group, and after `balancePartitions`, before the next
+balancing call. On images built before
+[apache/hugegraph#3233](https://github.com/apache/hugegraph/pull/3233)
+(merged 2026-09-24) the refusal is a bare HTTP 500 whose reason appears
+only in the PD log; after it, the reason comes back in the body as
+`{"status":1001,"error":"balance shard is processing, please try later!"}`.
+
+Telling a real run from a no-op takes the PD leader's log, because the
+responses do not: `patrolPartitions` answers the same empty success on the
+leader and on a follower, whether or not it repaired anything (look for
+`reallocShards`, `shardOffline` or `storeTurnoff` lines, or diff
+`/v1/shardGroups` before and after), and `balancePartitions` answers `{}`
+on the leader and an empty body on a follower. `balanceLeaders` is the one
+call whose body carries the work. Distinguishable task responses are
+upstream work, tracked in
+[apache/hugegraph#3231](https://github.com/apache/hugegraph/issues/3231).
+
+Run `patrolPartitions` after replacing a Store that is not coming back,
+`balancePartitions` once the cluster is stable again, and `balanceLeaders`
+after restarts that skewed leader placement.
+
+**Losing a Store volume.** A Store rebuilt with an empty PVC recovers in
+place on images carrying
+[apache/hugegraph#3234](https://github.com/apache/hugegraph/pull/3234)
+(merged 2026-09-24); on every earlier image, including all published
+release images, it does not. In both cases the replacement registers under
+a new Store ID while its Pod name, DNS name, and raft address are
+unchanged, so `/v1/stores` lists two IDs at one address.
+
+On post-#3234 images the retirement works: find the old ID in `/v1/stores`
+(the row at the replaced Pod's address that is not the newly registered
+one), `POST /v1/store/<oldId>` with `{"storeState":"Tombstone"}` on the PD
+leader, run `GET /v1/task/patrolPartitions`, and wait; verify every shard
+group is back to full shard count with one leader, no group names the old
+ID, and the replaced Store's own `:8520/v1/partition/<groupId>` answers
+200 for every group; then `DELETE /v1/store/<oldId>` to erase the retired
+record. Measured on a 3+3+3 install with images built from `master` at
+`dbb6663a`: the replacement was Ready in 156 s, all 12 groups converged
+onto the new ID 1 s after the Tombstone and patrol (the empty Store caught
+up by raft snapshot install), and a continuous writer lost 0 acknowledged
+writes.
+
+On images without #3234 the same retirement runs and does not repair the
+groups: PD fires the configuration change, but the group leader sees the
+address already in the group, so jraft has nothing to add and the group
+keeps the old ID. Measured: 20 minutes and three patrols later, all 12
+groups still listed the retired ID and the replacement Store held no
+partitions. Nothing in the health surface shows the failure; `/v1/stores`,
+cluster state, Hubble, and Pod readiness all read healthy while every
+shard group runs on two live replicas. The one check that shows it is the
+replaced Store's own `:8520/v1/partition/<groupId>`.
+
+So the default remains: replace a Store Pod, keep its PVC (the Store id
+lives in the data path, and the Pod comes back under the same id). Treat
+the empty-PVC procedure as recovery for post-#3234 images only; on a
+released image a genuinely lost volume leaves the cluster degraded, and
+expect to rebuild rather than to recover in place.
+
+Periodic leader balancing is tracked in
+[apache/hugegraph#3135](https://github.com/apache/hugegraph/issues/3135);
+disaster-recovery metrics in
+[apache/hugegraph#3136](https://github.com/apache/hugegraph/issues/3136).
+
+### 8 Scaling
+
+PD and Store reserve the maximum StatefulSet ordinal in their resource
+names, so scaling never renames a PersistentVolumeClaim or shifts a Pod
+identity; both are capped at 99 replicas. Server scales freely through
+`server.replicas` or `server.hpa` (with HPA on, the Deployment omits
+`spec.replicas` so upgrades do not overwrite the autoscaler).
+
+A staged rollout cannot be written in a values file (the schema requires
+one replica per component); stage it with `kubectl scale statefulset
+hugegraph-store --replicas=0` and scale back up when ready. The Servers
+wait, not ready, until Stores register, and the next `helm upgrade`
+restores the full topology from values.
+
+Changing PD or Store replicas on a live release is not a values change:
+raft and shard membership are persisted, and Pods alone do not reconfigure
+them. The chart rejects both directions for PD and a shrink for Store by

Review Comment:
   Minor: This section and the deployment page treat Store growth as a plain values change, but three things about it go undocumented. (1) With the default `store.pdb.minAvailable: 2`, `--set store.replicas=5` fails to render with "store.pdb.minAvailable must be at least store.replicas - 1" ([_helpers.tpl L780-781](https://github.com/apache/hugegraph/blob/8fd9841ebc6770df6119fdce07249fa9e558ae9e/helm/hugegraph/templates/_helpers.tpl#L780-L781)); `store.pdb.minAvailable` has to move with the replica count in both directions, which also affects the `helm upgrade` in step 5 of the shrink below. (2) `HG_PD_INITIAL_STORE_LIST` and `HG_PD_INITIAL_STORE_COUNT` live in the PD Pod template, so growing Store rolls every PD Pod. A `helm template` diff of `store.replicas` 3 against 5 shows only those two PD env values changing. (3) PD schedules no balance task ([TaskScheduleService.init](https://github.com/apache/hugegraph/blob/8fd9841ebc6770df6119fdce07249fa9e558ae9e/hugegraph-pd/hg-pd-core/src
 /main/java/org/apache/hugegraph/pd/TaskScheduleService.java#L121)), so new Stores hold no partitions until `balancePartitions` runs on the PD leader. Please add a short "Store, growing" paragraph that covers these three points and then the check from section 6 (full shard count, one Leader). Please sync the Chinese page, section 8 (line 283).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
bitflicker64 commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4051992998


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).

Review Comment:
   ⚠️ important: the PR body already links #3218, so this is only about merge order. The chart is not on apache/hugegraph master yet: `gh api repos/apache/hugegraph/contents/helm?ref=master` returns 404, #3132 was closed without merging, and #3218 is still an open draft. If this PR merges first, the site publishes a guide where the `helm install` in 3.2 fails because `helm/hugegraph` does not exist on master, and all seven `tree/master/helm/hugegraph` links on the page (EN and CN) are 404s. Please convert this PR to draft until #3218 merges.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later

Review Comment:
   🧹 minor: section 7 of this page never mentions `--reset-then-reuse-values`, so this cross-reference points at nothing (CN line 45 too). The chart README brings it up under Upgrading for a reason: `--reuse-values` keeps the old release values as the whole base, so a release created by an earlier chart revision does not pick up new defaults such as the hardened `securityContext`. Please add that sentence to section 7 next to the `--reuse-values` explanation, or drop the reference here.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |

Review Comment:
   🧹 minor: the PD and Store PodDisruptionBudgets are not what `values-cluster.yaml` adds. `values.yaml` already sets `pd.pdb.enabled: true` and `store.pdb.enabled: true`, and `helm template t ./helm/hugegraph` renders both PDBs with default values. The preset's addition is the Server PDB (`server.pdb.enabled: true`, `minAvailable: 2`); rendering with `-f values-cluster.yaml` gives pd, server and store PDBs. Please say "Server PodDisruptionBudget" here and in CN line 96. The chart README's Values Presets table has the same wording.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable

Review Comment:
   🧹 minor: the schema is stricter than this sentence. `pd.auth.value` must match `^([\x21-\x5b\x5d-\x7e][\x20-\x5b\x5d-\x7e]*)?$`, so a printable ASCII secret with a backslash or a leading space is rejected (`helm template` with `pd.auth.value: "abc\\def"` fails schema validation). The admin password pattern also rejects leading whitespace. Please list both: the PD secret is printable ASCII with no leading whitespace and no backslashes, and the admin password has no newlines, carriage returns, backslashes or leading whitespace. CN line 135 needs the same change.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** stay on `/v1/health` on purpose: a PD that merely lost its leader is
+still a healthy Raft member, and restarting it would make the outage worse.
+
+Server startup gets a matching budget: the image would normally kill a Server still starting after 120 seconds, so
+the chart derives `HG_SERVER_STARTUP_TIMEOUT_S` from the startup probe (450 seconds by default) and raises a lower

Review Comment:
   🧹 minor: "a matching budget" and "the image budget follows" read as if the image gets the full 450 s, but it does not. `hugegraph.server.startupTimeoutSeconds` in `_helpers.tpl` renders `min 86400 (max 120 (budget - 300))`, the probe budget minus the 300 s storage wait, and `tests/server_startup_timeout_test.yaml` asserts `"150"` for the defaults. Please say the probe budget is 450 s by default and the image gets that budget minus the 300 s storage wait (150 s by default, never below 120 s); CN lines 160-161 too. The chart README's Chart Details bullet also says the image gets 450, so #3218 may need the same fix.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
bitflicker64 commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4114363556


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,282 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+Day-2 work (NetworkPolicy details, disaster recovery, scaling, safe Store
+rolls, running Hubble outside the cluster) is on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity, NetworkPolicy on |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. One of its numbers deserves a note: it requests 5Gi and limits at 8Gi of memory per Store, well above the
+1Gi heap, because the Store's RocksDB caches live outside the JVM heap (a 4Gi limit OOM-killed Stores after about
+1 GB of data). Scale both numbers with data size. The full parameter reference (every component, probe,
+scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** derive from the replica count (`pd.livenessPath` overrides the
+choice). With more than one PD they stay on `/v1/health` on purpose: a PD that merely lost its leader is still a
+healthy Raft member, and restarting it would make the outage worse. A single PD is the exception and derives to
+`/v1/ready`: it has no election to lose, and one that steps down for good, as after a failed Raft snapshot on a
+full disk ([apache/hugegraph#3222](https://github.com/apache/hugegraph/issues/3222)), would answer `/v1/health`
+forever while serving no writes; the kubelet restarts it instead.
+
+Server startup gets a matching budget: the image would normally kill a Server still starting after 120 seconds, so
+the chart derives `HG_SERVER_STARTUP_TIMEOUT_S` from the startup probe (450 seconds by default) and raises a lower
+configured probe budget to that floor. Raise `server.probes.startup` if your storage takes longer to come up, and
+the image budget follows.
+
+### 6 Enable the Hubble UI
+
+Hubble is off by default so API-only clusters stay lean. Enable it on a running release:
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values --set hubble.enabled=true
+```
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-hubble 8088:8088
+```
+
+Open `http://127.0.0.1:8088` and log in as `admin` with the admin password from Section 3.4. Hubble discovers the
+Servers through PD, so the cluster operations view works without extra wiring. Hubble serves plain HTTP: reach it
+through a port-forward or an HTTPS-terminating Ingress, never directly from an untrusted network. Running Hubble
+outside the cluster is possible but takes more wiring; see
+[Reaching Hubble](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#reaching-hubble-pick-one-path) in
+the chart README.
+
+### 7 Upgrade
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values
+```
+
+`--reuse-values` keeps the release's existing overrides; without it the upgrade rebuilds the release from chart
+defaults. Any upgrade that changes a Pod template rolls that workload once. Points worth planning around:
+
+- **The first upgrade after a fresh install rolls PD, Server, and Hubble once**, when the Secret-tracking

Review Comment:
   Important: this bullet tells the reader the first upgrade rolls PD and Server together, but the page never says what that roll can break. The chart README lists it under Upgrading the Chart: a Server that starts while PD is rolling can come up without its Gremlin binding, pass readiness, serve REST, and fail every Gremlin request with `Could not rebind [graph]` for the life of the Pod. The operations page (section 10) measured 4 of 12 Server starts hitting this. Every fresh install reaches this case, and the Hubble command in section 6 is usually that first upgrade. Section 9 and the troubleshooting table on this page only describe the short convergence window after creating a graph, so a reader who follows this page has no reason to check. Please add a sentence here that after any upgrade that rolls PD and Server, Gremlin should be checked on each Server Pod and a failing Pod deleted, with a link to operations section 10, and add the persistent cause to the troubleshooting row. T
 he CN page needs the same change at lines 197-198.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,282 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+Day-2 work (NetworkPolicy details, disaster recovery, scaling, safe Store
+rolls, running Hubble outside the cluster) is on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity, NetworkPolicy on |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. One of its numbers deserves a note: it requests 5Gi and limits at 8Gi of memory per Store, well above the
+1Gi heap, because the Store's RocksDB caches live outside the JVM heap (a 4Gi limit OOM-killed Stores after about
+1 GB of data). Scale both numbers with data size. The full parameter reference (every component, probe,
+scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** derive from the replica count (`pd.livenessPath` overrides the
+choice). With more than one PD they stay on `/v1/health` on purpose: a PD that merely lost its leader is still a
+healthy Raft member, and restarting it would make the outage worse. A single PD is the exception and derives to
+`/v1/ready`: it has no election to lose, and one that steps down for good, as after a failed Raft snapshot on a
+full disk ([apache/hugegraph#3222](https://github.com/apache/hugegraph/issues/3222)), would answer `/v1/health`
+forever while serving no writes; the kubelet restarts it instead.
+
+Server startup gets a matching budget: the image would normally kill a Server still starting after 120 seconds, so
+the chart derives `HG_SERVER_STARTUP_TIMEOUT_S` from the startup probe (450 seconds by default) and raises a lower
+configured probe budget to that floor. Raise `server.probes.startup` if your storage takes longer to come up, and
+the image budget follows.
+
+### 6 Enable the Hubble UI
+
+Hubble is off by default so API-only clusters stay lean. Enable it on a running release:
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values --set hubble.enabled=true
+```
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-hubble 8088:8088
+```
+
+Open `http://127.0.0.1:8088` and log in as `admin` with the admin password from Section 3.4. Hubble discovers the
+Servers through PD, so the cluster operations view works without extra wiring. Hubble serves plain HTTP: reach it
+through a port-forward or an HTTPS-terminating Ingress, never directly from an untrusted network. Running Hubble
+outside the cluster is possible but takes more wiring; see
+[Reaching Hubble](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#reaching-hubble-pick-one-path) in
+the chart README.
+
+### 7 Upgrade
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values
+```
+
+`--reuse-values` keeps the release's existing overrides; without it the upgrade rebuilds the release from chart
+defaults. Any upgrade that changes a Pod template rolls that workload once. Points worth planning around:
+
+- **The first upgrade after a fresh install rolls PD, Server, and Hubble once**, when the Secret-tracking
+  annotations first observe the install-created Secrets. Store is untouched.
+- **Store rolling updates advance on a listener check, not on shard recovery**, so the controller can replace the
+  next Store while the previous one is still rejoining its shard groups. For a production image roll, set
+  `store.updateStrategy.type=OnDelete` and replace Store pods one at a time. `Up` in PD is not the between-pods
+  check: PD marks a Store `Up` at registration, before it restores partitions, and a stopped Store stays `Up`
+  until a 300 s keep-alive expires. Wait for the replaced Pod to be `Ready`, then confirm every shard group
+  reports its full shard count with one leader; the full procedure is on the
+  [operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/). PD restarts are one pod at a time
+  either way, and `pd.updateStrategy.type=OnDelete` gives the same manual control for maintenance windows.
+- **PVC sizes cannot be changed by upgrade**: Kubernetes forbids changing StatefulSet `volumeClaimTemplates`, so an
+  upgrade with a new `storage.size` is rejected in full. The chart README documents the resize procedure for
+  StorageClasses that support volume expansion.
+
+Scaling Server up and down is a values change (`server.replicas`, or `server.hpa`). Scaling **PD or Store down is
+not**: Raft and shard membership are persisted, deleting pods does not reconfigure them, and a 3-to-1 PD shrink
+permanently loses quorum. The chart rejects an upgrade whose replica count is below the live StatefulSet; the

Review Comment:
   Minor: this paragraph says only PD or Store scale-down is not a values change and that the chart rejects a replica count below the live StatefulSet. The chart also rejects PD growth: `templates/_helpers.tpl` in #3218 fails with `pd.replicas cannot grow from %d to %d through a helm upgrade` when the desired PD count is above the live one, because the rendered peer list reaches raft only as the initial configuration. The operations page (section 8) already says the chart rejects both directions for PD. A reader who stops at this page will expect a 3-to-5 PD upgrade to work. Please say that PD replicas cannot change in either direction and Store cannot shrink through `helm upgrade`, and link to operations section 8. Same wording in CN lines 208-210.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4102571008


##########
content/cn/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,356 @@
+---
+title: "在 Kubernetes 上运维 HugeGraph"
+linkTitle: "Kubernetes 运维 (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 适用范围
+
+本页面向已经用 Helm chart 部署好 HugeGraph 集群的运维场景。安装、升级、卸载见
+[部署页](/cn/docs/quickstart/hugegraph/hugegraph-helm/);完整参数参考仍在
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration)。
+
+下文命令假定 release 名为 `hugegraph`、namespace 为 `hugegraph`,请按需替换。两个凭据会反复用到,都从
+chart 管理的 Secret 读取:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 端口与健康
+
+| 组件 | 端口 | 用途 |
+|------|------|------|
+| PD | `8686` | gRPC(Store 与 Server 客户端) |
+| PD | `8620` | REST / 健康探测 |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / 健康探测 |
+| Server | `8080` | Gremlin 与 REST API |
+
+所有端口都可以通过 values 配置;修改 `server.port` 会同时更新监听、容器端口和 Service。进程存活但停止响应的组件由
+存活探测终结:默认 20 秒周期、3 次失败阈值把一个卡死 Store 的影响时间限制在约一分钟内,重启后 raft 几秒内就会转移
+它持有的分区 leader。
+
+通过 port-forward 访问 API:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs

Review Comment:
   这段代码会按顺序执行,但 `kubectl port-forward` 会一直占用前台,因此除非另开终端,后面的 `curl` 命令永远不会执行。请明确说明需要两个终端,确保这些健康检查可以照着运行。



##########
content/cn/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,251 @@
+---
+title: "使用 Helm 在 Kubernetes 上部署"
+linkTitle: "Kubernetes 部署 (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 概述
+
+Helm chart 在 Kubernetes 上部署一套分布式 HugeGraph 集群:PD、Store、Server,以及可选的 Hubble UI。chart 位于主仓库的
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph) 目录。
+
+| 组件 | 工作负载 | 默认副本数 | 作用 |
+|------|----------|------------|------|
+| PD | StatefulSet + PVC | 3 | 元数据管理:以 Raft 组跟踪 Store 与分区 |
+| Store | StatefulSet + PVC | 3 | 图数据存储 (HStore) |
+| Server | Deployment | 3 | Gremlin 与 REST 查询层 |
+| Hubble | Deployment | 0(默认关闭) | Web UI,通过 `hubble.enabled=true` 启用 |
+
+分布式 HugeGraph 集群有一套启动约定(Server 不执行 `init-store`、每个 Server 都通过 PD 读写图元数据、Store 等待 PD
+形成多数派、一个 PD REST 密钥由三个组件共用)。chart 把这套约定固化下来,运维人员无需手工处理;细节见
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details)。日常运维(NetworkPolicy
+细节、灾难恢复、伸缩、安全滚动 Store、在集群外运行 Hubble)见
+[运维页](/cn/docs/quickstart/hugegraph/hugegraph-helm-operations/)。
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes 集群
+        PD[PD StatefulSet<br>3 节点 Raft 组,PVC]
+        Store[Store StatefulSet<br>3 副本,PVC] -->|注册、心跳| PD
+        Server[Server Deployment<br>3 副本] -->|元数据、服务发现| PD
+        Server -->|gRPC 读写| Store
+        Hubble[Hubble Deployment<br>可选 UI] -->|通过 PD 发现 Server| PD
+    end
+    Client[客户端 / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+启动顺序由 chart 保证,而不是由运维人员保证:PD 先选出 leader,每个 Store Pod 的 init 容器等到多数 PD 汇报就绪后才启动,
+Server 则反复等待存储层,直到 Store 完成注册。全新安装无需手工干预即可收敛。
+
+### 2 前置条件
+
+- Kubernetes 1.23 及以上(chart 渲染 `autoscaling/v2` 和 `policy/v1`)
+- Helm 3;升级一节提到的 `--reset-then-reuse-values` 需要 Helm 3.14 及以上
+- 动态卷供给:有默认 StorageClass,或为 PD 和 Store 显式指定 `storageClassName`
+- 默认拓扑要运行九个 JVM 进程,内存需留足;见安装一节的资源说明
+
+chart 要求组件镜像包含 PD 就绪探测端点和 PD REST 认证(两者都已合入 1.7.0 之后的版本)。默认镜像 tag 指向的构建已包含
+这些改动;1.7.0 镜像不受支持。
+
+### 3 安装
+
+#### 3.1 获取 chart
+
+chart 尚未发布到 chart 仓库,从源码树安装:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 使用默认值安装
+
+先确认 `kubectl` 指向目标集群,且集群能供给存储卷。因缺少 StorageClass 而卡在 `Pending` 的 PVC 是最常见的首次安装
+故障:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+然后安装:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` 让 Helm 阻塞到所有工作负载就绪。对分布式集群来说,这个信号意味着 PD 已选出 leader、Store 已注册、Server 已
+启动;不加它,`helm install` 在对象创建完成后就返回。全新集群一般几分钟内收敛,15 分钟超时是给缓慢的镜像拉取留的余量。
+
+继续之前需要了解两个默认值:
+
+- **默认不设置 resources。** 每个 Pod 都是 BestEffort,JVM 按节点总内存计算堆大小。单节点没有问题;多节点集群上各个堆
+  会超订节点内存导致进程中止。超出笔记本范围的部署请使用 `values-cluster.yaml`,或按组件设置 `resources`。
+- **镜像 tag 跟踪 `latest`**,且 `pullPolicy: Always`,直到下一个 HugeGraph 版本发布。生产环境请固定 tag 或 digest。
+
+#### 3.3 拓扑预设
+
+chart 附带三个 values 文件:
+
+| 文件 | 拓扑 | 适用场景 |
+|------|------|----------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | 默认;preferred 反亲和,认证开启,Hubble 关闭 |
+| `values-single.yaml` | 1 + 1 + 1 | 单节点开发与 CI;PVC 更小 |
+| `values-cluster.yaml` | 3 + 3 + 3 | 生产起点:JVM 堆与资源设置、PD/Store PodDisruptionBudget、`required` 反亲和、NetworkPolicy 开启 |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` 是起点而非容量保证:请按图规模和流量重新核算资源。其中一个数字值得说明:它给每个 Store 申请
+5Gi、限制 8Gi 内存,远高于 1Gi 的堆,因为 Store 的 RocksDB 缓存在 JVM 堆之外(4Gi 的限制在约 1 GB 数据后就把
+Store OOM 杀掉了)。两个数字要随数据量一起放大。完整参数参考(每个组件的探针、调度、Secret 配置项)见
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration)。
+
+#### 3.4 验证安装
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+读取自动生成的 admin 密码并调用 API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions

Review Comment:
   `kubectl port-forward` 会以前台方式运行,因此直接复制这段命令时永远不会执行后面的 `curl`,安装验证会一直挂起。请明确拆分到两个终端,或让 port-forward 后台运行并在请求后清理它。



##########
content/cn/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,251 @@
+---
+title: "使用 Helm 在 Kubernetes 上部署"
+linkTitle: "Kubernetes 部署 (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 概述
+
+Helm chart 在 Kubernetes 上部署一套分布式 HugeGraph 集群:PD、Store、Server,以及可选的 Hubble UI。chart 位于主仓库的
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph) 目录。
+
+| 组件 | 工作负载 | 默认副本数 | 作用 |
+|------|----------|------------|------|
+| PD | StatefulSet + PVC | 3 | 元数据管理:以 Raft 组跟踪 Store 与分区 |
+| Store | StatefulSet + PVC | 3 | 图数据存储 (HStore) |
+| Server | Deployment | 3 | Gremlin 与 REST 查询层 |
+| Hubble | Deployment | 0(默认关闭) | Web UI,通过 `hubble.enabled=true` 启用 |
+
+分布式 HugeGraph 集群有一套启动约定(Server 不执行 `init-store`、每个 Server 都通过 PD 读写图元数据、Store 等待 PD
+形成多数派、一个 PD REST 密钥由三个组件共用)。chart 把这套约定固化下来,运维人员无需手工处理;细节见
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details)。日常运维(NetworkPolicy
+细节、灾难恢复、伸缩、安全滚动 Store、在集群外运行 Hubble)见
+[运维页](/cn/docs/quickstart/hugegraph/hugegraph-helm-operations/)。
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes 集群
+        PD[PD StatefulSet<br>3 节点 Raft 组,PVC]
+        Store[Store StatefulSet<br>3 副本,PVC] -->|注册、心跳| PD
+        Server[Server Deployment<br>3 副本] -->|元数据、服务发现| PD
+        Server -->|gRPC 读写| Store
+        Hubble[Hubble Deployment<br>可选 UI] -->|通过 PD 发现 Server| PD
+    end
+    Client[客户端 / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+启动顺序由 chart 保证,而不是由运维人员保证:PD 先选出 leader,每个 Store Pod 的 init 容器等到多数 PD 汇报就绪后才启动,
+Server 则反复等待存储层,直到 Store 完成注册。全新安装无需手工干预即可收敛。
+
+### 2 前置条件
+
+- Kubernetes 1.23 及以上(chart 渲染 `autoscaling/v2` 和 `policy/v1`)
+- Helm 3;升级一节提到的 `--reset-then-reuse-values` 需要 Helm 3.14 及以上
+- 动态卷供给:有默认 StorageClass,或为 PD 和 Store 显式指定 `storageClassName`
+- 默认拓扑要运行九个 JVM 进程,内存需留足;见安装一节的资源说明
+
+chart 要求组件镜像包含 PD 就绪探测端点和 PD REST 认证(两者都已合入 1.7.0 之后的版本)。默认镜像 tag 指向的构建已包含
+这些改动;1.7.0 镜像不受支持。
+
+### 3 安装
+
+#### 3.1 获取 chart
+
+chart 尚未发布到 chart 仓库,从源码树安装:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 使用默认值安装
+
+先确认 `kubectl` 指向目标集群,且集群能供给存储卷。因缺少 StorageClass 而卡在 `Pending` 的 PVC 是最常见的首次安装
+故障:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+然后安装:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` 让 Helm 阻塞到所有工作负载就绪。对分布式集群来说,这个信号意味着 PD 已选出 leader、Store 已注册、Server 已
+启动;不加它,`helm install` 在对象创建完成后就返回。全新集群一般几分钟内收敛,15 分钟超时是给缓慢的镜像拉取留的余量。
+
+继续之前需要了解两个默认值:
+
+- **默认不设置 resources。** 每个 Pod 都是 BestEffort,JVM 按节点总内存计算堆大小。单节点没有问题;多节点集群上各个堆
+  会超订节点内存导致进程中止。超出笔记本范围的部署请使用 `values-cluster.yaml`,或按组件设置 `resources`。
+- **镜像 tag 跟踪 `latest`**,且 `pullPolicy: Always`,直到下一个 HugeGraph 版本发布。生产环境请固定 tag 或 digest。
+
+#### 3.3 拓扑预设
+
+chart 附带三个 values 文件:
+
+| 文件 | 拓扑 | 适用场景 |
+|------|------|----------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | 默认;preferred 反亲和,认证开启,Hubble 关闭 |
+| `values-single.yaml` | 1 + 1 + 1 | 单节点开发与 CI;PVC 更小 |
+| `values-cluster.yaml` | 3 + 3 + 3 | 生产起点:JVM 堆与资源设置、PD/Store PodDisruptionBudget、`required` 反亲和、NetworkPolicy 开启 |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` 是起点而非容量保证:请按图规模和流量重新核算资源。其中一个数字值得说明:它给每个 Store 申请
+5Gi、限制 8Gi 内存,远高于 1Gi 的堆,因为 Store 的 RocksDB 缓存在 JVM 堆之外(4Gi 的限制在约 1 GB 数据后就把
+Store OOM 杀掉了)。两个数字要随数据量一起放大。完整参数参考(每个组件的探针、调度、Secret 配置项)见
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration)。
+
+#### 3.4 验证安装
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+读取自动生成的 admin 密码并调用 API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+以上命令假定 release 名为 `hugegraph`;用其他名字时,请替换成带 release 前缀的资源名(`kubectl get svc,secret -n
+<namespace>` 可以列出)。`helm install` 结束时打印的说明里包含填好名字的同样命令。
+
+### 4 认证与 Secret
+
+认证默认开启,chart 管理三个 Secret。每个凭据按同一顺序取值:你预先创建的 `existingSecret` 优先,其次是内联值,最后
+是安装时随机生成。
+
+| Secret | 键 | 用途 | 自带凭据的配置项 |
+|--------|-----|------|------------------|
+| `<release>-admin` | `password` | Server admin 账号、Hubble 登录 | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | 所有 Server 副本共用的 JWT 签名密钥 | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST 认证,由 PD、Server、Hubble 读取 | `pd.auth.existingSecret` |
+
+要自行管理凭据,请在安装前创建 Secret 并把对应的 `existingSecret` 指向它;chart 不会改动任何不是它创建的 Secret。取值
+约束:admin 密码不能包含换行、回车或反斜杠;JWT 密钥至少 32 字节;PD 密钥必须是可打印 ASCII。非法值会在渲染时或启动

Review Comment:
   The constraint list omits a rejection that the chart's Server wrapper also enforces: admin passwords beginning with a space or tab fail startup. Add the leading-whitespace restriction here so the Chinese page does not advertise a value that renders successfully but leaves the Server unable to start.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,483 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs

Review Comment:
   This code block is sequential, but `kubectl port-forward` remains in the foreground, so the following `curl` commands are never reached unless the reader opens a second terminal. Mark the two-terminal workflow so these health checks are actually runnable.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,282 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+Day-2 work (NetworkPolicy details, disaster recovery, scaling, safe Store
+rolls, running Hubble outside the cluster) is on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity, NetworkPolicy on |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. One of its numbers deserves a note: it requests 5Gi and limits at 8Gi of memory per Store, well above the
+1Gi heap, because the Store's RocksDB caches live outside the JVM heap (a 4Gi limit OOM-killed Stores after about
+1 GB of data). Scale both numbers with data size. The full parameter reference (every component, probe,
+scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable

Review Comment:
   The constraint list omits a rejection that the chart's Server wrapper also enforces: admin passwords beginning with a space or tab fail startup. Add the leading-whitespace restriction here so operators do not choose a value that renders successfully but leaves the Server unable to start.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,282 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+Day-2 work (NetworkPolicy details, disaster recovery, scaling, safe Store
+rolls, running Hubble outside the cluster) is on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity, NetworkPolicy on |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. One of its numbers deserves a note: it requests 5Gi and limits at 8Gi of memory per Store, well above the
+1Gi heap, because the Store's RocksDB caches live outside the JVM heap (a 4Gi limit OOM-killed Stores after about
+1 GB of data). Scale both numbers with data size. The full parameter reference (every component, probe,
+scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions

Review Comment:
   `kubectl port-forward` runs in the foreground, so copying this block never reaches the following `curl`; the API verification command is left hanging. Put the forward and curl in explicitly separate terminals, or background the forward and clean it up before running the request.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
bitflicker64 commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4166023740


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** stay on `/v1/health` on purpose: a PD that merely lost its leader is
+still a healthy Raft member, and restarting it would make the outage worse.
+
+Server startup gets a matching budget: the image would normally kill a Server still starting after 120 seconds, so
+the chart derives `HG_SERVER_STARTUP_TIMEOUT_S` from the startup probe (450 seconds by default) and raises a lower
+configured probe budget to that floor. Raise `server.probes.startup` if your storage takes longer to come up, and
+the image budget follows.
+
+### 6 Enable the Hubble UI
+
+Hubble is off by default so API-only clusters stay lean. Enable it on a running release:
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values --set hubble.enabled=true
+```
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-hubble 8088:8088
+```
+
+Open `http://127.0.0.1:8088` and log in as `admin` with the admin password from Section 3.4. Hubble discovers the
+Servers through PD, so the cluster operations view works without extra wiring. Hubble serves plain HTTP: reach it
+through a port-forward or an HTTPS-terminating Ingress, never directly from an untrusted network. Running Hubble
+outside the cluster is possible but takes more wiring; see
+[Reaching Hubble](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#reaching-hubble-pick-one-path) in
+the chart README.
+
+### 7 Upgrade
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values
+```
+
+`--reuse-values` keeps the release's existing overrides; without it the upgrade rebuilds the release from chart
+defaults. Any upgrade that changes a Pod template rolls that workload once. Points worth planning around:
+
+- **The first upgrade after a fresh install rolls PD, Server, and Hubble once**, when the Secret-tracking
+  annotations first observe the install-created Secrets. Store is untouched.
+- **Store rolling updates advance on a listener check, not on shard recovery**, so the controller can replace the
+  next Store while the previous one is still rejoining its shard groups. For a production image roll, set
+  `store.updateStrategy.type=OnDelete` and replace Store pods one at a time, confirming the previous Store shows

Review Comment:
   Fixed in c4ed3619c and tightened in 5e4cbd25c. The Up-only gate is gone: section 7 says `Up` is not the check, because PD marks a Store `Up` at registration and keeps a stopped one `Up` until the 300 s keep-alive expires. It asks for the replaced Pod to be Ready and every shard group at full shard count with one leader, and links operations section 6, which adds the fresh `lastHeartBeat` check. `values-cluster.yaml` sets Store `OnDelete`. CN matches.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** stay on `/v1/health` on purpose: a PD that merely lost its leader is
+still a healthy Raft member, and restarting it would make the outage worse.
+
+Server startup gets a matching budget: the image would normally kill a Server still starting after 120 seconds, so
+the chart derives `HG_SERVER_STARTUP_TIMEOUT_S` from the startup probe (450 seconds by default) and raises a lower
+configured probe budget to that floor. Raise `server.probes.startup` if your storage takes longer to come up, and
+the image budget follows.
+
+### 6 Enable the Hubble UI
+
+Hubble is off by default so API-only clusters stay lean. Enable it on a running release:
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values --set hubble.enabled=true
+```
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-hubble 8088:8088
+```
+
+Open `http://127.0.0.1:8088` and log in as `admin` with the admin password from Section 3.4. Hubble discovers the
+Servers through PD, so the cluster operations view works without extra wiring. Hubble serves plain HTTP: reach it
+through a port-forward or an HTTPS-terminating Ingress, never directly from an untrusted network. Running Hubble
+outside the cluster is possible but takes more wiring; see
+[Reaching Hubble](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#reaching-hubble-pick-one-path) in
+the chart README.
+
+### 7 Upgrade
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values
+```
+
+`--reuse-values` keeps the release's existing overrides; without it the upgrade rebuilds the release from chart
+defaults. Any upgrade that changes a Pod template rolls that workload once. Points worth planning around:
+
+- **The first upgrade after a fresh install rolls PD, Server, and Hubble once**, when the Secret-tracking
+  annotations first observe the install-created Secrets. Store is untouched.
+- **Store rolling updates advance on a listener check, not on shard recovery**, so the controller can replace the
+  next Store while the previous one is still rejoining its shard groups. For a production image roll, set
+  `store.updateStrategy.type=OnDelete` and replace Store pods one at a time, confirming the previous Store shows
+  `Up` in PD before the next; PD restarts are one pod at a time either way, and `pd.updateStrategy.type=OnDelete`
+  gives the same manual control for maintenance windows.
+- **PVC sizes cannot be changed by upgrade**: Kubernetes forbids changing StatefulSet `volumeClaimTemplates`, so an
+  upgrade with a new `storage.size` is rejected in full. The chart README documents the resize procedure for
+  StorageClasses that support volume expansion.
+
+Scaling Server up and down is a values change (`server.replicas`, or `server.hpa`). Scaling **PD or Store down is
+not**: Raft and shard membership are persisted, deleting pods does not reconfigure them, and a 3-to-1 PD shrink
+permanently loses quorum. The chart rejects an upgrade whose replica count is below the live StatefulSet; the
+manual drain-then-scale procedure is in the chart README under
+[Scaling](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#scaling).
+
+### 8 Uninstall
+
+```bash
+helm uninstall hugegraph --namespace hugegraph
+```
+
+Two kinds of state survive on purpose. PersistentVolumeClaims created by the StatefulSets are kept (Kubernetes
+behavior); delete them explicitly once the data is no longer needed. The chart-managed Secrets are also kept, so a
+later install under the same release name comes back with the same credentials.
+
+### 9 Limitations
+
+- No NetworkPolicy resources yet. With the PD Raft IP allowlist disabled in-cluster (pod IPs change; the allowlist

Review Comment:
   Fixed in c4ed3619c. The Limitations bullet now says NetworkPolicy is off by default and on in `values-cluster.yaml`, needs a network plugin that enforces it, and that every outside client, the Ingress controller included, must be listed in `networkPolicy.<component>.extraIngress`. Operations section 5 has the details and a worked example. CN matches.



##########
content/cn/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,356 @@
+---
+title: "在 Kubernetes 上运维 HugeGraph"
+linkTitle: "Kubernetes 运维 (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 适用范围
+
+本页面向已经用 Helm chart 部署好 HugeGraph 集群的运维场景。安装、升级、卸载见
+[部署页](/cn/docs/quickstart/hugegraph/hugegraph-helm/);完整参数参考仍在
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration)。
+
+下文命令假定 release 名为 `hugegraph`、namespace 为 `hugegraph`,请按需替换。两个凭据会反复用到,都从
+chart 管理的 Secret 读取:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 端口与健康
+
+| 组件 | 端口 | 用途 |
+|------|------|------|
+| PD | `8686` | gRPC(Store 与 Server 客户端) |
+| PD | `8620` | REST / 健康探测 |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / 健康探测 |
+| Server | `8080` | Gremlin 与 REST API |
+
+所有端口都可以通过 values 配置;修改 `server.port` 会同时更新监听、容器端口和 Service。进程存活但停止响应的组件由
+存活探测终结:默认 20 秒周期、3 次失败阈值把一个卡死 Store 的影响时间限制在约一分钟内,重启后 raft 几秒内就会转移
+它持有的分区 leader。
+
+通过 port-forward 访问 API:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs

Review Comment:
   Fixed in 686d3b930. Section 2 now keeps the port-forward in one terminal and runs the `curl` calls from a second, with `PASSWORD` from section 1. Section 10's per-Pod Gremlin check got the same split, and the deployment page's install check too, in EN and CN.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub) via issues" <is...@hugegraph.apache.org>.
bitflicker64 closed pull request #494: doc: add Helm chart deployment page for Kubernetes
URL: https://github.com/apache/hugegraph-doc/pull/494


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "imbajin (via GitHub)" <gi...@apache.org>.
imbajin commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4191812768


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,523 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward. It runs in the foreground, so keep
+it in one terminal:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+```
+
+and call the API from a second terminal, with `PASSWORD` set as above:
+
+```bash
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry. An
+in-cluster Hubble in `pd` mode combined with `server.advertiseUrl` also
+fails the render until `networkPolicy.hubble.extraEgress` admits the
+advertised destination: PD hands Hubble that URL for discovery, and
+Hubble's egress policy otherwise reaches only the release's own Pods.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. `values-cluster.yaml` therefore sets
+`store.updateStrategy.type=OnDelete` (set it yourself on any other
+production values): an upgrade then updates the StatefulSet without
+replacing any Store Pod, and you delete Store Pods one at a time, checking
+between deletions. `OnDelete` only stops automatic advancement; deleting
+Pods without the checks below carries the same risk.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.

Review Comment:
   ‼️ critical. Blocking: yes. Summary: This gate counts every shard entry, so a Leader+Follower+Learner group satisfies the full-count/one-Leader condition before the new replica is promoted; deleting another Store can leave only one voter. Please require one Leader and only Followers (no Learner/None) before continuing, including the shrink gate, and sync the Chinese instructions. Evidence: [PartitionEngine adds peers as Learners and promotes them only after waitForReplicate](https://github.com/apache/hugegraph/blob/8fd9841ebc6770df6119fdce07249fa9e558ae9e/hugegraph-store/hg-store-core/src/main/java/org/apache/hugegraph/store/PartitionEngine.java#L320-L368); [PD treats Learner as migration in progress](https://github.com/apache/hugegraph/blob/8fd9841ebc6770df6119fdce07249fa9e558ae9e/hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/TaskScheduleService.java#L313-L320).



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,523 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward. It runs in the foreground, so keep
+it in one terminal:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+```
+
+and call the API from a second terminal, with `PASSWORD` set as above:
+
+```bash
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:

Review Comment:
   ⚠️ important. Blocking: no. Summary: The statement that the release admits only its own traffic holds only when no other applicable NetworkPolicy allows traffic to these Pods; Kubernetes unions allowed rules, so a broader policy can admit sources omitted from extraIngress. Please qualify this boundary and advise operators to audit other policies selecting these Pods in both languages. Evidence: [Kubernetes documents additive NetworkPolicy rules and the union of allowed connections](https://kubernetes.io/docs/concepts/services-networking/network-policies/).



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,523 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward. It runs in the foreground, so keep
+it in one terminal:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+```
+
+and call the API from a second terminal, with `PASSWORD` set as above:
+
+```bash
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry. An
+in-cluster Hubble in `pd` mode combined with `server.advertiseUrl` also
+fails the render until `networkPolicy.hubble.extraEgress` admits the
+advertised destination: PD hands Hubble that URL for discovery, and
+Hubble's egress policy otherwise reaches only the release's own Pods.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. `values-cluster.yaml` therefore sets
+`store.updateStrategy.type=OnDelete` (set it yourself on any other
+production values): an upgrade then updates the StatefulSet without
+replacing any Store Pod, and you delete Store Pods one at a time, checking
+between deletions. `OnDelete` only stops automatic advancement; deleting
+Pods without the checks below carries the same risk.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, leader, and
+committed index (`logIndex`) that Store holds, and fails while the Store
+is down; compare the index with a peer Store rather than reading it
+alone. This route never fills its `term` field, so `term` always reads 0
+there. The plural `GET :8520/v1/partitions` answers 500 on any Store that
+follows a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a
+group that is short a shard or has no leader as a stop. A real
+restoration-complete signal is upstream work, tracked in
+[apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229).
+
+### 7 Disaster recovery
+
+What PD automates on current builds is narrow: a 60-second patrol only
+marks Stores that stopped sending heartbeats as `Offline`. There is no
+automatic re-replication; re-placing the replicas of a lost Store,
+reconciling shard groups, and processing tombstoned Stores run only when a
+partition patrol is triggered explicitly.
+
+The task endpoints execute locally on the PD that receives them, and a
+follower answers with an empty success while doing nothing.
+Port-forwarding the client Service selects an arbitrary PD, so identify
+the leader first, then port-forward that Pod (two terminals: the forward
+runs in the foreground):
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-pd-client 8620:8620
+# Read .data.pdLeader.raftUrl; its host names the leader Pod.
+curl -su "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/members
+# Stop the Service forward, then forward the leader Pod instead.
+kubectl port-forward -n hugegraph pod/<leader-pod> 8620:8620
+# Reconcile shard groups and process tombstoned Stores.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/patrolPartitions
+# If the patrol repaired a shard group, wait 180 s first (see below).
+# Spread Raft leaders, then partition data.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balanceLeaders
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balancePartitions
+```
+
+Read `/v1/members` again after the tasks: if leadership moved mid-sequence,
+the later tasks ran on a follower and did nothing. PD sets a
+balance-shard flag for 180 s in two cases: `patrolPartitions` sets it
+whenever it reallocates a shard group whose shard count is wrong, and
+`balancePartitions` sets it even when it moves nothing. Inside that
+window `balanceLeaders` is refused and `balancePartitions` returns
+without doing anything, so wait at least 180 s after a patrol that
+repaired a group, and after `balancePartitions`, before the next
+balancing call. On images built before
+[apache/hugegraph#3233](https://github.com/apache/hugegraph/pull/3233)
+(merged 2026-09-24) the refusal is a bare HTTP 500 whose reason appears
+only in the PD log; after it, the reason comes back in the body as
+`{"status":1001,"error":"balance shard is processing, please try later!"}`.
+
+Telling a real run from a no-op takes the PD leader's log, because the
+responses do not: `patrolPartitions` answers the same empty success on the
+leader and on a follower, whether or not it repaired anything (look for
+`reallocShards`, `shardOffline` or `storeTurnoff` lines, or diff
+`/v1/shardGroups` before and after), and `balancePartitions` answers `{}`
+on the leader and an empty body on a follower. `balanceLeaders` is the one
+call whose body carries the work. Distinguishable task responses are
+upstream work, tracked in
+[apache/hugegraph#3231](https://github.com/apache/hugegraph/issues/3231).
+
+Run `patrolPartitions` after replacing a Store that is not coming back,
+`balancePartitions` once the cluster is stable again, and `balanceLeaders`

Review Comment:
   ⚠️ important. Blocking: no. Summary: Tombstoning a Store starts a separate 30-minute cooldown: balancePartitionShard() returns null during that interval, even after the documented 180-second patrol window. Please document the Tombstone cooldown before advising balancePartitions, and distinguish it from the BALANCE_SHARD_KEY timer. Evidence: [The status listener records Tombstone time](https://github.com/apache/hugegraph/blob/8fd9841ebc6770df6119fdce07249fa9e558ae9e/hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/TaskScheduleService.java#L168-L174); [the cooldown constant and early return](https://github.com/apache/hugegraph/blob/8fd9841ebc6770df6119fdce07249fa9e558ae9e/hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/TaskScheduleService.java#L59-L60) and [the 30-minute guard](https://github.com/apache/hugegraph/blob/8fd9841ebc6770df6119fdce07249fa9e558ae9e/hugegraph-pd/hg-pd-core/src/main/java/org/apache/hugegraph/pd/TaskScheduleService.java#L281-L28
 3).



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,367 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+Day-2 work (NetworkPolicy details, disaster recovery, scaling, safe Store
+rolls, running Hubble outside the cluster) is on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` waits for Kubernetes readiness probes, not application workflows. A fresh cluster normally converges in
+a few minutes; the 15-minute timeout leaves room for slow image pulls. Verify graph queries after installation.
+Without `--wait`, Helm returns as soon as the objects are created.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort, and each JVM sets its maximum heap to half of the memory it
+  sees free on the node at start (up to a per-component ceiling), so the JVMs on one node can together claim more
+  memory than the node has. That holds for `values-single.yaml` on one node as well. Set `resources` per component on every install, the single-node
+  preset included; `values-cluster.yaml` sets them for a multi-node cluster.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, a Server PodDisruptionBudget, `required` anti-affinity, NetworkPolicy on, Store `OnDelete` updates |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. One of its numbers deserves a note: it requests 5Gi and limits at 8Gi of memory per Store, well above the
+1Gi heap, because the Store's RocksDB caches live outside the JVM heap (a 4Gi limit OOM-killed Stores after about
+1 GB of data). Scale both numbers with data size. The full parameter reference (every component, probe,
+scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph --logs --timeout 5m
+```
+
+The test first calls `/versions` and `/graphs` through the Server Service. It then resolves the headless Service
+`hugegraph-server-headless` and sends an authenticated Gremlin query bound to the `DEFAULT-hugegraph` graph to
+each Server Pod it lists, and it requires at least `server.replicas` Pods (`server.hpa.minReplicas` with HPA on).
+The headless Service lists only Ready Pods, the same Pods the Server Service routes to, so a Pod that is not Ready
+is not queried. A failing Pod is retried every 5 seconds for up to 150 seconds, so a short PD election is not
+reported as a broken Pod; after that the test fails and prints each failing Pod IP with its HTTP status. This is
+the check that catches a Server that passes readiness and serves REST while every Gremlin call on it fails (see
+Limitations). Large HPA fleets may need `helm test --timeout` above the 5-minute default.
+
+The hook verifies Server Gremlin, not Hubble login. With Hubble enabled, also verify a fresh login and graph query
+after installation or recovery; `/actuator/health` alone does not establish backend connectivity.
+
+To call the API, start a port-forward in one terminal; it runs in the foreground until you stop it:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+```
+
+Then, in a second terminal, read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must be printable
+ASCII with no spaces, colons, or backslashes (the image stores a space with a backslash before it, and the Server splits
+Basic-auth credentials on every colon, so either would leave the account unable to log in with the Secret value); the
+JWT key must be at least 32 bytes; the PD secret must be printable ASCII with no backslashes and no leading or trailing
+space. Invalid inline values are rejected at render time, and an `existingSecret` by the startup wrapper when the Pod
+starts, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.

Review Comment:
   ⚠️ important. Blocking: no. Summary: Rotating only through the Server auth API leaves the chart admin Secret unchanged, so the documented password lookup and helm test hook keep using the old credential. Please set the Secret to the API value and roll Server replicas to refresh their auth caches, or link to the chart README rotation procedure; sync Chinese. Evidence: [The test hook reads PASSWORD from the chart Secret](https://github.com/apache/hugegraph/blob/90345bb9d8804f6b0726db6c66d18adf33461bf4/helm/hugegraph/templates/tests/test-connection.yaml#L59-L65); [the chart README requires Secret synchronization and a Server rollout](https://github.com/apache/hugegraph/blob/90345bb9d8804f6b0726db6c66d18adf33461bf4/helm/hugegraph/README.md#L79-L84).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
bitflicker64 commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4166028897


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,483 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. For a production image roll, set
+`store.updateStrategy.type=OnDelete` and delete Store Pods one at a time,
+checking between deletions.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, term, and
+committed index that Store holds, and fails while the Store is down;
+compare term and index with a peer Store rather than reading them alone.
+The plural `GET :8520/v1/partitions` answers 500 on any Store that follows
+a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a
+group that is short a shard or has no leader as a stop. A real
+restoration-complete signal is upstream work, tracked in
+[apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229).
+
+### 7 Disaster recovery
+
+What PD automates on current builds is narrow: a 60-second patrol only
+marks Stores that stopped sending heartbeats as `Offline`. There is no
+automatic re-replication; re-placing the replicas of a lost Store,
+reconciling shard groups, and processing tombstoned Stores run only when a
+partition patrol is triggered explicitly.
+
+The task endpoints execute locally on the PD that receives them, and a
+follower answers with an empty success while doing nothing.
+Port-forwarding the client Service selects an arbitrary PD, so identify
+the leader first, then port-forward that Pod (two terminals: the forward
+runs in the foreground):
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-pd-client 8620:8620
+# Read .data.pdLeader.raftUrl; its host names the leader Pod.
+curl -su "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/members
+# Stop the Service forward, then forward the leader Pod instead.
+kubectl port-forward -n hugegraph pod/<leader-pod> 8620:8620
+# Reconcile shard groups and process tombstoned Stores.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/patrolPartitions
+# Spread Raft leaders, then partition data.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balanceLeaders
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balancePartitions
+```
+
+Read `/v1/members` again after the tasks: if leadership moved mid-sequence,
+the later tasks ran on a follower and did nothing. Wait at least 180 s
+before rerunning `balanceLeaders` after a `balancePartitions` call:
+`balancePartitions` sets a balance-shard flag for 180 s even when it moves
+nothing, and `balanceLeaders` inside that window is refused. On images
+built before
+[apache/hugegraph#3233](https://github.com/apache/hugegraph/pull/3233)
+(merged 2026-09-24) the refusal is a bare HTTP 500 whose reason appears
+only in the PD log; after it, the reason comes back in the body as
+`{"status":1001,"error":"balance shard is processing, please try later!"}`.
+
+Telling a real run from a no-op takes the PD leader's log, because the
+responses do not: `patrolPartitions` answers the same empty success on the
+leader and on a follower, whether or not it repaired anything (look for
+`reallocShards`, `shardOffline` or `storeTurnoff` lines, or diff
+`/v1/shardGroups` before and after), and `balancePartitions` answers `{}`
+on the leader and an empty body on a follower. `balanceLeaders` is the one
+call whose body carries the work. Distinguishable task responses are
+upstream work, tracked in
+[apache/hugegraph#3231](https://github.com/apache/hugegraph/issues/3231).
+
+Run `patrolPartitions` after replacing a Store that is not coming back,
+`balancePartitions` once the cluster is stable again, and `balanceLeaders`
+after restarts that skewed leader placement.
+
+**Losing a Store volume.** A Store rebuilt with an empty PVC recovers in
+place on images carrying
+[apache/hugegraph#3234](https://github.com/apache/hugegraph/pull/3234)
+(merged 2026-09-24); on every earlier image, including all published
+release images, it does not. In both cases the replacement registers under
+a new Store ID while its Pod name, DNS name, and raft address are
+unchanged, so `/v1/stores` lists two IDs at one address.
+
+On post-#3234 images the retirement works: find the old ID in `/v1/stores`
+(the row at the replaced Pod's address that is not the newly registered
+one), `POST /v1/store/<oldId>` with `{"storeState":"Tombstone"}` on the PD
+leader, run `GET /v1/task/patrolPartitions`, and wait; verify every shard
+group is back to full shard count with one leader, no group names the old
+ID, and the replaced Store's own `:8520/v1/partition/<groupId>` answers
+200 for every group; then `DELETE /v1/store/<oldId>` to erase the retired
+record. Measured on a 3+3+3 install with images built from `master` at
+`dbb6663a`: the replacement was Ready in 156 s, all 12 groups converged
+onto the new ID 1 s after the Tombstone and patrol (the empty Store caught
+up by raft snapshot install), and a continuous writer lost 0 acknowledged
+writes.
+
+On images without #3234 the same retirement runs and does not repair the
+groups: PD fires the configuration change, but the group leader sees the
+address already in the group, so jraft has nothing to add and the group
+keeps the old ID. Measured: 20 minutes and three patrols later, all 12
+groups still listed the retired ID and the replacement Store held no
+partitions. Nothing in the health surface shows the failure; `/v1/stores`,
+cluster state, Hubble, and Pod readiness all read healthy while every
+shard group runs on two live replicas. The one check that shows it is the
+replaced Store's own `:8520/v1/partition/<groupId>`.
+
+So the default remains: replace a Store Pod, keep its PVC (the Store id
+lives in the data path, and the Pod comes back under the same id). Treat
+the empty-PVC procedure as recovery for post-#3234 images only; on a
+released image a genuinely lost volume leaves the cluster degraded, and
+expect to rebuild rather than to recover in place.
+
+Periodic leader balancing is tracked in
+[apache/hugegraph#3135](https://github.com/apache/hugegraph/issues/3135);
+disaster-recovery metrics in
+[apache/hugegraph#3136](https://github.com/apache/hugegraph/issues/3136).
+
+### 8 Scaling
+
+PD and Store reserve the maximum StatefulSet ordinal in their resource
+names, so scaling never renames a PersistentVolumeClaim or shifts a Pod
+identity; both are capped at 99 replicas. Server scales freely through
+`server.replicas` or `server.hpa` (with HPA on, the Deployment omits
+`spec.replicas` so upgrades do not overwrite the autoscaler).
+
+A staged rollout cannot be written in a values file (the schema requires
+one replica per component); stage it with `kubectl scale statefulset
+hugegraph-store --replicas=0` and scale back up when ready. The Servers
+wait, not ready, until Stores register, and the next `helm upgrade`
+restores the full topology from values.
+
+Changing PD or Store replicas on a live release is not a values change:
+raft and shard membership are persisted, and Pods alone do not reconfigure
+them. The chart rejects both directions for PD and a shrink for Store by
+reading the live StatefulSet, so fresh installs at any count are
+unaffected.
+
+**PD, either direction.** The rendered peer list reaches raft only as its
+bootstrap configuration, which an initialized group ignores; a 3-to-5
+upgrade leaves the voting configuration at three, and a 3-to-1 shrink
+loses quorum outright. Membership changes go through the PD client API
+(no REST route exposes them), which the chart cannot wrap. Change the

Review Comment:
   Fixed in 795d5f835. Section 8 now says the peer-list change is exposed by the PD client API and by `POST /v1/members/change` in `MemberAPI`, that the route needs the same Basic authentication as the other PD REST routes (the interceptor covers `/**` and excludes only health, ready, actuator and prom targets), and that the chart wraps neither. The procedure stays marked as unverified. CN updated.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,483 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. For a production image roll, set
+`store.updateStrategy.type=OnDelete` and delete Store Pods one at a time,
+checking between deletions.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, term, and
+committed index that Store holds, and fails while the Store is down;
+compare term and index with a peer Store rather than reading them alone.
+The plural `GET :8520/v1/partitions` answers 500 on any Store that follows
+a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a
+group that is short a shard or has no leader as a stop. A real
+restoration-complete signal is upstream work, tracked in
+[apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229).
+
+### 7 Disaster recovery
+
+What PD automates on current builds is narrow: a 60-second patrol only
+marks Stores that stopped sending heartbeats as `Offline`. There is no
+automatic re-replication; re-placing the replicas of a lost Store,
+reconciling shard groups, and processing tombstoned Stores run only when a
+partition patrol is triggered explicitly.
+
+The task endpoints execute locally on the PD that receives them, and a
+follower answers with an empty success while doing nothing.
+Port-forwarding the client Service selects an arbitrary PD, so identify
+the leader first, then port-forward that Pod (two terminals: the forward
+runs in the foreground):
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-pd-client 8620:8620
+# Read .data.pdLeader.raftUrl; its host names the leader Pod.
+curl -su "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/members
+# Stop the Service forward, then forward the leader Pod instead.
+kubectl port-forward -n hugegraph pod/<leader-pod> 8620:8620
+# Reconcile shard groups and process tombstoned Stores.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/patrolPartitions
+# Spread Raft leaders, then partition data.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balanceLeaders
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balancePartitions
+```
+
+Read `/v1/members` again after the tasks: if leadership moved mid-sequence,
+the later tasks ran on a follower and did nothing. Wait at least 180 s
+before rerunning `balanceLeaders` after a `balancePartitions` call:
+`balancePartitions` sets a balance-shard flag for 180 s even when it moves
+nothing, and `balanceLeaders` inside that window is refused. On images
+built before
+[apache/hugegraph#3233](https://github.com/apache/hugegraph/pull/3233)
+(merged 2026-09-24) the refusal is a bare HTTP 500 whose reason appears
+only in the PD log; after it, the reason comes back in the body as
+`{"status":1001,"error":"balance shard is processing, please try later!"}`.
+
+Telling a real run from a no-op takes the PD leader's log, because the
+responses do not: `patrolPartitions` answers the same empty success on the
+leader and on a follower, whether or not it repaired anything (look for
+`reallocShards`, `shardOffline` or `storeTurnoff` lines, or diff
+`/v1/shardGroups` before and after), and `balancePartitions` answers `{}`
+on the leader and an empty body on a follower. `balanceLeaders` is the one
+call whose body carries the work. Distinguishable task responses are
+upstream work, tracked in
+[apache/hugegraph#3231](https://github.com/apache/hugegraph/issues/3231).
+
+Run `patrolPartitions` after replacing a Store that is not coming back,
+`balancePartitions` once the cluster is stable again, and `balanceLeaders`
+after restarts that skewed leader placement.
+
+**Losing a Store volume.** A Store rebuilt with an empty PVC recovers in
+place on images carrying
+[apache/hugegraph#3234](https://github.com/apache/hugegraph/pull/3234)
+(merged 2026-09-24); on every earlier image, including all published
+release images, it does not. In both cases the replacement registers under
+a new Store ID while its Pod name, DNS name, and raft address are
+unchanged, so `/v1/stores` lists two IDs at one address.
+
+On post-#3234 images the retirement works: find the old ID in `/v1/stores`
+(the row at the replaced Pod's address that is not the newly registered
+one), `POST /v1/store/<oldId>` with `{"storeState":"Tombstone"}` on the PD
+leader, run `GET /v1/task/patrolPartitions`, and wait; verify every shard
+group is back to full shard count with one leader, no group names the old
+ID, and the replaced Store's own `:8520/v1/partition/<groupId>` answers
+200 for every group; then `DELETE /v1/store/<oldId>` to erase the retired
+record. Measured on a 3+3+3 install with images built from `master` at
+`dbb6663a`: the replacement was Ready in 156 s, all 12 groups converged
+onto the new ID 1 s after the Tombstone and patrol (the empty Store caught
+up by raft snapshot install), and a continuous writer lost 0 acknowledged
+writes.
+
+On images without #3234 the same retirement runs and does not repair the
+groups: PD fires the configuration change, but the group leader sees the
+address already in the group, so jraft has nothing to add and the group
+keeps the old ID. Measured: 20 minutes and three patrols later, all 12
+groups still listed the retired ID and the replacement Store held no
+partitions. Nothing in the health surface shows the failure; `/v1/stores`,
+cluster state, Hubble, and Pod readiness all read healthy while every
+shard group runs on two live replicas. The one check that shows it is the
+replaced Store's own `:8520/v1/partition/<groupId>`.
+
+So the default remains: replace a Store Pod, keep its PVC (the Store id
+lives in the data path, and the Pod comes back under the same id). Treat
+the empty-PVC procedure as recovery for post-#3234 images only; on a
+released image a genuinely lost volume leaves the cluster degraded, and
+expect to rebuild rather than to recover in place.
+
+Periodic leader balancing is tracked in
+[apache/hugegraph#3135](https://github.com/apache/hugegraph/issues/3135);
+disaster-recovery metrics in
+[apache/hugegraph#3136](https://github.com/apache/hugegraph/issues/3136).
+
+### 8 Scaling
+
+PD and Store reserve the maximum StatefulSet ordinal in their resource
+names, so scaling never renames a PersistentVolumeClaim or shifts a Pod
+identity; both are capped at 99 replicas. Server scales freely through
+`server.replicas` or `server.hpa` (with HPA on, the Deployment omits
+`spec.replicas` so upgrades do not overwrite the autoscaler).
+
+A staged rollout cannot be written in a values file (the schema requires
+one replica per component); stage it with `kubectl scale statefulset
+hugegraph-store --replicas=0` and scale back up when ready. The Servers
+wait, not ready, until Stores register, and the next `helm upgrade`
+restores the full topology from values.
+
+Changing PD or Store replicas on a live release is not a values change:
+raft and shard membership are persisted, and Pods alone do not reconfigure
+them. The chart rejects both directions for PD and a shrink for Store by
+reading the live StatefulSet, so fresh installs at any count are
+unaffected.
+
+**PD, either direction.** The rendered peer list reaches raft only as its
+bootstrap configuration, which an initialized group ignores; a 3-to-5
+upgrade leaves the voting configuration at three, and a 3-to-1 shrink
+loses quorum outright. Membership changes go through the PD client API
+(no REST route exposes them), which the chart cannot wrap. Change the
+membership through PD, confirm it in `/v1/members`, scale the live
+StatefulSet, then `helm upgrade` with the matching value; until that
+sequence is verified on your own build, install the PD count you intend
+to keep.
+
+**Store, shrinking.** Draining is a state transition, not a balance:
+neither `patrolPartitions` nor `balancePartitions` retires a healthy
+Store. Retire the leaving Stores the way Disaster Recovery retires a
+replaced one:
+
+1. Check the remaining Stores still cover the persisted shard count
+   (`pd.partition.defaultShardCount`; empty derives 3 when
+   `store.replicas` is at least 3).
+2. Map the ordinals the shrink will delete (the highest ones) to Store
+   ids through `/v1/stores`, matching on the Pod address.
+3. `POST /v1/store/<id>` with `{"storeState":"Tombstone"}` for each
+   leaving id.
+4. Wait until `/v1/shardGroups` no longer lists those ids and every group
+   reports its full shard count with one leader.
+5. Scale the live StatefulSet, then `helm upgrade` with the matching
+   value.
+
+Deleting the PVCs of the removed ordinals is separate and permanent; do it

Review Comment:
   Fixed in 795d5f835. Section 8 now says the chart keeps the PVCs of removed ordinals (`whenScaled: Retain`), that such a PVC still holds the retired Store id, and that PD refuses to register a Tombstone or deleted id (`StoreNodeService.register()`), so the PVC must be deleted after step 4 and before that ordinal is reused. Checked in code, not run on a cluster. CN updated.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,282 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+Day-2 work (NetworkPolicy details, disaster recovery, scaling, safe Store
+rolls, running Hubble outside the cluster) is on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity, NetworkPolicy on |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. One of its numbers deserves a note: it requests 5Gi and limits at 8Gi of memory per Store, well above the
+1Gi heap, because the Store's RocksDB caches live outside the JVM heap (a 4Gi limit OOM-killed Stores after about
+1 GB of data). Scale both numbers with data size. The full parameter reference (every component, probe,
+scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** derive from the replica count (`pd.livenessPath` overrides the
+choice). With more than one PD they stay on `/v1/health` on purpose: a PD that merely lost its leader is still a
+healthy Raft member, and restarting it would make the outage worse. A single PD is the exception and derives to
+`/v1/ready`: it has no election to lose, and one that steps down for good, as after a failed Raft snapshot on a
+full disk ([apache/hugegraph#3222](https://github.com/apache/hugegraph/issues/3222)), would answer `/v1/health`
+forever while serving no writes; the kubelet restarts it instead.
+
+Server startup gets a matching budget: the image would normally kill a Server still starting after 120 seconds, so
+the chart derives `HG_SERVER_STARTUP_TIMEOUT_S` from the startup probe (450 seconds by default) and raises a lower
+configured probe budget to that floor. Raise `server.probes.startup` if your storage takes longer to come up, and
+the image budget follows.
+
+### 6 Enable the Hubble UI
+
+Hubble is off by default so API-only clusters stay lean. Enable it on a running release:
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values --set hubble.enabled=true
+```
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-hubble 8088:8088
+```
+
+Open `http://127.0.0.1:8088` and log in as `admin` with the admin password from Section 3.4. Hubble discovers the
+Servers through PD, so the cluster operations view works without extra wiring. Hubble serves plain HTTP: reach it
+through a port-forward or an HTTPS-terminating Ingress, never directly from an untrusted network. Running Hubble
+outside the cluster is possible but takes more wiring; see
+[Reaching Hubble](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#reaching-hubble-pick-one-path) in
+the chart README.
+
+### 7 Upgrade
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values
+```
+
+`--reuse-values` keeps the release's existing overrides; without it the upgrade rebuilds the release from chart
+defaults. Any upgrade that changes a Pod template rolls that workload once. Points worth planning around:
+
+- **The first upgrade after a fresh install rolls PD, Server, and Hubble once**, when the Secret-tracking

Review Comment:
   Fixed in 5e4cbd25c. The first-upgrade bullet now says a Server that restarts while PD rolls can lose its Gremlin binding, and to run `helm test` after any upgrade that rolled PD and Server; at chart 0e754b98c `helm test` queries Gremlin on every Ready Server Pod. Limitations covers the lasting case with a link to operations section 10, and troubleshooting has a `Gremlin failed on <Pod IP>` row. CN matches.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,282 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+Day-2 work (NetworkPolicy details, disaster recovery, scaling, safe Store
+rolls, running Hubble outside the cluster) is on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity, NetworkPolicy on |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. One of its numbers deserves a note: it requests 5Gi and limits at 8Gi of memory per Store, well above the
+1Gi heap, because the Store's RocksDB caches live outside the JVM heap (a 4Gi limit OOM-killed Stores after about
+1 GB of data). Scale both numbers with data size. The full parameter reference (every component, probe,
+scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** derive from the replica count (`pd.livenessPath` overrides the
+choice). With more than one PD they stay on `/v1/health` on purpose: a PD that merely lost its leader is still a
+healthy Raft member, and restarting it would make the outage worse. A single PD is the exception and derives to
+`/v1/ready`: it has no election to lose, and one that steps down for good, as after a failed Raft snapshot on a
+full disk ([apache/hugegraph#3222](https://github.com/apache/hugegraph/issues/3222)), would answer `/v1/health`
+forever while serving no writes; the kubelet restarts it instead.
+
+Server startup gets a matching budget: the image would normally kill a Server still starting after 120 seconds, so
+the chart derives `HG_SERVER_STARTUP_TIMEOUT_S` from the startup probe (450 seconds by default) and raises a lower
+configured probe budget to that floor. Raise `server.probes.startup` if your storage takes longer to come up, and
+the image budget follows.
+
+### 6 Enable the Hubble UI
+
+Hubble is off by default so API-only clusters stay lean. Enable it on a running release:
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values --set hubble.enabled=true
+```
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-hubble 8088:8088
+```
+
+Open `http://127.0.0.1:8088` and log in as `admin` with the admin password from Section 3.4. Hubble discovers the
+Servers through PD, so the cluster operations view works without extra wiring. Hubble serves plain HTTP: reach it
+through a port-forward or an HTTPS-terminating Ingress, never directly from an untrusted network. Running Hubble
+outside the cluster is possible but takes more wiring; see
+[Reaching Hubble](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#reaching-hubble-pick-one-path) in
+the chart README.
+
+### 7 Upgrade
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values
+```
+
+`--reuse-values` keeps the release's existing overrides; without it the upgrade rebuilds the release from chart
+defaults. Any upgrade that changes a Pod template rolls that workload once. Points worth planning around:
+
+- **The first upgrade after a fresh install rolls PD, Server, and Hubble once**, when the Secret-tracking
+  annotations first observe the install-created Secrets. Store is untouched.
+- **Store rolling updates advance on a listener check, not on shard recovery**, so the controller can replace the
+  next Store while the previous one is still rejoining its shard groups. For a production image roll, set
+  `store.updateStrategy.type=OnDelete` and replace Store pods one at a time. `Up` in PD is not the between-pods
+  check: PD marks a Store `Up` at registration, before it restores partitions, and a stopped Store stays `Up`
+  until a 300 s keep-alive expires. Wait for the replaced Pod to be `Ready`, then confirm every shard group
+  reports its full shard count with one leader; the full procedure is on the
+  [operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/). PD restarts are one pod at a time
+  either way, and `pd.updateStrategy.type=OnDelete` gives the same manual control for maintenance windows.
+- **PVC sizes cannot be changed by upgrade**: Kubernetes forbids changing StatefulSet `volumeClaimTemplates`, so an
+  upgrade with a new `storage.size` is rejected in full. The chart README documents the resize procedure for
+  StorageClasses that support volume expansion.
+
+Scaling Server up and down is a values change (`server.replicas`, or `server.hpa`). Scaling **PD or Store down is
+not**: Raft and shard membership are persisted, deleting pods does not reconfigure them, and a 3-to-1 PD shrink
+permanently loses quorum. The chart rejects an upgrade whose replica count is below the live StatefulSet; the

Review Comment:
   Fixed in 795d5f835. The scaling paragraph now says changing the PD count in either direction, or shrinking Store, is not a values change, that the chart rejects both (the `pd.replicas cannot grow` and `cannot shrink` checks in `_helpers.tpl` at 0e754b98c), and links operations section 8. CN updated.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "imbajin (via GitHub)" <gi...@apache.org>.
imbajin commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4083549002


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use

Review Comment:
   ⚠️ Blocking: no. Summary: The page says an unbounded single-node install is fine, but even values-single runs one JVM per component with no memory limit and each image allows a 50% node-memory heap. Evidence: the #3218 values leave component resources empty and all three Dockerfiles set MaxRAMPercentage=50, so the three heap ceilings can exceed one node's memory. Please remove the single-node assurance and require memory sizing for this preset too; update the Chinese text at line 84.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** stay on `/v1/health` on purpose: a PD that merely lost its leader is

Review Comment:
   ⚠️ Blocking: no. Summary: Startup and liveness do not always use /v1/health: the single-PD preset uses /v1/ready for both, changing when Kubernetes restarts a lone PD that loses readiness. Evidence: #3218's helper selects /v1/ready when pd.replicas is 1, and values-single sets that count. Please qualify this as multi-PD behavior and document the single-PD exception in Chinese line 157.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080

Review Comment:
   🧹 Blocking: no. Summary: kubectl port-forward runs in the foreground, so the curl later in this same code block never runs in that shell. Evidence: the block has sequential commands and no backgrounding or separate-terminal instruction. Please split the forward and curl into separate terminal steps or explain how to run the forward in the background; update Chinese line 116.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** stay on `/v1/health` on purpose: a PD that merely lost its leader is
+still a healthy Raft member, and restarting it would make the outage worse.
+
+Server startup gets a matching budget: the image would normally kill a Server still starting after 120 seconds, so
+the chart derives `HG_SERVER_STARTUP_TIMEOUT_S` from the startup probe (450 seconds by default) and raises a lower
+configured probe budget to that floor. Raise `server.probes.startup` if your storage takes longer to come up, and
+the image budget follows.
+
+### 6 Enable the Hubble UI
+
+Hubble is off by default so API-only clusters stay lean. Enable it on a running release:
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values --set hubble.enabled=true
+```
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-hubble 8088:8088
+```
+
+Open `http://127.0.0.1:8088` and log in as `admin` with the admin password from Section 3.4. Hubble discovers the
+Servers through PD, so the cluster operations view works without extra wiring. Hubble serves plain HTTP: reach it
+through a port-forward or an HTTPS-terminating Ingress, never directly from an untrusted network. Running Hubble
+outside the cluster is possible but takes more wiring; see
+[Reaching Hubble](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#reaching-hubble-pick-one-path) in
+the chart README.
+
+### 7 Upgrade
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values
+```
+
+`--reuse-values` keeps the release's existing overrides; without it the upgrade rebuilds the release from chart
+defaults. Any upgrade that changes a Pod template rolls that workload once. Points worth planning around:
+
+- **The first upgrade after a fresh install rolls PD, Server, and Hubble once**, when the Secret-tracking
+  annotations first observe the install-created Secrets. Store is untouched.
+- **Store rolling updates advance on a listener check, not on shard recovery**, so the controller can replace the
+  next Store while the previous one is still rejoining its shard groups. For a production image roll, set
+  `store.updateStrategy.type=OnDelete` and replace Store pods one at a time, confirming the previous Store shows

Review Comment:
   ‼️ Blocking: yes. Summary: PD can report Up before a Store restores its shards and can retain Up during the keepalive window, so following this check can replace the next Store while the prior one is still recovering. Evidence: chart #3218 README says Up is not a recovery check and requires Pod Ready, a fresh heartbeat, and per-shard membership/leadership checks. Please replace the Up-only gate and sync Chinese line 194.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** stay on `/v1/health` on purpose: a PD that merely lost its leader is
+still a healthy Raft member, and restarting it would make the outage worse.
+
+Server startup gets a matching budget: the image would normally kill a Server still starting after 120 seconds, so
+the chart derives `HG_SERVER_STARTUP_TIMEOUT_S` from the startup probe (450 seconds by default) and raises a lower
+configured probe budget to that floor. Raise `server.probes.startup` if your storage takes longer to come up, and
+the image budget follows.
+
+### 6 Enable the Hubble UI
+
+Hubble is off by default so API-only clusters stay lean. Enable it on a running release:
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values --set hubble.enabled=true
+```
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-hubble 8088:8088
+```
+
+Open `http://127.0.0.1:8088` and log in as `admin` with the admin password from Section 3.4. Hubble discovers the
+Servers through PD, so the cluster operations view works without extra wiring. Hubble serves plain HTTP: reach it
+through a port-forward or an HTTPS-terminating Ingress, never directly from an untrusted network. Running Hubble
+outside the cluster is possible but takes more wiring; see
+[Reaching Hubble](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#reaching-hubble-pick-one-path) in
+the chart README.
+
+### 7 Upgrade
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values
+```
+
+`--reuse-values` keeps the release's existing overrides; without it the upgrade rebuilds the release from chart
+defaults. Any upgrade that changes a Pod template rolls that workload once. Points worth planning around:
+
+- **The first upgrade after a fresh install rolls PD, Server, and Hubble once**, when the Secret-tracking
+  annotations first observe the install-created Secrets. Store is untouched.
+- **Store rolling updates advance on a listener check, not on shard recovery**, so the controller can replace the
+  next Store while the previous one is still rejoining its shard groups. For a production image roll, set
+  `store.updateStrategy.type=OnDelete` and replace Store pods one at a time, confirming the previous Store shows
+  `Up` in PD before the next; PD restarts are one pod at a time either way, and `pd.updateStrategy.type=OnDelete`
+  gives the same manual control for maintenance windows.
+- **PVC sizes cannot be changed by upgrade**: Kubernetes forbids changing StatefulSet `volumeClaimTemplates`, so an
+  upgrade with a new `storage.size` is rejected in full. The chart README documents the resize procedure for
+  StorageClasses that support volume expansion.
+
+Scaling Server up and down is a values change (`server.replicas`, or `server.hpa`). Scaling **PD or Store down is
+not**: Raft and shard membership are persisted, deleting pods does not reconfigure them, and a 3-to-1 PD shrink
+permanently loses quorum. The chart rejects an upgrade whose replica count is below the live StatefulSet; the
+manual drain-then-scale procedure is in the chart README under
+[Scaling](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#scaling).
+
+### 8 Uninstall
+
+```bash
+helm uninstall hugegraph --namespace hugegraph
+```
+
+Two kinds of state survive on purpose. PersistentVolumeClaims created by the StatefulSets are kept (Kubernetes
+behavior); delete them explicitly once the data is no longer needed. The chart-managed Secrets are also kept, so a
+later install under the same release name comes back with the same credentials.
+
+### 9 Limitations
+
+- No NetworkPolicy resources yet. With the PD Raft IP allowlist disabled in-cluster (pod IPs change; the allowlist

Review Comment:
   ⚠️ Blocking: no. Summary: The chart has NetworkPolicy resources; they are off in default values and enabled by values-cluster.yaml, so this statement misdescribes the recommended preset and its access boundary. Evidence: #3218 includes the NetworkPolicy template and cluster values; outside clients may need extraIngress and a NetworkPolicy-capable CNI. Please document default-off/cluster-on behavior and external ingress setup; update Chinese line 214.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
bitflicker64 commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4166021776


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** stay on `/v1/health` on purpose: a PD that merely lost its leader is
+still a healthy Raft member, and restarting it would make the outage worse.
+
+Server startup gets a matching budget: the image would normally kill a Server still starting after 120 seconds, so
+the chart derives `HG_SERVER_STARTUP_TIMEOUT_S` from the startup probe (450 seconds by default) and raises a lower

Review Comment:
   Fixed in 5e4cbd25c. Section 5 now says the probe guarantees at least 450 s, counted as `(failureThreshold - 1) * periodSeconds`, and that `HG_SERVER_STARTUP_TIMEOUT_S` is that time minus the 300 s storage wait: 150 s by default, never below 120 s. The chart README's Chart Details bullet at d05741d9c says the same. CN updated.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use

Review Comment:
   Fixed in 795d5f835. The single-node assurance is gone. Section 3.2 now says each JVM sets its maximum heap to half of the free node memory it sees at start (`calc_xmx` in the start scripts, with a per-component ceiling), so the JVMs on one node can claim more than the node has, `values-single.yaml` included, and asks for `resources` on every install. The troubleshooting row no longer says multi-node only. CN updated. The chart README's Limitations bullet still says "Fine on a single node"; #3218 needs the same change.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** stay on `/v1/health` on purpose: a PD that merely lost its leader is

Review Comment:
   Fixed in c4ed3619c. Section 5 now says startup and liveness derive from the replica count: `/v1/health` with more than one PD, and `/v1/ready` for a single PD, with the reason. Re-checked at chart 0e754b98c: with one PD, `helm template` renders `/v1/ready` for all three PD probes. The CN paragraph matches.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080

Review Comment:
   Fixed in 686d3b930. Section 3.4 now starts the port-forward in its own block and terminal, then reads the password and runs `curl` from a second terminal. The operations page health check and its per-Pod Gremlin check got the same split, in EN and CN.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
bitflicker64 commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4174084097


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable

Review Comment:
   Follow-up in a5fadccb0: chart 2a6e2c404 (apache/hugegraph#3218) narrowed the admin password to printable ASCII with no spaces, colons or backslashes, which also covers the old leading and trailing whitespace rule. The schema checks an inline value at render time and the Server wrapper checks an `existingSecret` at Pod start. Section 4 now says this in EN and CN. The PD secret rule has not changed.



##########
content/cn/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,251 @@
+---
+title: "使用 Helm 在 Kubernetes 上部署"
+linkTitle: "Kubernetes 部署 (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 概述
+
+Helm chart 在 Kubernetes 上部署一套分布式 HugeGraph 集群:PD、Store、Server,以及可选的 Hubble UI。chart 位于主仓库的
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph) 目录。
+
+| 组件 | 工作负载 | 默认副本数 | 作用 |
+|------|----------|------------|------|
+| PD | StatefulSet + PVC | 3 | 元数据管理:以 Raft 组跟踪 Store 与分区 |
+| Store | StatefulSet + PVC | 3 | 图数据存储 (HStore) |
+| Server | Deployment | 3 | Gremlin 与 REST 查询层 |
+| Hubble | Deployment | 0(默认关闭) | Web UI,通过 `hubble.enabled=true` 启用 |
+
+分布式 HugeGraph 集群有一套启动约定(Server 不执行 `init-store`、每个 Server 都通过 PD 读写图元数据、Store 等待 PD
+形成多数派、一个 PD REST 密钥由三个组件共用)。chart 把这套约定固化下来,运维人员无需手工处理;细节见
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details)。日常运维(NetworkPolicy
+细节、灾难恢复、伸缩、安全滚动 Store、在集群外运行 Hubble)见
+[运维页](/cn/docs/quickstart/hugegraph/hugegraph-helm-operations/)。
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes 集群
+        PD[PD StatefulSet<br>3 节点 Raft 组,PVC]
+        Store[Store StatefulSet<br>3 副本,PVC] -->|注册、心跳| PD
+        Server[Server Deployment<br>3 副本] -->|元数据、服务发现| PD
+        Server -->|gRPC 读写| Store
+        Hubble[Hubble Deployment<br>可选 UI] -->|通过 PD 发现 Server| PD
+    end
+    Client[客户端 / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+启动顺序由 chart 保证,而不是由运维人员保证:PD 先选出 leader,每个 Store Pod 的 init 容器等到多数 PD 汇报就绪后才启动,
+Server 则反复等待存储层,直到 Store 完成注册。全新安装无需手工干预即可收敛。
+
+### 2 前置条件
+
+- Kubernetes 1.23 及以上(chart 渲染 `autoscaling/v2` 和 `policy/v1`)
+- Helm 3;升级一节提到的 `--reset-then-reuse-values` 需要 Helm 3.14 及以上
+- 动态卷供给:有默认 StorageClass,或为 PD 和 Store 显式指定 `storageClassName`
+- 默认拓扑要运行九个 JVM 进程,内存需留足;见安装一节的资源说明
+
+chart 要求组件镜像包含 PD 就绪探测端点和 PD REST 认证(两者都已合入 1.7.0 之后的版本)。默认镜像 tag 指向的构建已包含
+这些改动;1.7.0 镜像不受支持。
+
+### 3 安装
+
+#### 3.1 获取 chart
+
+chart 尚未发布到 chart 仓库,从源码树安装:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 使用默认值安装
+
+先确认 `kubectl` 指向目标集群,且集群能供给存储卷。因缺少 StorageClass 而卡在 `Pending` 的 PVC 是最常见的首次安装
+故障:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+然后安装:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` 让 Helm 阻塞到所有工作负载就绪。对分布式集群来说,这个信号意味着 PD 已选出 leader、Store 已注册、Server 已
+启动;不加它,`helm install` 在对象创建完成后就返回。全新集群一般几分钟内收敛,15 分钟超时是给缓慢的镜像拉取留的余量。
+
+继续之前需要了解两个默认值:
+
+- **默认不设置 resources。** 每个 Pod 都是 BestEffort,JVM 按节点总内存计算堆大小。单节点没有问题;多节点集群上各个堆
+  会超订节点内存导致进程中止。超出笔记本范围的部署请使用 `values-cluster.yaml`,或按组件设置 `resources`。
+- **镜像 tag 跟踪 `latest`**,且 `pullPolicy: Always`,直到下一个 HugeGraph 版本发布。生产环境请固定 tag 或 digest。
+
+#### 3.3 拓扑预设
+
+chart 附带三个 values 文件:
+
+| 文件 | 拓扑 | 适用场景 |
+|------|------|----------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | 默认;preferred 反亲和,认证开启,Hubble 关闭 |
+| `values-single.yaml` | 1 + 1 + 1 | 单节点开发与 CI;PVC 更小 |
+| `values-cluster.yaml` | 3 + 3 + 3 | 生产起点:JVM 堆与资源设置、PD/Store PodDisruptionBudget、`required` 反亲和、NetworkPolicy 开启 |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` 是起点而非容量保证:请按图规模和流量重新核算资源。其中一个数字值得说明:它给每个 Store 申请
+5Gi、限制 8Gi 内存,远高于 1Gi 的堆,因为 Store 的 RocksDB 缓存在 JVM 堆之外(4Gi 的限制在约 1 GB 数据后就把
+Store OOM 杀掉了)。两个数字要随数据量一起放大。完整参数参考(每个组件的探针、调度、Secret 配置项)见
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration)。
+
+#### 3.4 验证安装
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+读取自动生成的 admin 密码并调用 API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+以上命令假定 release 名为 `hugegraph`;用其他名字时,请替换成带 release 前缀的资源名(`kubectl get svc,secret -n
+<namespace>` 可以列出)。`helm install` 结束时打印的说明里包含填好名字的同样命令。
+
+### 4 认证与 Secret
+
+认证默认开启,chart 管理三个 Secret。每个凭据按同一顺序取值:你预先创建的 `existingSecret` 优先,其次是内联值,最后
+是安装时随机生成。
+
+| Secret | 键 | 用途 | 自带凭据的配置项 |
+|--------|-----|------|------------------|
+| `<release>-admin` | `password` | Server admin 账号、Hubble 登录 | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | 所有 Server 副本共用的 JWT 签名密钥 | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST 认证,由 PD、Server、Hubble 读取 | `pd.auth.existingSecret` |
+
+要自行管理凭据,请在安装前创建 Secret 并把对应的 `existingSecret` 指向它;chart 不会改动任何不是它创建的 Secret。取值
+约束:admin 密码不能包含换行、回车或反斜杠;JWT 密钥至少 32 字节;PD 密钥必须是可打印 ASCII。非法值会在渲染时或启动

Review Comment:
   Follow-up in a5fadccb0: chart 2a6e2c404 (apache/hugegraph#3218) narrowed the admin password to printable ASCII with no spaces, colons or backslashes, which also covers the old leading and trailing whitespace rule. The schema checks an inline value at render time and the Server wrapper checks an `existingSecret` at Pod start. Section 4 now says this in EN and CN. The PD secret rule has not changed.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,282 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+Day-2 work (NetworkPolicy details, disaster recovery, scaling, safe Store
+rolls, running Hubble outside the cluster) is on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity, NetworkPolicy on |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. One of its numbers deserves a note: it requests 5Gi and limits at 8Gi of memory per Store, well above the
+1Gi heap, because the Store's RocksDB caches live outside the JVM heap (a 4Gi limit OOM-killed Stores after about
+1 GB of data). Scale both numbers with data size. The full parameter reference (every component, probe,
+scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable

Review Comment:
   Follow-up in a5fadccb0: chart 2a6e2c404 (apache/hugegraph#3218) narrowed the admin password to printable ASCII with no spaces, colons or backslashes, which also covers the old leading and trailing whitespace rule. The schema checks an inline value at render time and the Server wrapper checks an `existingSecret` at Pod start. Section 4 now says this in EN and CN. The PD secret rule has not changed.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,282 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+Day-2 work (NetworkPolicy details, disaster recovery, scaling, safe Store
+rolls, running Hubble outside the cluster) is on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity, NetworkPolicy on |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. One of its numbers deserves a note: it requests 5Gi and limits at 8Gi of memory per Store, well above the
+1Gi heap, because the Store's RocksDB caches live outside the JVM heap (a 4Gi limit OOM-killed Stores after about
+1 GB of data). Scale both numbers with data size. The full parameter reference (every component, probe,
+scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable
+ASCII. Invalid values are rejected at render time or by the startup wrapper, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating the PD REST Secret rolls PD, Server, and Hubble together on the next `helm upgrade`, which keeps their
+  copies in step. Template-only pipelines (`helm template`, GitOps renderers) cannot see live Secrets, so there the
+  rotation-detecting annotation is inert.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** derive from the replica count (`pd.livenessPath` overrides the
+choice). With more than one PD they stay on `/v1/health` on purpose: a PD that merely lost its leader is still a
+healthy Raft member, and restarting it would make the outage worse. A single PD is the exception and derives to
+`/v1/ready`: it has no election to lose, and one that steps down for good, as after a failed Raft snapshot on a
+full disk ([apache/hugegraph#3222](https://github.com/apache/hugegraph/issues/3222)), would answer `/v1/health`
+forever while serving no writes; the kubelet restarts it instead.
+
+Server startup gets a matching budget: the image would normally kill a Server still starting after 120 seconds, so
+the chart derives `HG_SERVER_STARTUP_TIMEOUT_S` from the startup probe (450 seconds by default) and raises a lower
+configured probe budget to that floor. Raise `server.probes.startup` if your storage takes longer to come up, and
+the image budget follows.
+
+### 6 Enable the Hubble UI
+
+Hubble is off by default so API-only clusters stay lean. Enable it on a running release:
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values --set hubble.enabled=true
+```
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-hubble 8088:8088
+```
+
+Open `http://127.0.0.1:8088` and log in as `admin` with the admin password from Section 3.4. Hubble discovers the
+Servers through PD, so the cluster operations view works without extra wiring. Hubble serves plain HTTP: reach it
+through a port-forward or an HTTPS-terminating Ingress, never directly from an untrusted network. Running Hubble
+outside the cluster is possible but takes more wiring; see
+[Reaching Hubble](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#reaching-hubble-pick-one-path) in
+the chart README.
+
+### 7 Upgrade
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values
+```
+
+`--reuse-values` keeps the release's existing overrides; without it the upgrade rebuilds the release from chart
+defaults. Any upgrade that changes a Pod template rolls that workload once. Points worth planning around:
+
+- **The first upgrade after a fresh install rolls PD, Server, and Hubble once**, when the Secret-tracking

Review Comment:
   Follow-up in a5fadccb0: at chart 2a6e2c404 a no-change upgrade rolls nothing, so the first-upgrade bullet is gone. Section 7 now says the annotations hash the credential value, or the `resourceVersion` of an `existingSecret`, and keeps the `helm test` advice for any upgrade that does roll PD and Server together, such as a PD REST Secret rotation. EN and CN match.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).

Review Comment:
   Still applies at a5fadccb0. Checked 2026-10-03: apache/hugegraph master (02628ed50) has no `helm/` directory, and apache/hugegraph#3218 is open at 2a6e2c404. Leaving this thread open as the merge-order gate: merge #3218 first, then this PR.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
bitflicker64 commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4166020304


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).

Review Comment:
   Still applies at 795d5f835. Checked 2026-10-02: apache/hugegraph master (176fb56dd) has no `helm/` directory, and apache/hugegraph#3218 is open (out of draft, head d05741d9c). Until it merges, the install in 3.2 and the `tree/master/helm/hugegraph` links fail. Leaving this thread open as the merge-order gate: merge #3218 first, or hold this PR until then.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later

Review Comment:
   Fixed in 795d5f835. Section 7 now says `--reuse-values` keeps the old values as the complete base, so a release from an earlier chart revision does not pick up new defaults such as the hardened `securityContext`, and that `-f` or `--reset-then-reuse-values` adopts them. The Prerequisites reference now points at real text. CN updated the same way.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |

Review Comment:
   Fixed in 795d5f835: the `values-cluster.yaml` row now says Server PodDisruptionBudget, in EN and CN. Re-checked at chart 0e754b98c: `values.yaml` enables the PD and Store PDBs, and `helm template -f values-cluster.yaml` adds the Server one. The chart README's Values Presets table at d05741d9c still says "PD/Store PDBs"; that is a #3218 follow-up, outside this PR.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,263 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort and each JVM sizes its heap against total node memory. That is
+  fine on a single node; on a multi-node cluster the heaps oversubscribe the nodes and pods abort. Use
+  `values-cluster.yaml` or set `resources` per component for anything beyond a laptop.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, PD/Store PodDisruptionBudgets, `required` anti-affinity |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. The full parameter reference (every component, probe, scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+Read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must not contain
+newlines, carriage returns, or backslashes; the JWT key must be at least 32 bytes; the PD secret must be printable

Review Comment:
   Fixed in 5e4cbd25c. Section 4 now says the admin password must not contain newlines, carriage returns or backslashes, or start or end with whitespace, and the PD secret must be printable ASCII with no backslashes and no leading or trailing space. That matches the `pd.auth.value` schema pattern at chart 0e754b98c, which also rejects a trailing space. CN updated the same way.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "imbajin (via GitHub)" <gi...@apache.org>.
imbajin commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4176317396


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,523 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one

Review Comment:
   ⚠️ Important: The 20 s period and three failures describe detection in about one minute, but the chart sets `store.terminationGracePeriodSeconds` to 300 s. Kubelet can wait through that grace period before forcing down an unresponsive Store, so the total restart and recovery window can be several minutes longer. Please call one minute the approximate detection time and mention the grace period; sync the Chinese page.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,523 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward. It runs in the foreground, so keep
+it in one terminal:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+```
+
+and call the API from a second terminal, with `PASSWORD` set as above:
+
+```bash
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry. An
+in-cluster Hubble in `pd` mode combined with `server.advertiseUrl` also
+fails the render until `networkPolicy.hubble.extraEgress` admits the
+advertised destination: PD hands Hubble that URL for discovery, and
+Hubble's egress policy otherwise reaches only the release's own Pods.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. `values-cluster.yaml` therefore sets
+`store.updateStrategy.type=OnDelete` (set it yourself on any other
+production values): an upgrade then updates the StatefulSet without
+replacing any Store Pod, and you delete Store Pods one at a time, checking
+between deletions. `OnDelete` only stops automatic advancement; deleting
+Pods without the checks below carries the same risk.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, leader, and
+committed index (`logIndex`) that Store holds, and fails while the Store
+is down; compare the index with a peer Store rather than reading it
+alone. This route never fills its `term` field, so `term` always reads 0
+there. The plural `GET :8520/v1/partitions` answers 500 on any Store that
+follows a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a

Review Comment:
   ⚠️ Important: This procedure tells operators to delete Store Pods one at a time, then says the PDB refuses a second eviction. If operators use ordinary Pod deletion, Kubernetes bypasses PDB enforcement; only Eviction API requests honor the budget. The PDB therefore cannot protect the manual rollout as written. Please specify an eviction-based procedure or limit this claim to `kubectl drain` and other eviction clients; sync Chinese. [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/).



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,523 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward. It runs in the foreground, so keep
+it in one terminal:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+```
+
+and call the API from a second terminal, with `PASSWORD` set as above:
+
+```bash
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry. An
+in-cluster Hubble in `pd` mode combined with `server.advertiseUrl` also
+fails the render until `networkPolicy.hubble.extraEgress` admits the
+advertised destination: PD hands Hubble that URL for discovery, and
+Hubble's egress policy otherwise reaches only the release's own Pods.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. `values-cluster.yaml` therefore sets
+`store.updateStrategy.type=OnDelete` (set it yourself on any other
+production values): an upgrade then updates the StatefulSet without
+replacing any Store Pod, and you delete Store Pods one at a time, checking
+between deletions. `OnDelete` only stops automatic advancement; deleting
+Pods without the checks below carries the same risk.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, leader, and
+committed index (`logIndex`) that Store holds, and fails while the Store
+is down; compare the index with a peer Store rather than reading it
+alone. This route never fills its `term` field, so `term` always reads 0
+there. The plural `GET :8520/v1/partitions` answers 500 on any Store that
+follows a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a
+group that is short a shard or has no leader as a stop. A real
+restoration-complete signal is upstream work, tracked in
+[apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229).
+
+### 7 Disaster recovery
+
+What PD automates on current builds is narrow: a 60-second patrol only
+marks Stores that stopped sending heartbeats as `Offline`. There is no
+automatic re-replication; re-placing the replicas of a lost Store,
+reconciling shard groups, and processing tombstoned Stores run only when a
+partition patrol is triggered explicitly.
+
+The task endpoints execute locally on the PD that receives them, and a
+follower answers with an empty success while doing nothing.
+Port-forwarding the client Service selects an arbitrary PD, so identify
+the leader first, then port-forward that Pod (two terminals: the forward
+runs in the foreground):
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-pd-client 8620:8620
+# Read .data.pdLeader.raftUrl; its host names the leader Pod.
+curl -su "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/members
+# Stop the Service forward, then forward the leader Pod instead.
+kubectl port-forward -n hugegraph pod/<leader-pod> 8620:8620
+# Reconcile shard groups and process tombstoned Stores.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/patrolPartitions
+# If the patrol repaired a shard group, wait 180 s first (see below).
+# Spread Raft leaders, then partition data.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balanceLeaders
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balancePartitions
+```
+
+Read `/v1/members` again after the tasks: if leadership moved mid-sequence,
+the later tasks ran on a follower and did nothing. PD sets a
+balance-shard flag for 180 s in two cases: `patrolPartitions` sets it
+whenever it reallocates a shard group whose shard count is wrong, and
+`balancePartitions` sets it even when it moves nothing. Inside that
+window `balanceLeaders` is refused and `balancePartitions` returns
+without doing anything, so wait at least 180 s after a patrol that
+repaired a group, and after `balancePartitions`, before the next
+balancing call. On images built before
+[apache/hugegraph#3233](https://github.com/apache/hugegraph/pull/3233)
+(merged 2026-09-24) the refusal is a bare HTTP 500 whose reason appears
+only in the PD log; after it, the reason comes back in the body as
+`{"status":1001,"error":"balance shard is processing, please try later!"}`.
+
+Telling a real run from a no-op takes the PD leader's log, because the
+responses do not: `patrolPartitions` answers the same empty success on the
+leader and on a follower, whether or not it repaired anything (look for
+`reallocShards`, `shardOffline` or `storeTurnoff` lines, or diff
+`/v1/shardGroups` before and after), and `balancePartitions` answers `{}`
+on the leader and an empty body on a follower. `balanceLeaders` is the one
+call whose body carries the work. Distinguishable task responses are
+upstream work, tracked in
+[apache/hugegraph#3231](https://github.com/apache/hugegraph/issues/3231).
+
+Run `patrolPartitions` after replacing a Store that is not coming back,
+`balancePartitions` once the cluster is stable again, and `balanceLeaders`
+after restarts that skewed leader placement.
+
+**Losing a Store volume.** A Store rebuilt with an empty PVC recovers in
+place on images carrying
+[apache/hugegraph#3234](https://github.com/apache/hugegraph/pull/3234)
+(merged 2026-09-24); on every earlier image, including all published
+release images, it does not. In both cases the replacement registers under
+a new Store ID while its Pod name, DNS name, and raft address are
+unchanged, so `/v1/stores` lists two IDs at one address.
+
+On post-#3234 images the retirement works: find the old ID in `/v1/stores`
+(the row at the replaced Pod's address that is not the newly registered
+one), `POST /v1/store/<oldId>` with `{"storeState":"Tombstone"}` on the PD
+leader, run `GET /v1/task/patrolPartitions`, and wait; verify every shard
+group is back to full shard count with one leader, no group names the old
+ID, and the replaced Store's own `:8520/v1/partition/<groupId>` answers
+200 for every group; then `DELETE /v1/store/<oldId>` to erase the retired
+record. Measured on a 3+3+3 install with images built from `master` at
+`dbb6663a`: the replacement was Ready in 156 s, all 12 groups converged
+onto the new ID 1 s after the Tombstone and patrol (the empty Store caught
+up by raft snapshot install), and a continuous writer lost 0 acknowledged
+writes.
+
+On images without #3234 the same retirement runs and does not repair the
+groups: PD fires the configuration change, but the group leader sees the
+address already in the group, so jraft has nothing to add and the group
+keeps the old ID. Measured: 20 minutes and three patrols later, all 12
+groups still listed the retired ID and the replacement Store held no
+partitions. Nothing in the health surface shows the failure; `/v1/stores`,
+cluster state, Hubble, and Pod readiness all read healthy while every
+shard group runs on two live replicas. The one check that shows it is the
+replaced Store's own `:8520/v1/partition/<groupId>`.
+
+So the default remains: replace a Store Pod, keep its PVC (the Store id
+lives in the data path, and the Pod comes back under the same id). Treat
+the empty-PVC procedure as recovery for post-#3234 images only; on a
+released image a genuinely lost volume leaves the cluster degraded, and
+expect to rebuild rather than to recover in place.
+
+Periodic leader balancing is tracked in
+[apache/hugegraph#3135](https://github.com/apache/hugegraph/issues/3135);
+disaster-recovery metrics in
+[apache/hugegraph#3136](https://github.com/apache/hugegraph/issues/3136).
+
+### 8 Scaling
+
+PD and Store reserve the maximum StatefulSet ordinal in their resource
+names, so scaling never renames a PersistentVolumeClaim or shifts a Pod
+identity; both are capped at 99 replicas. Server scales freely through
+`server.replicas` or `server.hpa` (with HPA on, the Deployment omits
+`spec.replicas` so upgrades do not overwrite the autoscaler).
+
+A staged rollout cannot be written in a values file (the schema requires
+one replica per component); stage it with `kubectl scale statefulset
+hugegraph-store --replicas=0` and scale back up when ready. The Servers
+wait, not ready, until Stores register, and the next `helm upgrade`
+restores the full topology from values.
+
+Changing PD or Store replicas on a live release is not a values change:
+raft and shard membership are persisted, and Pods alone do not reconfigure
+them. The chart rejects both directions for PD and a shrink for Store by
+reading the live StatefulSet, so fresh installs at any count are
+unaffected.
+
+**PD, either direction.** The rendered peer list reaches raft only as its
+bootstrap configuration, which an initialized group ignores; a 3-to-5
+upgrade leaves the voting configuration at three, and a 3-to-1 shrink
+loses quorum outright. Membership changes go through PD's peer-list
+change, which the PD client API and the PD REST route
+`POST /v1/members/change` both expose; the route needs the same Basic
+authentication as the other PD REST routes, and the chart wraps neither.
+Change the membership through PD, confirm it in `/v1/members`, scale the
+live StatefulSet, then `helm upgrade` with the matching value; until that
+sequence is verified on your own build, install the PD count you intend
+to keep.
+
+**Store, shrinking.** Draining is a state transition, not a balance:
+neither `patrolPartitions` nor `balancePartitions` retires a healthy
+Store. Retire the leaving Stores the way Disaster Recovery retires a
+replaced one:
+
+1. Check the remaining Stores still cover the persisted shard count
+   (`pd.partition.defaultShardCount`; empty derives 3 when
+   `store.replicas` is at least 3).
+2. Map the ordinals the shrink will delete (the highest ones) to Store
+   ids through `/v1/stores`, matching on the Pod address.
+3. `POST /v1/store/<id>` with `{"storeState":"Tombstone"}` for each
+   leaving id.
+4. Wait until `/v1/shardGroups` no longer lists those ids and every group
+   reports its full shard count with one leader.
+5. Scale the live StatefulSet, then `helm upgrade` with the matching
+   value.
+
+The chart keeps the PVCs of removed ordinals
+(`store.persistentVolumeClaimRetentionPolicy.whenScaled: Retain`), and a
+retained PVC still holds the retired Store id. PD refuses to register a
+Store id that is Tombstone or deleted, so a Store that later starts on
+that PVC, as when you scale the same ordinal back up, cannot join.
+Delete the PVCs of the removed ordinals after step 4 reports the data
+moved and before reusing those ordinals; the deletion is permanent.
+
+### 9 Running Hubble outside the cluster
+
+In-cluster Hubble (`hubble.enabled=true` plus a port-forward) is the
+recommended path and is covered on the deployment page. Two paths exist
+for a Hubble that must run outside the cluster.
+
+**Direct Server URL** (graph, schema, data, and Gremlin; no PD
+discovery): leave in-chart Hubble off, expose Server through an
+HTTPS-terminating Ingress or a NodePort/LoadBalancer `server.service.type`,
+and run a standalone Hubble image. The Service carries the plain-HTTP API,
+so the chart requires `server.service.allowInsecureExposure=true` for it;
+restrict who can reach it first. The Hubble properties are:
+
+```properties
+pd.enabled=false
+server.direct_url=https://<reachable-server-host>:<port>
+```
+
+Mount the file at `/hubble/conf/hugegraph-hubble.properties` (the image
+workdir is `/hubble`). Use HTTPS or a trusted channel for
+`server.direct_url`: login sends the Server credentials over that URL.
+
+**PD discovery** (the outside Hubble asks PD for the Server address):
+in-cluster names such as `*.svc` are not reachable from outside, so the
+chart provides two knobs. Set `server.advertiseUrl` to the absolute

Review Comment:
   ⚠️ Important: PD returns this advertised URL to Hubble, which then sends Server login credentials to the discovered URL. This section allows `http://` without the HTTPS or trusted-channel warning given for `server.direct_url` above. Please require HTTPS or a trusted private transport for production advertised URLs and sync Chinese.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,523 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward. It runs in the foreground, so keep
+it in one terminal:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+```
+
+and call the API from a second terminal, with `PASSWORD` set as above:
+
+```bash
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry. An
+in-cluster Hubble in `pd` mode combined with `server.advertiseUrl` also
+fails the render until `networkPolicy.hubble.extraEgress` admits the
+advertised destination: PD hands Hubble that URL for discovery, and
+Hubble's egress policy otherwise reaches only the release's own Pods.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. `values-cluster.yaml` therefore sets
+`store.updateStrategy.type=OnDelete` (set it yourself on any other
+production values): an upgrade then updates the StatefulSet without
+replacing any Store Pod, and you delete Store Pods one at a time, checking
+between deletions. `OnDelete` only stops automatic advancement; deleting
+Pods without the checks below carries the same risk.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, leader, and
+committed index (`logIndex`) that Store holds, and fails while the Store
+is down; compare the index with a peer Store rather than reading it
+alone. This route never fills its `term` field, so `term` always reads 0
+there. The plural `GET :8520/v1/partitions` answers 500 on any Store that
+follows a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a
+group that is short a shard or has no leader as a stop. A real
+restoration-complete signal is upstream work, tracked in
+[apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229).
+
+### 7 Disaster recovery
+
+What PD automates on current builds is narrow: a 60-second patrol only
+marks Stores that stopped sending heartbeats as `Offline`. There is no
+automatic re-replication; re-placing the replicas of a lost Store,
+reconciling shard groups, and processing tombstoned Stores run only when a
+partition patrol is triggered explicitly.
+
+The task endpoints execute locally on the PD that receives them, and a
+follower answers with an empty success while doing nothing.
+Port-forwarding the client Service selects an arbitrary PD, so identify
+the leader first, then port-forward that Pod (two terminals: the forward
+runs in the foreground):
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-pd-client 8620:8620
+# Read .data.pdLeader.raftUrl; its host names the leader Pod.
+curl -su "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/members
+# Stop the Service forward, then forward the leader Pod instead.
+kubectl port-forward -n hugegraph pod/<leader-pod> 8620:8620
+# Reconcile shard groups and process tombstoned Stores.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/patrolPartitions
+# If the patrol repaired a shard group, wait 180 s first (see below).
+# Spread Raft leaders, then partition data.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balanceLeaders
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balancePartitions
+```
+
+Read `/v1/members` again after the tasks: if leadership moved mid-sequence,
+the later tasks ran on a follower and did nothing. PD sets a
+balance-shard flag for 180 s in two cases: `patrolPartitions` sets it
+whenever it reallocates a shard group whose shard count is wrong, and
+`balancePartitions` sets it even when it moves nothing. Inside that
+window `balanceLeaders` is refused and `balancePartitions` returns
+without doing anything, so wait at least 180 s after a patrol that
+repaired a group, and after `balancePartitions`, before the next
+balancing call. On images built before
+[apache/hugegraph#3233](https://github.com/apache/hugegraph/pull/3233)
+(merged 2026-09-24) the refusal is a bare HTTP 500 whose reason appears
+only in the PD log; after it, the reason comes back in the body as
+`{"status":1001,"error":"balance shard is processing, please try later!"}`.
+
+Telling a real run from a no-op takes the PD leader's log, because the
+responses do not: `patrolPartitions` answers the same empty success on the
+leader and on a follower, whether or not it repaired anything (look for
+`reallocShards`, `shardOffline` or `storeTurnoff` lines, or diff
+`/v1/shardGroups` before and after), and `balancePartitions` answers `{}`
+on the leader and an empty body on a follower. `balanceLeaders` is the one
+call whose body carries the work. Distinguishable task responses are
+upstream work, tracked in
+[apache/hugegraph#3231](https://github.com/apache/hugegraph/issues/3231).
+
+Run `patrolPartitions` after replacing a Store that is not coming back,
+`balancePartitions` once the cluster is stable again, and `balanceLeaders`
+after restarts that skewed leader placement.
+
+**Losing a Store volume.** A Store rebuilt with an empty PVC recovers in
+place on images carrying
+[apache/hugegraph#3234](https://github.com/apache/hugegraph/pull/3234)
+(merged 2026-09-24); on every earlier image, including all published
+release images, it does not. In both cases the replacement registers under
+a new Store ID while its Pod name, DNS name, and raft address are
+unchanged, so `/v1/stores` lists two IDs at one address.
+
+On post-#3234 images the retirement works: find the old ID in `/v1/stores`
+(the row at the replaced Pod's address that is not the newly registered
+one), `POST /v1/store/<oldId>` with `{"storeState":"Tombstone"}` on the PD
+leader, run `GET /v1/task/patrolPartitions`, and wait; verify every shard
+group is back to full shard count with one leader, no group names the old
+ID, and the replaced Store's own `:8520/v1/partition/<groupId>` answers

Review Comment:
   ⚠️ Important: Full shard-group membership and HTTP 200 from this endpoint do not prove the replacement has caught up. `PartitionEngine.syncShardIdentities()` updates the shard IDs in PD before `waitForReplicate()` completes, and this endpoint exposes the current `logIndex` during that wait. Please compare the replacement's index with the leader or a current peer for every group before deleting the old Tombstone record; sync Chinese.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,523 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward. It runs in the foreground, so keep
+it in one terminal:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+```
+
+and call the API from a second terminal, with `PASSWORD` set as above:
+
+```bash
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry. An
+in-cluster Hubble in `pd` mode combined with `server.advertiseUrl` also
+fails the render until `networkPolicy.hubble.extraEgress` admits the
+advertised destination: PD hands Hubble that URL for discovery, and
+Hubble's egress policy otherwise reaches only the release's own Pods.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. `values-cluster.yaml` therefore sets
+`store.updateStrategy.type=OnDelete` (set it yourself on any other
+production values): an upgrade then updates the StatefulSet without
+replacing any Store Pod, and you delete Store Pods one at a time, checking
+between deletions. `OnDelete` only stops automatic advancement; deleting
+Pods without the checks below carries the same risk.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, leader, and
+committed index (`logIndex`) that Store holds, and fails while the Store
+is down; compare the index with a peer Store rather than reading it
+alone. This route never fills its `term` field, so `term` always reads 0
+there. The plural `GET :8520/v1/partitions` answers 500 on any Store that
+follows a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a
+group that is short a shard or has no leader as a stop. A real
+restoration-complete signal is upstream work, tracked in
+[apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229).
+
+### 7 Disaster recovery
+
+What PD automates on current builds is narrow: a 60-second patrol only
+marks Stores that stopped sending heartbeats as `Offline`. There is no
+automatic re-replication; re-placing the replicas of a lost Store,
+reconciling shard groups, and processing tombstoned Stores run only when a
+partition patrol is triggered explicitly.
+
+The task endpoints execute locally on the PD that receives them, and a
+follower answers with an empty success while doing nothing.
+Port-forwarding the client Service selects an arbitrary PD, so identify
+the leader first, then port-forward that Pod (two terminals: the forward
+runs in the foreground):
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-pd-client 8620:8620
+# Read .data.pdLeader.raftUrl; its host names the leader Pod.
+curl -su "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/members
+# Stop the Service forward, then forward the leader Pod instead.
+kubectl port-forward -n hugegraph pod/<leader-pod> 8620:8620
+# Reconcile shard groups and process tombstoned Stores.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/patrolPartitions
+# If the patrol repaired a shard group, wait 180 s first (see below).
+# Spread Raft leaders, then partition data.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balanceLeaders
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balancePartitions
+```
+
+Read `/v1/members` again after the tasks: if leadership moved mid-sequence,
+the later tasks ran on a follower and did nothing. PD sets a
+balance-shard flag for 180 s in two cases: `patrolPartitions` sets it
+whenever it reallocates a shard group whose shard count is wrong, and
+`balancePartitions` sets it even when it moves nothing. Inside that
+window `balanceLeaders` is refused and `balancePartitions` returns
+without doing anything, so wait at least 180 s after a patrol that
+repaired a group, and after `balancePartitions`, before the next
+balancing call. On images built before
+[apache/hugegraph#3233](https://github.com/apache/hugegraph/pull/3233)
+(merged 2026-09-24) the refusal is a bare HTTP 500 whose reason appears
+only in the PD log; after it, the reason comes back in the body as
+`{"status":1001,"error":"balance shard is processing, please try later!"}`.
+
+Telling a real run from a no-op takes the PD leader's log, because the
+responses do not: `patrolPartitions` answers the same empty success on the
+leader and on a follower, whether or not it repaired anything (look for
+`reallocShards`, `shardOffline` or `storeTurnoff` lines, or diff
+`/v1/shardGroups` before and after), and `balancePartitions` answers `{}`
+on the leader and an empty body on a follower. `balanceLeaders` is the one
+call whose body carries the work. Distinguishable task responses are
+upstream work, tracked in
+[apache/hugegraph#3231](https://github.com/apache/hugegraph/issues/3231).
+
+Run `patrolPartitions` after replacing a Store that is not coming back,
+`balancePartitions` once the cluster is stable again, and `balanceLeaders`
+after restarts that skewed leader placement.
+
+**Losing a Store volume.** A Store rebuilt with an empty PVC recovers in
+place on images carrying
+[apache/hugegraph#3234](https://github.com/apache/hugegraph/pull/3234)
+(merged 2026-09-24); on every earlier image, including all published
+release images, it does not. In both cases the replacement registers under
+a new Store ID while its Pod name, DNS name, and raft address are
+unchanged, so `/v1/stores` lists two IDs at one address.
+
+On post-#3234 images the retirement works: find the old ID in `/v1/stores`
+(the row at the replaced Pod's address that is not the newly registered
+one), `POST /v1/store/<oldId>` with `{"storeState":"Tombstone"}` on the PD
+leader, run `GET /v1/task/patrolPartitions`, and wait; verify every shard
+group is back to full shard count with one leader, no group names the old
+ID, and the replaced Store's own `:8520/v1/partition/<groupId>` answers
+200 for every group; then `DELETE /v1/store/<oldId>` to erase the retired
+record. Measured on a 3+3+3 install with images built from `master` at
+`dbb6663a`: the replacement was Ready in 156 s, all 12 groups converged
+onto the new ID 1 s after the Tombstone and patrol (the empty Store caught
+up by raft snapshot install), and a continuous writer lost 0 acknowledged
+writes.
+
+On images without #3234 the same retirement runs and does not repair the
+groups: PD fires the configuration change, but the group leader sees the
+address already in the group, so jraft has nothing to add and the group
+keeps the old ID. Measured: 20 minutes and three patrols later, all 12
+groups still listed the retired ID and the replacement Store held no
+partitions. Nothing in the health surface shows the failure; `/v1/stores`,
+cluster state, Hubble, and Pod readiness all read healthy while every
+shard group runs on two live replicas. The one check that shows it is the
+replaced Store's own `:8520/v1/partition/<groupId>`.
+
+So the default remains: replace a Store Pod, keep its PVC (the Store id
+lives in the data path, and the Pod comes back under the same id). Treat
+the empty-PVC procedure as recovery for post-#3234 images only; on a
+released image a genuinely lost volume leaves the cluster degraded, and
+expect to rebuild rather than to recover in place.
+
+Periodic leader balancing is tracked in
+[apache/hugegraph#3135](https://github.com/apache/hugegraph/issues/3135);
+disaster-recovery metrics in
+[apache/hugegraph#3136](https://github.com/apache/hugegraph/issues/3136).
+
+### 8 Scaling
+
+PD and Store reserve the maximum StatefulSet ordinal in their resource
+names, so scaling never renames a PersistentVolumeClaim or shifts a Pod
+identity; both are capped at 99 replicas. Server scales freely through
+`server.replicas` or `server.hpa` (with HPA on, the Deployment omits
+`spec.replicas` so upgrades do not overwrite the autoscaler).
+
+A staged rollout cannot be written in a values file (the schema requires
+one replica per component); stage it with `kubectl scale statefulset
+hugegraph-store --replicas=0` and scale back up when ready. The Servers
+wait, not ready, until Stores register, and the next `helm upgrade`
+restores the full topology from values.
+
+Changing PD or Store replicas on a live release is not a values change:
+raft and shard membership are persisted, and Pods alone do not reconfigure
+them. The chart rejects both directions for PD and a shrink for Store by
+reading the live StatefulSet, so fresh installs at any count are
+unaffected.
+
+**PD, either direction.** The rendered peer list reaches raft only as its
+bootstrap configuration, which an initialized group ignores; a 3-to-5
+upgrade leaves the voting configuration at three, and a 3-to-1 shrink
+loses quorum outright. Membership changes go through PD's peer-list
+change, which the PD client API and the PD REST route
+`POST /v1/members/change` both expose; the route needs the same Basic
+authentication as the other PD REST routes, and the chart wraps neither.
+Change the membership through PD, confirm it in `/v1/members`, scale the
+live StatefulSet, then `helm upgrade` with the matching value; until that
+sequence is verified on your own build, install the PD count you intend
+to keep.
+
+**Store, shrinking.** Draining is a state transition, not a balance:
+neither `patrolPartitions` nor `balancePartitions` retires a healthy
+Store. Retire the leaving Stores the way Disaster Recovery retires a
+replaced one:
+
+1. Check the remaining Stores still cover the persisted shard count
+   (`pd.partition.defaultShardCount`; empty derives 3 when
+   `store.replicas` is at least 3).
+2. Map the ordinals the shrink will delete (the highest ones) to Store
+   ids through `/v1/stores`, matching on the Pod address.
+3. `POST /v1/store/<id>` with `{"storeState":"Tombstone"}` for each
+   leaving id.
+4. Wait until `/v1/shardGroups` no longer lists those ids and every group
+   reports its full shard count with one leader.
+5. Scale the live StatefulSet, then `helm upgrade` with the matching
+   value.
+
+The chart keeps the PVCs of removed ordinals
+(`store.persistentVolumeClaimRetentionPolicy.whenScaled: Retain`), and a
+retained PVC still holds the retired Store id. PD refuses to register a
+Store id that is Tombstone or deleted, so a Store that later starts on
+that PVC, as when you scale the same ordinal back up, cannot join.
+Delete the PVCs of the removed ordinals after step 4 reports the data
+moved and before reusing those ordinals; the deletion is permanent.
+
+### 9 Running Hubble outside the cluster
+
+In-cluster Hubble (`hubble.enabled=true` plus a port-forward) is the
+recommended path and is covered on the deployment page. Two paths exist
+for a Hubble that must run outside the cluster.
+
+**Direct Server URL** (graph, schema, data, and Gremlin; no PD
+discovery): leave in-chart Hubble off, expose Server through an
+HTTPS-terminating Ingress or a NodePort/LoadBalancer `server.service.type`,
+and run a standalone Hubble image. The Service carries the plain-HTTP API,
+so the chart requires `server.service.allowInsecureExposure=true` for it;
+restrict who can reach it first. The Hubble properties are:
+
+```properties
+pd.enabled=false
+server.direct_url=https://<reachable-server-host>:<port>
+```
+
+Mount the file at `/hubble/conf/hugegraph-hubble.properties` (the image
+workdir is `/hubble`). Use HTTPS or a trusted channel for
+`server.direct_url`: login sends the Server credentials over that URL.
+
+**PD discovery** (the outside Hubble asks PD for the Server address):
+in-cluster names such as `*.svc` are not reachable from outside, so the
+chart provides two knobs. Set `server.advertiseUrl` to the absolute
+`http(s)://` URL the outside Hubble will use after discovery; the chart
+registers it with PD in place of the in-cluster Service URL. And expose
+the PD client Service (`pd.service.type` NodePort/LoadBalancer), which
+requires `pd.service.allowInsecureExposure=true` because PD gRPC has no
+authentication; restrict who can reach it first (with the chart's
+NetworkPolicy on, the render refuses the exposure until its callers are
+listed in `networkPolicy.pd.extraIngress`). Then run standalone Hubble
+with:
+
+```properties
+pd.enabled=true

Review Comment:
   ⚠️ Important: This PD-mode example omits Hubble's PD REST credentials. `operations.pd.password` defaults to empty, while the chart's default PD REST authentication requires credentials; chart-managed Hubble injects `operations.pd.username=hubble` and the PD secret. As written, the external Hubble operations collector gets authentication failures. Add these properties to the example and show how to provide the PD credential securely; sync Chinese.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "imbajin (via GitHub)" <gi...@apache.org>.
imbajin commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4102972552


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,483 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. For a production image roll, set
+`store.updateStrategy.type=OnDelete` and delete Store Pods one at a time,
+checking between deletions.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, term, and

Review Comment:
   ⚠️ important: `PartitionAPI.getPartition()` does not assign `term`; only the plural `/v1/partitions` handler sets it. The singular route's `term` therefore remains the DTO's default `0`, so this comparison can appear to confirm matching terms without reading the Raft term. Please remove the term/comparison claim or point to a compatible endpoint that actually returns it, and sync the Chinese page at line 189.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,483 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. For a production image roll, set
+`store.updateStrategy.type=OnDelete` and delete Store Pods one at a time,
+checking between deletions.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, term, and
+committed index that Store holds, and fails while the Store is down;
+compare term and index with a peer Store rather than reading them alone.
+The plural `GET :8520/v1/partitions` answers 500 on any Store that follows
+a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a
+group that is short a shard or has no leader as a stop. A real
+restoration-complete signal is upstream work, tracked in
+[apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229).
+
+### 7 Disaster recovery
+
+What PD automates on current builds is narrow: a 60-second patrol only
+marks Stores that stopped sending heartbeats as `Offline`. There is no
+automatic re-replication; re-placing the replicas of a lost Store,
+reconciling shard groups, and processing tombstoned Stores run only when a
+partition patrol is triggered explicitly.
+
+The task endpoints execute locally on the PD that receives them, and a
+follower answers with an empty success while doing nothing.
+Port-forwarding the client Service selects an arbitrary PD, so identify
+the leader first, then port-forward that Pod (two terminals: the forward
+runs in the foreground):
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-pd-client 8620:8620
+# Read .data.pdLeader.raftUrl; its host names the leader Pod.
+curl -su "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/members
+# Stop the Service forward, then forward the leader Pod instead.
+kubectl port-forward -n hugegraph pod/<leader-pod> 8620:8620
+# Reconcile shard groups and process tombstoned Stores.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/patrolPartitions
+# Spread Raft leaders, then partition data.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balanceLeaders

Review Comment:
   ⚠️ important: When `patrolPartitions` reallocates a shard group with a replica-count mismatch, PD sets `BALANCE_SHARD_KEY` for 180 seconds. Calling `balanceLeaders` immediately after it is rejected, and `balancePartitions` returns without work while the key is set. Please document this conditional cooldown and wait before balancing after a repair; sync the Chinese sequence at line 216.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,483 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. For a production image roll, set
+`store.updateStrategy.type=OnDelete` and delete Store Pods one at a time,
+checking between deletions.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, term, and
+committed index that Store holds, and fails while the Store is down;
+compare term and index with a peer Store rather than reading them alone.
+The plural `GET :8520/v1/partitions` answers 500 on any Store that follows
+a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a
+group that is short a shard or has no leader as a stop. A real
+restoration-complete signal is upstream work, tracked in
+[apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229).
+
+### 7 Disaster recovery
+
+What PD automates on current builds is narrow: a 60-second patrol only
+marks Stores that stopped sending heartbeats as `Offline`. There is no
+automatic re-replication; re-placing the replicas of a lost Store,
+reconciling shard groups, and processing tombstoned Stores run only when a
+partition patrol is triggered explicitly.
+
+The task endpoints execute locally on the PD that receives them, and a
+follower answers with an empty success while doing nothing.
+Port-forwarding the client Service selects an arbitrary PD, so identify
+the leader first, then port-forward that Pod (two terminals: the forward
+runs in the foreground):
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-pd-client 8620:8620
+# Read .data.pdLeader.raftUrl; its host names the leader Pod.
+curl -su "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/members
+# Stop the Service forward, then forward the leader Pod instead.
+kubectl port-forward -n hugegraph pod/<leader-pod> 8620:8620
+# Reconcile shard groups and process tombstoned Stores.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/patrolPartitions
+# Spread Raft leaders, then partition data.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balanceLeaders
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balancePartitions
+```
+
+Read `/v1/members` again after the tasks: if leadership moved mid-sequence,
+the later tasks ran on a follower and did nothing. Wait at least 180 s
+before rerunning `balanceLeaders` after a `balancePartitions` call:
+`balancePartitions` sets a balance-shard flag for 180 s even when it moves
+nothing, and `balanceLeaders` inside that window is refused. On images
+built before
+[apache/hugegraph#3233](https://github.com/apache/hugegraph/pull/3233)
+(merged 2026-09-24) the refusal is a bare HTTP 500 whose reason appears
+only in the PD log; after it, the reason comes back in the body as
+`{"status":1001,"error":"balance shard is processing, please try later!"}`.
+
+Telling a real run from a no-op takes the PD leader's log, because the
+responses do not: `patrolPartitions` answers the same empty success on the
+leader and on a follower, whether or not it repaired anything (look for
+`reallocShards`, `shardOffline` or `storeTurnoff` lines, or diff
+`/v1/shardGroups` before and after), and `balancePartitions` answers `{}`
+on the leader and an empty body on a follower. `balanceLeaders` is the one
+call whose body carries the work. Distinguishable task responses are
+upstream work, tracked in
+[apache/hugegraph#3231](https://github.com/apache/hugegraph/issues/3231).
+
+Run `patrolPartitions` after replacing a Store that is not coming back,
+`balancePartitions` once the cluster is stable again, and `balanceLeaders`
+after restarts that skewed leader placement.
+
+**Losing a Store volume.** A Store rebuilt with an empty PVC recovers in
+place on images carrying
+[apache/hugegraph#3234](https://github.com/apache/hugegraph/pull/3234)
+(merged 2026-09-24); on every earlier image, including all published
+release images, it does not. In both cases the replacement registers under
+a new Store ID while its Pod name, DNS name, and raft address are
+unchanged, so `/v1/stores` lists two IDs at one address.
+
+On post-#3234 images the retirement works: find the old ID in `/v1/stores`
+(the row at the replaced Pod's address that is not the newly registered
+one), `POST /v1/store/<oldId>` with `{"storeState":"Tombstone"}` on the PD
+leader, run `GET /v1/task/patrolPartitions`, and wait; verify every shard
+group is back to full shard count with one leader, no group names the old
+ID, and the replaced Store's own `:8520/v1/partition/<groupId>` answers
+200 for every group; then `DELETE /v1/store/<oldId>` to erase the retired
+record. Measured on a 3+3+3 install with images built from `master` at
+`dbb6663a`: the replacement was Ready in 156 s, all 12 groups converged
+onto the new ID 1 s after the Tombstone and patrol (the empty Store caught
+up by raft snapshot install), and a continuous writer lost 0 acknowledged
+writes.
+
+On images without #3234 the same retirement runs and does not repair the
+groups: PD fires the configuration change, but the group leader sees the
+address already in the group, so jraft has nothing to add and the group
+keeps the old ID. Measured: 20 minutes and three patrols later, all 12
+groups still listed the retired ID and the replacement Store held no
+partitions. Nothing in the health surface shows the failure; `/v1/stores`,
+cluster state, Hubble, and Pod readiness all read healthy while every
+shard group runs on two live replicas. The one check that shows it is the
+replaced Store's own `:8520/v1/partition/<groupId>`.
+
+So the default remains: replace a Store Pod, keep its PVC (the Store id
+lives in the data path, and the Pod comes back under the same id). Treat
+the empty-PVC procedure as recovery for post-#3234 images only; on a
+released image a genuinely lost volume leaves the cluster degraded, and
+expect to rebuild rather than to recover in place.
+
+Periodic leader balancing is tracked in
+[apache/hugegraph#3135](https://github.com/apache/hugegraph/issues/3135);
+disaster-recovery metrics in
+[apache/hugegraph#3136](https://github.com/apache/hugegraph/issues/3136).
+
+### 8 Scaling
+
+PD and Store reserve the maximum StatefulSet ordinal in their resource
+names, so scaling never renames a PersistentVolumeClaim or shifts a Pod
+identity; both are capped at 99 replicas. Server scales freely through
+`server.replicas` or `server.hpa` (with HPA on, the Deployment omits
+`spec.replicas` so upgrades do not overwrite the autoscaler).
+
+A staged rollout cannot be written in a values file (the schema requires
+one replica per component); stage it with `kubectl scale statefulset
+hugegraph-store --replicas=0` and scale back up when ready. The Servers
+wait, not ready, until Stores register, and the next `helm upgrade`
+restores the full topology from values.
+
+Changing PD or Store replicas on a live release is not a values change:
+raft and shard membership are persisted, and Pods alone do not reconfigure
+them. The chart rejects both directions for PD and a shrink for Store by
+reading the live StatefulSet, so fresh installs at any count are
+unaffected.
+
+**PD, either direction.** The rendered peer list reaches raft only as its
+bootstrap configuration, which an initialized group ignores; a 3-to-5
+upgrade leaves the voting configuration at three, and a 3-to-1 shrink
+loses quorum outright. Membership changes go through the PD client API
+(no REST route exposes them), which the chart cannot wrap. Change the

Review Comment:
   ⚠️ important: The PD server exposes `POST /v1/members/change` from `MemberAPI`, and the global REST interceptor applies Basic authentication to it; saying no REST route exposes membership changes is inaccurate. If this guide intends the PD client API as the supported procedure, please distinguish that from the route's existence and state its authentication boundary; sync the Chinese page at line 274.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,483 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs
+```
+
+### 3 Scheduling
+
+Every component (`pd`, `store`, `server`, `hubble`) exposes `nodeSelector`,
+`tolerations`, `affinity`, `topologySpreadConstraints`, and
+`priorityClassName`. Pinning Store to labeled nodes is just:
+
+```yaml
+store:
+  nodeSelector:
+    hugegraph/role: storage
+```
+
+`antiAffinity` (`required` | `preferred` | `disabled`) renders a hostname
+pod-anti-affinity preset for `pd`, `store`, and `server`; Hubble is
+single-replica by design and has no such key. Setting a raw `affinity`
+replaces the preset entirely. All three default to `preferred`, so the chart
+schedules on clusters with fewer nodes than replicas. The trade: under node
+pressure the scheduler may co-locate replicas, and a single node failure can
+then take more than one PD or Store replica with it. Production clusters with
+enough nodes should pin `pd.antiAffinity` and `store.antiAffinity` to
+`required`, as `values-cluster.yaml` does.
+
+### 4 Partition sharding
+
+A fresh install seeds PD with a partition shard count of 3 when
+`store.replicas` is at least 3, and 1 otherwise; without the seed, the PD
+image pins `partition.default-shard-count` to 1 and chart-deployed clusters
+would run without store-level HA. The chart passes the value as
+`-Dpartition.default-shard-count` in PD's `JAVA_OPTS`, so the image's JVM
+auto-sizing is unaffected.
+
+**The seed applies at first bootstrap only.** PD persists the shard count the
+first time it starts with empty storage; from then on the stored value is
+authoritative, and changing `pd.partition.defaultShardCount` or scaling
+`store.replicas` later has no effect on an initialized cluster. To change
+the shard count of a running cluster, use PD's own config API (odd values
+only, at most the live store count), then trigger
+`GET /v1/task/patrolPartitions` and expect shard-group reallocation.
+
+The shard count also fixes the initial partition count:
+`store.replicas x storeMaxShardCount / shardCount`, computed once at
+bootstrap. With the image default `store-max-shard-count` of 12, a default
+3-store install gets 12 partitions; raise
+`pd.partition.storeMaxShardCount` (likewise seeded once) when more
+partitions are wanted.
+
+An explicit `pd.partition.defaultShardCount` must be odd and at most
+`store.replicas`; the chart rejects other values at render time because PD
+would otherwise clamp or refuse them silently.
+
+### 5 NetworkPolicy
+
+`networkPolicy.enabled` renders one NetworkPolicy per component (PD, Store,
+Server, and Hubble when enabled). Each policy isolates its own Pods in both
+directions and lists the traffic they need, so apply order does not matter.
+It is off in `values.yaml`, because the base values cannot know who your
+clients are, and on in `values-cluster.yaml`.
+
+It only works when the cluster's network plugin enforces NetworkPolicy (kind
+v0.25 or later, k3s, Calico, Cilium); other plugins accept the objects and
+enforce nothing. To check, run a Pod without chart labels in another
+namespace and `curl` the PD client Service on the REST port: it must time
+out.
+
+With the policies on, the release admits only its own traffic:
+
+| To | From, ports |
+|---|---|
+| PD | PD: raft, gRPC. Store, Server, and Hubble in `pd` mode: gRPC, REST |
+| Store | Store: raft. Server: gRPC, REST. Hubble in `pd` mode: REST |
+| Server | Hubble and the `helm test` Pod: `server.port` |
+| Hubble | nothing (port-forward uses loopback and needs no rule) |
+
+Every component may also resolve DNS on port 53. Nothing outside the release
+is admitted unless it is listed in `networkPolicy.<component>.extraIngress`,
+including the Ingress controller and the clients of a NodePort or
+LoadBalancer Service. Exposing PD, Server or Hubble that way, or setting
+`server.advertiseUrl`, with an empty `extraIngress` fails the render instead
+of opening the port. The check sees only exposure the chart creates; a
+Service, Gateway route or proxy you add yourself needs its own entry.
+
+Two egress facts to plan around. PD, Store and Server reach nothing outside
+the release except DNS, so features that call out do not work with the
+policies on; the one default caller is the Store image, which downloads
+`libjemalloc.so` from github.com on every start. With the policies on that
+connection times out after about two minutes and the Store starts without
+jemalloc (measured on kind: Ready after 151 s instead of 11 s); the same
+happens on any cluster without internet access. And the `helm test` Pod is
+selected by no chart policy, so under a namespace-wide default-deny policy
+of your own you must allow it egress to `server.port` and DNS.
+
+**Letting other workloads in.** Every rule must name its peers in `from`;
+to admit any address, write an `ipBlock` such as `0.0.0.0/0` explicitly. A
+`namespaceSelector` and a `podSelector` in the same peer must both match;
+as two separate peers, either one is enough. What a NodePort or
+LoadBalancer client looks like from the Pod depends on the network plugin,
+`externalTrafficPolicy`, and the node the request arrives on. Measured with
+a NodePort Server on two-node kind clusters:
+
+- kindnet, and Cilium with kube-proxy replacement: a call to the Server's
+  own node arrived with the client address; through the other node it
+  arrived with that node's address.
+- Calico: through the other node the call arrived from that node's tunnel
+  address inside the Pod CIDR.
+- Cilium with kube-proxy: no `ipBlock` rule admitted NodePort traffic,
+  because Cilium identifies node addresses by its own node identities
+  rather than by CIDR.
+
+Test with the plugin you run and name the CIDR you see arriving. A worked
+example admitting an Ingress controller, an application namespace, and
+Prometheus:
+
+```yaml
+networkPolicy:
+  server:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: ingress-nginx
+            podSelector:
+              matchLabels:
+                app.kubernetes.io/name: ingress-nginx
+        ports:
+          - port: 8080
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: apps
+        ports:
+          - port: 8080
+  pd:
+    extraIngress:
+      - from:
+          - namespaceSelector:
+              matchLabels:
+                kubernetes.io/metadata.name: monitoring
+        ports:
+          - port: 8620
+```
+
+### 6 Rolling Store images safely
+
+Store rolling updates advance on a listener check, not on shard recovery,
+so the controller can replace the next Store while the previous one is
+still rejoining its shard groups. For a production image roll, set
+`store.updateStrategy.type=OnDelete` and delete Store Pods one at a time,
+checking between deletions.
+
+`Up` in PD is not that check. PD marks a Store `Up` at registration, before
+the Store has restored any partition, and a stopped Store stays `Up` in
+every shard group until its keep-alive entry expires (300 s on current
+images): a Pod deleted and back inside that window never leaves `Up` at
+all. Start with the Pod instead:
+
+```bash
+kubectl -n hugegraph wait --for=condition=Ready \
+  pod/hugegraph-store-<ordinal> --timeout=10m
+```
+
+Then check shard membership and leadership per group, read from the PD
+leader (see Disaster Recovery below for finding the leader):
+
+```bash
+curl -s -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/shardGroups | jq '
+  .shardGroups[] | {id: (.id // 0),
+                    shards: [.shards[] | {storeId, role}],
+                    leaders: [.shards[] | select(.role=="Leader")] | length}'
+```
+
+Delete the next Store only when the replaced Pod is `Ready`, its Store id
+shows a fresh `lastHeartBeat` in `/v1/stores`, and every group reports its
+full shard count with exactly one `Leader`.
+
+Know what this does not prove: the shard list is PD's membership record,
+not a statement that the Store caught up on the raft log. No endpoint on
+current images reports restoration-complete. For a closer look,
+port-forward the replaced Store and read its own view of a group:
+`GET :8520/v1/partition/<groupId>` returns the raft role, term, and
+committed index that Store holds, and fails while the Store is down;
+compare term and index with a peer Store rather than reading them alone.
+The plural `GET :8520/v1/partitions` answers 500 on any Store that follows
+a group on images built before
+[apache/hugegraph#3232](https://github.com/apache/hugegraph/pull/3232)
+(merged 2026-09-24); after it, it answers 200 on every Store, with `conf`
+and `peers` null for followed groups. The per-group path works on both.
+
+Leave a margin after the membership check, keep `store.pdb.minAvailable`
+at `replicas - 1` so an accidental second eviction is refused, and treat a
+group that is short a shard or has no leader as a stop. A real
+restoration-complete signal is upstream work, tracked in
+[apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229).
+
+### 7 Disaster recovery
+
+What PD automates on current builds is narrow: a 60-second patrol only
+marks Stores that stopped sending heartbeats as `Offline`. There is no
+automatic re-replication; re-placing the replicas of a lost Store,
+reconciling shard groups, and processing tombstoned Stores run only when a
+partition patrol is triggered explicitly.
+
+The task endpoints execute locally on the PD that receives them, and a
+follower answers with an empty success while doing nothing.
+Port-forwarding the client Service selects an arbitrary PD, so identify
+the leader first, then port-forward that Pod (two terminals: the forward
+runs in the foreground):
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-pd-client 8620:8620
+# Read .data.pdLeader.raftUrl; its host names the leader Pod.
+curl -su "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/members
+# Stop the Service forward, then forward the leader Pod instead.
+kubectl port-forward -n hugegraph pod/<leader-pod> 8620:8620
+# Reconcile shard groups and process tombstoned Stores.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/patrolPartitions
+# Spread Raft leaders, then partition data.
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balanceLeaders
+curl -u "hg:${PD_SECRET}" http://127.0.0.1:8620/v1/task/balancePartitions
+```
+
+Read `/v1/members` again after the tasks: if leadership moved mid-sequence,
+the later tasks ran on a follower and did nothing. Wait at least 180 s
+before rerunning `balanceLeaders` after a `balancePartitions` call:
+`balancePartitions` sets a balance-shard flag for 180 s even when it moves
+nothing, and `balanceLeaders` inside that window is refused. On images
+built before
+[apache/hugegraph#3233](https://github.com/apache/hugegraph/pull/3233)
+(merged 2026-09-24) the refusal is a bare HTTP 500 whose reason appears
+only in the PD log; after it, the reason comes back in the body as
+`{"status":1001,"error":"balance shard is processing, please try later!"}`.
+
+Telling a real run from a no-op takes the PD leader's log, because the
+responses do not: `patrolPartitions` answers the same empty success on the
+leader and on a follower, whether or not it repaired anything (look for
+`reallocShards`, `shardOffline` or `storeTurnoff` lines, or diff
+`/v1/shardGroups` before and after), and `balancePartitions` answers `{}`
+on the leader and an empty body on a follower. `balanceLeaders` is the one
+call whose body carries the work. Distinguishable task responses are
+upstream work, tracked in
+[apache/hugegraph#3231](https://github.com/apache/hugegraph/issues/3231).
+
+Run `patrolPartitions` after replacing a Store that is not coming back,
+`balancePartitions` once the cluster is stable again, and `balanceLeaders`
+after restarts that skewed leader placement.
+
+**Losing a Store volume.** A Store rebuilt with an empty PVC recovers in
+place on images carrying
+[apache/hugegraph#3234](https://github.com/apache/hugegraph/pull/3234)
+(merged 2026-09-24); on every earlier image, including all published
+release images, it does not. In both cases the replacement registers under
+a new Store ID while its Pod name, DNS name, and raft address are
+unchanged, so `/v1/stores` lists two IDs at one address.
+
+On post-#3234 images the retirement works: find the old ID in `/v1/stores`
+(the row at the replaced Pod's address that is not the newly registered
+one), `POST /v1/store/<oldId>` with `{"storeState":"Tombstone"}` on the PD
+leader, run `GET /v1/task/patrolPartitions`, and wait; verify every shard
+group is back to full shard count with one leader, no group names the old
+ID, and the replaced Store's own `:8520/v1/partition/<groupId>` answers
+200 for every group; then `DELETE /v1/store/<oldId>` to erase the retired
+record. Measured on a 3+3+3 install with images built from `master` at
+`dbb6663a`: the replacement was Ready in 156 s, all 12 groups converged
+onto the new ID 1 s after the Tombstone and patrol (the empty Store caught
+up by raft snapshot install), and a continuous writer lost 0 acknowledged
+writes.
+
+On images without #3234 the same retirement runs and does not repair the
+groups: PD fires the configuration change, but the group leader sees the
+address already in the group, so jraft has nothing to add and the group
+keeps the old ID. Measured: 20 minutes and three patrols later, all 12
+groups still listed the retired ID and the replacement Store held no
+partitions. Nothing in the health surface shows the failure; `/v1/stores`,
+cluster state, Hubble, and Pod readiness all read healthy while every
+shard group runs on two live replicas. The one check that shows it is the
+replaced Store's own `:8520/v1/partition/<groupId>`.
+
+So the default remains: replace a Store Pod, keep its PVC (the Store id
+lives in the data path, and the Pod comes back under the same id). Treat
+the empty-PVC procedure as recovery for post-#3234 images only; on a
+released image a genuinely lost volume leaves the cluster degraded, and
+expect to rebuild rather than to recover in place.
+
+Periodic leader balancing is tracked in
+[apache/hugegraph#3135](https://github.com/apache/hugegraph/issues/3135);
+disaster-recovery metrics in
+[apache/hugegraph#3136](https://github.com/apache/hugegraph/issues/3136).
+
+### 8 Scaling
+
+PD and Store reserve the maximum StatefulSet ordinal in their resource
+names, so scaling never renames a PersistentVolumeClaim or shifts a Pod
+identity; both are capped at 99 replicas. Server scales freely through
+`server.replicas` or `server.hpa` (with HPA on, the Deployment omits
+`spec.replicas` so upgrades do not overwrite the autoscaler).
+
+A staged rollout cannot be written in a values file (the schema requires
+one replica per component); stage it with `kubectl scale statefulset
+hugegraph-store --replicas=0` and scale back up when ready. The Servers
+wait, not ready, until Stores register, and the next `helm upgrade`
+restores the full topology from values.
+
+Changing PD or Store replicas on a live release is not a values change:
+raft and shard membership are persisted, and Pods alone do not reconfigure
+them. The chart rejects both directions for PD and a shrink for Store by
+reading the live StatefulSet, so fresh installs at any count are
+unaffected.
+
+**PD, either direction.** The rendered peer list reaches raft only as its
+bootstrap configuration, which an initialized group ignores; a 3-to-5
+upgrade leaves the voting configuration at three, and a 3-to-1 shrink
+loses quorum outright. Membership changes go through the PD client API
+(no REST route exposes them), which the chart cannot wrap. Change the
+membership through PD, confirm it in `/v1/members`, scale the live
+StatefulSet, then `helm upgrade` with the matching value; until that
+sequence is verified on your own build, install the PD count you intend
+to keep.
+
+**Store, shrinking.** Draining is a state transition, not a balance:
+neither `patrolPartitions` nor `balancePartitions` retires a healthy
+Store. Retire the leaving Stores the way Disaster Recovery retires a
+replaced one:
+
+1. Check the remaining Stores still cover the persisted shard count
+   (`pd.partition.defaultShardCount`; empty derives 3 when
+   `store.replicas` is at least 3).
+2. Map the ordinals the shrink will delete (the highest ones) to Store
+   ids through `/v1/stores`, matching on the Pod address.
+3. `POST /v1/store/<id>` with `{"storeState":"Tombstone"}` for each
+   leaving id.
+4. Wait until `/v1/shardGroups` no longer lists those ids and every group
+   reports its full shard count with one leader.
+5. Scale the live StatefulSet, then `helm upgrade` with the matching
+   value.
+
+Deleting the PVCs of the removed ordinals is separate and permanent; do it

Review Comment:
   ⚠️ important: The chart head defaults `store.persistentVolumeClaimRetentionPolicy.whenScaled` to `Retain`. After step 3 tombstones a Store ID, scaling that ordinal back up reuses the ID from its retained PVC, which PD rejects during registration. Please warn that the PVC must be deleted after data has moved and before reusing that ordinal, or document a verified ID-cleanup procedure; sync the Chinese page at line 288.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
bitflicker64 commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4175218380


##########
content/en/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,362 @@
+---
+title: "Deploy on Kubernetes with Helm"
+linkTitle: "Deploy on Kubernetes (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 Overview
+
+The Helm chart deploys a distributed HugeGraph cluster on Kubernetes: PD, Store, and Server, plus the optional
+Hubble UI. It lives in the main repository under
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph).
+
+| Component | Workload | Default replicas | Purpose |
+|-----------|----------|------------------|---------|
+| PD | StatefulSet + PVC | 3 | Placement driver: a Raft group tracking Stores and partitions |
+| Store | StatefulSet + PVC | 3 | Graph data storage (HStore) |
+| Server | Deployment | 3 | Gremlin and REST query layer |
+| Hubble | Deployment | 0 (off) | Web UI, enabled with `hubble.enabled=true` |
+
+A distributed HugeGraph cluster has a startup contract (no `init-store` on Server, every Server using PD for graph
+metadata, Store waiting for a PD quorum, one PD REST secret shared by three readers). The chart encodes that
+contract so operators do not have to; the details are in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details).
+Day-2 work (NetworkPolicy details, disaster recovery, scaling, safe Store
+rolls, running Hubble outside the cluster) is on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/).
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes cluster
+        PD[PD StatefulSet<br>Raft group of 3, PVC]
+        Store[Store StatefulSet<br>3 replicas, PVC] -->|register, heartbeat| PD
+        Server[Server Deployment<br>3 replicas] -->|metadata, discovery| PD
+        Server -->|gRPC read/write| Store
+        Hubble[Hubble Deployment<br>optional UI] -->|discovers Servers via PD| PD
+    end
+    Client[Client / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+Startup order is enforced by the chart, not by the operator: PD pods elect a leader first, each Store pod waits in
+an init container until a majority of PD peers report ready, and Servers keep restarting their storage wait until
+Stores have registered. A fresh install converges without manual steps.
+
+### 2 Prerequisites
+
+- Kubernetes 1.23 or later (the chart renders `autoscaling/v2` and `policy/v1`)
+- Helm 3; the `--reset-then-reuse-values` flag mentioned under Upgrade needs Helm 3.14 or later
+- Dynamic volume provisioning: a default StorageClass, or an explicit `storageClassName` for PD and Store
+- Memory for nine JVMs in the default topology; see the resource note under Install
+
+The chart requires component images that carry the PD readiness endpoint and PD REST authentication (both merged
+for the release after 1.7.0). The default image tags already point at builds that include them; 1.7.0 images are
+not supported.
+
+### 3 Install
+
+#### 3.1 Get the chart
+
+The chart is not published to a chart repository yet, so install it from the source tree:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 Install with default values
+
+First confirm `kubectl` points at the intended cluster and that it can provision volumes. PVCs stuck in `Pending`
+for want of a StorageClass are the most common first-run failure:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+Then install:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` makes Helm block until every workload is ready, which for a distributed cluster is the signal that PD
+elected a leader, Stores registered, and Servers came up; without it `helm install` returns as soon as the objects
+are created. A fresh cluster normally converges in a few minutes; the 15 minute timeout leaves room for slow image
+pulls.
+
+Two defaults to know before going further:
+
+- **No resources are set.** Every pod is BestEffort, and each JVM sets its maximum heap to half of the memory it
+  sees free on the node at start (up to a per-component ceiling), so the JVMs on one node can together claim more
+  memory than the node has. That holds for `values-single.yaml` on one node as well. Set `resources` per component on every install, the single-node
+  preset included; `values-cluster.yaml` sets them for a multi-node cluster.
+- **Image tags track `latest`** until the next HugeGraph release is published, with `pullPolicy: Always`. Pin tags
+  or digests for production.
+
+#### 3.3 Topology presets
+
+The chart ships three values files:
+
+| File | Topology | Intended use |
+|------|----------|--------------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | Default; preferred anti-affinity, auth on, Hubble off |
+| `values-single.yaml` | 1 + 1 + 1 | Single-node development and CI; smaller PVCs |
+| `values-cluster.yaml` | 3 + 3 + 3 | Production starting point: JVM heap and resource settings, a Server PodDisruptionBudget, `required` anti-affinity, NetworkPolicy on, Store `OnDelete` updates |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` is a starting point, not a capacity guarantee: recalculate resources for your graph size and
+traffic. One of its numbers deserves a note: it requests 5Gi and limits at 8Gi of memory per Store, well above the
+1Gi heap, because the Store's RocksDB caches live outside the JVM heap (a 4Gi limit OOM-killed Stores after about
+1 GB of data). Scale both numbers with data size. The full parameter reference (every component, probe,
+scheduling, and Secret knob) is kept in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+#### 3.4 Verify the install
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+The test first calls `/versions` and `/graphs` through the Server Service. It then resolves the headless Service
+`hugegraph-server-headless` and sends an authenticated Gremlin query bound to the `DEFAULT-hugegraph` graph to
+each Server Pod it lists, and it requires at least `server.replicas` Pods (`server.hpa.minReplicas` with HPA on).
+The headless Service lists only Ready Pods, the same Pods the Server Service routes to, so a Pod that is not Ready
+is not queried. A failing Pod is retried every 5 seconds for up to 150 seconds, so a short PD election is not
+reported as a broken Pod; after that the test fails and prints each failing Pod IP with its HTTP status. This is
+the check that catches a Server that passes readiness and serves REST while every Gremlin call on it fails (see
+Limitations). Large HPA fleets may need `helm test --timeout` above the 5-minute default.
+
+To call the API, start a port-forward in one terminal; it runs in the foreground until you stop it:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+```
+
+Then, in a second terminal, read the generated admin password and call the API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+The commands above assume the release is named `hugegraph`; with another name, substitute the release-prefixed
+resource names (`kubectl get svc,secret -n <namespace>` lists them). The post-install notes printed by
+`helm install` repeat these commands with the right names filled in.
+
+### 4 Authentication and Secrets
+
+Authentication is on by default and the chart manages three Secrets. Each credential resolves in the same order:
+an `existingSecret` you created wins, then an inline value, then a random value generated at install time.
+
+| Secret | Key | Used for | Bring your own with |
+|--------|-----|----------|---------------------|
+| `<release>-admin` | `password` | Server admin account, Hubble login | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | JWT signing key shared by all Server replicas | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST authentication, read by PD, Server, and Hubble | `pd.auth.existingSecret` |
+
+To manage a credential yourself, create the Secret before installing and point the matching `existingSecret` value
+at it; the chart never modifies a Secret it did not create. Value constraints: the admin password must be printable
+ASCII with no spaces, colons, or backslashes (the image stores a space with a backslash before it, and the Server splits
+Basic-auth credentials on every colon, so either would leave the account unable to log in with the Secret value); the
+JWT key must be at least 32 bytes; the PD secret must be printable ASCII with no backslashes and no leading or trailing
+space. Invalid inline values are rejected at render time, and an `existingSecret` by the startup wrapper when the Pod
+starts, not silently truncated.
+
+Chart-managed Secrets are kept on uninstall and reused by a later install under the same release name.
+
+<details>
+<summary>Rotation and caveats</summary>
+
+- The admin password is applied only when the auth metadata is first created, so changing the Secret later does not
+  rotate an existing cluster's password. Rotate it through the Server's auth API instead.
+- Rotating a credential rolls the Pods that read it once, on the next `helm upgrade`: PD, Server, and Hubble together
+  for the PD REST Secret, which keeps their copies in step, and Server for the admin password or JWT key.
+- Template-only pipelines (`helm template`, Argo CD, Flux in template mode) cannot see live Secrets, so a
+  chart-generated credential gets a new value on every render: each sync changes the Secret, rolls the Pods that read
+  it, and leaves the admin account created at first start out of step with the Secret. For such a pipeline, create the
+  three Secrets first and set the `existingSecret` values; see
+  [Template-only pipelines](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#template-only-pipelines-gitops)
+  in the chart README.
+- All three Secrets exist even if you only ever read one: the post-install notes print the exact `kubectl get
+  secret` commands for the admin password and the PD secret.
+</details>
+
+### 5 Health checks and startup order
+
+PD exposes two health endpoints, and the chart deliberately uses both:
+
+- `/v1/health` answers 200 as soon as the REST listener is up. It never consults Raft, so it cannot see a lost
+  quorum.
+- `/v1/ready` answers 503 until the PD Raft group has a leader, so it reports quorum, not just a live process.
+
+The chart puts PD **readiness** and the Store init-container wait on `/v1/ready`: a Store only starts once a
+majority of PD peers are quorum members, and a PD that lost its leader drops out of Service endpoints until a
+leader is back. PD **startup and liveness** derive from the replica count (`pd.livenessPath` overrides the
+choice). With more than one PD they stay on `/v1/health` on purpose: a PD that merely lost its leader is still a
+healthy Raft member, and restarting it would make the outage worse. A single PD is the exception and derives to
+`/v1/ready`: it has no election to lose, and one that steps down for good, as after a failed Raft snapshot on a
+full disk ([apache/hugegraph#3222](https://github.com/apache/hugegraph/issues/3222)), would answer `/v1/health`
+forever while serving no writes; the kubelet restarts it instead.
+
+Server startup gets a budget of at least 450 seconds, enough for the 300-second storage wait the image entrypoint
+runs before the start command, plus process startup. The chart counts the guaranteed probe time as
+`(failureThreshold - 1) * periodSeconds`, because the kubelet may run the first probe as soon as the container
+starts, and raises a lower configured `failureThreshold` to that floor (91 at the default 5-second period, the
+value `values.yaml` ships). The image would kill a Server still starting after 120 seconds, so the chart also sets
+`HG_SERVER_STARTUP_TIMEOUT_S` to the guaranteed probe time minus the 300-second storage wait: 150 seconds by
+default, never less than the image's 120. The start command and the probe then give up together. Raise
+`server.probes.startup` if your storage takes longer to come up, and the timeout follows; the variable is
+chart-managed, so change the probe rather than setting it in `server.extraEnv`.
+
+### 6 Enable the Hubble UI
+
+Hubble is off by default so API-only clusters stay lean. Enable it on a running release:
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values --set hubble.enabled=true
+```
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-hubble 8088:8088
+```
+
+Open `http://127.0.0.1:8088` and log in as `admin` with the admin password from Section 3.4. Hubble discovers the
+Servers through PD, so the cluster operations view works without extra wiring. Hubble serves plain HTTP: reach it
+through a port-forward or an HTTPS-terminating Ingress, never directly from an untrusted network; a NodePort or
+LoadBalancer Hubble Service is refused unless `hubble.service.allowInsecureExposure=true` acknowledges it. Running Hubble
+outside the cluster is possible but takes more wiring; see
+[Reaching Hubble](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#reaching-hubble-pick-one-path) in
+the chart README.
+
+### 7 Upgrade
+
+```bash
+helm upgrade hugegraph ./helm/hugegraph --namespace hugegraph --reuse-values
+```
+
+`--reuse-values` keeps the release's existing overrides; without it the upgrade rebuilds the release from chart
+defaults. It also keeps the old values as the complete base, so a release created by an earlier chart revision does
+not pick up new defaults such as the hardened `securityContext`; pass your own values with `-f`, or use
+`--reset-then-reuse-values`, to adopt them. Any upgrade that changes a Pod template rolls that workload once.
+Points worth planning around:
+
+- **A no-change upgrade rolls nothing.** The Secret-tracking annotations hash each credential's value, or the live
+  `resourceVersion` of an `existingSecret`, so a Pod rolls only when a credential it reads changes. An upgrade that
+  does roll PD and Server together, such as a PD REST Secret rotation or an image change on both, can leave a Server
+  without its Gremlin binding (see Limitations), so run `helm test` after any upgrade that rolled PD and Server
+  together.
+- **Store rolling updates advance on a listener check, not on shard recovery**, so the controller can replace the
+  next Store while the previous one is still rejoining its shard groups. `values-cluster.yaml` therefore sets
+  `store.updateStrategy.type=OnDelete`; `values.yaml` and `values-single.yaml` keep `RollingUpdate`, so set it
+  yourself on any other production values. Under `OnDelete` an upgrade updates the StatefulSet but replaces no
+  Store Pod, and you delete Store Pods one at a time. `OnDelete` only stops automatic advancement: deleting Pods
+  without checking between them carries the same risk. `Up` in PD is not that check: PD marks a Store `Up` at
+  registration, before it restores partitions, and a stopped Store stays `Up` until a 300 s keep-alive expires.
+  No endpoint on current images reports that a Store has finished restoring its partitions
+  ([apache/hugegraph#3229](https://github.com/apache/hugegraph/issues/3229)), so the check is indirect. Wait for
+  the replaced Pod to be `Ready`, then confirm every shard group reports its full shard count with one
+  leader; the full procedure is on the
+  [operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/#6-rolling-store-images-safely).
+- **The controller never rolls more than one PD or Store Pod at a time.** The chart leaves
+  `updateStrategy.rollingUpdate.maxUnavailable` unset and accepts only the integer `1` there: a larger number or
+  a percentage fails the render, because it would let the controller take down two members of a three-member
+  Raft group or shard at once, and a PodDisruptionBudget does not limit controller rollouts. For PD maintenance
+  windows, `pd.updateStrategy.type=OnDelete` gives the same manual control as for Store.
+- **PVC sizes cannot be changed by upgrade**: Kubernetes forbids changing StatefulSet `volumeClaimTemplates`, so an
+  upgrade with a new `storage.size` is rejected in full. The chart README documents the resize procedure for
+  StorageClasses that support volume expansion.
+- **Some values are fixed once the release is initialized.** `nameOverride`, `fullnameOverride`, the PD and Store
+  raft ports, and the storage settings are install-time identity: the chart refuses an override or raft port change
+  against the live StatefulSets, and Kubernetes refuses the storage change. `server.auth.admin.*` and the partition
+  shard counts apply at bootstrap only, so an initialized cluster ignores a new value. The chart README sorts the
+  values by
+  [lifecycle](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#settings-by-lifecycle).
+- **`helm rollback` runs none of the chart's guards.** A rollback, including the automatic one after a failed
+  `--atomic` upgrade, reapplies an earlier stored manifest without rendering the chart, so a rollback across a PD or
+  Store replica change scales the StatefulSet straight to the old count and can drop PD below quorum. Rollback across
+  a membership or identity change is unsupported: return to an earlier chart or image with a forward upgrade that
+  keeps the current topology values, and keep `--atomic` off for upgrades that change replicas. The chart README
+  covers the checks to run after any
+  [rollback](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#rollback).
+
+Scaling Server up and down is a values change (`server.replicas`, or `server.hpa`). Changing the **PD count in
+either direction, or shrinking Store, is not**: Raft and shard membership are persisted and Pods alone do not
+reconfigure them, so a 3-to-1 PD shrink permanently loses quorum and new PD Pods do not join the voting
+configuration. The chart reads the live StatefulSet and rejects an upgrade that changes the PD count or
+lowers the Store count; the manual procedures are on the
+[operations page](/docs/quickstart/hugegraph/hugegraph-helm-operations/#8-scaling).
+
+### 8 Uninstall
+
+```bash
+helm uninstall hugegraph --namespace hugegraph
+```
+
+Two kinds of state survive on purpose. PersistentVolumeClaims created by the StatefulSets are kept (Kubernetes

Review Comment:
   Minor: this section lists two kinds of state that survive uninstall, but there is a third. With `hubble.enabled=true` and `hubble.persistence.enabled=true`, `templates/hubble-pvc.yaml` at chart 2a6e2c404 annotates the Hubble PVC with `helm.sh/resource-policy: keep`, and its comment says the volume holds the stored connection metadata and credentials. An operator who follows this page and deletes only the StatefulSet PVCs leaves that volume, with its credentials, in the namespace. Please add the Hubble PVC here (for example: "With Hubble persistence on, its PVC is kept too; delete it to discard Hubble's stored connections and credentials") and make the same change in CN section 8, line 261.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub)" <gi...@apache.org>.
bitflicker64 commented on code in PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#discussion_r4166025318


##########
content/cn/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,251 @@
+---
+title: "使用 Helm 在 Kubernetes 上部署"
+linkTitle: "Kubernetes 部署 (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 概述
+
+Helm chart 在 Kubernetes 上部署一套分布式 HugeGraph 集群:PD、Store、Server,以及可选的 Hubble UI。chart 位于主仓库的
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph) 目录。
+
+| 组件 | 工作负载 | 默认副本数 | 作用 |
+|------|----------|------------|------|
+| PD | StatefulSet + PVC | 3 | 元数据管理:以 Raft 组跟踪 Store 与分区 |
+| Store | StatefulSet + PVC | 3 | 图数据存储 (HStore) |
+| Server | Deployment | 3 | Gremlin 与 REST 查询层 |
+| Hubble | Deployment | 0(默认关闭) | Web UI,通过 `hubble.enabled=true` 启用 |
+
+分布式 HugeGraph 集群有一套启动约定(Server 不执行 `init-store`、每个 Server 都通过 PD 读写图元数据、Store 等待 PD
+形成多数派、一个 PD REST 密钥由三个组件共用)。chart 把这套约定固化下来,运维人员无需手工处理;细节见
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details)。日常运维(NetworkPolicy
+细节、灾难恢复、伸缩、安全滚动 Store、在集群外运行 Hubble)见
+[运维页](/cn/docs/quickstart/hugegraph/hugegraph-helm-operations/)。
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes 集群
+        PD[PD StatefulSet<br>3 节点 Raft 组,PVC]
+        Store[Store StatefulSet<br>3 副本,PVC] -->|注册、心跳| PD
+        Server[Server Deployment<br>3 副本] -->|元数据、服务发现| PD
+        Server -->|gRPC 读写| Store
+        Hubble[Hubble Deployment<br>可选 UI] -->|通过 PD 发现 Server| PD
+    end
+    Client[客户端 / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+启动顺序由 chart 保证,而不是由运维人员保证:PD 先选出 leader,每个 Store Pod 的 init 容器等到多数 PD 汇报就绪后才启动,
+Server 则反复等待存储层,直到 Store 完成注册。全新安装无需手工干预即可收敛。
+
+### 2 前置条件
+
+- Kubernetes 1.23 及以上(chart 渲染 `autoscaling/v2` 和 `policy/v1`)
+- Helm 3;升级一节提到的 `--reset-then-reuse-values` 需要 Helm 3.14 及以上
+- 动态卷供给:有默认 StorageClass,或为 PD 和 Store 显式指定 `storageClassName`
+- 默认拓扑要运行九个 JVM 进程,内存需留足;见安装一节的资源说明
+
+chart 要求组件镜像包含 PD 就绪探测端点和 PD REST 认证(两者都已合入 1.7.0 之后的版本)。默认镜像 tag 指向的构建已包含
+这些改动;1.7.0 镜像不受支持。
+
+### 3 安装
+
+#### 3.1 获取 chart
+
+chart 尚未发布到 chart 仓库,从源码树安装:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 使用默认值安装
+
+先确认 `kubectl` 指向目标集群,且集群能供给存储卷。因缺少 StorageClass 而卡在 `Pending` 的 PVC 是最常见的首次安装
+故障:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+然后安装:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` 让 Helm 阻塞到所有工作负载就绪。对分布式集群来说,这个信号意味着 PD 已选出 leader、Store 已注册、Server 已
+启动;不加它,`helm install` 在对象创建完成后就返回。全新集群一般几分钟内收敛,15 分钟超时是给缓慢的镜像拉取留的余量。
+
+继续之前需要了解两个默认值:
+
+- **默认不设置 resources。** 每个 Pod 都是 BestEffort,JVM 按节点总内存计算堆大小。单节点没有问题;多节点集群上各个堆
+  会超订节点内存导致进程中止。超出笔记本范围的部署请使用 `values-cluster.yaml`,或按组件设置 `resources`。
+- **镜像 tag 跟踪 `latest`**,且 `pullPolicy: Always`,直到下一个 HugeGraph 版本发布。生产环境请固定 tag 或 digest。
+
+#### 3.3 拓扑预设
+
+chart 附带三个 values 文件:
+
+| 文件 | 拓扑 | 适用场景 |
+|------|------|----------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | 默认;preferred 反亲和,认证开启,Hubble 关闭 |
+| `values-single.yaml` | 1 + 1 + 1 | 单节点开发与 CI;PVC 更小 |
+| `values-cluster.yaml` | 3 + 3 + 3 | 生产起点:JVM 堆与资源设置、PD/Store PodDisruptionBudget、`required` 反亲和、NetworkPolicy 开启 |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` 是起点而非容量保证:请按图规模和流量重新核算资源。其中一个数字值得说明:它给每个 Store 申请
+5Gi、限制 8Gi 内存,远高于 1Gi 的堆,因为 Store 的 RocksDB 缓存在 JVM 堆之外(4Gi 的限制在约 1 GB 数据后就把
+Store OOM 杀掉了)。两个数字要随数据量一起放大。完整参数参考(每个组件的探针、调度、Secret 配置项)见
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration)。
+
+#### 3.4 验证安装
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+读取自动生成的 admin 密码并调用 API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions

Review Comment:
   Fixed in 686d3b930. Section 3.4 now starts the port-forward in its own block and terminal, then reads the password and runs `curl` from a second terminal. The operations page health check and its per-Pod Gremlin check got the same split, in EN and CN.



##########
content/cn/docs/quickstart/hugegraph/hugegraph-helm.md:
##########
@@ -0,0 +1,251 @@
+---
+title: "使用 Helm 在 Kubernetes 上部署"
+linkTitle: "Kubernetes 部署 (Helm)"
+weight: 4
+search_keywords:
+  - helm
+  - kubernetes
+  - k8s
+---
+
+### 1 概述
+
+Helm chart 在 Kubernetes 上部署一套分布式 HugeGraph 集群:PD、Store、Server,以及可选的 Hubble UI。chart 位于主仓库的
+[`helm/hugegraph`](https://github.com/apache/hugegraph/tree/master/helm/hugegraph) 目录。
+
+| 组件 | 工作负载 | 默认副本数 | 作用 |
+|------|----------|------------|------|
+| PD | StatefulSet + PVC | 3 | 元数据管理:以 Raft 组跟踪 Store 与分区 |
+| Store | StatefulSet + PVC | 3 | 图数据存储 (HStore) |
+| Server | Deployment | 3 | Gremlin 与 REST 查询层 |
+| Hubble | Deployment | 0(默认关闭) | Web UI,通过 `hubble.enabled=true` 启用 |
+
+分布式 HugeGraph 集群有一套启动约定(Server 不执行 `init-store`、每个 Server 都通过 PD 读写图元数据、Store 等待 PD
+形成多数派、一个 PD REST 密钥由三个组件共用)。chart 把这套约定固化下来,运维人员无需手工处理;细节见
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#chart-details)。日常运维(NetworkPolicy
+细节、灾难恢复、伸缩、安全滚动 Store、在集群外运行 Hubble)见
+[运维页](/cn/docs/quickstart/hugegraph/hugegraph-helm-operations/)。
+
+```mermaid
+flowchart LR
+    subgraph Kubernetes 集群
+        PD[PD StatefulSet<br>3 节点 Raft 组,PVC]
+        Store[Store StatefulSet<br>3 副本,PVC] -->|注册、心跳| PD
+        Server[Server Deployment<br>3 副本] -->|元数据、服务发现| PD
+        Server -->|gRPC 读写| Store
+        Hubble[Hubble Deployment<br>可选 UI] -->|通过 PD 发现 Server| PD
+    end
+    Client[客户端 / hugegraph-client] -->|REST / Gremlin| Server
+```
+
+启动顺序由 chart 保证,而不是由运维人员保证:PD 先选出 leader,每个 Store Pod 的 init 容器等到多数 PD 汇报就绪后才启动,
+Server 则反复等待存储层,直到 Store 完成注册。全新安装无需手工干预即可收敛。
+
+### 2 前置条件
+
+- Kubernetes 1.23 及以上(chart 渲染 `autoscaling/v2` 和 `policy/v1`)
+- Helm 3;升级一节提到的 `--reset-then-reuse-values` 需要 Helm 3.14 及以上
+- 动态卷供给:有默认 StorageClass,或为 PD 和 Store 显式指定 `storageClassName`
+- 默认拓扑要运行九个 JVM 进程,内存需留足;见安装一节的资源说明
+
+chart 要求组件镜像包含 PD 就绪探测端点和 PD REST 认证(两者都已合入 1.7.0 之后的版本)。默认镜像 tag 指向的构建已包含
+这些改动;1.7.0 镜像不受支持。
+
+### 3 安装
+
+#### 3.1 获取 chart
+
+chart 尚未发布到 chart 仓库,从源码树安装:
+
+```bash
+git clone https://github.com/apache/hugegraph.git
+cd hugegraph
+```
+
+#### 3.2 使用默认值安装
+
+先确认 `kubectl` 指向目标集群,且集群能供给存储卷。因缺少 StorageClass 而卡在 `Pending` 的 PVC 是最常见的首次安装
+故障:
+
+```bash
+kubectl config current-context
+kubectl get storageclass
+```
+
+然后安装:
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace --wait --timeout 15m
+```
+
+`--wait` 让 Helm 阻塞到所有工作负载就绪。对分布式集群来说,这个信号意味着 PD 已选出 leader、Store 已注册、Server 已
+启动;不加它,`helm install` 在对象创建完成后就返回。全新集群一般几分钟内收敛,15 分钟超时是给缓慢的镜像拉取留的余量。
+
+继续之前需要了解两个默认值:
+
+- **默认不设置 resources。** 每个 Pod 都是 BestEffort,JVM 按节点总内存计算堆大小。单节点没有问题;多节点集群上各个堆
+  会超订节点内存导致进程中止。超出笔记本范围的部署请使用 `values-cluster.yaml`,或按组件设置 `resources`。
+- **镜像 tag 跟踪 `latest`**,且 `pullPolicy: Always`,直到下一个 HugeGraph 版本发布。生产环境请固定 tag 或 digest。
+
+#### 3.3 拓扑预设
+
+chart 附带三个 values 文件:
+
+| 文件 | 拓扑 | 适用场景 |
+|------|------|----------|
+| `values.yaml` | 3 PD + 3 Store + 3 Server | 默认;preferred 反亲和,认证开启,Hubble 关闭 |
+| `values-single.yaml` | 1 + 1 + 1 | 单节点开发与 CI;PVC 更小 |
+| `values-cluster.yaml` | 3 + 3 + 3 | 生产起点:JVM 堆与资源设置、PD/Store PodDisruptionBudget、`required` 反亲和、NetworkPolicy 开启 |
+
+```bash
+helm install hugegraph ./helm/hugegraph --namespace hugegraph --create-namespace \
+    -f helm/hugegraph/values-single.yaml --wait --timeout 15m
+```
+
+`values-cluster.yaml` 是起点而非容量保证:请按图规模和流量重新核算资源。其中一个数字值得说明:它给每个 Store 申请
+5Gi、限制 8Gi 内存,远高于 1Gi 的堆,因为 Store 的 RocksDB 缓存在 JVM 堆之外(4Gi 的限制在约 1 GB 数据后就把
+Store OOM 杀掉了)。两个数字要随数据量一起放大。完整参数参考(每个组件的探针、调度、Secret 配置项)见
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration)。
+
+#### 3.4 验证安装
+
+```bash
+helm test hugegraph --namespace hugegraph
+```
+
+读取自动生成的 admin 密码并调用 API:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin -o jsonpath='{.data.password}' | base64 --decode)"
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+```
+
+以上命令假定 release 名为 `hugegraph`;用其他名字时,请替换成带 release 前缀的资源名(`kubectl get svc,secret -n
+<namespace>` 可以列出)。`helm install` 结束时打印的说明里包含填好名字的同样命令。
+
+### 4 认证与 Secret
+
+认证默认开启,chart 管理三个 Secret。每个凭据按同一顺序取值:你预先创建的 `existingSecret` 优先,其次是内联值,最后
+是安装时随机生成。
+
+| Secret | 键 | 用途 | 自带凭据的配置项 |
+|--------|-----|------|------------------|
+| `<release>-admin` | `password` | Server admin 账号、Hubble 登录 | `server.auth.admin.existingSecret` |
+| `<release>-auth-token` | `token_secret` | 所有 Server 副本共用的 JWT 签名密钥 | `server.auth.token.existingSecret` |
+| `<release>-pd-auth` | `secret-key` | PD REST 认证,由 PD、Server、Hubble 读取 | `pd.auth.existingSecret` |
+
+要自行管理凭据,请在安装前创建 Secret 并把对应的 `existingSecret` 指向它;chart 不会改动任何不是它创建的 Secret。取值
+约束:admin 密码不能包含换行、回车或反斜杠;JWT 密钥至少 32 字节;PD 密钥必须是可打印 ASCII。非法值会在渲染时或启动

Review Comment:
   Fixed in 5e4cbd25c. Section 4 now says the admin password must not start or end with whitespace, next to the newline, carriage-return and backslash rules, in EN and CN.



##########
content/en/docs/quickstart/hugegraph/hugegraph-helm-operations.md:
##########
@@ -0,0 +1,483 @@
+---
+title: "Operate HugeGraph on Kubernetes"
+linkTitle: "Operations on Kubernetes (Helm)"
+weight: 5
+search_keywords:
+  - helm
+  - kubernetes
+  - operations
+  - disaster recovery
+  - networkpolicy
+---
+
+### 1 Scope
+
+This page is for operating a HugeGraph cluster that the Helm chart already
+deployed. Installing, upgrading, and uninstalling are on the
+[deployment page](/docs/quickstart/hugegraph/hugegraph-helm/); the full
+parameter reference stays in the
+[chart README](https://github.com/apache/hugegraph/tree/master/helm/hugegraph#configuration).
+
+Commands below assume the release is named `hugegraph` in namespace
+`hugegraph`; substitute your own names. Two credentials come up repeatedly,
+both read from chart-managed Secrets:
+
+```bash
+PASSWORD="$(kubectl get secret -n hugegraph hugegraph-admin \
+  -o jsonpath='{.data.password}' | base64 --decode)"
+PD_SECRET="$(kubectl get secret -n hugegraph hugegraph-pd-auth \
+  -o jsonpath='{.data.secret-key}' | base64 --decode)"
+```
+
+### 2 Ports and health
+
+| Component | Port | Purpose |
+|------|-------------|---------|
+| PD | `8686` | gRPC (Store and Server clients) |
+| PD | `8620` | REST / health probes |
+| PD | `8610` | Raft |
+| Store | `8500` | gRPC |
+| Store | `8510` | Raft |
+| Store | `8520` | REST / health probes |
+| Server | `8080` | Gremlin and REST API |
+
+All ports are configurable through values; changing `server.port` updates the
+listener, container port, and Service together. A stalled component (process
+alive but frozen) is ended by its liveness probe: the default 20 s period and
+3-failure threshold bound the blast radius of a stalled Store at roughly one
+minute, and raft moves its partition leaders within seconds of the restart.
+
+Reach the API through a port-forward:
+
+```bash
+kubectl port-forward -n hugegraph svc/hugegraph-server 8080:8080
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/versions
+curl --user "admin:${PASSWORD}" http://127.0.0.1:8080/graphs

Review Comment:
   Fixed in 686d3b930. Section 2 now keeps the port-forward in one terminal and runs the `curl` calls from a second, with `PASSWORD` from section 1. Section 10's per-Pod Gremlin check got the same split, and the deployment page's install check too, in EN and CN.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org


Re: [PR] doc: add Helm chart deployment page for Kubernetes [hugegraph-doc]

Posted by "bitflicker64 (via GitHub) via issues" <is...@hugegraph.apache.org>.
bitflicker64 commented on PR #494:
URL: https://github.com/apache/hugegraph-doc/pull/494#issuecomment-6613123789

   Superseded by #560. The base Helm pages landed separately (#527, #533, #534, #549 to #551), so this one is out of date. #560 is a small follow-up: it lists the Helm pages under Operate and fixes the Vermeer and SeaTunnel details that drifted from the chart. Thanks for the reviews here.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@hugegraph.apache.org
For additional commands, e-mail: issues-help@hugegraph.apache.org