You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何同步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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 10:44:56