Kvindo™ Cloud Docs


Language

OpenSearch Cluster

An OpenSearch Cluster is a managed OpenSearch 3.9.0 deployment split into two dedicated roles: a cluster-manager quorum of 1 or 3 virtual machines that holds the metadata and runs the elections, and 1..N data nodes that hold the shards and answer queries. Every member runs on its own virtual machine, and the cluster is described as one resource — spec.dataNodes and spec.clusterManagers each hold one entry per member, listing only its name and subnet. There is no combined cluster-manager+data node and no mode flag: a data node under merge, GC or disk pressure would stall the metadata quorum while every shard kept answering, which is a silent outage, so the platform ships one topology and one playbook path.

Key concepts

• Two roles, sized independently — data nodes hold your data, cluster managers hold only the cluster metadata. Sizing is one offer triplet per role (dataVmOfferId/dataVolumeOfferId/dataVolumeSizeGiB and the manager* equivalents) rather than per member, so a role's members are interchangeable by design. An omitted offer is resolved to that role's default server-side and written back, never left null

• Cluster managers: exactly 1 or 3, never 2 or 4 — a majority is more than half, so an even count tolerates no more failures than the odd count below it while costing more. 1 is a documented non-HA tier (no quorum HA) that can be grown to 3; both joiners arrive in a single request, because 2 is not a valid quorum

• Data nodes: 1..N, scale-out only — a modify may add data nodes. OpenSearch has no scale-in path here, so removing one is rejected outright rather than silently ignored. The minimum cluster is therefore 2 VMs: 1 manager + 1 data node

• Node name is the real identity — the server resolves each entry against this cluster's existing members by name and reuses the same member (and its VM) when it matches. Renaming is indistinguishable from remove+add, and since scale-in is refused the rename is rejected rather than rebuilt, so do not rename a member you want to keep

• Indices are yours — there is no shard, replica, ISM or index-template field on this resource. The platform sets only cluster.default_number_of_replicas cluster-wide: 0 on a single-data-node cluster (so its indices are not permanently yellow) and 1 otherwise. Fields you cannot set are not offered rather than accepted and ignored

• Public access is TLS-only — private by default. Setting spec.createPublicIpv4 attaches a floating IP to every data node so the REST port 9200 is reachable from outside the VPC; a cluster manager never receives one, because client traffic must not be sent to the voting configuration. There is no plaintext listener at all: even a private client pins the cluster CA

• The CA certificate is in status — status.caCertificate is the credential-free thing a client pins (--cacert, or verify_certs plus ca_certs). It is minted once at create and never regenerated on reconcile, so a client that pinned it keeps working

• No cluster-wide credential on this resource — the break-glass admin credential is generated and stored server-side only. Create an OpenSearch User to get a real, tenant-facing credential

• Disk watermarks are platform-managed — past flood_stage (95%) every index with a shard on a full node gets a read-only block and writes start failing with index read-only. That threshold is deliberately not settable: it is the last thing between a tenant and a full volume. The low/high watermarks are tunable through a Parameter Set — see the error's own explanation if you try to set flood_stage there

• Backups and Dashboards are not in v1 — there is no snapshot repository, no restore and no OpenSearch Dashboards deployment. A cluster is a derived copy of data you can re-index, not a system of record

Parameters
UI Name API / kc name Terraform name Optional Format Default Is read only Description
Data nodes spec.dataNodes spec.data_nodes No list of objects — No One entry per data node — 1..N, scale-out only
Data node name dataNodes[].name data_nodes[].name No string — [a-z0-9][a-z0-9-], ≤64 chars — No The real identity — reuse it across modifies to keep the same node; a rename is rejected, not applied
Data node subnet dataNodes[].vpcSubnetId data_nodes[].vpc_subnet_id No ULID — references a VPC Subnet — No Subnet for this data node's VM
Cluster managers spec.clusterManagers spec.cluster_managers No list of objects — No Exactly 1 or 3 — never 2 or 4. Append-only, grows 1 -> 3
Cluster manager name clusterManagers[].name cluster_managers[].name No string — [a-z0-9][a-z0-9-], ≤64 chars — No The real identity — a rename is rejected, not applied
Cluster manager subnet clusterManagers[].vpcSubnetId cluster_managers[].vpc_subnet_id No ULID — references a VPC Subnet — No Subnet for this cluster manager's VM
Parameters set spec.parametersSetId spec.parameters_set_id Yes ULID — references an OpenSearchParametersSet — No Cluster-wide settings applied by the platform: allow-listed dynamic keys go through PUT _cluster/settings, the rest are rendered into opensearch.yml with a rolling restart
OpenSearch version spec.openSearchVersion spec.opensearch_version No string — full version, e.g. 3.9.0 — No Required. Must be a version the deployed image prefetched, because the platform installs only the package it ships. Immutable in v1: there is no rolling upgrade
Data node VM offer spec.dataVmOfferId spec.data_vm_offer_id No string (≤32) — compute offer — No Applies to every data node. Resolved and written back server-side when omitted; see the Console catalog for real offer ids
Data node volume offer spec.dataVolumeOfferId spec.data_volume_offer_id No string (≤32) — disk offer — No Applies to every data node. Changeable after creation; the volume is re-described
Data node volume size spec.dataVolumeSizeGiB spec.data_volume_size_gib No integer — GiB — No Applies to every data node. Increase only — a shrink is refused, because the platform cannot shrink a volume
Cluster manager VM offer spec.managerVmOfferId spec.manager_vm_offer_id No string (≤32) — compute offer — No Applies to every cluster manager — it serves metadata only, so it is sized far smaller than a data node
Cluster manager volume offer spec.managerVolumeOfferId spec.manager_volume_offer_id No string (≤32) — disk offer — No Applies to every cluster manager. Changeable after creation
Cluster manager volume size spec.managerVolumeSizeGiB spec.manager_volume_size_gib No integer — GiB — No Applies to every cluster manager. Increase only
Dashboards nodes spec.dashboardsNodes spec.dashboards_nodes No array — at most 1 — No The UI tier. Each entry is a name plus a subnet, exactly like a cluster manager. A dashboards node is NOT an OpenSearch node: no shards, no vote, never in the quorum. Reachable on port 5601 over the platform's managed certificate at the PRIVATE address only — there is no floating IP
Dashboards VM offer spec.dashboardsVmOfferId spec.dashboards_vm_offer_id No string (≤32) — compute offer — No Applies to the dashboards node. At least 4 GiB, like every OpenSearch VM
Dashboards volume offer spec.dashboardsVolumeOfferId spec.dashboards_volume_offer_id No string (≤32) — disk offer — No Applies to the dashboards node. Changeable after creation
Dashboards volume size spec.dashboardsVolumeSizeGiB spec.dashboards_volume_size_gib No integer — GiB — No Applies to the dashboards node. Increase only
Use FQDN spec.useFqdn spec.use_fqdn Yes boolean false No Announce DNS names instead of raw IPs in every node certificate and in status.dnsSeedFqdn, so an address can change without re-seeding every client. Immutable after creation — it re-signs every certificate
Public IPv4 spec.createPublicIpv4 spec.create_public_ipv4 Yes boolean false No Attaches a floating IP to every data node so the TLS REST port 9200 is reachable from outside the VPC; cluster managers never get one. Immutable after creation
Cluster name status.clusterName status.cluster_name — string — Yes The cluster id, lowercased — what an OpenSearch client reports and pins as cluster.name
Cluster state status.clusterState status.cluster_state — string — Yes ok | degraded | no-quorum | unknown. Losing quorum does not take the cluster down: reads keep working, but index creation, mapping changes and shard allocation fail
Health status.health status.health — string — Yes green | yellow | red | unknown — OpenSearch's own cluster health
REST endpoints status.restEndpoints status.rest_endpoints — list of strings — Yes host:9200 over TLS on the private network. Always over the DATA nodes — a cluster manager is never published
REST public endpoints status.restPublicEndpoints status.rest_public_endpoints — list of strings — Yes floating-ip:9200 on the data nodes that received one; empty on a private cluster
DNS seed FQDN status.dnsSeedFqdn status.dns_seed_fqdn — string — Yes A DNS name that round-robins over the data nodes — the stable way to seed a client's host list
CA certificate status.caCertificate status.ca_certificate — string (PEM) — Yes The cluster root CA — what a client pins to authenticate the nodes. Credential-free; minted once and never regenerated
Active cluster managers status.activeClusterManagerCount status.active_cluster_manager_count — integer — Yes How many cluster managers currently answer
Quorum size status.clusterManagerQuorumSize status.cluster_manager_quorum_size — integer — Yes How many cluster managers must agree: a MAJORITY of the voting configuration, so 1 of 1 or 2 of 3 — not the member count
Default replicas status.defaultNumberOfReplicas status.default_number_of_replicas — integer — Yes What the platform set cluster-wide: 0 on a single-data-node cluster, else 1. It applies to indices created from then on, not to existing ones
Index count status.indexCount status.index_count — integer — Yes How many indices the cluster currently has
Documents status.totalDocuments status.total_documents — integer — Yes Total document count across all indices
Data size status.totalDataBytes status.total_data_bytes — integer — bytes — Yes Total size of the index data
Unassigned shards status.unassignedShards status.unassigned_shards — integer — Yes Shards with no node at all — a non-zero value is the usual reason health is red or yellow
Relocating shards status.relocatingShards status.relocating_shards — integer — Yes Shards currently moving between nodes
Active shards status.activeShardsPercent status.active_shards_percent — integer — percent — Yes Share of shards that are active. It rarely reaches 100, because relocating shards are not counted
Yellow indices status.yellowIndexCount status.yellow_index_count — integer — Yes Indices with unassigned replicas — normal on a cluster with fewer data nodes than the replica count asks for
Red indices status.redIndexCount status.red_index_count — integer — Yes Indices with at least one unassigned primary — that index is unsearchable and losing writes
Any index read-only status.anyIndexReadonly status.any_index_readonly — boolean — Yes True when a node crossed flood_stage and a read-only block was placed on every index with a shard there. This is the number-one "my writes stopped" cause; the block clears by itself once usage falls back below high
Running version status.runningVersion status.running_version — string — Yes The OpenSearch version the nodes actually report
Last probe status.lastProbeUtc status.last_probe_utc — integer — Yes Unix time of the last health probe
Anti-affinity OK status.antiAffinityOk status.anti_affinity_ok — boolean — Yes Always null: the platform does not report hypervisor placement, so anti-affinity cannot be verified from here
Anti-affinity message status.antiAffinityMessage status.anti_affinity_message — string — Yes Human-readable detail behind antiAffinityOk
Data nodes status.dataNodes status.data_nodes — list of objects — Yes Observed state per data node
Node name dataNodes[].name data_nodes[].name — string — Yes Equal to the node's own node.name
Private IP dataNodes[].privateIpV4 data_nodes[].private_ip_v4 — string — Yes The node's address inside the VPC
Public IP dataNodes[].publicIpV4 data_nodes[].public_ip_v4 — string — Yes The floating IP, when spec.createPublicIpv4 is set
Announced FQDN dataNodes[].announceFqdn data_nodes[].announce_fqdn — string — Yes The DNS name announced in the node's certificate when spec.useFqdn is set
Observed state dataNodes[].observedState data_nodes[].observed_state — string — Yes ok | unreachable | unknown
Disk used dataNodes[].diskUsedBytes data_nodes[].disk_used_bytes — integer — bytes — Yes How much of the node's volume is in use
Disk free dataNodes[].diskFreeBytes data_nodes[].disk_free_bytes — integer — bytes — Yes Free space left on the node's volume — the number to watch against the watermarks
JVM heap used dataNodes[].jvmHeapUsedPercent data_nodes[].jvm_heap_used_percent — number — percent — Yes Share of the node's heap in use
Running version dataNodes[].runningVersion data_nodes[].running_version — string — Yes The version this node reports
Cluster managers status.clusterManagers status.cluster_managers — list of objects — Yes Observed state per cluster manager
Manager name clusterManagers[].name cluster_managers[].name — string — Yes The member's identity
Private IP clusterManagers[].privateIpV4 cluster_managers[].private_ip_v4 — string — Yes The manager's address inside the VPC — never published
Elected clusterManagers[].isElectedClusterManager cluster_managers[].is_elected_cluster_manager — boolean — Yes True for whichever member currently holds the election
Observed state clusterManagers[].observedState cluster_managers[].observed_state — string — Yes elected | candidate | unreachable | unknown
Notes

• Adding a data node does not raise number_of_replicas on indices that already exist. The platform changes the cluster default, which applies to indices created from then on — raising an existing index is your own PUT <pattern>/_settings

• On a single-data-node cluster there is no redundancy at all, and with backups deferred there is no restore path. Treat three data nodes as the production floor and raise the data-node offer before the node count

• index.number_of_shards is final for an index: it can only be set at creation, so plan the shard count up front — over-sharding a small cluster is the other classic mistake

• action.destructive_requires_name is true, so DELETE /logs-* and DELETE /_all are refused. Delete by explicit name, or use _delete_by_query

Examples

One cluster manager and two data nodes — the smallest topology that is both real and shard-safe, plus a parameter set and an index-granted user.

Terraform

Python SDK

kc CLI


Related pages

Resource docs

Examples

Guides

An unhandled error has occurred. Reload 🗙