手把手系列 - 搭建 efk 8 收集 docker 容器日志
目录
- Docker容器最佳实践
- 手把手系列 - 搭建 EFK 7 收集 docker 容器日志
- 手把手系列 - 搭建 EFK 8 收集 docker 容器日志
- 手把手系列 - 使用docker容器搭建efk8
前言
查看网络上真正搭建使用 efk 8.0 版本的并不多,于是本文记录搭建过程。
本文书写时间:2022-07-01 以 8.2.2 搭建一套 docker 容器的日志收集系统。
elasticsearch: 8.2.2
filebeat: 8.2.2
kibana: 8.2.2
阅读本文前,请对 docker 日志有个正确的认识,请参考:
系统版本
System: CentOS Linux release 7.9.2009 (Core)
Kernel: 3.10.0-1160.el7.x86_64
要求:主机可访问互联网,本文采用 yum 安装。
注意:'>' 为命令输入提示符 '>' 后为输入的命令
docker 版本
Docker-CE
* Server Version: 20.10.7
* Storage Driver: overlay2
安装过程
主机名 | ip地址 |
---|---|
efk-node | 192.168.1.101 |
安装顺序如下:
- 系统初始化
- docker-ce-20.10.7
- elasticsearch-8.2.2
- kibana-8.2.2
- filebeat-8.2.2
系统初始化
系统初始化分为以下几步:
- 修改主机名
- 关闭selinux 和 firewalld
- 配置国内yum源
- 校对时间
修改主机名
>hostnamectl set-hostname efk-node
>hostname efk-node
>echo "192.168.1.101 efk-node" >> /etc/hosts
#断开会话重新连接
root@efk-node(192.168.1.101)/root>hostname
efk-node
关闭selinux 和 firewalld
### 关闭 selinux
>sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
>systemctl disable firewalld
>reboot
配置国内yum源
>cd /etc/yum.repos.d/
#centos-7源
>curl http://mirrors.aliyun.com/repo/Centos-7.repo -o ./Centos-7.repo
>sed -i '/aliyuncs/d' Centos-7.repo
#docker-ce源
>curl http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -o ./docker-ce.repo
#epel-7源
>curl http://mirrors.aliyun.com/repo/epel-7.repo -o ./epel-7.repo
#efk源
>cat << EOF > elasticstack.repo
[elasticstack]
name = elasticstack
gpgcheck = 0
baseurl = https://mirrors.tuna.tsinghua.edu.cn/elasticstack/yum/elastic-8.x/
EOF
校对时间
>yum install -y ntpdate
>ntpdate tiger.sina.com.cn
Docker-ce
- 安装docker-ce
>yum install -y docker-ce
- 添加docker-ce 配置
>mkdir /etc/docker/
>cat << 'EOF' > /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"exec-opts": ["native.cgroupdriver=systemd"],
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
],
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
EOF
- 启动 docker
systemctl enable docker; systemctl start docker
查看docker 信息
>cat << 'EOF' >> /etc/sysctl.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
>sysctl --system
>docker info
Elasticsearch
Elasticsearch是个开源分布式搜索引擎,提供搜集、分析、存储数据三大功能。
- 安装elasticsearch
yum install -y elasticsearch-8.2.2
安装 elasticsearch 时候会出现如下提示:
注意:这里用户名为:elastic ,密码可以修改,但是这里最好也记录一下。
用户名:elastic
密 码:j7CopSyDuOGhan*ZmI*u
- 修改默认配置文件
>cd /etc/elasticsearch/
# 修改操作前,一定要做好源文件的备份
>cp -a elasticsearch.yml elasticsearch.yml.orig
# 修改后的配置文件
>egrep -v "^#|^$" elasticsearch.yml
path.data: /var/lib/elasticsearch //es数据存储目录
path.logs: /var/log/elasticsearch //es日志存储目录
network.host: 192.168.1.101 //es监听地址
http.port: 9200 //es端口
### 这两项需要配置,否则启动会报错 ###
discovery.seed_hosts: ["efk-node"] // 配置候选节点通信
### 开启x-pack 安全功能 及 https 功能
xpack.security.enabled: true
xpack.security.enrollment.enabled: true
xpack.security.http.ssl: //启用https
enabled: true
keystore.path: certs/http.p12
xpack.security.transport.ssl: //
enabled: true
verification_mode: certificate
keystore.path: certs/transport.p12
truststore.path: certs/transport.p12
cluster.initial_master_nodes: ["efk-node"] // 集群初始化提供master地址
http.host: 0.0.0.0
### 解决跨越问题 ###
http.cors.enabled: true
http.cors.allow-origin: "*"
- 启动elasticsearch
systemctl enable elasticsearch; systemctl start elasticsearch
启动完成后,elasticsearch会监听 9200 和 9300
>netstat -ntplu | egrep java
tcp6 0 0 192.168.1.101:9200 :::* LISTEN 4305/java
tcp6 0 0 192.168.1.101:9300 :::* LISTEN 4305/java
在 elasticsearch-8.2.2 中,无法使用 http 访问, 需要使用: https://192.168.1.101:9200/
Kibana
Kibana 也是一个开源和免费的工具,Kibana可以为 Logstash 和 ElasticSearch 提供的日志分析友好的 Web 界面,可以帮助汇总、分析和搜索重要数据日志。
- 安装 kibana
>yum install -y kibana-8.2.2
- 修改 kibana 配置文件
>egrep -v "^#|^$" kibana.yml
server.port: 5601 # 端口
server.host: "0.0.0.0" # 监听端口
elasticsearch.hosts: ["http://localhost:9200"] # es链接
logging:
appenders:
file:
type: file
fileName: /var/log/kibana/kibana.log
layout:
type: json
root:
appenders:
- default
- file
pid.file: /run/kibana/kibana.pid
i18n.locale: "zh-CN" # 汉化
- 启动 kibana
> systemctl enable kibana ; systemctl start kibana
kibana监听地址默认为:5601
>netstat -ntplu | egrep 5601
tcp 0 0 0.0.0.0:5601 0.0.0.0:* LISTEN 5784/node
- 通过浏览器访问
在centos7上获取命令如下:
> /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibana
执行以后,将 token 复制到【注册令牌】中。
点击 【配置 Elastic】 后,会跳出验证码:
查看 kibana 验证码:
输入验证码后,等待 kibana 验证完毕
完成后,出现登录界面
用户名密码就是安装 elasticsearch 生成的用户名密码:
用户名:elastic
密 码:j7CopSyDuOGhan*ZmI*u
Filebeat
- 安装 filebeat
>yum install -y filebeat-8.2.2
到此,所有安装的软件包都已经安装就位,接下来就是配置的修改及调整。所有软件包如下:
> rpm -qa | egrep "docker-ce|elasticsearch|kibana|filebeat"
elasticsearch-8.2.2-1.x86_64
filebeat-8.2.2-1.x86_64
docker-ce-20.10.7-3.el7.x86_64
kibana-8.2.2-1.x86_64
docker-ce-cli-20.10.7-3.el7.x86_64
docker-ce-rootless-extras-20.10.7-3.el7.x86_64
配置调试过程
本次以收集 nginx 容器日志为例,进行调试配置。
- 编写收集容器日志的 filebeat 配置文件
### 一定要在 /etc/filebeat/ 目录下编写配置文件,否则无法使用调试模式启动。
>cd /etc/filebeat/
在编写 filebeat 配置文件之前,得了解下 filebeat 配置文件结构,强烈建议参考官方文档:
https://www.elastic.co/guide/en/beats/filebeat/8.2/directory-layout.html
通过目录,可以简单理解,filebeat 分为 inputs 和 output 两部分,首先查看 inputs
对比 7.14 版本的 filebeat,在8.2.2中已经弃用了 docker 模块,只能使用 container
这里有直接的配置示例,直接抄写即可。
接下来,查看 output 部分。
因为,我们处于配置调试节点,所以将日志收集直接打印在控制台展示,如果觉得数据没问题,再进行配置到 elasticsearch 中,所以这里直接查看 Console
直接抄写 output 配置
综上,目前的 filebeat 配置文件如下:
>cat /etc/filebeat/docker-nginx.yml
filebeat.inputs:
- type: container
paths:
- '/var/lib/docker/containers/*/*.log'
output.console:
pretty: true
通过 filebeat 调试模式启动。
/etc/filebeat> filebeat -e -c docker-nginx.yml
既然要收集 nginx 容器的日志,就得有 nginx 容器,这里启动 nginx 容器
>docker run --name ngx -p 80:80 -d nginx:alpine
当容器启动成功后,filebeat 控制台就会打印如下信息日志:
{
"@timestamp": "2022-07-06T09:54:34.861Z",
"@metadata": {
"beat": "filebeat",
"type": "_doc",
"version": "8.2.2"
},
"host": {
"name": "efk-node"
},
"agent": {
"ephemeral_id": "21665b96-2ac4-4213-ae68-5be81c505ef9",
"id": "90fe1004-6c5c-4755-9372-a154c57bf136",
"name": "efk-node",
"type": "filebeat",
"version": "8.2.2"
},
"ecs": {
"version": "8.0.0"
},
"log": {
"offset": 2444,
"file": {
"path": "/var/lib/docker/containers/4c4e1811670c5745ad1307bf21ddfec7e63dd140388a012c07729da2308c2375/4c4e1811670c5745ad1307bf21ddfec7e63dd140388a012c07729da2308c2375-json.log"
}
},
"stream": "stderr",
"message": "2022/07/06 09:54:34 [notice] 1#1: start worker process 36",
"input": {
"type": "container"
}
}
出现这样的信息,说明filebeat 已经捕获到了 容器的日志信息
接下来就要对日志信息进行筛选,大段的日志信息有很多我们并不需要过多的去关注,因此需要剔除无用的信息,继续查看官方文档:
在上面除了,Input 和 output 还有一个 Processors 处理器,这个 Processors 也可以理解为 filter ,筛选器
在 Processors 子类中,找到了 drop_fields 删除字段配置,打开查看。
通过官方示例查看,when 当...时候... 这里就是通过条件筛选进行字段的删除,目前我们这里没有条件筛选,尝试直接删除字段。
注意:通过官方文档查看 processors 是与 input 和 output 平级的,所以注意格式。
于是,配置文件又修改为如下:
# /etc/filebeat/docker-nginx.yml
filebeat.inputs:
- type: container
paths:
- '/var/lib/docker/containers/*/*.log'
processors:
- drop_fields:
fields: ["log","agent","ecs"]
output.console:
pretty: true
在刚才的控制台 ctrl + c 结束,重新启动
>filebeat -e -c docker-nginx.yml
浏览器访问 nginx 后,查看控制台:
{
"@timestamp": "2022-07-06T10:05:49.917Z",
"@metadata": {
"beat": "filebeat",
"type": "_doc",
"version": "8.2.2"
},
"stream": "stdout",
"message": "192.168.1.2 - - [06/Jul/2022:10:05:49 +0000] \"GET / HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36\" \"-\"",
"input": {
"type": "container"
},
"host": {
"name": "efk-node"
}
}
到目前为止,已经提取出来对我们有用的日志信息,接下来就可以存储到 elasticsearch 中,查看官方文档如何存储到 es 中。
在 8 的版本中, elasticsearch 采用https 并开启了用户认证,这是区别 7 版本唯一的不同。官方文档也是采用三种不同的形式进行认证。
通过查证,可使用如下方式写入 elasticsearch :
output.elasticsearch:
hosts: ["https://[ES地址]:9200"]
ssl.verification_mode: "none"
username: "elastic"
password: "[密码]"
结合之前 filebeat 配置文件:
### /etc/filebeat/docker-nginx.yml
filebeat.inputs:
- type: container
paths:
- '/var/lib/docker/containers/*/*.log'
processors:
- drop_fields:
fields: ["log","agent","ecs"]
#output.console:
# pretty: true
output.elasticsearch:
hosts: ["https://192.168.1.101:9200"]
ssl.verification_mode: "none"
username: "elastic"
password: "j7CopSyDuOGhan*ZmI*u"
### 加入以下内容,output.elasticsearch.index 才会生效
setup.ilm.enabled: false # 关闭索引生命周期
setup.template.enabled: false # 允许自动生成index模板
setup.template.overwrite: true # 如果存在模块则覆盖
#setup.template.name: "docker" # 生成index模板的名称
#setup.template.pattern: "docker-*" # 生成index模板匹配的index格式
重启控制台
ctrl+c
>filebeat -e -c docker-nginx.yml
浏览器访问 nginx 容器生成日志,然后浏览器查看 es 中所有索引信息
我们通过 filebeat 存储进去的日志信息。这个索引名怎么看怎么奇怪,因为存储的是nginx 容器的日志,所以做好将索引名修改为 nginx 相关的名字,这样就可以通过索引名确定存储的数据信息。
修改 配置文件如下:
### /etc/filebeat/docker-nginx.yml
filebeat.inputs:
- type: container
paths:
- '/var/lib/docker/containers/*/*.log'
processors:
- drop_fields:
fields: ["log","agent","ecs"]
# output.console:
# pretty: true
output.elasticsearch:
hosts: ["https://192.168.1.101:9200"]
ssl.verification_mode: "none"
username: "elastic"
password: "j7CopSyDuOGhan*ZmI*u"
index: "docker-nginx-%{+yyyy.MM.dd}"
### 加入以下内容,output.elasticsearch.index 才会生效
setup.ilm.enabled: false # 关闭索引生命周期
setup.template.enabled: false # 允许自动生成index模板
setup.template.overwrite: true # 如果存在模块则覆盖
#setup.template.name: "docker" # 生成index模板的名称
#setup.template.pattern: "docker-*" # 生成index模板匹配的index格式
重启控制台
>filebeat -e -c docker-nginx.yml
浏览器访问后,查看索引
这里生成了 docker-nginx-* 索引
接下来就可以通过 kibana 展示出来。
这样就将 nginx 容器的日志信息收集展示出来了。
进阶配置过程
现在的数据就简化了很多,只保留对我们有用的信息。接下来就要考虑几个问题
-
nginx 日志分为 access.log 和 error.log 如何区分存储?
-
如果多个容器如果区分不同的容器日志?
stdout 及 stderr 存入不同索引
对于 nginx来说,可能只需要关注 错误日志,如何区分存储呢?其实查看上面控制台输出的日志内容不难发现一个字段:stream
{
"@timestamp": "2022-06-30T07:42:33.163Z",
"@metadata": {
"beat": "filebeat",
"type": "_doc",
"version": "7.17.5"
},
"input": {
"type": "container"
},
"host": {
"name": "efk-node"
},
"stream": "stdout", //这个字段
"message": "..."
}
其实对于 nginx 这样的容器,遵循一个标准,标准输出到 stdout 标准错误输出到 stderr 可进入容器查看:
~ # ls -l /var/log/nginx/
total 0
lrwxrwxrwx 1 root root 11 Jun 22 19:20 access.log -> /dev/stdout
lrwxrwxrwx 1 root root 11 Jun 22 19:20 error.log -> /dev/stderr
所以,对于 stream: stderr 就是需要关注的 错误日志,所以根据字段条件进行区分,修改 filebeat 配置文件如下:
### /etc/filebeat/docker-nginx.yml
filebeat.inputs:
- type: container
paths:
- '/var/lib/docker/containers/*/*.log'
processors:
- drop_fields:
fields: ["log","agent","ecs"]
# output.console:
# pretty: true
output.elasticsearch:
hosts: ["https://192.168.1.101:9200"]
ssl.verification_mode: "none"
username: "elastic"
password: "j7CopSyDuOGhan*ZmI*u"
indices:
- index: "docker-nginx-access-%{+yyyy.MM.dd}"
when.contains:
stream: "stdout"
- index: "docker-nginx-error-%{+yyyy.MM.dd}"
when.contains:
stream: "stderr"
### 加入以下内容,output.elasticsearch.index 才会生效
setup.ilm.enabled: false # 关闭索引生命周期
setup.template.enabled: false # 允许自动生成index模板
setup.template.overwrite: true # 如果存在模块则覆盖
#setup.template.name: "docker" # 生成index模板的名称
#setup.template.pattern: "docker-*" # 生成index模板匹配的index格式
根据了不同的条件存入不不同的索引中,这样可以通过 kibana 来展示出来。
这样, 就可以通过不同的索引展示各种所需日志数据。
总结
该部分解决的问题是:单容器,正常日志和错误日志分类存放的问题。
多容器及不同业务之间的日志汇集需要看下一个部分。
不同业务容器存入不同索引
容器使用场景,肯定会存在不同的程序或者不同的业务都运行于容器当中。举个最简单的架构 lnmp ,nginx 和 php 的日志如果存储在同一个索引里,日后查询排错还不如直接查看源日志文件,这就违背了搭建日志收集系统的初衷。
通过上面 filebeat 中 inputs 可以看到是 通过解析容器日志目录来获取日志信息的,而容器的名称和ID 都会随着生命周期而变动的,因此无法像物理或者虚拟主机一样通过IP联系起来。这个时候就需要为容器打标签,通过打标签的形式区分不同业务的容器集合。
注意:做这一部分示例前,请将运行中的容器关闭并删除、关闭 filebeat
docker rm -f `docker ps -aq`
systemctl stop filebeat
为容器打标签
- docker 直接启动打标签
docker run --name nginx -p 80:80 --label service=nginx --log-opt labels=service -d nginx:alpine
- 通过docker-compose 打标签
### docker-compose.yml
version: "3"
services:
nginx:
container_name: "nginx"
image: nginx:alpine
environment:
- "TZ=Asia/Shanghai"
labels:
service: nginx
logging:
options:
labels: "service"
ports:
- "80:80"
上面两种方式,任意执行一种。
通过浏览器访问 http://192.168.1.101/ , 查看容器日志:
>tail -1 /var/lib/docker/containers/b066871ed799d21c3633341ec15dcfdc712067b483b7a4c7e3b3f909cf380940/b066871ed799d21c3633341ec15dcfdc712067b483b7a4c7e3b3f909cf380940-json.log | jq
{
"log": "192.168.1.2 - - [01/Jul/2022:01:51:17 +0000] \"GET / HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36\" \"-\"\n",
"stream": "stdout",
"attrs": {
"service": "nginx"
},
"time": "2022-07-01T01:51:17.717295543Z"
}
日志中多有 attrs 属性字段,就是打的标签,然后可通过 filebeat output 中 when 条件来过滤。
示例:
需求:有两个不同的 web 服务, 一个开启80端口,一个开启 8080 端口,需要对它们日志存储到不同的索引里。
这里使用 docker-compose 启动容器,docker-compose如下:
### /root/manifests/docker-compose.yml
version: "3"
services:
# 80 web 服务
nginx:
container_name: "nginx"
image: nginx:alpine
environment:
- "TZ=Asia/Shanghai"
labels:
service: nginx # 标记
logging:
options:
labels: "service"
ports:
- "80:80"
# 8080 web 服务
httpd:
container_name: "httpd"
image: httpd:latest
environment:
- "TZ=Asia/Shanghai"
labels:
service: httpd # 标记
logging:
options:
labels: "service"
ports:
- "8080:80"
使用 dokcer-compose 启动
>docker-compose up -d
>docker-compose ps
NAME COMMAND SERVICE STATUS PORTS
httpd "httpd-foreground" httpd running 0.0.0.0:8080->80/tcp, :::8080->80/tcp
nginx "/docker-entrypoint.…" nginx running 0.0.0.0:80->80/tcp, :::80->80/tcp
然后编写 filebeat 配置文件:
#文件目录: /etc/filebeat/docker-compose-web.yml
filebeat.inputs:
- type: container
enabled: true
paths:
- '/var/lib/docker/containers/*/*.log'
processors:
- drop_fields:
fields: ["log","ecs","agent"]
output.elasticsearch:
hosts: ["https://192.168.1.101:9200"]
ssl.verification_mode: "none"
username: "elastic"
password: "j7CopSyDuOGhan*ZmI*u"
indices:
- index: "web-nginx-access-%{+yyyy.MM.dd}"
when.contains:
# 日志中包括 docker.attrs.service==nginx 且 stream=stdout 存入web-nginx-access-%{+yyyy.MM.dd}
docker.attrs.service: "nginx"
stream: "stdout"
- index: "web-nginx-error-%{+yyyy.MM.dd}"
when.contains:
# 日志中包括 docker.attrs.service==nginx 且 stream=stderr 存入web-nginx-error-%{+yyyy.MM.dd}
docker.attrs.service: "nginx"
stream: "stderr"
- index: "web-httpd-access-%{+yyyy.MM.dd}"
when.contains:
# 日志中包括 docker.attrs.service==httpd 且 stream=stdout 存入web-httpd-access-%{+yyyy.MM.dd}
docker.attrs.service: "httpd"
stream: "stdout"
- index: "web-httpd-error-%{+yyyy.MM.dd}"
when.contains:
# 日志中包括 docker.attrs.service==httpd 且 stream=stderr 存入web-httpd-error-%{+yyyy.MM.dd}
docker.attrs.service: "httpd"
stream: "stderr"
### 加入以下内容,output.elasticsearch.index 才会生效
setup.ilm.enabled: false # 关闭索引生命周期
setup.template.enabled: false # 允许自动生成index模板
setup.template.overwrite: true # 如果存在模块则覆盖
#setup.template.name: "docker" # 生成index模板的名称
#setup.template.pattern: "docker-*" # 生成index模板匹配的index格式
启动:
>cd /etc/filebeat
>filebeat -e -c docker-compose-web.yml
通过浏览器访问后,查看 索引
这里就通过不同的条件将不同业务不同类型的日志进行了分开存储,然后在 kibana 如上配置,就可以分类查看。