k8s集群中安装部署ECK技术栈 十八岁 2026-09-05 2026-09-05
k8s集群中安装部署ECK 官方文档:https://www.elastic.co/guide/en/cloud-on-k8s/master/k8s-deploy-eck.html
1.安装 Elastic Cloud on Kubernetes(ECK) Elastic Cloud on Kubernetes(ECK)是 Elastic 官方提供的 Kubernetes Operator。有了这些 CRD,才能用 YAML 声明式地创建 Elasticsearch 集群等资源。
1.1安装CRD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 kubectl create -f https://download.elastic.co/downloads/eck/3.5.0/crds.yaml # 执行过程如下: [root@k8s-master01 29-eck]# kubectl create -f https://download.elastic.co/downloads/eck/3.5.0/crds.yaml customresourcedefinition.apiextensions.k8s.io/agents.agent.k8s.elastic.co created customresourcedefinition.apiextensions.k8s.io/apmservers.apm.k8s.elastic.co created customresourcedefinition.apiextensions.k8s.io/autoopsagentpolicies.autoops.k8s.elastic.co created customresourcedefinition.apiextensions.k8s.io/beats.beat.k8s.elastic.co created customresourcedefinition.apiextensions.k8s.io/elasticmapsservers.maps.k8s.elastic.co created customresourcedefinition.apiextensions.k8s.io/elasticsearchautoscalers.autoscaling.k8s.elastic.co created customresourcedefinition.apiextensions.k8s.io/elasticsearches.elasticsearch.k8s.elastic.co created customresourcedefinition.apiextensions.k8s.io/enterprisesearches.enterprisesearch.k8s.elastic.co created customresourcedefinition.apiextensions.k8s.io/kibanas.kibana.k8s.elastic.co created customresourcedefinition.apiextensions.k8s.io/logstashes.logstash.k8s.elastic.co created customresourcedefinition.apiextensions.k8s.io/packageregistries.packageregistry.k8s.elastic.co created customresourcedefinition.apiextensions.k8s.io/stackconfigpolicies.stackconfigpolicy.k8s.elastic.co created
1.2ECK Operator 安装 镜像在国外,如果在线安装很慢的话可以改用我的镜像仓库,已经将镜像同步到阿里云
registry.cn-beijing.aliyuncs.com/k8s-liujunwei/eck-operator:3.5.0镜像是从官方docker.elastic.co/eck/eck-operator:3.5.0同步的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # 下载文件,也可以通过浏览器下载,然后把文件上传到服务器中 [root@k8s-master01 29-eck]# wget https://download.elastic.co/downloads/eck/3.5.0/operator.yaml --2026-08-24 15:52:22-- https://download.elastic.co/downloads/eck/3.5.0/operator.yaml Resolving download.elastic.co (download.elastic.co)... 34.120.127.130, 2600:1901:0:1d7:: Connecting to download.elastic.co (download.elastic.co)|34.120.127.130|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 22289 (22K) [application/yaml] Saving to: ‘operator.yaml’ operator.yaml 100%[===========================================================================>] 21.77K 113KB/s in 0.2s 2026-08-24 15:52:24 (113 KB/s) - ‘operator.yaml’ saved [22289/22289] [root@k8s-master01 29-eck]# ll total 836 -rw-r--r-- 1 root root 827819 Aug 24 15:32 crds.yaml -rw-r--r-- 1 root root 22289 Aug 4 16:43 operator.yaml # 修改operator.yaml文件中的镜像地址 [root@k8s-master01 29-eck]# vim operator.yaml # 修改527行的镜像下载地址 containers: # - image: "docker.elastic.co/eck/eck-operator:3.5.0" #原配置注释 - image: "registry.cn-beijing.aliyuncs.com/k8s-liujunwei/eck-operator:3.5.0" #改为自己的镜像地址
创建资源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # 资源创建在elastic-system命名空间 [root@k8s-master01 29-eck]# kubectl create -f operator.yaml namespace/elastic-system created serviceaccount/elastic-operator created secret/elastic-webhook-server-cert created configmap/elastic-operator created clusterrole.rbac.authorization.k8s.io/elastic-operator created clusterrole.rbac.authorization.k8s.io/elastic-operator-view created clusterrole.rbac.authorization.k8s.io/elastic-operator-edit created clusterrolebinding.rbac.authorization.k8s.io/elastic-operator created service/elastic-webhook-server created statefulset.apps/elastic-operator created validatingwebhookconfiguration.admissionregistration.k8s.io/elastic-webhook.k8s.elastic.co created # 安装成功后,查看创建的资源情况 [root@k8s-master01 29-eck]# kubectl get all -n elastic-system NAME READY STATUS RESTARTS AGE pod/elastic-operator-0 1/1 Running 0 39s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elastic-webhook-server ClusterIP 10.96.1.175 <none> 443/TCP 39s NAME READY AGE statefulset.apps/elastic-operator 1/1 40s
2.在k8s中部署Elasticsearch集群 Elasticsearch 的角色是 存储与搜索引擎
由 ECK 管理 (Elasticsearch CRD)
核心职责
索引存储 : 按天/周创建 Index(如 app-log-2026.08.30)
全文检索 : 支持关键词搜索、聚合分析
生命周期管理 : ILM 策略自动 hot→warm→cold→delete
ECK 额外提供 : 自动化部署、滚动升级、证书管理、快照备份、弹性伸缩
2.1部署一个小型集群 接下来即可使用自定义资源 Elasticsearch 一键启动一个 ES 集群。不推荐把Operator 资源 和组件的资源放在同一个命名空间。
首先创建一个用于放置日志收集工具的 Namespace:
1 2 3 # 创建一个单独的命名空间logging,专门放置日志收集组件的 [root@k8s-master01 29-eck]# kubectl create ns logging namespace/logging created
创建一个定义 Elasticsearch 集群的 Yaml 文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 apiVersion: elasticsearch.k8s.elastic.co/v1 kind: Elasticsearch metadata: name: es-cluster namespace: logging spec: version: 9.5 .2 image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/elasticsearch:9.5.2 nodeSets: - name: default count: 3 volumeClaimTemplates: - metadata: name: elasticsearch-data spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi storageClassName: cfs-sc podTemplate: spec: initContainers: - name: sysctl securityContext: privileged: true runAsUser: 0 command: - sh - -c - sysctl -w vm.max_map_count=1048576
创建集群:
1 2 [root@k8s-master01 29-eck]# kubectl create -f Elasticsearch.yaml elasticsearch.elasticsearch.k8s.elastic.co/es-cluster created
查看资源状态:
1 2 3 4 5 6 7 8 9 10 11 [root@k8s-master01 29-eck]# kubectl get po -n logging NAME READY STATUS RESTARTS AGE es-cluster-es-default-0 1/1 Running 0 72m es-cluster-es-default-1 1/1 Running 0 72m es-cluster-es-default-2 1/1 Running 0 72m # es集群的HEALTH字段是green表示集群健康 [root@k8s-master01 29-eck]# kubectl get es -n logging NAME HEALTH NODES VERSION PHASE AGE es-cluster green 3 9.5.2 Ready 73m
服务启动完成后可以使用下面命令查看集群状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 # 获取密码 [root@k8s-master01 29-eck]# PASSWORD=$(kubectl get secret es-cluster-es-elastic-user -n logging -o go-template='{{.data.elastic | base64decode}}') [root@k8s-master01 29-eck]# echo $PASSWORD OT2jCVwU2cvx8ZQpZE6SmNQg [root@k8s-master01 29-eck]# kubectl get svc -n logging NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE es-cluster-es-default ClusterIP None <none> 9200/TCP 75m es-cluster-es-http ClusterIP 10.96.49.28 <none> 9200/TCP 75m es-cluster-es-internal-http ClusterIP 10.96.42.43 <none> 9200/TCP 75m es-cluster-es-transport ClusterIP None <none> 9300/TCP 75m # [root@k8s-master01 29-eck]# curl -u "elastic:$PASSWORD " https://10.96.49.28:9200/_cluster/health?pretty -k { "cluster_name" : "es-cluster", "status" : "green", "timed_out" : false, "number_of_nodes" : 3, "number_of_data_nodes" : 3, "active_primary_shards" : 3, "active_shards" : 6, "relocating_shards" : 0, "initializing_shards" : 0, "unassigned_shards" : 0, "unassigned_primary_shards" : 0, "delayed_unassigned_shards" : 0, "number_of_pending_tasks" : 0, "number_of_in_flight_fetch" : 0, "task_max_waiting_in_queue_millis" : 0, "active_shards_percent_as_number" : 100.0 }
2.2多节点集群案例 大型生产集群可以配置多个节点组,每个节点组定义不同的角色来分别处理不同的工作任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 apiVersion: elasticsearch.k8s.elastic.co/v1 kind: Elasticsearch metadata: name: es-cluster namespace: logging spec: version: 9.5 .2 image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/elasticsearch:9.5.2 nodeSets: - name: masters count: 3 config: node.roles: ["master" ] volumeClaimTemplates: - metadata: name: elasticsearch-data spec: accessModes: ["ReadWriteOnce" ] resources: requests: storage: 10Gi storageClassName: cfs-sc podTemplate: spec: initContainers: - name: sysctl securityContext: privileged: true runAsUser: 0 command: ["sh" , "-c" , "sysctl -w vm.max_map_count=1048576" ] containers: - name: elasticsearch resources: requests: memory: 4Gi cpu: 1 limits: memory: 4Gi cpu: 2 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: elasticsearch.k8s.elastic.co/cluster-name: es-cluster topologyKey: kubernetes.io/hostname - name: hot count: 6 config: node.roles: ["data_hot" , "data_content" , "ingest" ] volumeClaimTemplates: - metadata: name: elasticsearch-data spec: accessModes: ["ReadWriteOnce" ] resources: requests: storage: 100Gi storageClassName: cfs-sc podTemplate: spec: initContainers: - name: sysctl securityContext: privileged: true runAsUser: 0 command: ["sh" , "-c" , "sysctl -w vm.max_map_count=1048576" ] containers: - name: elasticsearch resources: requests: memory: 16Gi cpu: 4 limits: memory: 16Gi cpu: 8 - name: warm count: 3 config: node.roles: ["data_warm" ] volumeClaimTemplates: - metadata: name: elasticsearch-data spec: accessModes: ["ReadWriteOnce" ] resources: requests: storage: 300Gi storageClassName: cfs-sc podTemplate: spec: initContainers: - name: sysctl securityContext: privileged: true runAsUser: 0 command: ["sh" , "-c" , "sysctl -w vm.max_map_count=1048576" ] containers: - name: elasticsearch resources: requests: memory: 16Gi cpu: 2 limits: memory: 16Gi cpu: 4
2.3多节点配置说明 配置一个节点,例如:
1 2 3 nodeSets: - name: default count: 3
这是是小型集群中最常见的方案,相当于一个人承担多个岗位;
而配置多节点的,例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 apiVersion: elasticsearch.k8s.elastic.co/v1 kind: Elasticsearch metadata: name: es-cluster spec: version: 9.5 .2 nodeSets: - name: masters count: 3 config: node.roles: ["master" ] - name: hot count: 6 config: node.roles: ["data_hot" , "data_content" , "ingest" ] - name: warm count: 3 config: node.roles: ["data_warm" ]
这是中大型日志平台的方案,相当于公司中老板,财务,销售,技术分别处理不同的工作。
需要注意的是,只写名字(masters / hot / warm)没有任何实际作用 。名字只是给你自己看的标签,Elasticsearch 不会因为你叫它 “hot” 就自动变成热节点。
真正决定节点职责的是 config.node.roles 。如果不写 node.roles,所有节点默认都会拥有几乎全部角色(master + data + data_hot + data_warm + ingest + ml 等),它们之间没有分工 。
两种配置的本质区别:
配置
实际效果
适用场景
单一 nodeSet(default count: 3)
3 个节点全部是“全能节点”,每个节点都能当 master、存数据、处理写入和查询
小集群、开发/测试、数据量不大
多个 nodeSet(masters + hot + warm)
只有正确配置了 node.roles 之后 ,才会真正分工: • masters:只负责集群管理 • hot:负责最新数据写入 + 高频查询 • warm:负责较老的数据(低频查询)
生产环境、有时间序列数据(日志、指标等)、需要成本优化
它们是有明确分工和协作关系 的,典型是 Hot-Warm 架构 (常配合 Index Lifecycle Management / ILM 使用):
masters(专用主节点)
角色:node.roles: [“master”]
职责:只负责集群状态管理、选举、分片分配等
不存业务数据,资源要求相对较低但要稳定
生产环境强烈建议专用(尤其是节点数较多时)
hot(热节点)
角色通常:node.roles: [“data_hot”, “data_content”, “ingest”](有时也加 master)
职责:
接收新写入的数据
存放最近、最常被查询 的数据
需要较高的 CPU、内存和快速磁盘(SSD)
数据一开始都落在 hot 节点
warm(温节点)
角色:node.roles: [“data_warm”]
职责:存放已经变“冷”一点 的数据(比如超过几天/几周的日志)
查询频率低,可以用更大但更便宜的磁盘
通过 ILM 策略,数据会自动从 hot 迁移到 warm
2.4容器配置说明 不需要单独配置正式的 Elasticsearch 容器,这是 ECK 的设计机制。在不配置主容器时,ECK Operator 会自动生成并注入主容器(名字固定为 elasticsearch)。如果写了主容器的配置,那么就会覆盖ECK Operator自动注入的配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # ---------- Warm 节点(低频查询、较大存储) ---------- - name: warm count: 3 config: node.roles: ["data_warm"] volumeClaimTemplates: #针对多个节点组的配置,每个节点组需要单独配置存储 - metadata: name: elasticsearch-data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 300Gi storageClassName: cfs-sc podTemplate: spec: initContainers: - name: sysctl securityContext: privileged: true runAsUser: 0 command: ["sh", "-c", "sysctl -w vm.max_map_count=1048576"] containers: - name: elasticsearch resources: requests: memory: 16Gi cpu: 2 limits: memory: 16Gi cpu: 4
初始化容器(sysctl) :每个 nodeSet 都最好单独写 :
生产环境如果 Kubernetes 节点数量比较固定,运维上更干净的方法其实是直接给所有可能调度 Elasticsearch 的宿主机永久配置 :
1 2 3 4 5 cat >/etc/sysctl.d/99-elasticsearch.conf <<EOF vm.max_map_count=1048576 EOF sysctl --system
然后 Elasticsearch CR 中甚至可以完全去掉这个 initContainer。这样Node 本身已经满足 ES 环境要求,就可以不配置initContainer:
主容器(elasticsearch) :不是每个都需要写 ,只在你想覆盖资源、环境变量等的时候才写。
2.5多节点中定义存储 在上述多节点的集群案例中,每个节点中都单独定义了存储,每个 nodeSet 里的 volumeClaimTemplates 都写了相同的名字name: elasticsearch-data
实际创建出来的 PVC 名字是不同的 。ECK 会为每个 nodeSet 创建独立的 StatefulSet ,PVC 的最终命名规则是:
1 {volumeClaimTemplate.name}-{statefulset-name}-{pod-序号}
举例(假设集群名叫 es-cluster):
节点组
StatefulSet 名称
实际 PVC 名称示例
masters
es-cluster-es-masters
elasticsearch-data-es-cluster-es-masters-0
hot
es-cluster-es-hot
elasticsearch-data-es-cluster-es-hot-0
warm
es-cluster-es-warm
elasticsearch-data-es-cluster-es-warm-0
所以即使模板里的 name 都叫 elasticsearch-data,最终生成的 PVC 是完全独立的,不会互相覆盖或冲突。
为什么必须叫 elasticsearch-data?
这是 ECK 的约定名称 。
ECK 默认会把名字为 elasticsearch-data 的卷挂载到 Elasticsearch 容器的数据目录(/usr/share/elasticsearch/data)。
如果你改成其他名字(比如 data 或 es-data),Operator 就不会自动挂载,除非你自己在 podTemplate 里手动配置 volumeMounts,比较麻烦,不推荐。
2.6多节点数据迁移策略 集群按照 masters + hot + warm 定义角色后,只要节点角色配置正确,集群就能正常启动和运行 。
数据默认会优先分配到拥有 data_hot / data_content 角色的节点(也就是你的 hot 节点组)。
没有 ILM 的情况下:
数据会一直待在 hot 节点上
不会自动迁移到 warm 节点
集群功能完全正常(写入、查询、搜索都没问题)
什么时候才需要配置 ILM?
场景
是否需要 ILM
只是想把节点按角色分开,数据全部留在 hot 节点
不需要
希望数据根据时间/大小自动从 hot 迁移到 warm
需要
想节省 hot 节点的昂贵存储成本
强烈建议配置
有明确的数据保留策略(比如 7 天 hot → 30 天 warm → 删除)
必须配置
总结
集群能跑起来 ≠ 必须配 ILM
想让数据自动流动 (hot → warm)→ 才需要配 ILM + Index Template
如果目前只是想先把集群跑起来验证功能,可以先不配 ILM ,等业务写入数据后再根据实际需求添加策略。这里由于资源限制并没有分角色部署集群,暂时先不记录配置ILM策略,后续有环境在补充。
3.在k8s中部署kibana Kibana — 可视化与运维平台
由 ECK 管理 (Kibana CRD)
核心职责
日志查询与展示 (Discover)
构建仪表盘 (Dashboard)
告警规则 配置
Index Pattern / Data View 管理
ECK 集成后还可通过 Kibana 查看 ES 集群健康状态
3.1部署Kibana服务 Kibana 不需要像 Elasticsearch 那样定义角色、持久化存储和初始化容器。
Kibana 是无状态服务 (状态都存在 Elasticsearch 里),ECK 用 Deployment 来管理它,配置比 ES 简单很多。
在上述创建的Elasticsearch 集群的步骤中我定义的 Elasticsearch CR 名称是 es-cluster,位于 logging namespace,版本是 9.5.2,因此建议 **Kibana 也部署到 logging,并使用相同版本 9.5.2**。ECK 的 Kibana 通过 elasticsearchRef 直接关联 ECK 管理的 Elasticsearch,Operator 会自动处理 Kibana 到 Elasticsearch 的认证、TLS CA 和连接配置,不需要自己填写 ES 用户名、密码或 elasticsearch.hosts
创建kibana资源文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 [root@k8s-master01 29 -eck ] apiVersion: kibana.k8s.elastic.co/v1 kind: Kibana metadata: name: kibana namespace: logging spec: version: 9.5 .2 image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/kibana:9.5.2 count: 2 elasticsearchRef: name: es-cluster http: service: spec: type: NodePort sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 10800 tls: selfSignedCertificate: disabled: true
创建kibana:
1 2 3 [root@k8s-master01 29-eck]# kubectl create -f Kibana.yaml kibana.kibana.k8s.elastic.co/kibana created
查看创建的资源情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # kibana-kb-xxxx的pod已经Running [root@k8s-master01 ~]# kubectl get po -n logging NAME READY STATUS RESTARTS AGE es-cluster-es-default-0 1/1 Running 0 5h43m es-cluster-es-default-1 1/1 Running 0 5h43m es-cluster-es-default-2 1/1 Running 0 5h43m kibana-kb-b889dbf5f-8vx2n 1/1 Running 0 27m kibana-kb-b889dbf5f-vw8d6 1/1 Running 0 27m # kibana资源已经是green [root@k8s-master01 ~]# kubectl get kb -n logging NAME HEALTH NODES VERSION AGE kibana green 2 9.5.2 29m
接下来可以通过svc的NodePort在浏览器中访问,用户密码和ES的一致:
1 2 3 4 5 6 7 [root@k8s-master01 ~]# kubectl get svc -n logging NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE es-cluster-es-default ClusterIP None <none> 9200/TCP 5h46m es-cluster-es-http ClusterIP 10.96.244.191 <none> 9200/TCP 3h19m es-cluster-es-internal-http ClusterIP 10.96.42.43 <none> 9200/TCP 5h46m es-cluster-es-transport ClusterIP None <none> 9300/TCP 5h46m kibana-kb-http NodePort 10.96.17.95 <none> 5601:30682/TCP 30m
3.2其他配置案例说明 如果需要单独定义kibana中容器的配置可以参考下面的模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 apiVersion: kibana.k8s.elastic.co/v1 kind: Kibana metadata: name: kibana namespace: logging spec: version: 9.5 .2 image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/kibana:9.5.2 count: 2 elasticsearchRef: name: es-cluster config: server.publicBaseUrl: "https://kibana.jiugen.cn" secureSettings: - secretName: kibana-encryption-keys http: service: spec: type: ClusterIP podTemplate: spec: containers: - name: kibana env: - name: NODE_OPTIONS value: "--max-old-space-size=2048" resources: requests: memory: 2Gi cpu: "1" limits: memory: 2Gi cpu: "2" affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: common.k8s.elastic.co/type: elasticsearch topologyKey: kubernetes.io/hostname
参数
含义
如何根据实际情况配置
version
Kibana 版本
必须与 Elasticsearch 版本兼容 (最好完全一致)
image
自定义镜像
无法拉取官方镜像时必须配置,和 ES 一样
count
副本数
测试环境 1,生产环境 建议 ≥2 (高可用)
elasticsearchRef.name
关联的 ES 集群
填写你 ES 资源的 metadata.name
config.server.publicBaseUrl
对外访问地址
有域名 + Ingress 时强烈建议设置,否则部分功能(Reporting、Alerting)异常
http.service.spec.type
Service 类型
生产推荐 ClusterIP + Ingress;测试可用 NodePort 或 LoadBalancer
NODE_OPTIONS
Node.js 堆大小
内存 2Gi 时设 --max-old-space-size=1536 或 2048;内存更大可调高
resources
CPU/内存
生产起步建议 2Gi 内存。使用 Security、Reporting、Alerting 等功能时建议 ≥2Gi
affinity
调度策略
可选,避免和 ES 重负载节点在同一台机器上
3.3配置详解
config 部分的意思:
1 2 3 4 5 config: server.publicBaseUrl: "https://kibana.jiugen.com" #ingress中定义的host # xpack.security.encryptionKey: "..." # xpack.reporting.encryptionKey: "..." # xpack.encryptedSavedObjects.encryptionKey: "..."
作用:
server.publicBaseUrl: 告诉 Kibana「用户最终用浏览器访问它的完整外部地址」。 有 Ingress / 域名时强烈建议配置 ,否则会出现:
Alerting / Reporting 生成的链接错误
登录跳转地址不对
部分功能(如分享、邮件通知)链接指向内部地址
值必须是完整 URL(带 https://),且不能以 / 结尾 。
三个 encryptionKey: 用于加密保存的对象、报表、会话等敏感数据。 生产环境强烈建议配置 (推荐用 secureSettings 管理,而不是明文写在 config 里),否则重启后部分加密数据可能无法解密。
secureSettings 管理encryptionKey
参数
作用
xpack.security.encryptionKey
加密会话 cookie、登录状态等安全相关数据
xpack.reporting.encryptionKey
加密 Reporting(生成 PDF/CSV 报表)相关的数据
xpack.encryptedSavedObjects.encryptionKey
加密保存的对象(Saved Objects),比如仪表盘、可视化、告警规则等敏感配置
正确的配置方法是不要把密钥明文写在 config 里,而是用 secureSettings参数配置:
第一步:创建Secret
在Linux机器上可以执行openssl rand -base64 32指令来获取32位随机字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 cat kibana-encryption-keys.yaml apiVersion: v1 kind: Secret metadata: name: kibana-encryption-keys namespace: logging type: Opaque stringData: xpack.security.encryptionKey: "ufK5OZNdgLf0z8HPXNlPN3XcvedQn1H2sZTapo4l874=" xpack.reporting.encryptionKey: "iyQTuI8k+Fm7UptJgQqpHWPF3eEsslqu4Q80GRKSWdI=" xpack.encryptedSavedObjects.encryptionKey: "gOvjXOgthBlZE6byrFLcb/5Qioeu7Nw8ussNcbuQrW4="
第二步:在 Kibana 资源中引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 cat kibana.yaml apiVersion: kibana.k8s.elastic.co/v1 kind: Kibana metadata: name: kibana namespace: logging spec: version: 9.5 .2 config: server.publicBaseUrl: "https://kibana.jiugen.cn" secureSettings: - secretName: kibana-encryption-keys
第三步:创建Ingress
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 cat kibana-ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: kibana namespace: logging annotations: nginx.ingress.kubernetes.io/affinity: "cookie" nginx.ingress.kubernetes.io/session-cookie-name: "kibana_affinity" nginx.ingress.kubernetes.io/session-cookie-expires: "172800" nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" nginx.ingress.kubernetes.io/session-cookie-path: "/" nginx.ingress.kubernetes.io/backend-protocol: "HTTP" nginx.ingress.kubernetes.io/proxy-body-size: "50m" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" spec: ingressClassName: nginx tls: - hosts: - kibana.jiugen.cn secretName: kibana-tls-secret rules: - host: kibana.jiugen.cn http: paths: - path: / pathType: Prefix backend: service: name: kibana-kb-http port: number: 5601
部署上述资源:
1 2 3 4 5 6 7 8 # 1. 先创建加密密钥 Secret kubectl apply -f kibana-encryption-keys.yaml # 2. 部署 Kibana kubectl apply -f kibana.yaml # 3. 再部署 Ingress kubectl apply -f kibana-ingress.yaml
访问地址:https://kibana.jiugen.cn
登录账号使用 Elasticsearch 的 elastic 用户(密码可通过下面命令获取):
1 kubectl get secret es-cluster-es-elastic-user -n logging -o go-template='{{.data.elastic | base64decode}}'
注意: 如果不配置secureSettings参数,那么Operator 会自动生成密钥
1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: kibana.k8s.elastic.co/v1 kind: Kibana metadata: name: kibana namespace: logging spec: version: 9.5.2 # ... config: server.publicBaseUrl: "https://kibana.jiugen.cn" secureSettings: #在测试环境该配置可以不配置,生产环境建议手动配置,不用Operator 自动生成的 - secretName: kibana-encryption-keys #这里引用第一步中创建的名字是kibana-encryption-keys的Secret
不管是 Operator 自动生成的密钥,还是你自己创建的 secureSettings Secret,一旦密钥丢失 ,数据就无法解密。 这和「Operator 还是你手动配置」没有直接关系 ,核心是密钥的管理方式 。
自动生成密钥(不写 secureSettings)的实现方式
ECK 会自动为每个 Kibana 资源创建一个 持久的 Secret (名称通常是 kibana-{name}-kb-config)。
这个 Secret 包含三个加密密钥(xpack.security.encryptionKey、xpack.reporting.encryptionKey、xpack.encryptedSavedObjects.encryptionKey)。
Operator 会把密钥注入到每个 Pod 的 keystore 中,并持续监控这个 Secret。
日常运维 (Pod 重建、滚动更新、节点故障)完全没问题 ,因为密钥一直存在。
自己手动配置的实现方式(写 secureSettings)
你创建的 Secret 内容会被 Operator 直接注入到 Pod 的 keystore。
优点是完全由你控制 ,随时可以备份、轮转、删除旧密钥。
两种方式的唯一区别
维度
Operator 自动生成
你手动创建 Secret
密钥管理方式
Operator 自动生成并注入
你手动创建 Secret 并引用
密钥丢失风险
删除整个 Kibana 资源 + Secret 丢失
你自己删 Secret
密钥轮转
麻烦(需要修改 Operator 生成规则)
轻松(你直接改 Secret)
生产推荐
不推荐
强烈推荐
结论 : 密钥丢失 = 数据无法解密。 「自动生成」和「手动创建」本身不是问题 ,管理好密钥 才是关键。
生产环境强烈建议 手动创建 Secret(之前配置的 kibana-encryption-keys),这样密钥完全在你手里,可以定期备份、轮转、审计。
4.在 K8s 中部署 Zookeeper ZooKeeper — Kafka 协调服务
核心职责
Kafka Broker 的注册与发现
Topic 分区分配、Leader 选举
维护 Kafka 集群元数据和配置
注意 : 较新版本的 Kafka(KRaft 模式)已可去掉 ZK,但很多 ECK/Helm 部署仍使用 ZK 方案
⚠️ ZK 本身不处理日志数据,只服务于 Kafka
在 ECK(Elastic Cloud on Kubernetes)日志架构中,zookeeper 和 Kafka 不是 ECK 本身的组件 ,而是作为日志缓冲层 插入在”日志采集端”和”Elasticsearch 存储端”之间的。
Zookeeper 和 Kafka 并不属于 ECK 所管理的资源,Kafka/ZooKeeper 是整个日志采集架构中的中间消息系统,而 ECK 只负责管理 Elasticsearch/Kibana 等 Elastic 资源。所以使用 Helm 进行安装Zookeeper和kafka服务:
在安装部署zk和kafka之前先了解两个事件:
第一,Bitnami 于 2025-08-28 调整了公共镜像目录 。所有带版本号的旧镜像(如 bitnami/kafka:3.9.0-debian-12-r12)被迁移到 docker.io/bitnamilegacy,docker.io/bitnami 只保留极少数 latest 标签的硬化镜像,公共仓库的删除后来推迟到 9 月底并做了多次 brownout。结果就是:老 chart 直接装会 ImagePullBackOff,必须手动把镜像仓库指向 bitnamilegacy,并加上 global.security.allowInsecureImages=true。
第二,Kafka 4.0 彻底移除了 ZooKeeper 。Bitnami Kafka chart 从 32.0.0 起(appVersion 4.0.0,当前 32.4.4)默认且只支持 KRaft 模式,zookeeper 已不再是 chart 依赖,所有 zookeeper.* / kraft.* 参数被删除。也就是说,该笔记中”先装 ZooKeeper 集群、再装 Kafka 集群连上去”这个架构,只能用 kafka chart ≤ 31.5.0 (appVersion 3.9.0)才能复现。
此笔记采用旧版 ZooKeeper + Kafka 3.9的组合方式。
Bitnami 采用的是单体仓库(monorepo) 模式:
仓库地址:https://github.com/bitnami/charts.git
所有 chart 都放在同一个仓库的 bitnami/ 目录下。
对应关系:
ZooKeeper chart → bitnami/zookeeper/
Kafka chart → bitnami/kafka/
还有大量其他服务(redis、postgresql、mysql、elasticsearch 等)也都在同一个仓库里。
4.1准备工作-检查环境 确认环境满足 chart 要求:Kubernetes 1.23+、Helm 3.8.0+(OCI 支持需要 3.8)、集群里有可用的 StorageClass(Kafka 和 ZooKeeper 都是 StatefulSet,需要动态 PV,否则 Pod 会一直卡在 Pending 或 ContainerCreating)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # k8s版本大于1.23+ [root@k8s-master01 ~]# kubectl version Client Version: v1.31.4 Kustomize Version: v5.4.2 Server Version: v1.31.4 # helm版本大于3.8.0 [root@k8s-master01 ~]# helm version version.BuildInfo{Version:"v4.0.4", GitCommit:"8650e1dad9e6ae38b41f60b712af9218a0d8cc11", GitTreeState:"clean", GoVersion:"go1.25.5", KubeClientVersion:"v1.34"} # 集群中有共享存储,这里用的cubefs [root@k8s-master01 ~]# kubectl get sc NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE cfs-sc (default) csi.cubefs.com Delete Immediate true 242d nfs-csi nfs.csi.k8s.io Delete Immediate true 256d # 命名空间 [root@k8s-master01 ~]# kubectl get ns|grep logging logging Active 2d23h
4.2获取安装包 从 GitHub 源码获取(最稳,Apache-2.0 授权,官方承诺持续可用)
Bitnami 明确说明 chart 源码继续在 GitHub 维护开放。
1 2 3 4 5 git clone https://github.com/bitnami/charts.git cd charts # 用 kafka/31.5.0 这个 tag(当时仓库里的 zookeeper 也是兼容版本) git checkout kafka/31.5.0
如果在拉取github仓库时由于网络的问题无法拉取代码时,通过下面命令设置网络代理:
1 2 3 4 5 6 7 # 查看当前代理设置 git config --global --get http.proxy git config --global --get https.proxy # 如果需要设置代理 (根据自己的实际代理地址修改),192.168.0.4是我自己的电脑ip,7897是我电脑上代理软件的端口 git config --global http.proxy http://192.168.0.4:7897 git config --global https.proxy http://192.168.0.4:7897
4.3安装zookeeper 修改values.yaml文件:
1 2 3 4 5 6 7 8 9 10 11 12 # 进入zk的文件目录 [root@k8s-master01 charts]# cd bitnami/zookeeper/ [root@k8s-master01 zookeeper]# ll total 244 -rw-r--r-- 1 root root 107465 Aug 26 21:13 CHANGELOG.md -rw-r--r-- 1 root root 226 Aug 26 21:13 Chart.lock drwxr-xr-x 2 root root 31 Aug 26 23:13 charts -rw-r--r-- 1 root root 970 Aug 26 21:13 Chart.yaml -rw-r--r-- 1 root root 79952 Aug 26 21:13 README.md drwxr-xr-x 2 root root 4096 Aug 26 21:13 templates -rw-r--r-- 1 root root 44164 Aug 26 22:56 values.yaml
按照下面配置对values.yaml文件进行修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 global: security: allowInsecureImages: true image: registry: registry.cn-beijing.aliyuncs.com repository: k8s-liujunwei/zookeeper tag: 3.9 .3 -debian-12-r8 pullPolicy: IfNotPresent replicaCount: 3 heapSize: 512 resources: requests: cpu: 250m memory: 1Gi limits: cpu: "1" memory: 2Gi podAntiAffinityPreset: soft persistence: enabled: true storageClass: "cfs-sc" accessModes: - ReadWriteOnce size: 20Gi auth: client: enabled: false quorum: enabled: false volumePermissions: enabled: false image: registry: registry.cn-beijing.aliyuncs.com repository: k8s-liujunwei/os-shell tag: 12 -debian-12-r39 networkPolicy: enabled: false allowExternal: true metrics: enabled: false serviceMonitor: enabled: false podSecurityContext: enabled: true fsGroup: 1001 containerSecurityContext: enabled: true runAsUser: 1001 runAsGroup: 1001 runAsNonRoot: true readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: ["ALL" ] pdb: create: true maxUnavailable: 1 logLevel: ERROR autopurge: snapRetainCount: 10 purgeInterval: 1 fourlwCommandsWhitelist: srvr,mntr,ruok
从https://github.com/bitnami/charts.git下载的源码中是没有chart依赖的,在部署前需要先下载依赖
1 2 3 4 5 6 7 8 # 查看当前 chart 声明了哪些依赖(主要是 common 库 chart) helm dependency list # 把 Chart.yaml 里声明的依赖(尤其是 common)下载到 charts/ 目录。本地从 GitHub 克隆后,依赖一般不会预先打包好,不执行这一步,helm install 很可能会失败(找不到 common 模板)。 helm dependency build # 强烈建议语法检查,能提前发现 values 写错、模板问题等,但不是强制的。 helm lint .
网络原因导致依赖无法下载解决方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # 如果执行 helm dependency build 遇到以下报错时,依然是网络原因导致的,还是通过设置代理解决 Downloading common from repo oci://registry-1.docker.io/bitnamicharts ... dial tcp 67.230.169.182:443: connect: connection refused # 1. 设置代理(当前 shell 有效),代理软件上要打开允许局域网连接,参考4.2中的图 [root@k8s-master01 zookeeper]# export HTTPS_PROXY=http://192.168.0.4:7897 [root@k8s-master01 zookeeper]# export HTTP_PROXY=http://192.168.0.4:7897 [root@k8s-master01 zookeeper]# export NO_PROXY=localhost,127.0.0.1,192.168.0.0/16,.svc,.cluster.local # 2. 可选:先测一下能否访问 Docker Hub [root@k8s-master01 zookeeper]# curl -I --connect-timeout 10 https://registry-1.docker.io/v2/ HTTP/1.1 200 Connection established HTTP/2 401 date: Thu, 27 Aug 2026 08:38:58 GMT content-type: application/json content-length: 87 docker-distribution-api-version: registry/2.0 www-authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io" strict-transport-security: max-age=31536000
网络问题解决后在以此执行依赖安装和部署zk:
1 2 3 4 5 6 7 8 # 安装chart的依赖 helm dependency build # 语法检查 helm lint . # 安装zk,注意所在目录charts/bitnami/zookeeper,在values.yaml所在的目录中执行 [root@k8s-master01 zookeeper]# helm install zookeeper . -n logging
检查zk服务的pod部署状态:
1 2 3 4 5 6 # zk的服务已经成功运行 [root@k8s-master01 zookeeper]# kubectl get po -n logging NAME READY STATUS RESTARTS AGE zookeeper-0 1/1 Running 0 18h zookeeper-1 1/1 Running 0 18h zookeeper-2 1/1 Running 0 18h
创建后会产生哪些资源:chart 会创建一个 StatefulSet(zookeeper-0/1/2 顺序启动)、一个 headless Service(zookeeper-headless,供节点间用稳定 DNS 互相发现,即 zookeeper-0.zookeeper-headless.logging.svc.cluster.local:2888/3888)、一个普通 ClusterIP Service(zookeeper,客户端连 2181 用)、三个 PVC,以及一个存放配置的 ConfigMap。每个 Pod 启动时会根据自己的序号写入 myid 文件,这就是为什么必须用 StatefulSet 而不是 Deployment。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [root@k8s-master01 zookeeper]# kubectl get all -n logging NAME READY STATUS RESTARTS AGE pod/zookeeper-0 1/1 Running 0 21h pod/zookeeper-1 1/1 Running 0 21h pod/zookeeper-2 1/1 Running 0 21h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/zookeeper ClusterIP 10.96.62.2 <none> 2181/TCP,2888/TCP,3888/TCP 21h service/zookeeper-headless ClusterIP None <none> 2181/TCP,2888/TCP,3888/TCP 21h NAME READY AGE statefulset.apps/zookeeper 3/3 21h [root@k8s-master01 zookeeper]# kubectl get pvc -n logging NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE data-zookeeper-0 Bound pvc-ba10584f-eecc-4f3a-8a57-adf6956a6f7d 10Gi RWO cfs-sc <unset> 21h data-zookeeper-1 Bound pvc-b03d8e93-d92b-439e-8427-d14c10bb576f 10Gi RWO cfs-sc <unset> 21h data-zookeeper-2 Bound pvc-c248e352-e319-4f2d-8b10-1912c95c830b 10Gi RWO cfs-sc <unset> 21h [root@k8s-master01 zookeeper]# kubectl get cm -n logging NAME DATA AGE zookeeper-scripts 2 21h
验证集群:批量检查 ZooKeeper 集群中每个节点的角色状态 (Leader / Follower / Standalone)。
1 2 3 4 [root@k8s-master01 zookeeper]# for i in 0 1 2; do echo -n "zookeeper-$i: "; kubectl exec -n logging zookeeper-$i -- bash -c 'ZOO_LOG_DIR=/tmp zkServer.sh status 2>/dev/null | grep Mode'; done zookeeper-0: Mode: follower zookeeper-1: Mode: follower zookeeper-2: Mode: leader
一个健康的 3 节点 ZK 集群应该恰好有 1 个 leader + 2 个 follower
如果某个节点没有输出或显示 Error,说明该节点异常或未就绪
如果所有节点都是 standalone,说明集群未成功组网 ,各节点独立运行
2>/dev/null 很重要,因为 zkServer.sh status 在容器环境中经常输出大量无关日志,不加这个会导致输出混乱
5.在k8s中部署kafka Kafka — 消息缓冲队列
核心职责
削峰填谷 : 当日志量突增时,Kafka 缓冲数据,防止下游 ES/Logstash 被压垮
解耦 : Filebeat 和 Logstash 不需要直接感知对方
持久化 : 即使 Logstash 短暂宕机,日志也不会丢失
多消费者支持 : 同一份日志可被多个消费组消费(如同时用于日志分析和安全审计)
为什么需要它 : 生产环境中日志量波动大,没有 Kafka 的话 ES 写入容易出现 bulk reject
如果日志量较小(<50GB/天),也可以不使用kafka。
Kafka 用 chart ≤ 31.5.0(支持 ZK);
修改values.yaml文件:
1 2 3 4 5 6 7 8 9 10 11 12 # 进入kafka的文件目录 [root@k8s-master01 charts]# cd bitnami/kafka/ [root@k8s-master01 kafka]# ll total 564 -rw-r--r-- 1 root root 179294 Aug 26 21:13 CHANGELOG.md -rw-r--r-- 1 root root 316 Aug 26 21:13 Chart.lock drwxr-xr-x 2 root root 59 Aug 28 00:08 charts -rw-r--r-- 1 root root 1355 Aug 26 21:13 Chart.yaml -rw-r--r-- 1 root root 239104 Aug 26 21:13 README.md drwxr-xr-x 7 root root 4096 Aug 26 21:13 templates -rw-r--r-- 1 root root 123686 Aug 28 00:00 values.yaml
按照下面配置对values.yaml文件进行修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 global: security: allowInsecureImages: true image: registry: registry.cn-beijing.aliyuncs.com repository: k8s-liujunwei/kafka tag: 3.9 .0 -debian-12-r12 pullPolicy: IfNotPresent kraft: enabled: false zookeeper: enabled: false externalZookeeper: servers: - zookeeper.logging.svc.cluster.local:2181 controller: replicaCount: 0 broker: replicaCount: 3 podAntiAffinityPreset: soft heapOpts: "-Xmx2048m -Xms2048m" resources: requests: cpu: 500m memory: 2Gi limits: cpu: "2" memory: 4Gi persistence: enabled: true storageClass: "cfs-sc" size: 20Gi pdb: create: true maxUnavailable: 1 listeners: client: protocol: PLAINTEXT interbroker: protocol: PLAINTEXT extraConfig: | default.replication.factor=3 offsets.topic.replication.factor=3 transaction.state.log.replication.factor=3 min.insync.replicas=2 auto.create.topics.enable=true log.retention.hours=168 volumePermissions: enabled: false image: registry: registry.cn-beijing.aliyuncs.com repository: k8s-liujunwei/os-shell tag: 12 -debian-12-r39
从https://github.com/bitnami/charts.git下载的源码中是没有chart依赖的,在部署前需要先下载依赖
1 2 3 4 5 6 7 8 # 查看当前 chart 声明了哪些依赖(主要是 common 库 chart) helm dependency list # 把 Chart.yaml 里声明的依赖(尤其是 common)下载到 charts/ 目录。本地从 GitHub 克隆后,依赖一般不会预先打包好,不执行这一步,helm install 很可能会失败(找不到 common 模板)。 helm dependency build # 强烈建议语法检查,能提前发现 values 写错、模板问题等,但不是强制的。 helm lint .
网络原因导致依赖无法下载解决方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # 如果执行 helm dependency build 遇到以下报错时,依然是网络原因导致的,还是通过设置代理解决 Downloading common from repo oci://registry-1.docker.io/bitnamicharts ... dial tcp 67.230.169.182:443: connect: connection refused # 1. 设置代理(当前 shell 有效),代理软件上要打开允许局域网连接,参考4.2中的图 [root@k8s-master01 zookeeper]# export HTTPS_PROXY=http://192.168.0.4:7897 [root@k8s-master01 zookeeper]# export HTTP_PROXY=http://192.168.0.4:7897 [root@k8s-master01 zookeeper]# export NO_PROXY=localhost,127.0.0.1,192.168.0.0/16,.svc,.cluster.local # 2. 可选:先测一下能否访问 Docker Hub [root@k8s-master01 zookeeper]# curl -I --connect-timeout 10 https://registry-1.docker.io/v2/ HTTP/1.1 200 Connection established HTTP/2 401 date: Thu, 27 Aug 2026 08:38:58 GMT content-type: application/json content-length: 87 docker-distribution-api-version: registry/2.0 www-authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io" strict-transport-security: max-age=31536000
网络问题解决后在以此执行依赖安装和部署zk:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 # 安装chart的依赖 helm dependency build # 成功的信息如下 [root@k8s-master01 kafka]# helm dependency build Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "aliyun" chart repository ...Successfully got an update from the "bitnami" chart repository Update Complete. ⎈Happy Helming!⎈ Saving 2 charts Downloading zookeeper from repo oci://registry-1.docker.io/bitnamicharts Pulled: registry-1.docker.io/bitnamicharts/zookeeper:13.7.4 Digest: sha256:7b6aef19b1af10de823c3c0ca2ff0465fcc5db5c5e2c15b2ca1a207783688f99 Downloading common from repo oci://registry-1.docker.io/bitnamicharts Pulled: registry-1.docker.io/bitnamicharts/common:2.30.0 Digest: sha256:b5c0e27c5404be46ccffdc6e1ce3d5d5e86ef5e5d372308f3f0afeaa3f34a5f7 Deleting outdated charts # 语法检查 helm lint . # 检查语法,0个失败 [root@k8s-master01 kafka]# helm lint . ==> Linting . 1 chart(s) linted, 0 chart(s) failed # 安装kafka,注意所在目录charts/bitnami/kafka,在values.yaml所在的目录中执行 [root@k8s-master01 kafka]# helm install kafka . -n logging NAME: kafka LAST DEPLOYED: Sat Sep 5 20:29:36 2026 NAMESPACE: logging STATUS: deployed REVISION: 1 DESCRIPTION: Install complete TEST SUITE: None NOTES: CHART NAME: kafka CHART VERSION: 31.5.0 APP VERSION: 3.9.0 Did you know there are enterprise versions of the Bitnami catalog? For enhanced secure software supply chain features, unlimited pulls from Docker, LTS support, or application customization, see Bitnami Premium or Tanzu Application Catalog. See https://www.arrow.com/globalecs/na/vendors/bitnami for more information. ** Please be patient while the chart is being deployed ** Kafka can be accessed by consumers via port 9092 on the following DNS name from within your cluster: kafka.logging.svc.cluster.local Each Kafka broker can be accessed by producers via port 9092 on the following DNS name(s) from within your cluster: kafka-broker-0.kafka-broker-headless.logging.svc.cluster.local:9092 kafka-broker-1.kafka-broker-headless.logging.svc.cluster.local:9092 kafka-broker-2.kafka-broker-headless.logging.svc.cluster.local:9092 The CLIENT listener for Kafka client connections from within your cluster have been configured with the following security settings: - SASL authentication To connect a client to your Kafka, you need to create the 'client.properties' configuration files with the content below: security.protocol=SASL_PLAINTEXT sasl.mechanism=SCRAM-SHA-256 sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required \ username="user1" \ password="$(kubectl get secret kafka-user-passwords --namespace logging -o jsonpath='{.data.client-passwords}' | base64 -d | cut -d , -f 1)"; To create a pod that you can use as a Kafka client run the following commands: kubectl run kafka-client --restart='Never' --image registry.cn-beijing.aliyuncs.com/k8s-liujunwei/kafka:3.9.0-debian-12-r12 --namespace logging --command -- sleep infinity kubectl cp --namespace logging /path/to/client.properties kafka-client:/tmp/client.properties kubectl exec --tty -i kafka-client --namespace logging -- bash PRODUCER: kafka-console-producer.sh \ --producer.config /tmp/client.properties \ --bootstrap-server kafka.logging.svc.cluster.local:9092 \ --topic test CONSUMER: kafka-console-consumer.sh \ --consumer.config /tmp/client.properties \ --bootstrap-server kafka.logging.svc.cluster.local:9092 \ --topic test \ --from-beginning WARNING: There are "resources" sections in the chart not set. Using "resourcesPreset" is not recommended for production. For production installations, please set the following values according to your workload needs: - broker.resources +info https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ ⚠ SECURITY WARNING: Original containers have been substituted. This Helm chart was designed, tested, and validated on multiple platforms using a specific set of Bitnami and Tanzu Application Catalog containers. Substituting other containers is likely to cause degraded security and performance, broken chart features, and missing environment variables. Substituted images detected: - registry.cn-beijing.aliyuncs.com/k8s-liujunwei/kafka:3.9.0-debian-12-r12 - registry.cn-beijing.aliyuncs.com/k8s-liujunwei/kubectl:1.32.2-debian-12-r3 - registry.cn-beijing.aliyuncs.com/k8s-liujunwei/os-shell:12-debian-12-r39 - registry.cn-beijing.aliyuncs.com/k8s-liujunwei/jmx-exporter:1.1.0-debian-12-r7 ⚠ SECURITY WARNING: Verifying original container images was skipped. Please note this Helm chart was designed, tested, and validated on multiple platforms using a specific set of Bitnami and Tanzu Application Catalog containers. Substituting other containers is likely to cause degraded security and performance, broken chart features, and missingenvironment variables.
6.在k8s中部署Logstash集群 Logstash — 日志处理器(Processor)
核心职责
从 Kafka 消费 日志数据
解析与转换 : Grok 正则提取字段、JSON 解析、时间格式化
过滤与富化 : 删除敏感字段、GeoIP 查询、关联 CMDB 信息
路由 : 根据条件将不同日志发送到不同的 ES Index
批量写入 Elasticsearch
vs Filebeat : Filebeat 只做简单采集,Logstash 做重型 ETL 处理
6.1部署前检查工作 确认ES是green状态,kafka都是READY,以及有Logstash CRD和存储storageclasses
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # es集群式green状态 [root@k8s-master01 kafka]# kubectl get elasticsearch es-cluster -n logging NAME HEALTH NODES VERSION PHASE AGE es-cluster green 3 9.5.2 Ready 4d8h # kafka|zookeeper|es-cluster 的pod都是READY [root@k8s-master01 kafka]# kubectl get po -n logging NAME READY STATUS RESTARTS AGE es-cluster-es-default-0 1/1 Running 0 4d8h es-cluster-es-default-1 1/1 Running 0 4d8h es-cluster-es-default-2 1/1 Running 0 4d8h kafka-broker-0 1/1 Running 0 46h kafka-broker-1 1/1 Running 0 46h kafka-broker-2 1/1 Running 0 46h kibana-kb-b889dbf5f-8vx2n 1/1 Running 0 4d3h kibana-kb-b889dbf5f-vw8d6 1/1 Running 0 4d3h zookeeper-0 1/1 Running 0 2d23h zookeeper-1 1/1 Running 0 2d23h zookeeper-2 1/1 Running 0 2d23h # 存储 [root@k8s-master01 kafka]# kubectl get sc NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE cfs-sc (default) csi.cubefs.com Delete Immediate true 244d nfs-csi nfs.csi.k8s.io Delete Immediate true 259d # Logstash的CRD也有 [root@k8s-master01 kafka]# kubectl get crd logstashes.logstash.k8s.elastic.co NAME CREATED AT logstashes.logstash.k8s.elastic.co 2026-08-24T07:38:30Z
6.2取出 Kafka 密码并用 Secret保存 在创建好kafka服务时会给信息提示密码保存的位置,在 logging命名空间中名字时kafka-user-passwords 的secret中:
1 2 username="user1" \ password="$(kubectl get secret kafka-user-passwords --namespace logging -o jsonpath='{.data.client-passwords}' | base64 -d | cut -d , -f 1)";
获取密码并解密,两条命令都可以(常见 key:client-passwords)
1 2 3 4 5 6 [root@k8s-master01 kafka]# password="$(kubectl get secret kafka-user-passwords --namespace logging -o jsonpath='{.data.client-passwords}' | base64 -d | cut -d , -f 1)" [root@k8s-master01 kafka]# echo $password pCdVrGJ1kq [root@k8s-master01 kafka]# kubectl get secrets -n logging kafka-user-passwords -o jsonpath='{.data.client-passwords}' | base64 -d ; echo pCdVrGJ1kq
创建给 Logstash 用的 Secret(把密码换成自己查到的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 可以通过yaml文件创建,也可以通过一条命令创建,二选一即可 # yaml文件配置如下: apiVersion: v1 data: kafka-password: Yzk4dm9BdVFOSA== kafka-username: dXNlcjE= kind: Secret metadata: creationTimestamp: null name: logstash-credentials namespace: logging # 一条命令也能创建 [root@k8s-master01 kafka]# kubectl create secret generic logstash-credentials -n logging --from-literal=kafka-username=user1 --from-literal=kafka-password='pCdVrGJ1kq' --dry-run=client -o yaml | kubectl apply -f - secret/logstash-credentials created
ES 的 elastic 密码不要抄进 YAML,直接引用已有 Secret:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 [root@k8s-master01 kafka]# kubectl get secrets -n logging es-cluster-es-elastic-user -oyaml apiVersion: v1 data: elastic: cW4zekFYQm1wa1JHSE5zTDczVjhoR2p2 kind: Secret metadata: creationTimestamp: "2026-08-25T06:19:27Z" labels: common.k8s.elastic.co/type: elasticsearch eck.k8s.elastic.co/credentials: "true" eck.k8s.elastic.co/owner-kind: Elasticsearch eck.k8s.elastic.co/owner-name: es-cluster eck.k8s.elastic.co/owner-namespace: logging eck.k8s.elastic.co/watched: "true" elasticsearch.k8s.elastic.co/cluster-name: es-cluster name: es-cluster-es-elastic-user namespace: logging resourceVersion: "88015959" uid: 0270776a-2384-49a9-98e1-751048f715c8 type: Opaque
6.3提前创建Topic 建议自己提前创建Topic,也可以不提前创建,kafka会自动创建
启动一个临时的pod手动创建一个Topic
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 # 启动临时pod [root@k8s-master01 kafka]# kubectl run kafka-client -n logging --rm -it --restart=Never \ --image registry.cn-beijing.aliyuncs.com/k8s-liujunwei/kafka:3.9.0-debian-12-r12 \ -- bash If you don't see a command prompt, try pressing enter. I have no name!@kafka-client:/$ BS=kafka.logging.svc.cluster.local:9092 I have no name!@kafka-client:/$ cat > /tmp/client.properties << 'EOF' security.protocol=SASL_PLAINTEXT sasl.mechanism=PLAIN sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="user1" password="pCdVrGJ1kq"; EOF -rw-r--r-- 1 1001 root 176 Aug 29 15:44 /tmp/client.properties I have no name!@kafka-client:/$ cat /tmp/client.properties security.protocol=SASL_PLAINTEXT sasl.mechanism=PLAIN sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="user1" password="pCdVrGJ1kq"; I have no name!@kafka-client:/$ kafka-topics.sh --bootstrap-server $BS \ --command-config /tmp/client.properties \ --create --topic k8spodlogs \ --partitions 3 \ --replication-factor 3 \ --if-not-exists Picked up JAVA_TOOL_OPTIONS: Created topic k8spodlogs. # 查看创建的Topic I have no name!@kafka-client:/$ kafka-topics.sh --bootstrap-server $BS \ --command-config /tmp/client.properties \ --describe --topic k8spodlogs Picked up JAVA_TOOL_OPTIONS: Topic: k8spodlogs TopicId: _wjfR3laTJCWZ9CtITWk9A PartitionCount: 3 ReplicationFactor: 3 Configs: min.insync.replicas=2 Topic: k8spodlogs Partition: 0 Leader: 102 Replicas: 102,100,101 Isr: 102,100,101 Elr: N/A LastKnownElr: N/A Topic: k8spodlogs Partition: 1 Leader: 101 Replicas: 101,102,100 Isr: 101,102,100 Elr: N/A LastKnownElr: N/A Topic: k8spodlogs Partition: 2 Leader: 100 Replicas: 100,101,102 Isr: 100,101,102 Elr: N/A LastKnownElr: N/A
6.4准备Logstash镜像 可能由于网络的原因无法拉取ECK 拉官方镜像,我已经提前同步到我的仓库中,Logstash版本要和 ES 对齐 9.5.2
6.5准备Logstash资源文件 创建 Logstash.yaml。
说明:ECK 3.5 对字段名可能是 elasticsearchRef 或 elasticsearchRefs。若 apply 报 unknown field,执行 kubectl explain logstash.spec | grep -i elastic 按实际字段改「关联 ES」那一段即可,其余不变。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 [root@k8s-master01 kafka ] apiVersion: logstash.k8s.elastic.co/v1alpha1 kind: Logstash metadata: name: logstash namespace: logging spec: version: 9.5 .2 image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/logstash:9.5.2 count: 3 elasticsearchRefs: - name: es-cluster clusterName: es-cluster namespace: logging pipelines: - pipeline.id: main config.string: | input { kafka { # Kafka 集群初始连接地址(host:port)。客户端通过它发现整个集群的 broker 列表。 # 生产环境优先使用 K8s 内部 DNS(如 kafka.logging.svc.cluster.local:9092)。 bootstrap_servers => "kafka.logging.svc.cluster.local:9092" # 要消费的 Kafka 主题列表。支持多个主题,用数组表示。 # 按业务拆分主题可提升隔离性与扩展性。 topics => ["k8spodlogs"] # 指定消费的 Kafka topic group_id => "logstash-logging-prod" # 消费者组名,用于分摊分区,自定义一个名字即可 codec => json #消息解码方式 consumer_threads => 1 enable_auto_commit => true auto_commit_interval_ms => "1000" auto_offset_reset => "earliest" security_protocol => "SASL_PLAINTEXT" sasl_mechanism => "SCRAM-SHA-256" sasl_jaas_config => 'org.apache.kafka.common.security.scram.ScramLoginModule required username="${KAFKA_USERNAME}" password="${KAFKA_PASSWORD}";' } } output { elasticsearch { hosts => ["https://es-cluster-es-http:9200" ] index => "k8spodlogs-%{+YYYY.MM.dd} " user => "${ELASTICSEARCH_USERNAME}" password => "${ELASTICSEARCH_PASSWORD}" ssl_enabled => true ssl_certificate_authorities => "${ES_CLUSTER_ES_SSL_CERTIFICATE_AUTHORITY}" } } podTemplate: spec: containers: - name: logstash resources: requests: cpu: "500m" memory: "1Gi" limits: cpu: "1" memory: "2Gi" env: - name: KAFKA_USERNAME valueFrom: secretKeyRef: name: logstash-credentials key: kafka-username - name: KAFKA_PASSWORD valueFrom: secretKeyRef: name: logstash-credentials key: kafka-password - name: ELASTICSEARCH_USERNAME value: "elastic" - name: ELASTICSEARCH_PASSWORD valueFrom: secretKeyRef: name: es-cluster-es-elastic-user key: elastic volumeClaimTemplates: - metadata: name: logstash-data spec: accessModes: - ReadWriteOnce storageClassName: cfs-sc resources: requests: storage: 20Gi
创建logstash资源:
1 2 [root@k8s-master01 29-eck]# kubectl create -f Logstash.yaml logstash.logstash.k8s.elastic.co/logstash created
查看服务创建情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 [root@k8s-master01 29-eck]# kubectl get logstashes.logstash.k8s.elastic.co -n logging NAME HEALTH AVAILABLE EXPECTED AGE VERSION logstash red 3 3m57s 9.5.2 [root@k8s-master01 29-eck]# kubectl get po -n logging |grep log logstash-ls-0 0/1 Init:0/1 0 92s logstash-ls-1 0/1 Init:0/1 0 92s logstash-ls-2 0/1 Init:0/1 0 92s # 过了大概4分钟左右服务正常启动 [root@k8s-master01 29-eck]# kubectl get logstashes.logstash.k8s.elastic.co -n logging NAME HEALTH AVAILABLE EXPECTED AGE VERSION logstash green 3 3 4m29s 9.5.2 [root@k8s-master01 29-eck]# kubectl get po -n logging |grep log logstash-ls-0 1/1 Running 0 4m35s logstash-ls-1 1/1 Running 0 4m35s logstash-ls-2 1/1 Running 0 4m35s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 4.NetworkPolicy是什么意思?我不明白 10.按照你的建议来 11.索引命名规范你自己决定 12.我没有配置ILM 14.协议是SASL_PLAINTEXT 15.用户名密码写到secret 16.日志 topic 正式名称必须要提前创建吗?我没创建过 17.分区数和副本数是什么意思?有什么用?必须配置吗? 我没有事先配置过 18.消费组命名规范你自己决定,符合生产即可 22.持久化 queue(防重启丢数据)是什么意思?生产建议开启那就配置开启 26.你看着配置 27.PDB是什么?按照你建议的配置 30.日志应该是从Filebeat来,因为课程的文档后面还会部署Filebeat 31到34按照你的建议来即可,但是最好要符合生产的要求 我之前没接触过这块的只是,还希望你详细的讲解每一个步骤,并解释其原因和过程
7.在k8s中部署Filebeat收集日志 Filebeat — 日志采集器(Shipper)
部署方式 : DaemonSet(每个节点一个 Pod)
核心职责
监控 /var/log/containers/*.log(即你之前问的那个目录)
读取容器日志,添加 K8s 元数据(Pod名、Namespace、Node、Labels等)
将日志轻量级转发 到 Kafka
特点 : 资源占用极低,不做复杂处理,只做”搬运工”
Filebeat 使用的镜像版本必须与 Elasticsearch 版本一致。
7.1准备ServiceAccount和RBAC Filebeat 需要提前准备 ServiceAccount (SA) 和 RBAC,因为它作为 DaemonSet 运行在每个节点上,需要访问 Kubernetes API Server 来获取 Pod/容器的元数据信息。
Filebeat 采集的是 /var/log/containers/*.log 中的原始日志,但这些日志文件本身不包含 K8s 上下文信息 。为了让日志可查询、可过滤,Filebeat 需要通过 K8s API 自动为每条日志补充元数据 ,所以就需要相应的RBAC。
创建sa以及rbac资源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 [root@k8s-master01 29 -eck ] apiVersion: v1 kind: ServiceAccount metadata: name: filebeat namespace: logging labels: app: filebeat k8s-app: filebeat --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: filebeat labels: app: filebeat rules: - apiGroups: ["" ] resources: - namespaces - pods - nodes - nodes/metrics - nodes/stats - nodes/proxy - nodes/spec - nodes/logs verbs: ["get" , "list" , "watch" ] - apiGroups: ["apps" ] resources: - replicasets - deployments - statefulsets - daemonsets verbs: ["get" , "list" , "watch" ] - apiGroups: ["batch" ] resources: - jobs - cronjobs verbs: ["get" , "list" , "watch" ] - apiGroups: ["" ] resources: ["events" ] verbs: ["get" , "list" , "watch" ] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: filebeat labels: app: filebeat roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: filebeat subjects: - kind: ServiceAccount name: filebeat namespace: logging
创建上述资源:
1 2 3 4 [root@k8s-master01 29-eck]# kubectl create -f Filebeat-sa-rbac.yaml serviceaccount/filebeat created clusterrole.rbac.authorization.k8s.io/filebeat created clusterrolebinding.rbac.authorization.k8s.io/filebeat created
7.2准备Filebeat资源部署清单 准备filebeat资源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 [root@k8s-master01 29 -eck ] apiVersion: beat.k8s.elastic.co/v1beta1 kind: Beat metadata: name: filebeat namespace: logging labels: app: filebeat spec: type: filebeat version: "9.5.2" image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/filebeat:9.5.2 config: name: "filebeat-${NODE_NAME}" logging.level: info logging.to_stderr: true logging.metrics.enabled: false filebeat.autodiscover: providers: - type: kubernetes node: ${NODE_NAME} hints.enabled: true hints.default_config: type: filestream id: "kubernetes-container-${data.kubernetes.container.id}" paths: - /var/log/containers/*${data.kubernetes.container.id}.log parsers: - container: stream: all format: auto prospector.scanner: fingerprint.enabled: true symlinks: true file_identity.fingerprint: {} close.on_state_change.removed: false ignore_older: 72h close.on_state_change.inactive: 5m clean_inactive: 96h fields: log_topic: k8spodlogs cluster: production fields_under_root: false processors: - add_host_metadata: when.not.contains.tags: forwarded netinfo.enabled: true - drop_event: when: equals: kubernetes.container.name: "filebeat" output.kafka: hosts: - "kafka.logging.svc.cluster.local:9092" topic: "k8spodlogs" required_acks: 1 compression: gzip max_message_bytes: 1000000 username: "user1" password: "${KAFKA_PASSWORD}" sasl.mechanism: "SCRAM-SHA-256" queue.mem: events: 4096 flush.min_events: 512 flush.timeout: 5s http.enabled: true http.host: localhost http.port: 5066 daemonSet: updateStrategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 podTemplate: metadata: labels: app: filebeat k8s-app: filebeat annotations: co.elastic.logs/enabled: "false" spec: serviceAccountName: filebeat automountServiceAccountToken: true hostNetwork: true dnsPolicy: ClusterFirstWithHostNet securityContext: runAsUser: 0 terminationGracePeriodSeconds: 30 containers: - name: filebeat resources: requests: cpu: 100m memory: 200Mi limits: cpu: 1000m memory: 1Gi env: - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName - name: KAFKA_PASSWORD valueFrom: secretKeyRef: name: kafka-user-passwords key: client-passwords volumeMounts: - name: varlogcontainers mountPath: /var/log/containers - name: varlogpods mountPath: /var/log/pods - name: varlibdockercontainers mountPath: /var/lib/docker/containers - name: data mountPath: /usr/share/filebeat/data volumes: - name: varlogcontainers hostPath: path: /var/log/containers - name: varlogpods hostPath: path: /var/log/pods - name: varlibdockercontainers hostPath: path: /var/lib/docker/containers - name: data hostPath: path: /var/lib/filebeat-data type: DirectoryOrCreate
创建filebeat:
1 2 [root@k8s-master01 29-eck]# kubectl create -f Filebeat.yaml beat.beat.k8s.elastic.co/filebeat created
查看资源:
1 2 3 4 5 6 7 8 # 每个节点上都运行了一个filebeat服务 [root@k8s-master01 29-eck]# kubectl get po -n logging -owide|grep filebeat-beat filebeat-beat-filebeat-26qsh 1/1 Running 0 24m 192.168.0.85 k8s-node02 <none> <none> filebeat-beat-filebeat-9c8nj 1/1 Running 0 24m 192.168.0.84 k8s-node01 <none> <none> filebeat-beat-filebeat-kxp28 1/1 Running 0 24m 192.168.0.83 k8s-master03 <none> <none> filebeat-beat-filebeat-mrhcm 1/1 Running 0 24m 192.168.0.86 k8s-node03 <none> <none> filebeat-beat-filebeat-rbw5x 1/1 Running 0 24m 192.168.0.81 k8s-master01 <none> <none> filebeat-beat-filebeat-smgfm 1/1 Running 0 24m 192.168.0.82 k8s-master02 <none> <none>
8.在kibana中查询日志 8.1通过web访问kibana 1 2 3 4 5 6 7 8 9 10 11 12 13 # kibana-kb-http 是web端访问的SVC [root@k8s-master01 29-eck]# kubectl get svc -n logging NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE es-cluster-es-default ClusterIP None <none> 9200/TCP 7d5h es-cluster-es-http ClusterIP 10.96.244.191 <none> 9200/TCP 7d3h es-cluster-es-internal-http ClusterIP 10.96.42.43 <none> 9200/TCP 7d5h es-cluster-es-transport ClusterIP None <none> 9300/TCP 7d5h kafka ClusterIP 10.96.92.118 <none> 9092/TCP 4d19h kafka-broker-headless ClusterIP None <none> 9094/TCP,9092/TCP 4d19h kibana-kb-http NodePort 10.96.17.95 <none> 5601:30682/TCP 7d logstash-ls-api ClusterIP None <none> 9600/TCP 2d5h zookeeper ClusterIP 10.96.62.2 <none> 2181/TCP,2888/TCP,3888/TCP 5d20h zookeeper-headless ClusterIP None <none> 2181/TCP,2888/TCP,3888/TCP 5d20h
这里登录用的账号和Elasticsearch 的用户密码一致(获取方式见2.1)
用户是:elastic
密码是:qn3zAXBmpkRGHNsL73V8hGjv
8.2验证整条链路 检查日志是否进入Elasticsearch,按照下图操作并检查是否有索引:
左侧 Management(管理) → Stack Management → Index Management(索引管理)
点击【索引管理】,能看到 数据索引、且 docs.count(文档计数) > 0,说明链路通了。
8.3创建数据视图 创建数据视图
名称:Kibana 里显示的数据视图名称,只是一个友好名称,可以自定义
索引模式:指定这个数据视图要匹配哪些 Elasticsearch 索引
其他参考图中配置即可。
8.4通过Discover看日志 在 Discover 里看日志
在搜索字段名称中根据自己的需要输入字段,message 字段是真正的日志 正文