K8s 里跑了几年业务之后,你会发现一个规律:像 Elasticsearch 这种有状态应用,最难的不是第一次把它装起来,而是后续每一次版本升级、节点扩容、故障恢复都像是在跟一堆底层细节搏斗。我最早也是老老实实写好 StatefulSet、Service、PVC、ConfigMap 一整套 YAML,后来折腾到崩溃,才转向了 ECK(Elastic Cloud on Kubernetes)。这个方案的使用方式跟你直觉里可能想的不太一样——它本身只需要两个 YAML 就能装完,后面要做的反而是通过 CRD 资源声明“我要几个 ES 节点、要给多少存储”,剩下的编排交给 Operator。接下来我把整个从零到一把 ECK 装起来、再把 Elasticsearch 和 Kibana 拉起来的完整过程写出来,包括我实际踩过的那些坑。
这篇内容主要适合两类人:一类是已经有一套 K8s 集群、正在为 Elasticsearch 运维发愁的团队;另一类是想从手动维护 ES 状态副本集切换到 Operator 模式、但还没摸清入门路径的同学。整个安装过程完全围绕 YAML 展开,我会把每一步为什么这么写、背后依赖什么条件都交代清楚。
1. 为什么我建议用 YAML 装 ECK,而不是自己组装 StatefulSet 跑 ES
1.1 先回顾一下在 K8s 上手动部署 ES 的痛点
最早在 K8s 上跑 Elasticsearch,会让人瞬间理解什么叫“有状态应用”的麻烦。首先是节点角色的拆分,master、data、ingest 三类角色如果放在同一个 StatefulSet 里,后续扩容某个角色就很尴尬,因为 StatefulSet 的副本配置是一体的。其次是存储,每个 data 节点必须挂一块持久化磁盘,这就要设计 volumeClaimTemplates,还要考虑存储类的 IOPS 是否满足 ES 的写入需求。再然后是配置,ES 的 jvm.options、elasticsearch.yml、安全证书、账号密码,每一块都要单独做成 ConfigMap 或 Secret,然后挂载进 Pod。
把这些都做完,你得到的只是一套“能跑”的 ES,而不是一套“能长期运维”的 ES。下次升级版本,你得关心滚动升级的顺序;节点挂了,你得自己确认数据分片能不能恢复;证书过期了,你得手动重新生成并分发。这个过程我完整走过一遍,当时最大的感受是:K8s 本身给无状态应用带来的便利,在 ES 这种组件上几乎全部失效了,因为 ES 内部还有自己的集群元数据、选主、分片恢复逻辑,跟 K8s 的调度体系是两套系统在互相配合。
1.2 ECK 是什么,它能帮你管理哪些组件
ECK 是 Elastic 官方推出的 K8s 管理运维方案,本质上是“自定义资源定义(CRD)+ Operator”的典型实现。它把 Elasticsearch、Kibana、APM Server、Enterprise Search 这些组件都定义成 K8s 里的自定义资源,比如 Elasticsearch 资源的 apiVersion 是 elasticsearch.k8s.elastic.co/v1,Kibana 资源是 kibana.k8s.elastic.co/v1。你只需要提交这些资源的 YAML,Operator 就会在后台负责创建对应的 StatefulSet、Service、Secret、自动生成证书、处理滚动升级、执行健康检查。
用大家最容易理解的话说:你不告诉 K8s “ES 这个 Pod 的启动命令是什么、探针怎么配、PV 怎么挂”,你只告诉它“我要一个三节点、每个节点 100GB 存储、版本 8.13.0 的 ES 集群”,剩下的事情 Operator 接管了。这正是 Operator 模式比手写一堆资源清单更先进的地方——它是把领域知识写进了控制器逻辑里,而不是停留在 YAML 的静态描述层面。
1.3 为什么不直接用 Helm Chart 而先用 YAML
有人会问,既然 ECK 有现成的 Helm Chart,为什么这篇一定要用 YAML 直接装?我的看法是,YAML 方式更利于理解 ECK 的工作原理。Helm Chart 内部其实也是在 apply 同一套 CRD 和 Operator 清单,只是帮你把参数模板化了。如果你还不太清楚 ECK 在集群里到底创建了什么对象,直接用 YAML 装一遍,再配合 kubectl get 看看它产生的资源,你会对整个机制形成远比 Chart 更清晰的心智模型。
另外,在实际交付场景里,很多集群出于安全要求并不允许直接拉取外部 Chart 仓库,而是要求把 YAML 文件下载、评审、入库后再离线应用。这时候你用 YAML 方式安装反而是更常见、更可控的流程。所以别嫌它“原始”,这种原始恰恰是可控性的来源。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手前把三件事确认好:K8s 版本、资源配额、存储类
2.1 K8s 版本和 RBAC 权限要求
ECK 对 K8s 版本有明确要求,我这次用的是 ECK 2.13.0,官方支持的最低版本是 Kubernetes 1.19 以上,但我不建议你在太老的集群上跑。一个很现实的原因是 ECK 会用到一些较新的 API,比如 ValidatingWebhookConfiguration、Lease 等,老版本集群上这些能力可能有差异。我的建议是至少使用 1.24 及以上的版本,稳定的生产环境可以直接用 1.26 之后的小版本。
权限方面,由于 Operator 需要监听集群范围内的自定义资源,它必须要一个 ClusterRole。我见过不少同学在自己搭的测试集群上,因为 RBAC 配置不完整导致 Operator 没有权限 watch 其他命名空间的资源,结果 Elasticsearch 资源提交后一直不生效。用官方提供的 operator.yaml 时,ClusterRole 已经被定义好了,但如果你要在离线环境部署,记得把 operator.yaml 里的 ClusterRole、ClusterRoleBinding、ServiceAccount 一并导入,缺一个都不行。
这里提供一个快速检查 K8s 版本的命令:
bash复制kubectl version --short
kubectl get nodes -o wide
确认版本没问题后,再看一下集群里有没有现成的 StorageClass:
bash复制kubectl get sc
这一步是在为后面的 PVC 做准备,别等 Pod 建好了才发现存储没着落。
2.2 Operator 和 Elasticsearch 的资源规格估算
ECK Operator 本身是一个比较轻量的控制面组件,官方推荐的资源限制大概是 1 核 CPU 和 1Gi 内存,实际运行时会根据托管对象的数量浮动。如果你在集群里同时管理十几套 ES,内存占用会明显上涨,所以我的习惯是先把 Limit 放宽到 2Gi,观察一段时间再收紧。
真正吃资源的是 Elasticsearch 节点。ES 的 JVM 堆内存默认是容器内存的一半,所以你在 Pod 的 resource 里写多少内存,直接决定了 ES 能用的堆大小。一个建议是单节点内存不小于 4Gi,如果是日志场景或者要承载较大索引,8Gi 到 16Gi 会更稳。CPU 方面,ES 对 CPU 核心数比较敏感,尤其是 data 节点在做 indexing 和查询时都吃 CPU,建议单节点至少分配 2 核。
这里有一个容易被忽视的点:如果 Pod 设置了 CPU limit,并且节点上 CPU 资源紧张,K8s 会对容器做 CPU Throttling,表现为 ES 查询延迟忽高忽低、GC 时间异常。我在生产环境遇到过一次非常诡异的“ES 偶发慢查询”,排查到最后发现是 CPU limit 设得太死,触发了内核级别的带宽限制。所以在给 ES 设资源配额时,要么不给 CPU Limit,要么给一个明显高于实际预期的值。
2.3 存储类决定了你的数据能不能安全落地
ES 的 data 节点需要持久化存储,ECK 通过 volumeClaimTemplates 为每个 Pod 动态申请 PVC,而 PVC 要绑到 PV,依赖的就是 StorageClass 的动态供给能力。
这块我建议优先选块存储类型,比如云厂商的 SSD 云盘或者自建机房的 Local Persistent Volume。NFS 之类的网络文件系统不是不能用,但性能上限和锁语义可能在高并发写入时出问题。你可以在部署前先验证一下默认 StorageClass 能不能正常动态创建 PV:
bash复制cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
EOF
kubectl get pvc test-pvc
如果 PVC 状态一直处于 Pending,说明默认 StorageClass 有问题,需要先解决存储供给,否则后面部署 ES 时 Pod 会一直卡在 Pending。
3. 安装 ECK 本体:CRD 和 Operator 两个 YAML
3.1 先注册 CRD,为什么这里建议用 create
ECK 的安装入口是官方仓库里的两个 YAML 文件。先执行 CRD 的注册:
bash复制kubectl create -f https://download.elastic.co/downloads/eck/2.13.0/crds.yaml
这里注意官方文档用的是 kubectl create 而不是 kubectl apply。原因在于 crds.yaml 文件里面包含了多个 CRD 定义,总体积很大,而 kubectl apply 会在对象上写入 last-applied-configuration 注解,当 JSON 体积超过 etcd 的 request limit 时就会报错。用 create 则只是简单地创建对象,不会写入这个注解,能够避免在大文件场景下的容量问题。
注册完成之后,你可以用下面命令确认自定义资源已经存在:
bash复制kubectl get crd | grep elastic.co
正常情况下你会看到 elasticsearch.k8s.elastic.co、kibana.k8s.elastic.co、apmserver.k8s.elastic.co、enterprisesearch.k8s.elastic.co 等一系列 CRD。这些 CRD 就相当于给 K8s 安装了几个全新的“对象类型”,后面的 Elasticsearch、Kibana 资源本质上都是这些新类型的实例。
有的同学在这一步会看到 connection refused 或者 timeout 的错误,多半是因为网络访问不了 download.elastic.co。这时候就应该手动下载 crds.yaml 和 operator.yaml,再通过本地文件安装。离线环境下,这种做法也是最稳妥的路径。
3.2 部署 Operator 到 elastic-system
CRD 注册好之后,再执行 Operator 的部署:
bash复制kubectl apply -f https://download.elastic.co/downloads/eck/2.13.0/operator.yaml
operator.yaml 里定义了一整套与 Operator 运行相关的对象,包括 ServiceAccount、ClusterRole、ClusterRoleBinding、ValidatingWebhookConfiguration,以及最终运行的 Operator 工作负载。ECK 2.x 里 Operator 是以 StatefulSet 方式运行在 elastic-system 命名空间中的,这种设计主要是为了让 Operator 有稳定的网络标识和持久化状态。
检查 Operator 是否启动成功:
bash复制kubectl -n elastic-system get pods
kubectl -n elastic-system get statefulset
正常情况下你会看到一个名为 elastic-operator 的 Pod,状态为 Running。接着看日志:
bash复制kubectl -n elastic-system logs -f statefulset/elastic-operator
日志里会出现大量 controller 启动信息,比如 Starting workers、Starting EventSource 之类的输出,这说明 Operator 已经正常连接 K8s API Server 并开始监听资源。
需要注意一个细节:ValidatingWebhookConfiguration 的注册依赖 K8s 的 admission webhook 机制。如果你在集群里禁用了 webhook,比如通过 --disable-admission-plugins=ValidatingAdmissionWebhook 启动的 apiserver,那么 Operator 虽然能启动,但在校验 Elasticsearch 资源时会走不到 webhook 的验证逻辑。这种情况下操作依然可以继续,但你会失去一层安全检查,我不建议在正式环境这样做。
3.3 验证 Operator 对自定义资源的响应
Operator 启动之后,可以提交一个最简单的 Elasticsearch 资源,验证端到端链路是否打通。比如:
bash复制kubectl apply -f - <<EOF
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: smoke-test
namespace: default
spec:
version: 8.13.0
nodeSets:
- name: default
count: 1
config:
node.store.allow_mmap: false
EOF
等十几秒后,查看:
bash复制kubectl get elasticsearch
kubectl get pods -l elasticsearch.k8s.elastic.co/cluster-name=smoke-test
如果 Operator 工作正常,你会看到 ES Pod 被自动创建出来,并且 elasticsearch 资源的状态会显示为绿色。这个 smoke-test 只是验证链路用的,验证完可以删掉。删除时直接 kubectl delete elasticsearch smoke-test,ECK 会连带着把由它创建出来的 StatefulSet、PVC、Service 一起清理掉,这也是手动部署做不到的便捷之处。
4. 用 YAML 声明 Elasticsearch:单节点起步,再到生产多节点
4.1 最小可用配置逐行解释
我们来看一个真正可用的最小 ES 配置:
yaml复制apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: production-es
namespace: elastic-system
spec:
version: 8.13.0
http:
tls:
selfSignedCertificate:
disabled: false
nodeSets:
- name: master
count: 3
config:
node.roles: ["master"]
podTemplate:
spec:
containers:
- name: elasticsearch
resources:
requests:
memory: 4Gi
cpu: 1
limits:
memory: 4Gi
cpu: 2
volumeClaimTemplates:
- metadata:
name: elasticsearch-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: standard
- name: data
count: 3
config:
node.roles: ["data", "ingest"]
podTemplate:
spec:
containers:
- name: elasticsearch
resources:
requests:
memory: 8Gi
cpu: 2
limits:
memory: 8Gi
cpu: 4
volumeClaimTemplates:
- metadata:
name: elasticsearch-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Gi
storageClassName: standard
这里有几个字段值得展开说一下。
version 字段指定了 ES 的版本,ECK 会下载对应版本的 Elasticsearch 镜像并保证镜像版本与 CR 元数据一致。你在生产环境要升级 ES 时,只需要把这里的版本号改掉再 apply,Operator 就会自动做滚动升级。
nodeSets 是一个数组,可以定义多组不同的节点池,每一组节点可以有自己的名称、角色、资源和存储。这种设计比手动创建多个 StatefulSet 优雅很多,因为它们都被统一收纳在一个 Elasticsearch 资源下,由 Operator 统一调度和协调。
config 字段里可以直接写 elasticsearch.yml 的配置项,不需要你单独去创建 ConfigMap。ECK 会自动把这部分配置合并进最终的 elasticsearch.yml 文件里。
node.roles 字段用来指定节点角色。master 节点最少 3 个才有高可用意义,data/ingest 角色可以根据数据量和写入吞吐横向扩展。
podTemplate 字段允许你定制 Pod 的模板,最常用的就是设置容器的 resources,以及在 volumeClaimTemplates 里申请持久化存储。
4.2 生产环境的多节点配置怎么拆分角色
真正生产环境里,我强烈建议把 master 和 data 拆成两个独立的 nodeSets。原因是 master 节点负责集群状态维护,对磁盘 IO 要求不高,但稳定性非常重要;data 节点负责实际数据存储和查询,对磁盘和 CPU 的要求都不一样。混部的话,数据节点的 IO 抖动可能直接拖累 master 的选主响应,进而影响整个集群稳定性。
还有一个细节是 ES 默认会做 bootstrap checks,如果 master 节点不满足 discovery.seed_hosts 等配置,集群启动可能失败。但在 ECK 模式下,网络发现和种子节点配置都由 Operator 自动生成,你通常不需要自己处理。只要保证 master 节点数是奇数(比如 3 个或 5 个),并且每个 master 节点独立存储即可。
我这边给出的配置里,master 组用了 4Gi 内存和 20Gi 存储,这是考虑到 master 节点本身不存数据,不需要太大磁盘。data 组则给了 200Gi 存储,内存 8Gi。如果是日志量很大的场景,data 节点的磁盘和内存还需要进一步扩大。
4.3 Operator 自动帮你搞定的隐藏任务:证书、Service、Secret
当你 apply 完上面的 Elasticsearch YAML 之后,看起来只是提交了一个自定义资源,但 Operator 在后台做的事远比这多。它会自动为你的 ES 集群生成内部 TLS 证书,并创建对应的 Secret 保存私钥和证书内容;它会创建无头 Service 用于集群内节点间的通信,还会创建一个对外的 Service 用于客户端访问;每个 ES Pod 启动前,Operator 会注入一个初始化容器,负责调整系统参数和文件权限。
这些隐藏任务恰恰是 ECK 最值钱的地方。我在手动部署 ES 时,最怕的就是处理证书:要在每个节点上生成、分发、配置信任证书,稍有不慎节点之间就无法互相通信。ECK 把这一整套逻辑固化成了自动化流程,你只需要知道证书放在哪个 Secret 里即可。
查看 ECK 为 ES 创建的 Service 和 Secret:
bash复制kubectl -n elastic-system get svc -l elasticsearch.k8s.elastic.co/cluster-name=production-es
kubectl -n elastic-system get secret -l elasticsearch.k8s.elastic.co/cluster-name=production-es
这能帮你建立起一个意识:你的 YAML 只是宣告期望状态,具体实现由 Operator 负责。
5. 把 Kibana 拉起来:关联配置、密码获取与服务暴露
5.1 通过 elasticsearchRef 关联 Elasticsearch
Elasticsearch 集群起来了,接下来需要有一个可视化入口,这就是 Kibana 的用武之地。在 ECK 中,Kibana 的 YAML 配置非常简单:
yaml复制apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
name: production-kb
namespace: elastic-system
spec:
version: 8.13.0
count: 1
elasticsearchRef:
name: production-es
podTemplate:
spec:
containers:
- name: kibana
resources:
requests:
memory: 1Gi
cpu: 500m
limits:
memory: 2Gi
cpu: 1
这里的核心是 elasticsearchRef,它告诉 Operator 这个 Kibana 要连接哪一个 Elasticsearch 集群。需要特别注意的是,name 指向的 Elasticsearch 必须与 Kibana 在同一个命名空间。如果两个资源不在同一个命名空间,就需要额外的 namespace 字段并配合权限设置,但在绝大多数场景下,把 Kibana 和 Elasticsearch 放在同一个命名空间是更省事也更符合直觉的做法。
Operator 会通过内部网络自动解析 Elasticsearch 的地址,并且自动设置 Kibana 连接 ES 时需要用到的证书和账号。你不需要手动在 Kibana 配置里写 elasticsearch.hosts 或者 elasticsearch.username,这些都会由 ECK 自动注入。这也是很多人用 ECK 之后最直观的感受:配置项少了特别多。
5.2 获取 elastic 用户密码和访问入口
通过 ECK 创建 ES 集群后,它会自动创建一个名为 {cluster-name}-es-elastic-user 的 Secret,里面保存了超级用户 elastic 的密码。获取方式:
bash复制kubectl -n elastic-system get secret production-es-es-elastic-user -o go-template='{{.data.elastic | base64decode}}'
这个密码在你第一次访问 Kibana 时需要使用。如果你需要为其他用户单独创建账号,我建议直接使用 Kibana 的 UI 或者在 ES 里创建相应角色,而不是去修改 Secret 里的密码。原因是 ECK 会管理这些内置 Secret,手动改动可能在下一次 reconcile 时被覆盖掉。
Kibana 默认会通过 ClusterIP Service 暴露在集群内部,你可以先稍微验证一下是否能连通:
bash复制kubectl -n elastic-system get svc -l kibana.k8s.elastic.co/name=production-kb
如果你是在本地测试集群,可以使用 kubectl port-forward 快速访问:
bash复制kubectl -n elastic-system port-forward svc/production-kb-kb-http 5601:5601
打开浏览器访问 https://localhost:5601,使用 elastic 用户和刚才获取到的密码登录,就能进入 Kibana 界面了。
5.3 用 Ingress 暴露 Kibana 的推荐姿势
如果集群里有 Ingress Controller,我更建议直接用 Ingress 暴露 Kibana,而不是把 Service 类型改成 LoadBalancer 或者 NodePort。原因是 Ingress 能够更方便地管理 TLS 证书和域名,也符合大多数团队对于南北流量的统一治理方式。
一个典型的 Ingress YAML 如下:
yaml复制apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kibana-ingress
namespace: elastic-system
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
ingressClassName: nginx
rules:
- host: kibana.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: production-kb-kb-http
port:
number: 5601
这里有一个非常容易踩的坑:ECK 默认创建的 Kibana Service 走的是 HTTPS,因为 Elastic 栈默认启用了传输安全层。所以 Ingress 注解里必须写明 nginx.ingress.kubernetes.io/backend-protocol: "HTTPS",否则 Ingress 会把请求用 HTTP 转发给后端,Kibana 直接返回 400 错误,因为它的 TLS 层根本不认 HTTP 明文。
同样的思路也适用于访问 Elasticsearch。
6. 安装和调试中我踩过的坑:Pod 起不来、内存超卖、存储类不匹配
6.1 Pod 一直 Pending,先查 PVC 绑没绑上
ECK 安装完成后最大的问题通常是 Pod 状态一直 Pending。我见过很多同学第一反应是看 K8s 事件、看节点资源,但忽略了最根本的 PVC 绑定状态。ECK 创建的 ES 节点一定会申请 PVC,而 PVC 若无法绑定到 PV,Pod 就会无限期 Pending。
排查命令:
bash复制kubectl -n elastic-system get pvc
kubectl -n elastic-system get events --sort-by=.lastTimestamp
如果 PVC 卡在 Pending,大概率是 StorageClass 没有创建或者不支持动态供应。有时候集群里存在多个 StorageClass,但默认的 StorageClass 指向的存储后端不可用。这时候要么调整 storageClassName 字段,要么把可用的 StorageClass 设为默认:
bash复制kubectl patch storageclass <your-sc-name> -p '{"metadata": {"annotations": {"storageclass.kubernetes.io/is-default-class": "true"}}}'
注意这个操作会影响集群里其他组件的 PVC 创建行为,建议在确认没有冲突的情况下执行。
6.2 Pod 反复 OOMKilled,调参方向是什么
内存资源不足是 ES 在 K8s 上最常见的故障之一。ECK 默认根据 Pod 的 memory limit 来设置 JVM 堆大小,堆大小一般取 limit 的 50%。比如 limit 是 8Gi,那 JVM 堆就是 4Gi。如果你因为省资源把 limit 压到 2Gi,堆就只剩 1Gi,ES 很容易在索引写入稍大一点时触发 OOM。
另外一个容易被忽略的原因是节点本身的空闲内存不够。即便你的 Pod 申请了 8Gi,如果宿主机内存已经被其他 Pod 占满,K8s 调度时会直接把新 Pod 放到 Pending,或者运行一段时间后被 OOM Killer 干掉。这时排查方向不应该只盯着 ES 的 Pod,还要看节点整体内存水位:
bash复制kubectl top nodes
kubectl describe pod <es-pod-name> | tail -30
我遇到过一种情况,ES Pod 并没有 OOMKilled,但业务反馈写入超时,看监控发现内存剩余很多,CPU 却触发了 throttle。这种问题往往是 CPU limit 设置过低,这时候最快捷的方式是提高 CPU Limit,或者干脆删掉 CPU Limit 让 ES 使用节点上可用的 CPU 配额。
6.3 一些容易被忽略的细节汇总
ECK 安装和 Elastic 栈部署还有其他不少细节,我把值得注意的几条汇总一下。
第一,node.store.allow_mmap 的问题。ES 底层使用 mmap 来访问索引文件,而 K8s 节点上默认的 vm.max_map_count 通常只有 65530,ES 官方要求至少 262144。ECK 会自动尝试在初始化容器里调整这个参数,但这要求节点的 /proc/sys 可写。如果你的节点用 containerd 且开启了 read-only host filesystem,初始化容器可能会失败。最简单的规避方式就是在 ES 配置里增加:
yaml复制config:
node.store.allow_mmap: false
代价是索引访问性能有一定下降,所以只是应急方案,生产环境最好还是调大节点内核参数。
第二,镜像拉取问题。ECK 需要拉取 Elastic 官方镜像和 ECK Operator 镜像。如果你所在网络无法直接访问 Docker Hub 或 Elastic 的镜像仓库,要先配置 imagePullSecret 或者私有镜像仓库的地址映射。可以在 podTemplate 里直接指定 imagePullSecrets:
yaml复制podTemplate:
spec:
imagePullSecrets:
- name: registry-secret
第三,删除资源时的级联清理。ECK 的一大优点是删除 Elasticsearch 资源时,它创建的 PVC 也会一并清理。但如果你手动创建了 PVC 再挂到 ES 上,删除行为可能不符合预期。建议始终使用 volumeClaimTemplates 而不是手动创建 PVC。
第四,eck 的 Webhook 校验。ECK 注册了 ValidatingWebhookConfiguration,会对 Elasticsearch、Kibana 等资源的字段做校验。如果你改了 version 字段但 ES 版本不存在或者版本号格式不正确,Webhook 会直接拒绝资源创建。这时候你要先看事件的错误信息:
bash复制kubectl describe elasticsearch production-es
事件里一般会直接告诉你版本不支持或者字段不合法,比对着日志找半天要快得多。
第五,elastic-operator 本身如果崩溃,所有 Elastic 资源的 reconcile 都会停摆。建议在生产环境中给 operator 加上资源配额监控,并在出问题时先看 operator 自己的状态:
bash复制kubectl -n elastic-system get pods -l control-plane=elastic-operator
kubectl -n elastic-system logs -l control-plane=elastic-operator --tail=200
如果 operator 被 OOMKilled,把它的内存 limit 调大,同时检查是不是在管理过多集群时超过了默认配额。
最后再分享一个技巧。很多人在初次验证 ECK 时,会反复提交修改 Elasticsearch 资源的 YAML,然后盯 Pod 状态。其实你完全不用那么紧张,ECK 的 Operator 会在每次资源变更后自动完成滚动重启,你只需要确定最终要的节点数、内存、角色分配和存储大小,把 YAML 一次性写好提交。我现在的习惯是把这些 YAML 全部收进 Git 仓库做版本管理,每次变更都走 MR 评审,这个流程真的比手动改线上 StatefulSet 可靠太多了。
说回怎么判断安装是否成功,就看两个指标是否满足:Elasticsearch 资源状态是 green,Kibana 能正常打开。只要这两点成立,你对 YAML 层面就不用再操心了,可以把精力放到索引设计和数据接入上去。
