一、简介
“ELK”是三个开源项目的首字母缩写,这三个项目分别是:Elasticsearch、Logstash 和 Kibana。
Elasticsearch 是一个搜索和分析引擎。
Logstash 是服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到诸如 Elasticsearch 等“存储库”中。
Kibana 则可以让用户在 Elasticsearch 中使用图形和图表对数据进行可视化。
Elastic Stack 是 ELK Stack 的更新换代产品。向原ELK 中加入了 Beats。
二、环境
本文采用Docker形式,其他形式如果有问题,可以留言,看到会回复的
- 系统:CentOS 7.9
- Docker:20.10.8
- ELK的版本有一定的依赖性,本文采用以下:
: ElasticSearch 7.14.0
: Kibana 7.14.0
: Logstash 7.14.0
1、安装Docker、Docker Compose
参照我的另一篇文章:参考官网整理笔记:CentOS安装Docker、Docker Compose
三、部署Elastic Stack(ELK)
1、部署ElasticSearch(Distributed, RESTful search and analytics.)
- 拉取Docker镜像
docker pull docker.elastic.co/elasticsearch/elasticsearch:7.14.0
- 本地目录权限配置
创建目录data、config、plugins、certs,后面配置都会用到
数据持久化等需要挂在目录或文件,如果本地主机用户不是root用户,挂载本地目录会发生权限不足的问题
# 修改宿主机挂在的目录权限
chmod 777 -R <host file path>
- 运行单节点服务(选择此方式,跳过4-6步,直接进行第7步)
为了后续Kibana和Logstash等服务可以和ElasticSearch互联,需要创建网络elastic-clus-networks,默认就是bridge模式
docker network create elastic-clus-networks
在config目录创建文件elasticsearch.yml
cluster.name: "docker-cluster"
network.host: 0.0.0.0
discovery.type: "single-node"
bootstrap.memory_lock: true
# 修改config及目录中的文件权限
chmod 777 -R config
启动单节点ElasticSearch容器时,连接到网络,并挂载目录
docker run -itd -p 9200:9200 -p 9300:9300 --net elastic-clus-networks -v /本地挂挂载目录/data/es-single-node:/usr/share/elasticsearch/data -v /本地挂挂载目录/plugins:/usr/share/elasticsearch/plugins -v /本地挂挂载目录/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /本地挂挂载目录/certs:/usr/share/elasticsearch/config/certificates --name es-single-node --restart=always docker.elastic.co/elasticsearch/elasticsearch:7.14.0
- 配置集群启动信息
启动并运行一个三节点 Elasticsearch 集群,您可以使用 Docker Compose:
创建一个docker-compose.yml文件如下:
version: '3.9'
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0
container_name: es01
environment:
- node.name=es01
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es02,es03
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data01:/usr/share/elasticsearch/data
# - config01:/usr/share/elasticsearch/config/elasticsearch.yml
ports:
- 127.0.0.1:9200:9200
networks:
- elastic-clus-networks
logging:
driver: "local"
options:
max-size: "5m" # 单个文件大小为5m
max-file: "80" # 最多80个文件
es02:
image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0
container_name: es02
environment:
- node.name=es02
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es01,es03
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data02:/usr/share/elasticsearch/data
# - config02:/usr/share/elasticsearch/config/elasticsearch.yml
networks:
- elastic-clus-networks
logging:
driver: "local"
options:
max-size: "5m" # 单个文件大小为5m
max-file: "80" # 最多80个文件
es03:
image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0
container_name: es03
environment:
- node.name=es03
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es01,es02
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data03:/usr/share/elasticsearch/data
# - config03:/usr/share/elasticsearch/config/elasticsearch.yml
networks:
- elastic-clus-networks
logging:
driver: "local"
options:
max-size: "5m" # 单个文件大小为5m
max-file: "80" # 最多80个文件
volumes:
data01:
driver: local
driver_opts:
type: none
device: /本地挂挂载目录/es-node01
o: bind
data02:
driver: local
driver_opts:
type: none
device: /本地挂挂载目录/es-node02
o: bind
data03:
driver: local
driver_opts:
type: none
device: /本地挂挂载目录/es-node03
o: bind
networks:
elastic-clus-networks:
driver: bridge
注意:
1.此示例 Docker Compose 文件启动了一个三节点 Elasticsearch 集群。节点es01上侦听localhost:9200,并es02和es03通过docker-networks与es01连接。
2.此配置未公开9200端口,只可以从本机访问,想对外开放的话,需要使用ng等代理
3.默认情况下,Elasticsearch 根据节点的角色和节点容器可用的总内存自动调整 JVM 堆的大小 。对于大多数生产环境,我们建议使用此默认大小。不设置ES_JAVA_OPTS。
4.为了性能和节点稳定性,需要禁用交换。ulimits.memlock.soft: -1/hard: -1
5.此配置中的data01、data02、data03为本地存储,重启后数据依然存在,自行修改data01、data02、data03的device为自己本地存储数据的目录,注意要3个目录分开存储各自节点的数据,如果目录不存在,请在启动集群前创建对应的目录
6.挂载 Elasticsearch 配置文件,此配置中的config01、config02、config03为本地存储文件,创建自定义配置文件并将它们绑定挂载到 Docker 映像中的相应文件上。配置同data,参考配置即可,如果使用自己本地挂载配置文件,配置中的environment参数就不要用了,由于环境变量被转换为 CLI 参数,因此它们优先于配置文件
7.日志模型使用自定义的,默认json-file
8.根据服务器性能适当选择节点数目
9.以上配置基于3.9版本的规范,其他版本参考官方文档:https://docs.docker.com/compose/compose-file/
- 启动集群
使用compose启动,注意这些compose配置文件启动位置要统一,保证启动的命名空间一致,否则可能找不到其他服务
docker-compose -f Elasticsearch的docker-compose文件 up
#-f, --file FILE Specify an alternate compose file
# (default: docker-compose.yml)
#-d 后台启动
- 集群的操作
启动集群
docker-compose up
查看集群日志
docker-compose logs
停止集群
docker-compose down
要关闭集群时删除数据卷
docker-compose down -v
- 生产环境中使用Docker运行ElasticSearch建议
如在生产环境中使用Docker运行ElasticSearch,有以下建议事项。
设置vm.max_map_count至少为262144。
如何设置vm.max_map_count取决于您的平台:
更多平台设置请参考:ElasticSearch Docker指南:在生产中使用 Docker 镜像
- Linux
该vm.max_map_count设置应在/etc/sysctl.conf设置,使其永久生效
grep vm.max_map_count /etc/sysctl.conf
vm.max_map_count=262144
要在实时系统上应用设置,请运行
sysctl -w vm.max_map_count=262144
- 查看节点是否已启动并正在运行
curl -X GET "localhost:9200/_cat/nodes?v=true&pretty"
- 安装ik分词器
IK分词器:https://github.com/medcl/elasticsearch-analysis-ik/releases
- 容器内通过命令在线安装
# 进入容器
docker exec -it es-single-node /bin/bash
# 使用elasticsearch-plugin安装插件 版本可以再github查,安装对应版本
/usr/share/elasticsearch/bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.14.0/elasticsearch-analysis-ik-7.14.0.zip
# 查看插件容器内目录或者宿主机挂在目录,会有analysis-ik文件夹则为安装成功
cd /usr/share/elasticsearch/plugins
- 离线安装(上面启动plugins目录都挂载到宿主机目录)
下载插件包
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.14.0/elasticsearch-analysis-ik-7.14.0.zip
在宿主机的plugins挂载目录中解压下载的插件包
cd "宿主机plugins挂载目录"
# 解压下载的插件包
unzip elasticsearch-analysis-ik-7.14.0.zip
重启容器
docker restart es-single-node
2、部署Kibana(Visualize your data. Navigate the Stack.)
首先保证ElasticSearch服务正常,因为该服务需要使用上面ElasticSearch配置的节点名(es-single-node/es-node01~03)和网络名(elastic-clus-networks),同一网络内的各个容器可以直接通过名称访问,不用在意IP
- 拉取镜像
docker pull docker.elastic.co/kibana/kibana:7.14.0
- 编写kibana.yml配置文件,修改目录及文件权限为777,同ElasticSearch中第2步
更多配置详见:https://www.elastic.co/guide/en/kibana/7.14/settings.html
"server.name": "kibana.example.org"
# 如果您在代理后面运行,则server.basePath允许您指定代理挂载的Kibana路径。 kibana会删除这些内容以保证正常访问
"server.basePath": "/kibana" # 没有代理则无需该项配置 不能以(/)结尾
"server.publicBaseUrl": "http://kibana.example.org" # 最终访问kibana的路径,按需增加basePath 不能以(/)结尾
"server.host": "0.0.0.0"
"elasticsearch.hosts": ["http://es-single-node:9200"] # docker内部网络端口,容器名称访问的都是内部网络
"i18n.locale": "zh-CN" # 语言默认是英文,支持en, zh-CN, ja-JP
- 启动单节点Kibana服务(使用此方式可以跳过4-5)
创建certs目录并挂载,之后配置TLS会用到,现在不影响使用
创建data目录在宿主机保存使用数据
修改目录及文件权限为777
加入网络elastic-clus-networks,挂载配置文件
# 如果ElasticSearch是单节点启动的-net参数就不要了
docker run -itd -p 5601:5601 --net elastic-clus-networks -v /宿主机挂挂载目录/config/kibana.yml:/usr/share/kibana/config/kibana.yml -v /宿主机挂挂载目录/data:/usr/share/kibana/data -v /宿主机挂挂载目录/certs:/usr/share/kibana/certificates --name kibana-server --restart=always docker.elastic.co/kibana/kibana:7.14.0
- 编写kibana的docker compose文件
version: '3.9'
services:
kibana-server:
image: docker.elastic.co/kibana/kibana:7.14.0
container_name: kibana-server
volumes:
- 本地kibana配置目录/config/kibana.yml:/usr/share/kibana/config/kibana.yml
ports:
- 5601:5601
networks:
- elastic-clus-networks
logging:
driver: "local"
options:
max-size: "5m" # 单个文件大小为5m
max-file: "80" # 最多80个文件
networks:
elastic-clus-networks:
driver: bridge
- 启动docker compose
使用compose启动,注意这些compose配置文件启动位置要统一,保证启动的命名空间一致,否则可能找不到其他服务
# 启动
docker compose -f kibana的docker-compose文件 up
# 查看日志
docker compose -f kibana的docker-compose文件 logs
- 检查启动状态
浏览器访问服务器IP:5601或者指定端口,如图页面,即为成功
3、部署信息收集服务
下图来自Elastic官网,现在我们已经完成了ElasticSearch(信息存储)、Kibana(信息展示),接下来要在目标服务器增加Beats来收集、分析日志等信息,并输出到ElasticSearch,在向ElasticSearch传输时Logstash还可以规范化不同来源的数据(可选),最终通过Kibana查看。
Kibana中选择添加数据-日志,也会有引导如何配置的
3.1、Filebeat 轻量级数据传送器
目前服务的结构中,主要使用Filebeat实现信息收集(以下摘自官网介绍):
Filebeat 是一个轻量级的传送器,用于转发和集中日志数据。Filebeat作为代理安装在您的服务器上,所以一般和ElasticSearch、Kibana服务不在一台服务器,监控您指定的日志文件或位置,收集日志事件,并将它们转发到Elasticsearch或Logstash以进行索引。
Filebeat 的工作原理如下:
当您启动 Filebeat 时,它会启动一个或多个输入,这些输入会在您为日志数据指定的位置中查找。
对于Filebeat 找到的每个日志,Filebeat 都会启动一个收割机。每个收割机读取新内容的单个日志,并将新日志数据发送到libbeat,后者聚合事件并将聚合数据发送到您为Filebeat 配置的输出,也就是ElasticSearch。
所有的信息都可以使用Filebeat收集,因为Filebeat有收集不同平台数据(如:Tomcat、Nginx、.Net、ElasticSearch……)的配置模块,详见https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html
以CentOS中Tomcat为例的日志收集
- 保证ElasticSearch和Kibana已正常运行,再进行如下操作
- 要下载和安装 Filebeat,请使用适用于您系统的命令,之后的配置及使用都有不同操作系统的区分,详见:安装Filebeat
- 在一台业务的服务器上,下载Filebeat
curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.14.0-linux-x86_64.tar.gz
tar xzvf filebeat-7.14.0-linux-x86_64.tar.gz
- 连接到 Elasticsearch 和 Kibana,设置Filebeat目录下的filebeat.yml
- 配置Elasticsearch服务器的地址,此处需要ElasticSearch服务的地址公开使业务系统可以访问,并为Filebeat设置有权访问ElasticSearch的用户名和密码(如果ES没有设置权限则忽略)
此示例显示了硬编码密码,但您应该将敏感值存储在secrets keystore中
output.elasticsearch:
hosts: ["ES-host:9200"]
# username: "filebeat_internal"
# password: "YOUR_PASSWORD"
- 如果您计划使用Kibana仪表板,请配置Kibana的信息。如果Kibana与Elasticsearch在同一台主机上运行,可不配置此项,但在Filebeat启动时日志输出的连接Kibana地址不正确就配置一下
Kibana的username和password设置是可选的。如果您没有为 Kibana 指定凭据,Filebeat 将使用 为 Elasticsearch 输出指定的username和password
host需要和Kibana的publicUrl一致
setup.kibana:
host: "mykibanahost:5601"
username: "my_kibana_user"
password: "{pwd}"
- 收集日志数据
- 使用 Filebeat 收集日志数据的方法有以下几种:
: 数据采集模块——简化常见日志格式的采集、解析和可视化
: ECS 记录器——将应用程序日志结构化和格式化为 ECS 兼容的 JSON
: 手动 Filebeat 配置,配置输入 - 要查看模块的完整变量列表,请参阅Modules文档
- 数据采集模块-收集日志数据
# 查看模块列表
./filebeat modules list
# 启用指定模块 如:下面的命令启用tomcat模块
./filebeat modules enable tomcat
修改目录modules.d下模块的配置,适配业务系统,如:tomcat.yml设置日志目录位置
- module: tomcat
log:
enabled: true
var.input: file
var.paths:
- /var/log/tomcat/*.log
- 手动 Filebeat 配置-收集日志数据
编辑filebeat.yml,更多参考配置输入
filebeat.inputs:
- type: log # 有很多中方式见上方配置输入链接
enabled: true
paths:
- /var/log/*.log
# 如下是
filebeat.inputs:
- type: filestream # 有很多中方式见上方配置输入链接
enabled: true
paths:
- /var/log/*.log
- 配置Kibana仪表板,创建索引,不配置之后输出日志的时候也会自动创建索引
setup 命令加载 Kibana 仪表板。如果仪表板已设置,请省略此命令。
# -e 是可选的,并将输出发送到标准错误而不是配置的日志输出。
filebeat setup -e
成功后Kibana中会看到有个索引
- 启动Filebeat
# 授权root权限给目录module、filebeat.yml和上文配置的modules中那些配置文件
sudo chown root filebeat.yml
sudo chown root -R module
sudo chown root modules.d/tomcat.yml
# 启动服务
sudo ./filebeat
启动成功如图,之后会定期输出Start next scan
- 查看Kibana
Kibana中,点击左侧菜单 => 发现 => Kibana/索引模式 => 下方创建索引模式,使用正则过滤要看的多个索引(因为beat默认会按天创建新的索引,创建模式就可以查看通配索引中的所有数据了)
选择时间字段,点击创建
在侧边导航中,点击发现。查看 Filebeat 数据。左侧选择要查看的信息字段,点击字段旁边的加号,右侧的视图就可以看到数据了(比如message就是获取日志文件中的一行信息)
在侧边导航中,单击仪表板,然后选择要打开的仪表板。创建可视化视图
3.2、Logstash(Ingest, transform, enrich, and output.)
Logstash 介绍
Logstash 是一个开源数据收集引擎,具有实时流水线功能。Logstash 可以动态统一来自不同来源的数据,并将数据规范化为您选择的目的地。为各种高级下游分析和可视化用例清理和民主化您的所有数据。
- 下载镜像
docker pull docker.elastic.co/logstash/logstash:7.14.0
- 编辑配置文件
创建目录config,下面创建文件log4j2.properties、logstash.yml
创建目录pipeline,下面创建文件logstash.conf(可以在logstash.yml中配置管道,此文件可选)
创建certs,用于保存ssl证书
- 编辑要挂载的映射配置文件
- Logstash 实例中运行多个管道的框架和说明,更多说明见多管道
/usr/share/logstash/pipeline/logstash.conf - 在 Docker 下,Logstash 日志默认转到标准输出。要修改配置的话要编辑此文件,更多参考Log4j2
/usr/share/logstash/config/log4j2.properties - 包含 Logstash 的主要配置,更多参考logstash.yml
/usr/share/logstash/config/logstash.yml
- Logstash 实例中运行多个管道的框架和说明,更多说明见多管道
log4j2.properties
logger.elasticsearchoutput.name = logstash.outputs.elasticsearch
logger.elasticsearchoutput.level = debug
status = error
name = LogstashPropertiesConfig
appender.console.type = Console
appender.console.name = plain_console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]}%notEmpty{[%X{plugin.id}]} %m%n
appender.json_console.type = Console
appender.json_console.name = json_console
appender.json_console.layout.type = JSONLayout
appender.json_console.layout.compact = true
appender.json_console.layout.eventEol = true
rootLogger.level = ${sys:ls.log.level}
rootLogger.appenderRef.console.ref = ${sys:ls.log.format}_console
logstash.yml,在同一网络中使用节点名
http.host: "0.0.0.0"
xpack.monitoring.elasticsearch.hosts: ["http://es-single-node:9200"]
修改以上配置文件目录的权限
sudo chmod -R 777 config
sudo chmod -R 777 pipeline
sudo chmod -R 777 certs
- 启动Logstash,这里直接挂载pipeline和config两个目录到本地的两个目录,就会自动读取目录下文件了,不用单独挂载文件
挂载config目录的话需要目录下包含以下文件
jvm.options log4j2.properties logstash-sample.conf logstash.yml pipelines.yml startup.options
可以直接在Logstash的Docker容器中复制出来,然后只修改我们用的配置文件,其余的默认配置即可
docker run -itd -p 5044:5044 -p 9600:9600 --net elastic-clus-networks -v ~/config/:/usr/share/logstash/config/ -v ~/pipeline/:/usr/share/logstash/pipeline/ -v ~/certs/:/usr/share/logstash/certificates/ --name logstash-server --restart=always docker.elastic.co/logstash/logstash:7.14.0
这时候还没有配置Logstash的输入和pipeline服务,所以没有日志展示和处理,下面直接结合Filebeat配置日志输入和pipeline,检查服务是否已运行
curl -X GET "localhost:9600"
# 输出如下服务版本信息即可
{"host":"840fa2cbb5d4","version":"7.14.0","http_address":"0.0.0.0:9600","id":"e211e566-0390-4878-92a7-9d1c88f3b179","name":"840fa2cbb5d4","ephemeral_id":"ff95eb2d-2339-4c1f-991f-e230953d723e","status":"green","snapshot":false,"pipeline":{"workers":8,"batch_size":125,"batch_delay":50},"build_date":"2021-07-29T19:43:14Z","build_sha":"29d52f1e490de0a97194846bbfc2aa00dce23b54","build_snapshot":false}
4、Logstash与Filebeat互补实现安全日志转发
使用Filebeat将各个代理服务器的不同数据,转发到Logstash,再由Logstash规范化
- 在Filebeat目录下的filebeat.yml,配置Logstash服务器的访问地址,关掉ElasticSearch输出地址
# ================================== General ===================================
fields:
# 增加pipe.type为了之后多节点,做多管道区分的标识
"pipe.type": "a-web-logs"
# ================================== output ===================================
#output.elasticsearch:
#hosts: ["ES-host:9200"]
#username: "filebeat_internal"
#password: "YOUR_PASSWORD"
output.logstash:
hosts: ["Logstash-host:5044"]
# 此参数的值将分配给该metadata.beat字段。默认值为 Beat 名称。例如"filebeat"
# 然后可以在 Logstash 的输出部分访问它作为%{[@metadata][beat]}
index: "test-beat"
重启Filebeat
sudo ./filebeat -e
- 配置Logstash的Filebeat输入
- pipeline目录中创建几个单管道配置文件
logstash-base-pipeline.cfg
input {
beats {
# 绑定主机 默认是0.0.0.0
host => "0.0.0.0"
port => 5044
# 额外添加字段,区分来自哪一个插件
add_field => {"[fields][class]" => "Logst-beats"}
}
}
output {
if [fields][pipe][type] == "a-web-logs" {
pipeline { send_to => aweblogs }
} else if [fields][pipe][type] == "b-web-logs" {
pipeline { send_to => bweblogs }
} else {
pipeline { send_to => defaultlogs }
}
}
a-input.cfg/b-input.cfg/default-pipeline.cfg(内部替换address和其他独立的处理逻辑)
input {
pipeline {
address => aweblogs
}
}
output {
elasticsearch {
hosts => ["https://es-single-node:9200"]
index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
}
}
- config目录中创建多管道管理文件pipelines.yml(此文件必须放在/usr/share/logstash/config/文件夹中,或挂载的宿主机的config目录中,否则启动Logstash时不会加载该管道配置),加载管道配置文件,之后增加管道重复这两步
# This file is where you define your pipelines. You can define multiple.
# For more information on multiple pipelines, see the documentation:
# https://www.elastic.co/guide/en/logstash/current/multiple-pipelines.html
# 类型隔离 使用docker容器内的绝对路径访问宿主机的pipeline挂载目录
- pipeline.id: logstash-base-pipeline
queue.type: persisted
path.config: "/usr/share/logstash/pipeline/logstash-base-pipeline.cfg"
- pipeline.id: a-input
queue.type: persisted
path.config: "/usr/share/logstash/pipeline/a-input.cfg"
- pipeline.id: b-input
queue.type: persisted
path.config: "/usr/share/logstash/pipeline/b-input.cfg"
- pipeline.id: default-pipeline
queue.type: persisted
path.config: "/usr/share/logstash/pipeline/default-pipeline.cfg"
- 修改配置文件权限,重启Logstash
docker restart logstash-server
使服务产出日志,然后再Kibana查看到新的日志。即为成功
日志流向:Beats -> Logstash -> Elasticsearch pipeline
Show with Kibana
4.1、配置管道过滤器(规范化日志)
修改pipeline目录中的filebeat-input.cfg中增加filter配置
以下针对不同日志的过滤配置,其他日志格式化参考类似即可
- 如日志信息为以下格式
Apr 26 12:20:02 localhost systemd[1]: Starting system activity accounting tool...
配置如下
# 提取字段和整理数据
filter {
dissect {
# message 拆分新属性名 格式(包含空格)对应原消息 即可进行自动匹配
mapping => { "message" => "%{ts} %{+ts} %{+ts} %{src} %{prog}[%{pid}]: %{msg}" }
}
date {
match => [ "timestamp" , "dd/MMM/yyyy:HH:mm:ss Z" ]
}
}
过滤之后的将具有以下属性
{
"msg" => "Starting system activity accounting tool...",
"@timestamp" => 2017-04-26T19:33:39.257Z,
"timestamp" => "26/Apr/2017:19:33:39 -0800",
"src" => "localhost",
"@version" => "1",
"host" => "localhost.localdomain",
"pid" => "1",
"message" => "Apr 26 12:20:02 localhost systemd[1]: Starting system activity accounting tool...",
"type" => "stdin",
"prog" => "systemd",
"ts" => "Apr 26 12:20:02"
}
- 实际输出的多行日志为一行,多行合一行处理,配置如下
进入Logstash容器安装multiline插件
# 进入容器
sudo docker exec -it logstash-server /bin/bash
# 安装插件
/usr/share/logstash/bin/logstash-plugin install logstash-filter-multiline
输出如下,安装成功
OpenJDK 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
Validating logstash-filter-multiline
Installing logstash-filter-multiline
/usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/bundler-1.17.3/lib/bundler/rubygems_integration.rb:200: warning: constant Gem::ConfigMap is deprecated
Installation successful
# 提取字段和整理数据
filter {
# 没匹配上这种正则开头的行,全部合并到匹配上正则的行里面作为一段
multiline {
pattern => "^\[\d{4}-\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2}:\d{1,2}"
# 匹配正则
negate => true
# 以正则形式的开头
what => "previous"
}
dissect {
# message 拆分新属性名 格式(包含空格)对应原消息 即可进行自动匹配
mapping => { "message" => "%{ts} %{+ts} %{+ts} %{src} %{prog}[%{pid}]: %{msg}" }
}
# 移出原message
mutate {
remove_field => ["message"]
}
}
- 如果具有键值对的日志格式
ip=1.2.3.4 error=REFUSED
配置如下
filter {
kv { }
}
过滤之后的将具有以下属性
ip: 1.2.3.4
error: REFUSED
- grok过滤器,对于如下日志
55.3.244.1 GET /index.html 15824 0.043
配置过滤器
filter {
grok {
match => { "message" => "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}" }
}
}
过滤之后的将具有以下属性
client: 55.3.244.1
method: GET
request: /index.html
bytes: 15824
duration: 0.043
- 修改后重启服务即可,在Kibana查看格式化之后的日志
四、进阶:部署TLS的ElasticSearch、Kibana集群(启用安全性)
如果想在正式环境使用安全功能(SSL),您必须为 Elasticsearch 传输层配置传输层安全 (TLS) 加密。
这样才可以使用角色+用户控制使用Kibana的权限,否则Kibana中获取的所有的数据就是公开的了,非常不安全
Kibana的安全相关功能前提也是要求开启TLS安全性才支持
集群配置TLS请见官网文档:Run in Docker with TLS enabled
- 图片来自Kibana官网
1、生成证书
- 在一个目录下创建以下配置文件
- instances.yml 标识您需要为其创建证书的实例。name是证书名,dns配置主机名和域名,ip配置服务器提供服务的IP,如果对外没有域名使用IP则包括外网IP。
- .env 设置环境变量以指定 Elasticsearch 版本和将创建 Elasticsearch 证书的位置。
- create-certs.yml 是一个 Docker Compose 文件,它启动一个容器来为 Elasticsearch 和 Kibana 生成证书。
instances.yml
instances:
- name: "es-single-node"
dns:
- "es-single-node"
- "localhost"
ip:
- "127.0.0.1"
- name: "kibana-server"
dns:
- "kibana-server"
- "localhost"
ip:
- "127.0.0.1"
- name: "logstash-server"
dns:
- "logstash-server"
- "localhost"
ip:
- "127.0.0.1"
.env
COMPOSE_PROJECT_NAME=es-cert
CERTS_DIR=/usr/share/elasticsearch/config/certificates
VERSION=7.14.0
create-certs.yml(这里默认使用pem生成CA,pkcs#12算法生成服务证书,后续都是用适配该算法的配置)
version: '2.2'
services:
create_certs:
image: docker.elastic.co/elasticsearch/elasticsearch:${VERSION}
container_name: es_create_certs
command: >
bash -c '
yum install -y -q -e 0 unzip;
if [[ ! -f /certs/ca.zip ]]; then
bin/elasticsearch-certutil ca --silent --pem -out /certs/ca.zip && unzip /certs/ca.zip -d /certs;
bin/elasticsearch-certutil cert --silent --ca-cert /certs/ca/ca.crt --ca-key /certs/ca/ca.key --in config/certificates/instances.yml -out /certs/bundle.zip --pass testpassword;
unzip /certs/bundle.zip -d /certs;
fi;
chown -R 1000:0 /certs
'
working_dir: /usr/share/elasticsearch
volumes:
# 目录下创建的的一个文件夹挂载,生成的证书保存的位置
- ./certs:/certs
# 当前目录挂载,需要读取当亲目录的配置文件及环境变量
- .:/usr/share/elasticsearch/config/certificates
# 之前使用的网络
networks:
- elastic-clus-networks
networks:
elastic-clus-networks:
name: elastic-clus-networks
- 启动create-certs容器为 Elasticsearch 生成证书
docker-compose -f create-certs.yml up
等待一会,输出如下,即为成功
Starting es_create_certs ... done
Attaching to es_create_certs
es_create_certs | Archive: /certs/ca.zip
es_create_certs | creating: /certs/ca/
es_create_certs | inflating: /certs/ca/ca.crt
es_create_certs | inflating: /certs/ca/ca.key
es_create_certs | Archive: /certs/bundle.zip
es_create_certs | creating: /certs/es-single-node/
es_create_certs | inflating: /certs/es-single-node/es-single-node.p12
es_create_certs | creating: /certs/kibana-server/
es_create_certs | inflating: /certs/kibana-server/kibana-server.p12
es_create_certs | creating: /certs/logstash-server/
es_create_certs | inflating: /certs/logstash-server/logstash-server.p12
es_create_certs exited with code 0
删除es_create_certs容器,因为这里有自动运行,避免启动后自动执行带来不便
docker rm es_create_certs
本地certs目录中会有如下文件,每个文件夹中有个.p12的文件(这个文件中包含了CA、节点证书、节点密钥)
这里的ca就是所有证书的本地证书颁发机构 (CA),之后生成的证书,都要使用该CA证书及密钥创建服务证书,使服务的证书配置一致,避免验证发生错误
2、配置ElasticSearch的TLS
- 修改ElasticSearch配置文件,增加如下配置
xpack.license.self_generated.type: "trial"
xpack.security.enabled: true
# 客户端配置
xpack.security.http.ssl.enabled: true
# pkcs 12
xpack.security.http.ssl.keystore.password: "testpassword"
xpack.security.http.ssl.keystore.path: "/usr/share/elasticsearch/config/certificates/es-single-node.p12"
xpack.security.http.ssl.truststore.password: "testpassword"
xpack.security.http.ssl.truststore.path: "/usr/share/elasticsearch/config/certificates/es-single-node.p12"
# 节点间配置
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: "certificate"
# pkcs 12
xpack.security.transport.ssl.keystore.password: "testpassword"
xpack.security.transport.ssl.keystore.path: "/usr/share/elasticsearch/config/certificates/es-single-node.p12"
xpack.security.transport.ssl.truststore.password: "testpassword"
xpack.security.transport.ssl.truststore.path: "/usr/share/elasticsearch/config/certificates/es-single-node.p12"
- 前文搭建ElasticSearch服务的时候,在ElasticSearch本地的certs目录已经挂载到容器中的/usr/share/elasticsearch/config/certificates目录,所以修改配置文件ssl后,将证书放在ElasticSearch本地的certs中
- 现在将刚刚生成证书的certs文件夹中的es-single-node文件夹的p12复制到本地ElasticSearch的certs目录中,修改权限
cp es-single-node/es-single-node.p12 ~/elasticsearch本地目录/certs/
sudo chmod -R 777 ~/elasticsearch本地目录/certs/
- 如果目录结构和我不一样,只要和容器挂载的一致即可
- 重启ElasticSearch
docker restart es-single-node
-
验证服务是否正常
访问https://IP:9200/,应提示如下,则说明ElasticSearch的SSL配置成功
-
运行该elasticsearch-setup-passwords工具为所有内置用户(包括kibana_system用户)生成密码
docker exec es-single-node /bin/bash -c "bin/elasticsearch-setup-passwords auto --batch --url https://es-single-node:9200"
得到如下输出,则说明生成密码成功,记住这些密码,可以使用kibana_system用户登录ElasticSearch的页面
3、配置Kibana的TLS
- 修改Kibana配置文件,增加如下配置
# ElasticSearch安全配置
elasticsearch.username: "kibana_system"
elasticsearch.password: "kibana_system的密码"
elasticsearch.ssl.keystore.path: "/usr/share/kibana/certificates/kibana-server.p12"
elasticsearch.ssl.keystore.password: "testpassword"
elasticsearch.ssl.truststore.path: "/usr/share/kibana/certificates/kibana-server.p12"
elasticsearch.ssl.truststore.password: "testpassword"
# Kibana客户端安全配置
server.ssl.enabled: "true"
server.ssl.keystore.path: "/usr/share/kibana/certificates/kibana-server.p12"
server.ssl.keystore.password: "testpassword"
server.ssl.truststore.path: "/usr/share/kibana/certificates/kibana-server.p12"
server.ssl.truststore.password: "testpassword"
# 需要设置32个字符以上
"xpack.encryptedSavedObjects.encryptionKey": "kibana-encryptedSavedObjects-encryptionKey-32"
# 任意文本字符串
"xpack.reporting.encryptionKey": "kibana-reporting-encryptionKey"
# 需要设置32个字符以上
"xpack.security.encryptionKey": "kibana-security-encryptionKey-32"
修改原配置中的http为https
"elasticsearch.hosts": ["https://es-single-node:9200"]
- 前文搭建Kibana服务的时候,在Kibana本地的certs目录已经挂载到容器中的/usr/share/kibana/certificates目录,所以修改配置文件ssl后,将证书放在Kibana本地的certs中
- 现在将刚刚生成证书的certs文件夹中的kibana-server文件夹的p12复制到本地Kibana的certs目录中,修改权限
cp kibana-server/kibana-server.p12 ~/Kibana本地目录/certs/
sudo chmod -R 777 ~/Kibana本地目录/certs/
- 如果目录结构和我不一样,只要和容器挂载的一致即可
- 重启Kibana
docker restart kibana-server
使用https协议访问Kibana,验证SSL配置,如下即为成功(目前只能使用生成密码中最大权限的elastic用户登录Elastic)
现在Filebeat和Logstash一定是访问不到ElasticSearch和Kibana了,因为有密码了,所以还要继续配置,否则无法收集配置
4、配置Logstash的TLS
- 配置用户
-
在Kibana管理中创建角色logstash_writer,配置如图(能够管理索引模板、创建索引以及在它创建的索引中写入和删除文档。),如果您使用自定义 Logstash 索引模式,请指定索引自定义模式而不是默认logstash-*模式
-
在Kibana管理中创建角色logstash_reader,配置如图(授予用户访问 Logstash 索引的权限),如果您使用自定义 Logstash 索引模式,请指定索引自定义模式而不是默认logstash-*模式
-
在Kibana管理中创建具有logstash_admin、logstash_writer角色的用户logstash_admin_user
- 修改Logstash
- 前文搭建Logstash服务的时候,在Logstash本地的certs目录已经挂载到容器中的/usr/share/logstash/certificates目录,所以修改配置文件ssl后,将证书放在Logstash本地的certs中
- 现在将刚刚生成证书的certs文件夹中的logstash-server、ca文件夹复制到本地Logstash的certs目录中,修改权限
logstash 不能够直接使用 PKCS#12类型的证书!!!
logstash 不能够直接使用 PKCS#12类型的证书!!!
logstash 不能够直接使用 PKCS#12类型的证书!!!
所以要从.p12 的证书中提取pem类型的信息,并生成PKCS#8的私钥 + ca证书的形式
cp logstash-server/logstash-server.p12 ~/Logstash本地目录/certs/
cp -R ca ~/Logstash本地目录/certs/
# 从.p12 的证书中提取密钥对等信息
openssl pkcs12 -in logstash-server.p12 -out logstash-server.pem
# 提示输入密码 输入testpassword即可,还会要求设置PEM格式文件的密码
# 拆分得到证书
openssl x509 -in logstash-server.pem -out logstash-server.crt
# 拆分得到私钥
openssl rsa -in logstash-server.pem -out logstash-server.key
# 提示输入密码 输入testpassword即可
# RSA算法pkcs8模式补足 转化为pk8的私钥
openssl pkcs8 -topk8 -inform PEM -in logstash-server.key -outform PEM -out logstash-server.key.pk8
# 提示设置文件的密码
# 会看到多以下文件
logstash-server.pem
logstash-server.crt # Logstash使用的ssl证书文件
logstash-server.key
logstash-server.key.pk8 # Logstash使用的私钥文件
# 修改目录权限
sudo chmod -R 777 ~/Logstash本地目录/certs/
如果目录结构和我不一样,只要和容器挂载的一致即可
- 编辑配置文件logstash.yml,修改以下
# 修改http为https
xpack.monitoring.elasticsearch.hosts: [ "https://es-single-node:9200" ]
- logstash.yml新增以下
xpack.monitoring.enabled: true
# Logstash 集中管道管理凭据
xpack.management.elasticsearch.username: logstash_admin_user
xpack.management.elasticsearch.password: 创建的密码
# Logstash监控 数据凭据
xpack.monitoring.elasticsearch.username: logstash_system
xpack.monitoring.elasticsearch.password: ElasticSearch中生成的密码
xpack.monitoring.elasticsearch.ssl.verification_mode: certificate
xpack.monitoring.elasticsearch.ssl.certificate_authority: "/usr/share/logstash/certificates/ca/ca.crt"
- 编辑pipeline中的管道文件filebeat-input.cfg
input {
beats {
host => "0.0.0.0"
port => "5044"
codec => plain {
charset => "UTF-8"
}
# 额外添加字段,区分来自哪一个插件
add_field => {"[fields][class]" => "beats"}
ssl => true
ssl_certificate_authorities => ["/usr/share/logstash/certificates/ca/ca.crt"]
ssl_certificate => "/usr/share/logstash/certificates/logstash-server.crt"
ssl_key => "/usr/share/logstash/certificates/logstash-server.key.pk8"
ssl_key_passphrase => "testpassword"
ssl_verify_mode => "force_peer"
}
}
output{
elasticsearch {
# http改为https
hosts => ["https://es-single-node:9200"]
index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
# 对请求启用 gzip 压缩
http_compression => true
ssl => true
user => "elastic"
password => "elastic密码"
cacert => "/usr/share/logstash/certificates/ca/ca.crt"
}
}
- 重启Logstash
docker restart logstash-server
- Logstash服务验证
访问http://IP:9600查看是否启动成功,得到如下信息为成功,因为9600没有配置SSL所以还是用http
{"host":"c70f0aac16ef","version":"7.14.0","http_address":"0.0.0.0:9600","id":"649f16ab-……
验证5044端口的SSL服务是否正常
curl -v --cacert certs/ca/ca.crt --cert certs/logstash-server.crt --key certs/logstash-server.key.pk8 https://127.0.0.1:5044
响应如下说明成功(之后Filebeat使用同样的方式使用TLS)
* About to connect() to 127.0.0.1 port 5044 (#0)
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 5044 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: certs/logstash-server-ca.crt
CApath: none
* NSS: client certificate from file
* subject: CN=logstash-server
* start date: Aug 31 09:57:29 2021 GMT
* expire date: Aug 30 09:57:29 2024 GMT
* common name: logstash-server
* issuer: CN=Elastic Certificate Tool Autogenerated CA
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
* subject: CN=logstash-server
* start date: Aug 31 09:57:29 2021 GMT
* expire date: Aug 30 09:57:29 2024 GMT
* common name: logstash-server
* issuer: CN=Elastic Certificate Tool Autogenerated CA
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:5044
> Accept: */*
>
* Empty reply from server
* Connection #0 to host 127.0.0.1 left intact
curl: (52) Empty reply from server
5、配置Filebeat的TLS
修改Filebeat的连接ElasticSearch或者Logstash的配置为SSL
- 生成Filebeat服务器用的证书
Filebeat服务器的证书,每次都要生成专用的,因为证书需要设置主机的hostname,假设运行Filebeat服务的hostname为filebeat-host
使用ElasticSearch镜像运行一个临时生成证书的容器
docker run -it --net elastic-clus-networks -v /本地存放证书的目录/certs:/certs --name create_filebeat_certs docker.elastic.co/elasticsearch/elasticsearch:7.14.0 /bin/bash
已有就直接进入容器
docker start create_filebeat_certs
docker exec -it create_filebeat_certs /bin/bash
启动会直接进入容器内终端
[root@ecfe35a16648 elasticsearch]#
容器的证书目录还是挂载本地的certs,执行以下命令生成证书
- 使用创建ELK证书时导出保存的CA根证书创建新的服务证书和私钥,因为服务配置了证书鉴权验证,所以以后所有使用TLS安全访问的服务,certificate_authorities参数都需要以统一的CA根证书,新生成服务的证书也要依据该CA根证书生成
- 注意修改–ca-cert <file_path> 指定现有 CA 证书的路径(采用 PEM 格式)、–ca-key <file_path> 指定现有 CA 私钥的路径(PEM 格式)、–name(证书名)、–dns(主机hostname,多个以逗号分隔)、–ip(主机IP,多个以逗号分隔)、-out(输出证书文件路径,建议以p12为扩展名,并且在certs目录中,否则回到宿主机就看不到了)、–pass(建议证书的加密密码,如果不需要就是用空字符串"")
- 注意:本地用来保存生成证书的certs目录,读取权限设置
sudo chmod -R 777 certs
#生成证书文件,文件中包含CA、证书、私钥
bin/elasticsearch-certutil cert --silent --ca-cert /certs/ca/ca.crt --ca-key /certs/ca/ca.key -pem --name filebeatCrtName --dns filebeat.com --ip 192.168.7.1 -out /certs/filebeatCrtName.zip --pass testpassword && unzip /certs/filebeatCrtName.zip -d /certs
#退出容器
exit
- 本地certs目录中刚刚创建的证书和ca放到运行Filebeat的服务器中,用于证书配置
Archive: /certs/filebeatCrtName.zip
creating: /certs/filebeatCrtName/
inflating: /certs/filebeatCrtName/filebeatCrtName.crt
inflating: /certs/filebeatCrtName/filebeatCrtName.key
- 在Filebeat服务器创建certs目录,存放创建的证书,修改certs目录的权限为775
chmod -R 775 certs
- 修改配置文件filebeat.yml
setup.kibana:
host: "https://Kibana-IP:5601"
username: "beats_system"
password: "beats_system的密码"
ssl.enabled: true
ssl.certificate_authorities: ["/本地证书目录/ca/ca.crt"]
ssl.certificate: "/本地证书目录/filebeatCrtName.crt"
ssl.key: "/本地证书目录/filebeatCrtName.key"
# 证书密码
ssl.key_passphrase: "testpassword"
# 如果使用ElasticSearch,如下,使用Logstash就将ElasticSearch配置注释掉,只能留一个输出
output.elasticsearch:
hosts: ["elasticsearch-IP:9200"]
protocol: "https"
username: "elastic"
password: "elastic的密码"
ssl.certificate_authorities: ["/本地证书目录/ca/ca.crt"]
ssl.certificate: "/本地证书目录/filebeatCrtName.crt"
ssl.key: "/本地证书目录/filebeatCrtName.key"
# 证书密码
ssl.key_passphrase: "testpassword"
# 使用logstash,如下,使用ElasticSearch就将Logstash配置注释掉,只能留一个输出
output.logstash:
hosts: ["logstash-IP:5044"]
index: "test-beat"
ssl.certificate_authorities: ["/本地证书目录/ca/ca.crt"]
ssl.certificate: "/本地证书目录/filebeatCrtName.crt"
ssl.key: "/本地证书目录/filebeatCrtName.key"
# 证书密码
ssl.key_passphrase: "testpassword"
- 重启Filebeat
启动日志显示如下,说明连接Logstash成功
pipeline/output.go:151 Connection to backoff(async(tcp://192.168.10.7:5044)) established
使用服务产生日志,在Kibana查看即可,右下角也不会提醒数据不安全了,以及需要安全支持的服务也可以使用了,Kibana还有很多功能,逐渐探索吧!!!
Successful
The Elastic Stack的全局的TLS就构建完成了,可以放心使用了,完美竣工!!!