如何同步K8s中带独立PV的多Pod数据?Elasticsearch集群配置求助
解决Elasticsearch StatefulSet部署下的数据同步与读写分离问题
你当前的问题核心是两个Elasticsearch Pod并未组成集群,只是各自独立的单节点实例,数据无法在Pod间同步,导致请求路由到无数据的Pod时出现索引不存在错误。要实现数据同步+单Pod写入多Pod查询,需要将它们配置成Elasticsearch集群,并设置主从节点分工。
一、核心原理说明
Elasticsearch集群通过主节点(Master Node)负责集群管理和写入操作,数据会自动同步到所有数据节点(Data Node);查询请求可发送到任意数据节点,保证任意Pod都能查到完整数据。
二、具体配置修改
1. 调整Elasticsearch ConfigMap配置
先修改(或创建)你的elasticsearch-configmap,添加集群相关参数:
apiVersion: v1 kind: ConfigMap metadata: name: elasticsearch-configmap data: es.cluster.name: "es-cluster" es.discovery.type: "cluster" es.node.name: "${NODE_NAME}" # 用Pod主机名作为ES节点名,StatefulSet Pod主机名格式为<statefulset-name>-<ordinal> es.discovery.seed_hosts: "elastic-stateful-headless.default.svc.cluster.local" # Headless Service的DNS名,替换default为你的命名空间 es.cluster.initial_master_nodes: "elastic-stateful-0,elastic-stateful-1" # 初始主节点列表,对应两个Pod es.xpack.security.enabled: "false" # 先关闭安全简化配置,后续再开启 es.xpack.security.enrollment.enabled: "false" es.xpack.security.http.ssl.enabled: "false" es.node.master: "true" # 允许两个节点作为候选主节点 es.node.data: "true" # 两个节点都作为数据节点存储数据
2. 创建Headless Service用于节点发现
StatefulSet需要Headless Service提供稳定DNS记录,让ES节点能互相发现:
apiVersion: v1 kind: Service metadata: name: elastic-stateful-headless spec: clusterIP: None # 标记为Headless Service selector: app: elastic-label ports: - name: transport port: 9300 # ES集群通信端口,必须开放 targetPort: 9300 - name: http port: 9200 targetPort: 9200
3. 修改StatefulSet配置
更新你的StatefulSet,补充必要环境变量和端口:
apiVersion: apps/v1 kind: StatefulSet metadata: name: elastic-stateful spec: replicas: 2 selector: matchLabels: app: elastic-label serviceName: elastic-stateful-headless # 指定关联的Headless Service template: metadata: name: elastic-pod labels: app: elastic-label spec: initContainers: - name: fix-permissions image: busybox:1.32 command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"] securityContext: privileged: true volumeMounts: - name: elastic-pvc mountPath: /usr/share/elasticsearch/data containers: - name: elastic-container image: elasticsearch:8.4.3 ports: - containerPort: 9200 # HTTP端口 - containerPort: 9300 # 集群通信端口,必须开放 env: - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName # 获取Pod主机名作为ES节点名 - name: cluster.name valueFrom: configMapKeyRef: name: elasticsearch-configmap key: es.cluster.name - name: discovery.type valueFrom: configMapKeyRef: name: elasticsearch-configmap key: es.discovery.type - name: node.name valueFrom: configMapKeyRef: name: elasticsearch-configmap key: es.node.name - name: discovery.seed_hosts valueFrom: configMapKeyRef: name: elasticsearch-configmap key: es.discovery.seed_hosts - name: cluster.initial_master_nodes valueFrom: configMapKeyRef: name: elasticsearch-configmap key: es.cluster.initial_master_nodes - name: xpack.security.enabled valueFrom: configMapKeyRef: name: elasticsearch-configmap key: es.xpack.security.enabled - name: xpack.security.enrollment.enabled valueFrom: configMapKeyRef: name: elasticsearch-configmap key: es.xpack.security.enrollment.enabled - name: xpack.security.http.ssl.enabled valueFrom: configMapKeyRef: name: elasticsearch-configmap key: es.xpack.security.http.ssl.enabled - name: node.master valueFrom: configMapKeyRef: name: elasticsearch-configmap key: es.node.master - name: node.data valueFrom: configMapKeyRef: name: elasticsearch-configmap key: es.node.data volumeMounts: - name: elastic-pvc mountPath: /usr/share/elasticsearch/data volumeClaimTemplates: - metadata: name: elastic-pvc spec: accessModes: [ "ReadWriteOnce" ] # ES通过分片复制同步数据,无需共享存储 resources: requests: storage: 1Gi
4. 配置读写分离(可选)
如果需要强制写入请求只发到主节点,查询请求可发到任意节点,可创建两个Service:
- 主节点Service(用于写入):
apiVersion: v1 kind: Service metadata: name: elastic-master-service spec: type: ClusterIP selector: app: elastic-label node-role.kubernetes.io/master: "" # 需在ES节点配置中添加对应标签 ports: - protocol: TCP port: 9200 targetPort: 9200
- 数据节点Service(用于查询):
apiVersion: v1 kind: Service metadata: name: elastic-data-service spec: type: ClusterIP selector: app: elastic-label node-role.kubernetes.io/data: "" # 需在ES节点配置中添加对应标签 ports: - protocol: TCP port: 9200 targetPort: 9200
注:原生ES镜像不会自动添加上述标签,可通过修改ES配置添加
node.attr.role: master/node.attr.role: data,再调整Service的selector匹配对应标签。
三、验证集群状态
部署完成后,进入任意Pod执行:
curl http://localhost:9200/_cluster/health?pretty
返回status: green即表示集群正常运行,数据已同步,此时无论请求路由到哪个Pod,都能查询到完整数据。
四、关键注意事项
- 必须开放9300端口用于ES节点间通信,否则集群无法组建。
- 初始主节点列表必须包含所有候选主节点,否则集群启动失败。
- 每个Pod的PVC使用
ReadWriteOnce即可,ES通过分片复制实现数据同步,无需共享存储。 - 后续开启X-Pack安全时,需先设置集群密码并配置SSL,避免节点间通信失败。
内容的提问来源于stack exchange,提问作者user21236160
相关产品推荐
相关产品推荐

