Cluster Architecture
A 3-node Elasticsearch cluster with full TLS encryption, dual-network topology, and production-grade resource configuration.
Cluster Topology
┌─────────────────────────────────────────────────────────────────┐
│ MacLab Docker Network │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ es01 │ │ es02 │ │ es03 │ │
│ │ │ │ │ │ │ │
│ │ Master ✓ │◄──►│ Master ✓ │◄──►│ Master ✓ │ │
│ │ Data ✓ │ │ Data ✓ │ │ Data ✓ │ │
│ │ Ingest ✓ │ │ Ingest ✓ │ │ Ingest ✓ │ │
│ │ │ │ │ │ │ │
│ │ 2GB RAM │ │ 2GB RAM │ │ 2GB RAM │ │
│ │ 1GB Heap │ │ 1GB Heap │ │ 1GB Heap │ │
│ │ │ │ │ │ │ │
│ │ :9200 HTTP │ │ :9201 HTTP │ │ :9202 HTTP │ │
│ │ :9300 TCP │ │ :9301 TCP │ │ :9302 TCP │ │
│ └──────┬──────┘ └─────────────┘ └─────────────┘ │
│ │ TLS Transport (port 9300) │
│ │ TLS HTTP (port 9200) │
│ │ │
│ ┌──────▼──────┐ │
│ │ Kibana │ │
│ │ :5601 │──── TLS ────► es01:9200 │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘Resource Allocation
Nodes
3
All identical roles
RAM per Node
2GB
mem_limit in compose
JVM Heap
1GB
50% of container RAM
Total Cluster
6GB
3 x 2GB containers
The 50% Heap Rule
Elasticsearch recommends setting the JVM heap to no more than 50% of available memory. The remaining memory is used by Lucene for file system caching, which is critical for search performance. In our cluster, each container has 2GB RAM with 1GB allocated to the JVM heap (ES_JAVA_OPTS=-Xms1g -Xmx1g), leaving 1GB for Lucene segment caching and OS overhead.
For production clusters with more than 64GB RAM, the heap should be capped at 30-31GB to stay below the compressed ordinary object pointers (oops) threshold. Beyond 32GB, the JVM switches to 64-bit pointers, reducing the effective heap capacity.
Node Roles
| Role | es01 | es02 | es03 |
|---|---|---|---|
| master-eligible | yes | yes | yes |
| data | yes | yes | yes |
| ingest | yes | yes | yes |
| HTTP port | 9200 | 9201 | 9202 |
In a small cluster (3 nodes), all nodes hold all roles. For larger deployments, dedicated master-only, data-only, and coordinating-only nodes are recommended.
TLS Encryption
Transport Layer (9300)
Inter-node communication is encrypted using TLS certificates generated by elasticsearch-certutil. Each node has its own certificate signed by a shared CA. The transport layer handles cluster state, shard allocation, and data replication.
HTTP Layer (9200)
Client-facing HTTP connections are also encrypted. Kibana connects to es01 over HTTPS with certificate verification. The CA certificate is shared across all containers via a Docker volume for trust establishment.
Network Architecture
networks:
maclab: # Application network — Kibana, external access
external: true
data: # Data network — inter-node communication
external: true
# es01, es02, es03: connected to both maclab + data
# kibana: connected to maclab only, reaches es01 via maclab network
# Separation ensures data replication traffic doesn't compete
# with application trafficThe dual-network design mirrors production best practices: a dedicated data network for cluster-internal traffic (shard replication, master election) and an application network for external access. This prevents heavy replication traffic from impacting search latency.