Kubernetes 部署 Elasticsearch + Kibana

Kubernetes 部署 Elasticsearch + Kibana

本文介绍如何在 Kubernetes 集群中部署 Elasticsearch 6.8.23 三节点集群与 Kibana 6.8.23 可视化面板。Elasticsearch 采用 DaemonSet 部署确保每个指定节点运行一个实例,Kibana 采用 Deployment 部署并通过 NodePort 对外暴露访问。


一、架构概述

组件 部署方式 节点数 端口 说明
Elasticsearch DaemonSet 3 :9200 / :9300 数据存储与检索引擎
Kibana Deployment 1 :5601 可视化面板
Service NodePort 1 :30056 → :5601 Kibana 外部访问入口

关键设计决策

  • DaemonSet — 每个标记节点精确运行一个 ES Pod,与节点绑定
  • hostNetwork: true — ES 直接使用宿主机网络,免去 Service 转发
  • hostAliases — Kibana Pod 内注入 ES 主机名解析
  • hostPath 挂载 — ES 数据和日志持久化到宿主机目录
  • postStart lifecycle — Pod 启动后自动设置 vm.max_map_countulimit

二、部署配置文件

完整的 elastic.yaml 配置:

2.1 Kibana Service

apiVersion: v1
kind: Service
metadata:
  labels:
    app: elastic-kibana
  name: elastic-kibana
  namespace: bjac-elastic
spec:
  type: NodePort
  ports:
    - port: 5601
      targetPort: 5601
      nodePort: 30056
  selector:
    app: elastic-kibana

2.2 Elasticsearch DaemonSet

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: elastic
  namespace: bjac-elastic
  labels:
    app: elastic
spec:
  selector:
    matchLabels:
      app: elastic
  template:
    metadata:
      labels:
        app: elastic
    spec:
      imagePullSecrets:
        - name: aliyunregsecret
      nodeSelector:
        elastic-server: "true"
      hostNetwork: true
      volumes:
      - name: elastic-data
        hostPath:
          path: /home/elastic/data
      - name: elastic-logs
        hostPath:
          path: /home/elastic/logs
      containers:
      - name: elastic
        env:
        - name: network.host
          value: "0.0.0.0"
        - name: transport.host
          value: "0.0.0.0"
        - name: discovery.zen.ping.unicast.hosts
          value: "elasticserver1"
        - name: discovery.zen.minimum_master_nodes
          value: "1"
        - name: cluster.name
          value: "k8s-es"
        - name: ES_JAVA_OPTS
          value: "-Xms8g -Xmx8g"
        - name: xpack.security.enabled
          value: "false"
        - name: xpack.monitoring.enabled
          value: "true"
        - name: xpack.ml.enabled
          value: "true"
        - name: xpack.graph.enabled
          value: "true"
        - name: xpack.watcher.enabled
          value: "true"
        - name: http.cors.enabled
          value: "true"
        - name: http.cors.allow-origin
          value: "*"
        image: registry.cn-beijing.aliyuncs.com/<YOUR_REPO>/es-cn:6.8.23
        lifecycle:
          postStart:
            exec:
              command:
              - /bin/sh
              - -c
              - |
                sysctl -w vm.max_map_count=262144
                ulimit -l unlimited
                ulimit -n 65536
        ports:
        - containerPort: 9200
        - containerPort: 9300
        volumeMounts:
        - name: elastic-data
          mountPath: /usr/share/elasticsearch/data/
        - name: elastic-logs
          mountPath: /usr/share/elasticsearch/logs/

2.3 Kibana Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: elastic-kibana
  name: elastic-kibana
  namespace: bjac-elastic
spec:
  replicas: 1
  selector:
    matchLabels:
      app: elastic-kibana
  template:
    metadata:
      labels:
        app: elastic-kibana
    spec:
      hostAliases:
      - ip: "<ES_NODE_IP_1>"
        hostnames:
        - "elasticserver1"
      - ip: "<ES_NODE_IP_2>"
        hostnames:
        - "elasticserver2"
      - ip: "<ES_NODE_IP_3>"
        hostnames:
        - "elasticserver3"
      containers:
        - name: elastic-kibana
          env:
          - name: ELASTICSEARCH_URL
            value: "http://elasticserver1:9200"
          image: docker.elastic.co/kibana/kibana:6.8.23
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 5601
      nodeSelector:
        elastic-server: "true"

配置要点说明

配置项 说明
kind DaemonSet / Deployment ES 用 DaemonSet,Kibana 用 Deployment
hostNetwork true (ES) ES 直接使用宿主机网络栈
nodeSelector elastic-server: "true" 只在标记节点上部署
discovery.zen.ping.unicast.hosts elasticserver1 ES 集群节点发现(单播)
discovery.zen.minimum_master_nodes 1 最少 Master 节点数
ES_JAVA_OPTS -Xms8g -Xmx8g JVM 堆内存,建议设为相同值
xpack.security.enabled false 关闭安全认证(内网环境)
http.cors.enabled true 允许跨域请求(方便前端工具接入)
postStart lifecycle sysctl/ulimit Pod 启动后设置内核参数
hostAliases (Kibana) 3 个 ES 节点 IP Kibana 内通过主机名连接 ES

三、部署步骤

3.1 为节点打标签

kubectl get node --show-labels=true
kubectl label nodes <NODE_1> elastic-server=true
kubectl label nodes <NODE_2> elastic-server=true
kubectl label nodes <NODE_3> elastic-server=true

3.2 创建数据目录

每个 ES 节点上执行:

mkdir -p /home/elastic/data /home/elastic/logs
chmod -R 777 /home/elastic

3.3 配置内核参数

Elasticsearch 要求 vm.max_map_count 至少为 262144,在每个 ES 节点上执行:

cat <<EOF | tee -a /etc/sysctl.conf
vm.max_map_count = 262144
EOF

sysctl -w vm.max_map_count=262144

# 验证
grep vm.max_map_count /etc/sysctl.conf

说明:Pod 的 postStart hook 中也设置了此参数,但宿主机级别设置更可靠,Pod 内 sysctl 可能因权限不足而失败。

3.4 配置 hosts 解析

每个 ES 节点/etc/hosts 中添加:

echo "<ES_NODE_IP_1> elasticserver1" >> /etc/hosts
echo "<ES_NODE_IP_2> elasticserver2" >> /etc/hosts
echo "<ES_NODE_IP_3> elasticserver3" >> /etc/hosts

3.5 创建命名空间和镜像 Secret

kubectl create namespace bjac-elastic

kubectl create secret docker-registry aliyunregsecret \
  --docker-server=registry.cn-beijing.aliyuncs.com \
  --docker-username=<YOUR_USERNAME> \
  --docker-password=<YOUR_PASSWORD> \
  -n bjac-elastic

3.6 执行部署

kubectl apply -f elastic.yaml

3.7 验证部署

# 查看 Pod
kubectl get pod -n bjac-elastic -o wide

# 查看 Pod 详情(排错用)
kubectl -n bjac-elastic describe pod <POD_NAME>

# 查看 Pod 日志
kubectl -n bjac-elastic logs <ES_POD_NAME> --all-containers=true
kubectl -n bjac-elastic logs <KIBANA_POD_NAME> --all-containers=true

3.8 验证 Elasticsearch 集群

进入 ES Pod 检查集群状态:

kubectl exec -it pod/<ES_POD_NAME> -n bjac-elastic -- bash

curl http://localhost:9200/_cluster/health?pretty
curl http://localhost:9200/_cat/nodes?v

3.9 访问 Kibana

通过 NodePort 访问 Kibana 面板:

http://<ANY_NODE_IP>:30056

四、访问控制

生产环境中,Elasticsearch 的 9200 端口不应对外开放。通过 iptables 限制访问:

4.1 限制 9200 端口访问

# 默认拒绝所有 9200 端口访问
iptables -I INPUT -p tcp --dport 9200 -j DROP

# 允许内网网段访问
iptables -I INPUT -s <INTERNAL_SUBNET>/24 -p tcp --dport 9200 -j ACCEPT

# 允许指定 IP 访问
iptables -I INPUT -s <SPECIFIC_IP> -p tcp --dport 9200 -j ACCEPT

4.2 删除规则

iptables -D INPUT -p tcp --dport 9200 -j DROP
iptables -D INPUT -s <INTERNAL_SUBNET>/24 -p tcp --dport 9200 -j ACCEPT
iptables -D INPUT -s <SPECIFIC_IP> -p tcp --dport 9200 -j ACCEPT

最佳实践:iptables 规则的顺序很重要 — ACCEPT 规则必须在 DROP 规则之前(使用 -I 插入到链头),否则会被 DROP 规则拦截。


五、常见问题排查

问题 原因 解决方案
Pod 启动失败,max_map_count 错误 宿主机内核参数未设置 在宿主机执行 sysctl -w vm.max_map_count=262144
Pod 启动失败,ulimit 错误 容器内资源限制不足 确保 postStart hook 正确执行
集群无法发现节点 hosts 解析未配置 确保宿主机 /etc/hosts 配置正确
Kibana 无法连接 ES hostAliases 未配置 确保 Kibana Deployment 中 hostAliases 包含所有 ES 节点
数据目录权限错误 目录权限不足 chmod -R 777 /home/elastic
镜像拉取失败 Secret 未创建 创建 aliyunregsecret

六、注意事项

  1. vm.max_map_count 必须设置 — ES 6.x 要求此值至少 262144,否则无法启动
  2. 目录权限 — ES 进程需要对数据目录有写入权限,建议 chmod -R 777
  3. JVM 堆内存XmsXmx 建议设为相同值,避免动态调整带来的性能抖动
  4. minimum_master_nodes — 三节点集群建议设为 2,此处设为 1 是因为初始只有一个 Master
  5. xpack.security — 内网环境可关闭,公网环境必须开启并配置认证
  6. hostNetwork — ES 使用宿主机网络,9200/9300 端口直接绑定宿主机,需确保端口未被占用
  7. postStart hook — 容器内 sysctl 可能因权限问题失败,建议在宿主机层面持久化设置

附录:资源清单

资源类型 名称 数量
Namespace bjac-elastic 1
Service elastic-kibana (NodePort :30056) 1
DaemonSet elastic 3 Pod (按节点数)
Deployment elastic-kibana 1 Pod
Secret aliyunregsecret 1
hostPath Volume /home/elastic/data 每节点 1
hostPath Volume /home/elastic/logs 每节点 1

阅读更多

Ghost 邮箱订阅功能在中国大陆的困境:Mailgun 注册受阻实录

Ghost 邮箱订阅功能在中国大陆的困境:Mailgun 注册受阻实录

本文记录了 Ghost 博客邮箱订阅功能因 Mailgun 在中国大陆无法注册而被迫关闭的完整过程,包括注册尝试、工单沟通及最终应对方案。 一、背景:Ghost 与 Mailgun Ghost 博客平台内置了邮箱订阅(Newsletter)功能,读者可以通过输入邮箱地址订阅博客更新,Ghost 会自动将新文章以邮件形式推送给订阅者。这一功能的邮件发送能力依赖于第三方邮件服务——Mailgun。 Ghost 官方推荐使用 Mailgun 作为邮件传输层,配置方式如下: 配置项 说明 示例值 mail.from 发件人地址 newsletter@yourdomain.com mail.transport 传输协议 SMTP mail.options.host SMTP 主机 smtp.mailgun.org mail.options.port

By 菱角
Kubernetes 全栈监控体系:kube-prometheus-stack + 7 大 Exporter 生产实践

Kubernetes 全栈监控体系:kube-prometheus-stack + 7 大 Exporter 生产实践

本文基于 kube-prometheus-stack Helm Chart 在 Kubernetes 上构建完整监控体系的实战,覆盖 Prometheus、Grafana、Alertmanager 及 7 个专用 Exporter 的部署与配置。 一、监控体系全景架构 整套监控以 kube-prometheus-stack 为核心,通过 ServiceMonitor CRD 自动发现并采集 7 大数据源,配合 Alertmanager 分级告警与 Grafana 可视化: 组件 版本 作用 Prometheus v2.45.0 指标采集与存储,10 天数据保留 Alertmanager v0.25.0 告警路由与邮件推送,2 副本 HA

By 菱角
基于 Docker Compose 部署 Apache APISIX:全栈 API 网关实践

基于 Docker Compose 部署 Apache APISIX:全栈 API 网关实践

本文基于 APISIX 3.9.1 + Dashboard 3.0.1 + etcd 3.5.15 + Prometheus + Grafana 的生产级 Docker Compose 部署实践。 一、整体架构 本次部署采用 Docker Compose 编排五大组件,形成从配置管理到流量监控的完整闭环: 组件 版本 作用 端口 APISIX 3.9.1-debian API 网关核心,路由转发、插件执行 9080/9443 Dashboard 3.0.1-alpine 可视化配置管理界面 9000 etcd 3.5.15

By 菱角
在 Kubernetes 上部署 Apache Flink:生产实战指南

在 Kubernetes 上部署 Apache Flink:生产实战指南

本文基于 Flink 1.15.2 + Kubernetes 的生产环境部署实践。 一、架构概览 Flink 在 Kubernetes 上采用经典的 JobManager + TaskManager 主从架构,JobManager 负责作业调度与协调,TaskManager 承载实际的计算任务。 资源分配一览 组件 作用 副本数 Task Slots 内存配置 JobManager 作业调度、Checkpoint 管理、协调 1 — 8G TaskManager 执行计算任务 3 80/Pod 48G 总计 — 4 240 — 二、Namespace 隔离 为 Flink 创建独立 Namespace,

By 菱角