部署 ELK 日志系统
适用范围与安全说明:本文原始案例基于 CentOS 7 和早期 Elastic Stack,保留用于理解旧环境。CentOS 7 已于 2024 年 6 月 30 日停止维护,新建生产环境应选择仍受支持的 Linux 发行版,并使用 Elastic 官方镜像或软件仓库。生产部署不得关闭主机防火墙、不得禁用 SELinux、不得跳过 TLS 校验,也不得把固定密码写入文章、命令行或版本库。
生产环境先做这些
- 明确版本矩阵,锁定 Elasticsearch、Kibana、Logstash 和 Beats 的相同主版本,不使用浮动的
latest。 - 仅开放确有需要的端口:Kibana 5601 面向管理网,Elasticsearch 9200 面向受信客户端,集群传输端口 9300 仅允许节点间访问。
- 启用身份验证、最小权限角色和 HTTP/传输层 TLS。客户端只分发 CA 公共证书,绝不能分发 CA 私钥。
- 密码、API Key 和服务令牌放入 Elastic Keystore、Docker Secret 或受限权限的环境文件,并制定轮换和吊销流程。
- 下载镜像、脚本或配置后先核对来源、版本和摘要;不要把未经审查的远程脚本直接通过管道交给 shell。
- 上线前验证快照仓库、索引生命周期策略、磁盘水位、恢复演练、告警和容量预估。
1.ELK概述
ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana , 是一个日志搜集、分析的整体解决方案。
1.1.为什么要使用ELK
日志分析是运维工程师解决系统故障,发现问题的主要手段。日志主要包括系统日志、程序日志、安全日志。通过对日志分析,了解服务器软硬件信息、检查配置过程中的错误以及错误发生的原因。
往往单台机器的日志,使用grep、awk等工具就能基本实现简单分析,但是当日志被分散的储存在不同的设备上,或者管理上百台服务器,依次登录每台机器查阅日志就会很繁琐且效率低下。而使用开源的 syslog 虽然可以将所有服务器上的日志集中化管理,但对于要求更高的查询、排序和统计等要求和庞大的机器数量,仍然使用grep、awk和wc等Linux命令难免有点力不从心。
一般大型系统是一个分布式部署的架构,不同的服务模块部署在不同的服务器上,问题出现时,大部分情况需要根据问题暴露的关键信息,定位到具体的服务器和服务模块,构建一套集中式日志系统,可以提高定位问题的效率。
1.2.ELK架构图
1.3.ELK工作原理
在所有需要收集日志的服务器上部署Logstash,或者先将日志进行集中化管理在日志服务器上,再在日志服务器上部署Logstash。
- Logstash 收集日志,将日志格式化并输出到 ElasticSearch 中
- ElasticSearch 对格式化后的数据进行索引和存储
- Kibana 从 ES 中查询数据生成图表,并进行前端数据的展示
注:Filebeat是一种轻量级的开源日志文件数据搜集器,它能快速收集数据,并发送给 logstash 进行解析,或是直接发给Elasticsearch存储,性能上相比运行于JvM上的logstash优势明显,是对它的替代。常应用于EFLK架构当中。
2.安装部署
2.1.前提条件
- 硬件:至少使用2核CPU、16G内存、60G磁盘,推荐8核CPU、64G内存、500G磁盘
- 软件:原案例使用 CentOS 7.9 x64,仅供旧环境复现;新部署应改用仍受支持的系统。示例 IP 为 192.168.4.222,请替换为实验网地址。
2.2.安装服务端
- 1.安装Docker CE
curl -sL 'http://iso.sqlfans.cn/docker/install_docker_2401.sh' | bash
sudo docker --version
- 2.安装docker-compose
curl -sL 'http://iso.sqlfans.cn/docker/install_docker_compose_2181.sh' | bash
sudo docker-compose --version
- 3.调整防火墙规则(内网环境可关闭防火墙)
# 不要清空 iptables、关闭 firewalld 或禁用 SELinux。
# 请依据节点角色,只允许可信网段访问 5601/9200/9300 等必需端口。
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="<TRUSTED_CIDR>" port port="5601" protocol="tcp" accept'
firewall-cmd --reload
- 4.配置vm.max_map_count
sed -i 's/^vm.max_map_count.*/vm.max_map_count=655360/g' /etc/sysctl.conf
cat /etc/sysctl.conf | grep "^vm.max_map_count" > /dev/null || sudo bash -c "echo 'vm.max_map_count=655360' >> /etc/sysctl.conf"
sudo /sbin/sysctl -p /etc/sysctl.conf
- 5.配置dns并安装基础软件
sed -i 's/^nameserver.*/nameserver 223.5.5.5/g' /etc/resolv.conf
cat /etc/resolv.conf | grep "^nameserver" > /dev/null || echo "nameserver 223.5.5.5" > /etc/resolv.conf
yum install -y -q curl wget ntp ntpdate lrzsz telnet zip unzip net-tools
- 6.修改时区并同步时间
timedatectl set-timezone Asia/Shanghai
/usr/sbin/ntpdate -u ntp.aliyun.com
- 7.编辑yml配置文件
sudo mkdir -p /data/docker/elk/{elasticsearch/{config/certs,data,plugins},kibana}
# 按容器实际 UID/GID 授权,避免 777;以下 UID 仅为示例,先核对镜像说明。
sudo chown -R 1000:0 /data/docker/elk/elasticsearch/data
sudo chmod 750 /data/docker/elk/elasticsearch/data
sudo curl -sL http://iso.sqlfans.cn/docker/yml/docker-elk-single-es.yml -o /data/docker/elk/docker-elk.yml
sudo curl -sL http://iso.sqlfans.cn/docker/yml/elk-env.yml -o /data/docker/elk/.env
sudo curl -sL http://iso.sqlfans.cn/docker/yml/elk-kibana.yml -o /data/docker/elk/kibana/kibana.yml
sudo cat /data/docker/elk/.env | egrep "(VERSION|PASSWORD|MEM_LIMIT)"
- 8.下载yml文件中配置的镜像并启动
docker-compose -f /data/docker/elk/docker-elk.yml up -d
netstat -lnpt | grep "0.0.0.0" | egrep "(5601|9200|9300)"
docker ps
- 9.浏览器访问(防火墙开放5601、9200)
# elk地址:http://192.168.4.222:5601
# es地址:https://192.168.4.222:9200
# 首次登录凭据应在部署时安全生成并立即保存到密码库,不在文档中固定。
2.3.配置客户端
- 服务端:将es证书从容器内拷贝出来
sudo docker cp elk-es-1:/usr/share/elasticsearch/config/certs/ca/ca.crt /data/docker/elk/elasticsearch/config/certs/
ll /data/docker/elk/elasticsearch/config/certs/
- 服务端:只把 CA 公共证书
ca.crt分发给 Filebeat。CA 私钥必须留在受控签发环境中,不得放入文件服务器。
http://iso.sqlfans.cn/docker/yml/elk-ca.crt
- 客户端:下载es证书到本地
sudo mkdir -p /etc/filebeat/certs
sudo curl -sL http://iso.sqlfans.cn/docker/yml/elk-ca.crt -o /etc/filebeat/certs/ca.crt
# 客户端只需要 CA 公共证书,不得复制或下载 CA 私钥。
- 客户端:配置filebeat收集本地日志并输出给es
#.下载安装文件
sudo curl -L http://iso.sqlfans.cn/linux/filebeat-8.2.2-x86_64.rpm -o /opt/filebeat-8.2.2-x86_64.rpm
sudo yum localinstall -y /opt/filebeat-8.2.2-x86_64.rpm
#.修改filebeat配置
sudo mkdir -p /etc/filebeat/certs
sudo curl -sL http://iso.sqlfans.cn/docker/yml/elk-filebeat.yml -o /etc/filebeat/filebeat.yml
sudo cat /etc/filebeat/filebeat.yml | egrep "(host:|hosts:|password:|index:)"
#.启动filebeat服务
sudo filebeat test config /etc/filebeat/filebeat.yml
sudo filebeat modules enable system
sudo sed -i "s/enabled: false/enabled: true/" /etc/filebeat/modules.d/system.yml
sudo filebeat setup
sudo systemctl restart filebeat
sudo systemctl status filebeat
sudo filebeat version
- 服务端:确认es索引
curl --cacert /etc/filebeat/certs/ca.crt -u elastic https://192.168.4.222:9200/_cat/indices?v
3.使用指导
3.1.初次登陆
3.2.创建数据视图
- 1.进入主页,打开 Management
- 2.创建数据视图,假设filebeat推送的es索引为
sam-gateway-YYYYMMDD,可将数据视图命名为sam-gateway-*,则会自动匹配相关的es索引
- 3.返回 Discover,从下拉框中选择某个数据视图,就可以查看相关的日志记录
- 4.打开某个数据视图的日志,还可以根据多个字段对日志进行筛选,比如:只看
host.ip 是 10.30.4.192的日志
3.3.权限设置
- 1.创建 spcae 管理空间,用来分离不用的权限
- 2.创建 role 角色
- 3.创建 user 用户
- 4.定时更新spcae,用户可以看到新的dashboard。同时更新roles index权限,用户可以看到新的index
4.使用规范
4.1.基本规范
所有接入elk的服务日志都应该遵循下述原则:
- 非必要不采集,避免日志过大而占用过多的es存储空间
- es日志只保留15天,超过15天则自动清理
- 日志存放统一路径:/data/logs,再根据应用创建子目录
- 日志切分和过期处理标准:单个日志文件不超过100M、存放时间7天
- 日志格式统一采用 JSON,便于 ELK 解析处理,比如
2022-08-10 16:15:09,155 INFO org.springframework.web.servlet.handler.SimpleUrlHandlerMapping {"orderId": 1, "userId":30, "payed":1, "exception":"failed to ....."}
4.2.服务索引命名规范
使用ES存储日志的时候,可以按照索引名切分后再存储,切分方式有:
- 按业务切分,比如 xxx-gateway 代表 xxx系统网关服务
- 按日期切分,日志量小就可以按月、年来做切分,量大就按天来做切分
通常会结合上面两种方式对索引名做切割,比如 xxx-gateway-20200122 代表xxx系统网关服务2020年1月22日的日志
4.3.日志采集来源
| 日志类型 | 日志来源 | 备注 |
|---|---|---|
| 访问日志 | Apache、Nginx、Tomcat | |
| 业务日志 | 程序写入的日志文件 | 推荐开发同事采集异常日志用于分析 |
| 系统日志 | /var/log/*、rsyslog | |
| 网络日志 | 防火墙、交换机、路由器 | 可以不采集 |
4.4.日志采集模板
根据“非必要不采集”的原则,请开发同事参考如下模板,填写需要采集的日志清单:
| 业务系统 | ip地址 | 服务名称 | 服务日志路径 | 建议索引名称 | 备注 |
|---|---|---|---|---|---|
| xxx系统 | 192.168.x.x |
gateway服务 | /data/logs/gateway/application.log | xxx-gateway | 这是一个样例 |
4.5.filebeat客户端配置模板
- 范例1:假设 elk 服务端为 192.168.4.222:5601,es账密为 elastic/xxx,以下则是 filebeat 客户端配置模板:
filebeat.inputs:
- type: log
enabled: true
paths:
- "/data/logs/gateway/application.log"
filebeat.config.modules:
path: /etc/filebeat/modules.d/*.yml
reload.enabled: false
setup.template.enabled: false
setup.template.overwrite: true
setup.ilm.enabled: false
setup.template.settings:
index.number_of_shards: 1
setup.kibana:
host: "192.168.4.222:5601"
output.elasticsearch:
hosts: ["192.168.4.222:9200"]
protocol: "https"
username: "elastic"
password: "${ELASTIC_PASSWORD}"
ssl.certificate_authorities: "/etc/filebeat/certs/ca.crt"
indices:
- index: "xxx-gateway-%{+yyyyMMdd}"
processors:
- add_host_metadata:
when.not.contains.tags: forwarded
- add_cloud_metadata: ~
- 范例2:单机多日志监控并写入不同es索引
#================ input =====================
filebeat.inputs:
- type: log
enabled: true
paths:
- "/var/log/*.log"
tags: ["syslog"]
fields:
index: "syslog"
multiline.pattern: '^\s'
multiline.negate: true
multiline.match: after
- type: log
enabled: true
paths:
- /usr/local/nginx/logs/error.log
tags: ["nginx"]
fields:
index: "nginx"
multiline.pattern: '^\s'
multiline.negate: true
multiline.match: after
#================ output =====================
output.elasticsearch:
# hosts: ["192.168.0.21:9200","192.168.0.22:9200"]
hosts: ["192.168.4.222:9200"]
protocol: "https"
username: "elastic"
password: "xxx"
ssl.certificate_authorities: "/etc/filebeat/certs/ca.crt"
indices:
- index: "syslog-log-%{+yyyyMMdd}"
when.contains:
fields:
index: "syslog"
- index: "nginx-log-%{+yyyyMMdd}"
when.contains:
fields:
index: "nginx"
#============== Elasticsearch template setting ==========
filebeat.config.modules:
path: /etc/filebeat/modules.d/*.yml
reload.enabled: false
setup.template.enabled: false
setup.template.overwrite: true
setup.ilm.enabled: false
setup.template.settings:
index.number_of_shards: 1
setup.kibana:
host: "192.168.4.222:5601"
#================== processors config ===================
processors:
- add_host_metadata:
when.not.contains.tags: forwarded
- add_cloud_metadata: ~
5.服务器维护
5.1.ES索引定期清理
当elk运行一段时间之后,ES中会保存大量的日志,需要定时清理。下面将创建一个定时清理14天以前es索引的任务。
- 将如下脚本保存为:
/scripts/crontab/es_clear_daily.sh
#!/bin/bash
iport=192.168.4.222:9200
user=es_index_maintainer
ca_file=/etc/elasticsearch/certs/ca.crt
: "${ES_PASSWORD:?请通过受控环境变量或密钥服务提供 ES_PASSWORD}"
dte=`date -d "14 days ago" +%Y%m%d`
for idx in `curl --fail --silent --show-error --cacert "$ca_file" -u "$user:$ES_PASSWORD" "https://$iport/_cat/indices?v" | awk '{print $3}' | grep "$dte"`;
do
curl --fail --show-error --cacert "$ca_file" -u "$user:$ES_PASSWORD" -X DELETE "https://$iport/$idx";
done
- 添加计划任务
echo "9 2 * * * /scripts/crontab/es_clear_daily.sh > /dev/null 2>&1" >> /var/spool/cron/`whoami`








