Files
docker_practice/19_observability/19.2_elk.md
2026-03-09 20:04:16 -07:00

214 lines
7.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 19.2 ELK 套件
ELK (ElasticsearchLogstashKibana) 是目前业界最流行的开源日志解决方案而在容器领域由于 Fluentd 更加轻量级且对容器支持更好EFK (ElasticsearchFluentdKibana) 组合也变得非常流行
### 19.2.1 方案架构
我们将采用以下架构
1. **Docker Container**容器将日志输出到标准输出 (stdout/stderr)
2. **Fluentd**作为 Docker Logging Driver 或运行为守护容器收集容器日志
3. **Elasticsearch**存储从 Fluentd 接收到的日志数据
4. **Kibana** Elasticsearch 读取数据并进行可视化展示
### 19.2.2 部署流程
我们将使用 Docker Compose 来一键部署整个日志堆栈
#### 1. 编写 Compose 文件
1. 编写 `compose.yaml` ( `docker-compose.yml`) 配置如下
```yaml
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.17.0
container_name: elasticsearch
environment:
- "discovery.type=single-node"
- "xpack.security.enabled=false"
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ports:
- "9200:9200"
volumes:
- es_data:/usr/share/elasticsearch/data
networks:
- logging
kibana:
image: docker.elastic.co/kibana/kibana:8.17.0
container_name: kibana
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- "5601:5601"
links:
- elasticsearch
networks:
- logging
fluentd:
image: fluent/fluentd-kubernetes-daemonset:v1.17-debian-elasticsearch8-1
container_name: fluentd
environment:
- "FLUENT_ELASTICSEARCH_HOST=elasticsearch"
- "FLUENT_ELASTICSEARCH_PORT=9200"
- "FLUENT_ELASTICSEARCH_SCHEME=http"
- "FLUENT_UID=0"
ports:
- "24224:24224"
- "24224:24224/udp"
links:
- elasticsearch
volumes:
- ./fluentd/conf:/fluentd/etc
networks:
- logging
volumes:
es_data:
networks:
logging:
```
#### 2. 配置 Fluentd
创建 `fluentd/conf/fluent.conf`
```ini
<source>
@type forward
port 24224
bind 0.0.0.0
</source>
<match *.**>
@type copy
<store>
@type elasticsearch
host elasticsearch
port 9200
logstash_format true
logstash_prefix docker
logstash_dateformat %Y%m%d
include_tag_key true
type_name access_log
tag_key @log_name
flush_interval 1s
</store>
<store>
@type stdout
</store>
</match>
```
#### 3. 配置应用容器使用 fluentd 驱动
启动一个测试容器指定日志驱动为 `fluentd`
```bash
docker run -d \
--log-driver=fluentd \
--log-opt fluentd-address=localhost:24224 \
--log-opt tag=nginx-test \
--name nginx-test \
nginx
```
**注意**确保 `fluentd` 容器已经启动并监听在 `localhost:24224`在生产环境中如果你是在不同机器上需要将 `localhost` 替换为运行 fluentd 的主机 IP
#### 4. Kibana 中查看日志
1. 访问 `http://localhost:5601`
2. 进入 **Management**->**Kibana**->**Index Patterns**
3. 创建新的 Index Pattern输入 `docker-*` (我们在 fluent.conf 中配置的前缀)
4. 选择 `@timestamp` 作为时间字段
5. **Discover** 页面你就能看到 Nginx 容器的日志了
#### Kibana 建索引模式常见坑
首次接入 EFK/ELK Elasticsearch 有数据但 Kibana 看不到很常见通常是 Kibana 配置或时间窗口问题
* **Index Pattern 不匹配**确认 Kibana Index Pattern 与实际索引前缀一致可以先用 `_cat/indices` 查看真实索引名
* **时间字段选择错误**若索引里包含 `@timestamp`一般选择它如果选择了错误的字段会导致 Discover 无法按时间筛选
* **时间窗口/时区**Discover 右上角的时间范围默认可能是最近 15 分钟且时区可能影响显示建议先把范围扩大到最近 24 小时再验证
* **数据解析失败**若日志是非结构化文本仍可入库但字段不可用生产环境建议输出 JSON 并在采集端解析
#### 5. 验证日志是否写入 Elasticsearch (生产排错必备)
当你在 Kibana 看不到日志时建议先跳过 UI从存储端直接验证日志是否入库
1. 查看索引是否创建
```bash
curl -s http://localhost:9200/_cat/indices?v
```
如果 Fluentd 使用了 `logstash_format true` `logstash_prefix docker`通常会看到形如 `docker-YYYY.MM.DD` 的索引
2. 查看最近一段时间的日志文档
```bash
curl -s -H 'Content-Type: application/json' \
http://localhost:9200/docker-*/_search \
-d '{"size":1,"sort":[{"@timestamp":"desc"}]}'
```
如果 Elasticsearch 中已经有文档 Kibana 仍然为空常见原因是
* Index Pattern 没匹配到索引 (例如写成了 `docker-*` 但实际索引前缀不同)
* 时间字段没选对或时区不一致导致 Discover 时间窗口内看不到数据
### 19.2.3 总结
通过 Docker 的日志驱动机制结合 ELK/EFK 强大的收集和分析能力我们可以轻松构建一个能够处理海量日志的监控平台这对于排查生产问题至关重要
### 19.2.4 生产要点
在生产环境中日志系统往往比监控系统更容易因为容量与写入压力出问题建议特别关注
* **容量规划**日志增长速度与磁盘占用直接相关建议设置日志保留周期与索引生命周期策略 (ILM)避免 Elasticsearch 因磁盘水位触发只读或不可用
* **资源配置**Elasticsearch JVM Heap 较敏感除示例中的 `ES_JAVA_OPTS` 生产环境需要结合节点内存分片规模查询压力做评估
* **链路可靠性**采集端到存储端要考虑网络抖动背压与重试策略 Elasticsearch 写入变慢时采集端的缓冲与落盘策略决定了是否会丢日志
* **日志格式**推荐应用输出结构化日志 (JSON) 并包含关键字段 ( `trace_id``request_id``service``env`)以便快速过滤与关联分析
#### 索引与保留策略的落地建议
无论是 EFK 还是 ELK生产上都需要回答两个问题
* 日志保留多久
* 保留期内的日志如何保证可查询不过度占用存储
建议按环境与业务重要性对日志分层并制定不同的保留周期例如
* **生产环境**730
* **测试环境**17
实现方式通常有两类
* **按天滚动索引** `docker-YYYY.MM.DD`再定期删除过期索引
* **使用 ILM**定义 Hot/Warm/Cold/删除阶段按时间与容量自动滚动与回收
对于中小规模集群先把按天滚动 + 过期删除做扎实往往就能解决 80% 的容量问题当日志量上来查询压力变大后再逐步引入 ILM分层存储与更精细的分片规划
#### 最小可用的过期索引清理示例
如果你采用按天滚动索引 (例如 `docker-YYYY.MM.DD`)可以通过 Elasticsearch API 定期清理过期索引
下面示例仅用于演示思路获取所有 `docker-` 前缀索引并删除指定索引生产环境建议基于日期计算灰度验证与权限控制后再执行自动化清理
1. 列出索引
```bash
curl -s http://localhost:9200/_cat/indices/docker-*?v
```
2. 删除某个过期索引 (示例)
```bash
curl -X DELETE http://localhost:9200/docker-2026.02.01
```
如果你希望更自动化的治理能力可以进一步使用 ILM 为索引配置滚动与删除策略