ELK日志采集服务搭建

配置环境:DOCKER ELK版本7.6.2

ELK简介:

ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana , 它们都是开源软件。新增了一个FileBeat,它是一个轻量级的日志收集处理工具(Agent),Filebeat占用资源少,适合于在各个服务器上搜集日志后传输给Logstash,官方也推荐此工具。

Elasticsearch 是个开源分布式搜索引擎,提供搜集、分析、存储数据三大功能。它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等。

Logstash 主要是用来日志的搜集、分析、过滤日志的工具,支持大量的数据获取方式。一般工作方式为c/s架构,client端安装在需要收集日志的主机上,server端负责将收到的各节点日志进行过滤、修改等操作在一并发往elasticsearch上去。

Kibana 是一个开源和免费的工具,Kibana可以为 Logstash 和 ElasticSearch 提供的日志分析友好的 Web 界面,可以帮助汇总、分析和搜索重要数据日志。

Filebeat(搜集文件数据)

搭建ELK服务的步骤为:

  1. 安装配置elasticsearch服务
  2. 安装配置kibana(管理es的可视化界面)
  3. 安装logstash
  4. 安装filebeat
  5. 配置nginx、kibana登录验证

安装elasticsearch服务

创建es挂载目录

mkdir  /app/elk/elasticsearch
mkdir /app/elk/elasticsearch/{data,plugins,config,logs}

创建并配置 vi /app/elk/elasticsearch/config/elasticsearch.yml

cluster.name: "logs-es"
network.host: 0.0.0.0
http.port: 9200

创建docker内网连接,同个内网中,可以通过容器名访问

docker network create elknet

运行docker容器 es运行内存可以适当改大

docker run --name es -p 9200:9200 -p 9300:9300 --restart=always \
--net elknet \
-e TAKE_FILE_OWNERSHIP=true --privileged=true \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms256m -Xmx256m" \
-v /app/elk/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /app/elk/elasticsearch/data:/usr/share/elasticsearch/data \
-v /app/elk/elasticsearch/logs:/usr/share/elasticsearch/logs \
-v /app/elk/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d docker.elastic.co/elasticsearch/elasticsearch:7.6.2

启动成功,访问http://ip:9200

安装kibana

创建kibana挂载目录

mkdir  /app/elk/kibana
mkdir  /app/elk/kibana/config

创建并配置 vi /app/elk/kibana/config/kibana.yml

server.name: kibana
server.host: "0.0.0.0"
elasticsearch.hosts: ["http://es:9200"]
xpack.monitoring.ui.container.elasticsearch.enabled: true
i18n.locale: "zh-CN"

docker 运行kibana

docker run --name kibana  -p 5601:5601 --restart=always \
-e TAKE_FILE_OWNERSHIP=true --privileged=true \
--net elknet \
--log-driver json-file \
--log-opt max-size=100m  \
--log-opt max-file=2 \
-v /app/elk/kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml \
-d docker.elastic.co/kibana/kibana:7.6.2

启动成功,访问http://ip:5601

安装logstash

创建logstash挂载文件

mkdir /app/elk/logstash
mkdir /app/elk/logstash/{conf.d,config}

创建并配置 /app/elk/logstash/config/logstash.yml

http.host: "0.0.0.0"
xpack.monitoring.elasticsearch.hosts: [ "http://es:9200" ]
path.config: /usr/share/logstash/conf.d/*.conf

创建并配置 vi /app/elk/logstash/conf.d/logstash.conf,正则匹配filebeat传过来的日志文件, 并输入到es中。注意:正则字符串不能换行,否则logstash可能匹配不到

input {
beats {
port => 5044
}
}
filter {
 if "[request " in [message]{
     grok{
         match => {
             "message" =>"%{TIMESTAMP_ISO8601:log_date} %{WORD:log_level} \s?\[%{USERNAME:log_service_name} %{USERNAME:log_trace_id} %{USERNAME:log_span_id}\] \[%{DATA:log_thread}\] %{JAVAFILE:logger_name} : \[%{WORD:log_request_response} %{USERNAME:log_session_id} %{IP:log_ip}\] \[%{USERNAME:log_app} %{USERNAME:log_version} %{USERNAME:log_from_service}\] \[(?<log_request_type>([A-Z]+)) %{PATH:log_url}\] %{GREEDYDATA:log_content}"  
                }
        overwrite => ["message"]
    }    
  }
  else if "[response " in [message]{
     grok{
         match => {
            "message" =>"%{TIMESTAMP_ISO8601:log_date} %{WORD:log_level} \s?\[%{USERNAME:log_service_name} %{USERNAME:log_trace_id} %{USERNAME:log_span_id}\] \[%{DATA:log_thread}\] %{JAVAFILE:logger_name} : \[%{WORD:log_request_response} %{USERNAME:log_session_id}\] \[(?<log_request_type>([A-Z]+)) %{PATH:log_url} %{INT:log_response_time}\] %{GREEDYDATA:log_content}"    
                }
         overwrite => ["message"]
     }     
  }
  else{
     grok{
         match => {
        "message" =>"%{TIMESTAMP_ISO8601:log_date} %{WORD:log_level} \s?\[%{USERNAME:log_service_name} %{USERNAME:log_trace_id} %{USERNAME:log_span_id}\] \[%{DATA:log_thread}\] %{JAVAFILE:logger_name} : %{GREEDYDATA:log_content}"   
            }
        overwrite => ["message"]
     }
  }
}
output {
  elasticsearch {
    hosts => ["http://es:9200"]
    index => "springboot_log_%{+YYYY-MM-dd}"
  }
}

docker运行logstash logstash内存可以适当改大

docker run -d --restart=always --name logstash -p 5044:5044 \
--net elknet  \
-e ES_JAVA_OPTS="-Xms256m -Xmx256m" \
-e TAKE_FILE_OWNERSHIP=true --privileged=true \
--log-driver json-file \
--log-opt max-size=100m \
--log-opt max-file=2 \
-v /app/elk/logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml \
-v /app/elk/logstash/conf.d/:/usr/share/logstash/conf.d/ \
-d docker.elastic.co/logstash/logstash:7.6.2

查看是否启动成功:docker logs logstash

安装filebeat

创建挂载文件 vi /app/elk/filebeat/filebeat.yml

filebeat.inputs:
- type: log
  enabled: true
  paths:
   - /xxxx/xxxx.log
   - /xxxxxxxx/xxxx.log
  multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}'
  multiline.negate: true
  multiline.match: after

output.logstash:
  hosts: ["logstash_host:5044"]

docker 启动filebeat,--hostname 主机名称,判断日志来自于台主机

docker run --restart=always --hostname hysz-ali-debug-web1 \
--name=filebeat --user=root  \
-v /app/elk/filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml \
-v /data0:/data0 \
-d docker.elastic.co/beats/filebeat:7.6.2 \
filebeat -e -strict.perms=false

配置nginx、kibana登录验证

kibana配置登录验证方式①

使用httpd-tools 工具生成密钥验证

安装httpd-tools

yum install httpd-tools

创建密钥文件

mkdir /etc/nginx/passwd

生成密钥文件

htpasswd -c -b /etc/nginx/passwd/kibana.passwd 登录用户名 密码

配置nginx代理kibana

server{
    listen 80;
    server_name kibana.com;
    auth_basic "Kibana Auth";
    auth_basic_user_file /etc/nginx/passwd/kibana.passwd;
 location / {
    proxy_pass http://kibana_host:5601;
    proxy_redirect off;
 }
}

配置完成-》访问配置的kibana的域名

kibana配置登录方式②

使用 nginx-ldap-auth-daemon 验证

下载nginx-ldap-auth-daemon源码

git clone https://github.com/nginxinc/nginx-ldap-auth.git

将cd到nginx-ldap-auth-daemon目录并将其打包成docker镜像,打包过程有点久,耐心等待

docker build -t nginx-ldap-auth-daemon .

打包完成启动容器

docker run  --name=nginx-ldap  -p 8888:8888  -d nginx-ldap-auth-daemon:latest

配置nginx的映射登录

http {
 #......省略其他配置
 #开启nginx验证的cookie缓存空间 #无操作10分钟过期
 proxy_cache_path cache/ keys_zone=auth_cache:10m; 
 #扫描这个目录下的所有.conf 
 include /etc/nginx/conf/*.conf;
}

配置nginx的kibana域名映射 /etc/nginx/conf/kibana.conf 本文中的xxxx更换成实际使用的文本

server {
        listen 80;
        server_name kibana.xxxx.com;
        location / {
            auth_request /auth-proxy;
            proxy_pass http://xxxx:5601/;
        }
        # 这是用做 auth_request 请求的路径
        location = /auth-proxy {
            internal;
            # nginx-ldap-auth-daemon 启动的地址
            proxy_pass http://nginx-ldap-host:8888;

            proxy_pass_request_body off;
            proxy_set_header Content-Length "";
            proxy_cache auth_cache;
            proxy_cache_valid 200 10m;  #无操作10分钟过期

            # cookie 会加在这里
            proxy_cache_key "$http_authorization$cookie_nginxauth";

            # ldap 的地址
            proxy_set_header X-Ldap-URL      "ldap://xxxx:389";
            
            # ldap 的  BaseDN
            proxy_set_header X-Ldap-BaseDN   "dc=xxxx,dc=com";

            # ldap 的 binddn,也就是有查询权限的账号
            proxy_set_header X-Ldap-BindDN   "cn=admin,dc=xxxx,dc=com";

            # binddn 的密码
            proxy_set_header X-Ldap-BindPass "xxxx";
            
            # cookie 的名字和值
            proxy_set_header X-CookieName "nginxauth";
            proxy_set_header Cookie nginxauth=$cookie_nginxauth;

            # ldap 的 searchFilter,就是拿哪个字段作为认证的用户名
            proxy_set_header X-Ldap-Template "(&(uid=%(username)s)(memberOf=cn=kibana-test,ou=servers-login,dc=xxxx,dc=com))";
        }
    }

配置完成-》访问配置的kibana的域名