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_count和ulimit
二、部署配置文件
完整的 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 的
postStarthook 中也设置了此参数,但宿主机级别设置更可靠,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 |
六、注意事项
- vm.max_map_count 必须设置 — ES 6.x 要求此值至少 262144,否则无法启动
- 目录权限 — ES 进程需要对数据目录有写入权限,建议
chmod -R 777 - JVM 堆内存 —
Xms和Xmx建议设为相同值,避免动态调整带来的性能抖动 - minimum_master_nodes — 三节点集群建议设为 2,此处设为 1 是因为初始只有一个 Master
- xpack.security — 内网环境可关闭,公网环境必须开启并配置认证
- hostNetwork — ES 使用宿主机网络,9200/9300 端口直接绑定宿主机,需确保端口未被占用
- 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 |