ELK企业级日志分析系统

221 阅读20分钟

前言 · ELKstack 中文指南 (elasticsearch.cn)

Elasticsearch 中文文档 (kilvn.com)

ES

ES 使⽤架构 将 ES 应⽤到项⽬中时,可以有两种架构 ⼀种是使⽤ ES 作为唯⼀的后端; 另⼀种是 ES 与数据库系统配合,⼀同作为后端。

ES 作为唯⼀后端

ES 作为⼀个现代化的搜索引擎,它本身除了拥有检索功能外,还拥有存储功能。 因此,在⼀个不复杂的项⽬中,可以将 ES 作为唯⼀的后端来使⽤

ES 与数据库系统配合

在⽐较复杂的项⽬中,ES ⽆法提供传统数据库的所有功能(⽐如事务处理),因此需要将 ES 和传统数据 库来配合使⽤

Elasticsearch安装

从 ES 7.0 开始,ES 内置了 Java 环境,所以如果安装的是 7.0 及以上版本的 ES,就不需要额外安装 Java 环境了。

ES下面链接: Download Elasticsearch | Elastic

[root@devops01 ~]#rpm -ivh elasticsearch-7.9.1-x86_64.rpm

cat > /etc/elasticsearch/elasticsearch.yml << 'EOF'    
node.name: node-1
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: 127.0.0.1,10.0.0.51
http.port: 9200
discovery.seed_hosts: ["10.0.0.51"]
cluster.initial_master_nodes: ["10.0.0.51"]
EOF
systemctl daemon-reload
systemctl start elasticsearch.service

version: '2'
services:
  elasticsearch1:
    image: docker.elastic.co/elasticsearch/elasticsearch:5.0.1
    container_name: elasticsearch1
    environment:
      - cluster.name=docker-cluster
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    mem_limit: 1g
    cap_add:
      - IPC_LOCK
    volumes:
      - esdata1:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - esnet
      
volumes:
  esdata1:
    driver: local

networks:
  esnet:
    driver: bridge

查看ES配置⽂件

[root@devops01 ~]#rpm -qc elasticsearch /etc/elasticsearch/elasticsearch.yml # 主配置 
/etc/elasticsearch/jvm.options # es占⽤多少内存
/etc/elasticsearch/log4j2.properties /etc/elasticsearch/role_mapping.yml
/etc/elasticsearch/roles.yml /etc/elasticsearch/users
/etc/elasticsearch/users_roles
/etc/init.d/elasticsearch # 启动脚本
/etc/sysconfig/elasticsearch # 环境变量 
/usr/lib/sysctl.d/elasticsearch.conf # 内核参数 /usr/lib/systemd/system/elasticsearch.service

索引管理

查看索引
浏览器
http://192.168.91.112:9200/_cat/indices?v&pretty
命令行
curl -XGET 'localhost:9200/_cat/indices?v&pretty'
curl -XGET 'localhost:9200/_cat/indices?v&health=red  查看状态为红的索引
curl -XGET 'localhost:9200/_cat/indices?v&health=yellow  查看状态为红的索引
curl -XGET 'localhost:9200/_cat/indices?v&health=green  查看状态为红的索引
查看索引设置
curl -XGET 'localhost:9200/索引名/_settings'
查看分片情况
curl -XGET 'localhost:9200/_cat/shards?v&h=n,index,shard,prirep,state,sto,sc,unassigned.reason,unassigned.details'


ALLOCATION_FAILED:由于分片分配失败而未分配。  
CLUSTER_RECOVERED:由于集群恢复而未分配。  
DANGLING_INDEX_IMPORTED:由于导入了悬空索引导致未分配。  
EXISTING_INDEX_RESTORED:由于恢复为已关闭的索引导致未分配。  
INDEX_CREATED:由于API创建索引而未分配。  
INDEX_REOPENED:由于打开已关闭索引而未分配。  
NEW_INDEX_RESTORED:由于恢复到新索引而未分配。  
NODE_LEFT:由于托管的节点离开集群而未分配。  
REALLOCATED_REPLICA:确定了更好的副本位置,并导致现有副本分配被取消。  
REINITIALIZED:当分片从开始移动回初始化,导致未分配。  
REPLICA_ADDED:由于显式添加副本而未分配。  
REROUTE_CANCELLED:由于显式取消重新路由命令而未分配。


查看分配失败的具体原因
curl -XGET 'localhost:9200/_cluster/allocation/explain  

磁盘满了es会自动变成只读模式,磁盘恢复后要手动将索引改为可写模式

curl -XPUT -H "Content-Type: application/json" http://127.0.0.1:9200/_all/_settings -d '{"index.blocks.read_only_allow_delete": false}'

性能调优参数

禁止内存交换

为了避免不必要的es jvm堆中数据被交换到磁盘,造成垃圾收集性能较差,可能造成分钟级别的垃圾收集,es内存使用通过jvm堆的大小控制,不需要交换内存。以下有三种解决方式。

  1. 修改/etc/fstab文件,注释掉包含“swap”关键字的行。
  2. 修改/etc/sysctl.conf文件中的配置 vm.swappiness = 1。此配置降低Linux内核的交换偏好性,此配置不会禁用内存交换,在某些紧急条件下仍然可能触发内存交换
  3. 修改es的elasticsearch.yml文件,配置bootstrap.memory_lock: true。此配置会锁定es进程的内存地址空间,避免被交换出内存,需要注意的是当尝试分配更多的内存空间(超过锁定的内存地址空间)es进程会退出;通常启动es的用户不被允许锁定内存空间,需要采用root用户修改/etc/security/limits.conf文件,配置memlock为unlimited。
  • soft   memlock         unlimited      
  • hard   memlock         unlimited
curl -X GET "localhost:9200/_nodes?filter_path=**.mlockall"

如果输出 "mlockall": true,说明内存锁定已生效

文件描述符

Elasticsearch使用大量的文件描述符或文件句柄。文件描述符超限在运行时灾难性的,很可能导致数据丢失。请确保调大运行Elasticsearchd的用户允许打开文件描述符数量到65536或更大。

如果使用的是.zip.tar.gz安装包,在启动elasticsearch前通过root用户设置ulimit -n 65536,或者是设置/etc/security/limits.conf的nofile65536

elasticsearch hard nofile 65536

elasticsearch soft nofile 65536

RPM和Debian软件包已经默认文件描述符的最大数量为65536,不需要进一步配置。

你可以通过各节点的Nodes StatsAPI来检查max_file_descriptions:

GET _nodes/stats/process?filter_path=**.max_file_descriptors
线程数

Elasticsearch不同类的操作使用不同的线程池。在必要的时候创建新的线程非常重要,确保elasticsearch用户可以创建的线程数至少为2048。注意此文件修改后需要重新登录用户,才会生效

elasticsearch soft nproc 4096

elasticsearch hard nproc 4096

虚拟内存

Elasticsearch默认采用[hybrid mmapfs / niofs]目录来保存索引。默认的操作系统mmap数限制看起来太小,这可能会导致内存溢出的异常。

在Linux系统,你可以使用root用户通过如下命令来增加限制数:


echo "vm.max_map_count=262144" >> /etc/sysctl.conf 

参考数据(分配 2g/262144,4g/4194304,8g/8388608)
#一个进程能够分配的最大内存大小
#使修改立即生效
sysctl -p

es写数据原理

  • 待写入的文档并没有立马写入磁盘。首先写入的是es虚拟机堆内存中(memory cache)
  • memory cache中的数据默认没隔一秒中会被refresh刷新到操作系统缓存中(os cache),即在操作系统级别的内存中产生一个segment file;同时会在os cache中记录translog日志,此时被索引的数据可以被搜索到。
  • 默认位于os cache中记录的translog日志数据每隔5秒会被写入磁盘持久化。最多丢失5秒的数据
  • 默认每隔30分钟或者translog日志文件大小大到一定阈值,会触发commit(flush)操作。会将os cache中的segment file数据强制写入磁盘,并清空和重开translog

说明:默认情况下es被索引的数据需要等待1秒后才能被搜索到,最多丢失5秒的数据。

安装 Elasticsearch-head 插件

安装⽅式推荐

  1. npm安装
  2. docker安装 docker run -p 9100:9100 mobz/elasticsearch-head:7
  3. google浏览器装插件 GitHub - mobz/elasticsearch-head: A web front end for an elastic search cluster

image.png

es CRUD

创建索引
# 创建名为"products"的索引
PUT /products
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1
  }
}
插入文档
# 插入一条文档到products索引,ID为1
PUT /products/_doc/1
{
  "name": "iPhone 13",
  "price": 799,
  "description": "Latest Apple smartphone",
  "stock": 100
}

# 不指定ID,让ES自动生成
POST /products/_doc
{
  "name": "Samsung Galaxy S22",
  "price": 699,
  "description": "Latest Samsung smartphone",
  "stock": 150
}
查询文档
# 根据ID查询
GET /products/_doc/1

# 简单搜索
GET /products/_search
{
  "query": {
    "match": {
      "name": "iPhone"
    }
  }
}

# 查询所有文档
GET /products/_search
{
  "query": {
    "match_all": {}
  }
}
更新文档
# 完全替换文档
PUT /products/_doc/1
{
  "name": "iPhone 13 Pro",
  "price": 999,
  "description": "Latest Pro Apple smartphone",
  "stock": 80
}

# 部分更新
POST /products/_update/1
{
  "doc": {
    "price": 899,
    "stock": 90
  }
}
删除文档和索引
# 删除ID为1的文档
DELETE /products/_doc/1

# 删除整个索引
DELETE /products
批量操作
POST /products/_bulk
{ "index": { "_id": "101" } }
{ "name": "MacBook Pro", "price": 1999, "category": "laptop" }
{ "index": { "_id": "102" } }
{ "name": "iPad Air", "price": 599, "category": "tablet" }
{ "delete": { "_id": "103" } }
{ "update": { "_id": "101" } }
{ "doc": { "price": 1899 } 

es集群

 #node01节点
 hostnamectl set-hostname node01
 su
 vim /etc/hosts
 192.168.121.10 node01
 192.168.121.20 node02
 ​
 #node02节点
 hostnamectl set-hostname node02
 su
 vim /etc/hosts
 192.168.121.10 node01
 192.168.121.20 node02




# 指定集群名称3个节点必须一致
cluster.name: docker-cluster
#指定节点名称,每个节点名字唯一
node.name: node-1
#是否有资格为master节点,默认为true
node.master: true
#是否为data节点,默认为true
node.data: true
# 绑定ip,开启远程访问,可以配置0.0.0.0
network.host: 0.0.0.0
#指定web端口
#http.port: 9200
#指定tcp端口
#transport.tcp.port: 9300
#用于节点发现,三个节点的主机号
discovery.seed_hosts: ["xxx.xxx.xxx.166", "xxx.xxx.xxx.167", "xxx.xxx.xxx.168"]
#初始化集群的master节点的候选列表,列表中的节点都可能竞选成为master节点
cluster.initial_master_nodes: ["node-1","node-2","node-3"]

在es集群中配置2到3个主节点并且让它们只负责管理不负责存储,从节点只负责存储
​
 grep -v "^#" /etc/elasticsearch/elasticsearch.yml

es密码

xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
设置密码
/usr/share/elasticsearch/bin/elasticsearch-setup-passwords interactive
## 自动生成密码
/usr/share/elasticsearch/bin/elasticsearch-setup-passwords auto

ELK

ELK的工作原理

(1)在所有需要收集日志的服务器上部署Logstash; 或者先将日志进行集中化管理在日志服务器上, 在日志服务器上部署 Logs tash。

(2)Logstash 收集日志,将日志格式化并输出到 Elasticsearch 群集中。

(3)Elasticsearch 对格式化后的数据进行索引和存储。

(4)Kibana 从 ES 群集中查询数据生成图表,并进行前端数据的展示。

Elasticsearch 默认端口9200;Kibana默认端口5601

image.png

ELK、ELFK、EFLKL

ELK:  ES+logstash+kibana

ELFK:  ES+logstash+filebeat+kibana

ELFK:  ES+filebeat+logstash+kafka+kibana

image.png

Filebeat:

  • 轻量级的开源日志文件数据搜集器。通常在需要采集数据的客户端安装 Filebeat,并指定目录与日志格式,Filebeat 就能快速收集数据,并发送给 logstash 进行解析,或是直接发给 Elasticsearch 存储,性能上相比运行于 JVM 上的 logstash 优势明显,是对它的替代。常应用于 EFLK 架构当中。(如果要使用过滤功能的话,Filebeat不能完全替代logstash,Filebeat没有过滤功能,收集数据后需要发送给 logstash 进行处理)

filebeat 结合 logstash 带来好处:

  1. 通过 Logstash 具有基于磁盘的自适应缓冲系统,该系统将吸收传入的吞吐量,从而减轻 Elasticsearch 持续写入数据的压力。
  2. 从其他数据源(例如数据库,S3对象存储或消息传递队列)中提取。
  3. 将数据发送到多个目的地,例如S3,HDFS(Hadoop分布式文件系统)或写入文件。
  4. 使用条件数据流逻辑组成更复杂的处理管道。

Fluentd:

  • 是一个流行的开源数据收集器。由于 logstash 太重量级的缺点,Logstash 性能低、资源消耗比较多等问题,随后就有 Fluentd 的出现。相比较 logstash,Fluentd 更易用、资源消耗更少、性能更高,在数据处理上更高效可靠,受到企业欢迎,成为 logstash 的一种替代方案,常应用于 EFK 架构当中。在 Kubernetes 集群中也常使用 EFK 作为日志数据收集的方案。
  • 在 Kubernetes 集群中一般是通过 DaemonSet 来运行 Fluentd,以便它在每个 Kubernetes 工作节点上都可以运行一个 Pod。 它通过获取容器日志文件、过滤和转换日志数据,然后将数据传递到 Elasticsearch 集群,在该集群中对其进行索引和存储。

ELK集群部署

实验环境:

服务器类型系统和IP地址需要安装的组件硬件方面
node03节点CentOS7.4(64 位) 192.168.91.105Elasticsearch 、Kibana2核4G
node04节点CentOS7.4(64 位) 192.168.91.106Elasticsearch2核4G
Apache节点CentOS7.4(64 位) 192.168.121.30Logstash、Apache2核4G
优化elasticsearch用户拥有的内存权限:

由于ES构建基于lucene, 而lucene设计强大之处在于lucene能够很好的利用操作系统内存来缓存索引数据,以提供快速的查询性能。lucene的索引文件segements是存储在单文件中的,并且不可变,对于OS来说,能够很友好地将索引文件保持在cache中,以便快速访问;因此,我们很有必要将一半的物理内存留给lucene ; 另一半的物理内存留给ES(JVM heap )。所以, 在ES内存设置方面,可以遵循以下原则:

  • 当机器内存小于64G时,遵循通用的原则,50%给ES,50%留给操作系统,供lucene使用。
  • 当机器内存大于64G时,遵循原则:建议分配给ES分配 4~32G 的内存即可,其它内存留给操作系统,供lucene使用。

创建数据存放路径并授权

mkdir -p /data/elasticsearch
chown elasticsearch:elasticsearch /data/elasticsearch/

6、启动elasticsearch是否成功开启

 systemctl start elasticsearch.service
 systemctl enable elasticsearch.service
 netstat -antp | grep 9200

7、查看节点信息

 浏览器访问  
 http://192.168.91.112:9200
 http://192.168.91.113:9200 
 查看节点 Node1、Node2 的信息。
 ​
 浏览器访问 
 http://192.168.91.112:9200/_cluster/health?pretty   http://192.168.91.113:9200/_cluster/health?pretty
 查看群集的健康情况,可以看到 status 值为 green(绿色), 表示节点健康运行。
 ​
 浏览器访问 http://192.168.91.112:9200/_cluster/state?pretty  检查群集状态信息。

Logstash 部署(在 Apache 节点上操作)

Logstash 一般部署在需要监控其日志的服务器。在本案例中,Logstash 部署在 Apache 服务器上,用于收集 Apache 服务器的日志信息并发送到 Elasticsearch。

1、更改主机名

 hostnamectl set-hostname apache

2、安装Apahce服务(httpd)

 yum -y install httpd
 systemctl start httpd

3、安装Java环境

 yum -y install java
 java -version

4、安装logstash

 #上传软件包 logstash-5.5.1.rpm 到/opt目录下
 cd /opt
 rpm -ivh logstash-5.5.1.rpm                           
 systemctl start logstash.service                      
 systemctl enable logstash.service
 ​
 #将logstash放入PATH环境变量的目录中,便于系统识别
 ln -s /usr/share/logstash/bin/logstash  /usr/local/bin/

5、测试 Logstash

(1)Logstash 命令常用选项:

选项作用
-f通过这个选项可以指定 Logstash 的配置文件,根据配置文件配置 Logstash 的输入和输出流。
-e从命令行中获取,输入、输出后面跟着字符串,该字符串可以被当作 Logstash 的配置(如果是空,则默认使用 stdin 作为输入,stdout 作为输出)。
-t测试配置文件是否正确,然后退出。

(2)定义输入和输出流:

 #1.输入采用标准输入,输出采用标准输出(类似管道)
 logstash -e 'input { stdin{} } output { stdout{} }'
 ......
 www.baidu.com                                       #键入内容(标准输入)
 2020-12-22T03:58:47.799Z node1 www.baidu.com        #输出结果(标准输出)
 www.sina.com.cn                                     #键入内容(标准输入)
 2017-12-22T03:59:02.908Z node1 www.sina.com.cn      #输出结果(标准输出)
 ​
 //执行 ctrl+c 退出
 ​
 ​
 #2.使用 rubydebug 输出详细格式显示,codec 为一种编解码器
 logstash -e 'input { stdin{} } output { stdout{ codec=>rubydebug } }'
 ......
 www.baidu.com                                       #键入内容(标准输入)
 {
     "@timestamp" => 2020-12-22T02:15:39.136Z,       #输出结果(处理后的结果)
       "@version" => "1",
           "host" => "apache",
        "message" => "www.baidu.com"
 }
 ​
 ​
 #3.使用 Logstash 将信息写入 Elasticsearch 中
 logstash -e 'input { stdin{} } output { elasticsearch { hosts=>["192.168.80.10:9200"] } }'
               输入                输出          对接
 ......
 www.baidu.com                                       #键入内容(标准输入)
 www.sina.com.cn                                     #键入内容(标准输入)
 www.google.com                                      #键入内容(标准输入)
 ​
 //结果不在标准输出显示,而是发送至 Elasticsearch 中,可浏览器访问 http://192.168.121.10:9100/ 查看索引信息和数据浏览。

6、定义 logstash配置文件

Logstash 配置文件基本由三部分组成:input、output 以及 filter(可选,根据需要选择使用)。

  • input:表示从数据源采集数据,常见的数据源如Kafka、日志文件等。
  • filter:表示数据处理层,包括对数据进行格式化处理、数据类型转换、数据过滤等,支持正则表达式。
  • output:表示将Logstash收集的数据经由过滤器处理之后输出到Elasticsearch。
 #格式如下:
 input {...}
 filter {...}
 output {...}
 ​
 #在每个部分中,也可以指定多个访问方式。例如,若要指定两个日志来源文件,则格式如下:
 input {
     file { path =>"/var/log/messages" type =>"syslog"}
     file { path =>"/var/log/httpd/access.log" type =>"apache"}
 }

修改Logstash 配置文件:

 #修改 Logstash 配置文件,让其收集系统日志/var/log/messages,并将其输出到 elasticsearch 中。
 chmod +r /var/log/messages                  #让 Logstash 可以读取日志
 ​
 vim /etc/logstash/conf.d/system.conf
 input {
     file{
         path =>"/var/log/messages"                      #指定要收集的日志的位置
         type =>"system"                                 #自定义日志类型标识
         start_position =>"beginning"                    #表示从开始处收集
     }
 }
 output {
     elasticsearch {                                     #输出到 elasticsearch
         hosts => ["192.168.121.10:9200","192.168.121.20:9200"]  #指定 elasticsearch 服务器的地址和端口
         index =>"system-%{+YYYY.MM.dd}"                 #指定输出到 elasticsearch 的索引格式
     }
 }
 ​
 systemctl restart logstash 
 ​
 浏览器访问 http://192.168.91.112:9100/ 查看索引信息

Kiabana 部署

1、安装 Kiabana

www.elastic.co/cn/what-is/…

 #上传软件包 kibana-5.5.1-x86_64.rpm 到/opt目录
 cd /opt
 rpm -ivh kibana-5.5.1-x86_64.rpm

2、设置 Kibana 的主配置文件

 vim /etc/kibana/kibana.yml
 #--第2行--取消注释,Kiabana 服务的默认监听端口为5601
 server.port: 5601
 ​
 #--第7行--取消注释,设置 Kiabana 的监听地址,0.0.0.0代表所有地址
 server.host: "0.0.0.0"
 ​
 #--第28行--取消注释,配置es服务器的ip,如果是集群则配置该集群中master节点的ip
 elasticsearch.url:  ["http://192.168.121.10:9200","http://192.168.121.20:9200"]
 ​
 #--第37行--取消注释,设置在 elasticsearch 中添加.kibana索引
 kibana.index: ".kibana"
 ​
 #--第96行--取消注释,配置kibana的日志文件路径(需手动创建),不然默认是messages里记录日志
 logging.dest: /var/log/kibana.log



6.7开始支持中文
i18n.locale: "zh-CN"


3、创建日志文件,启动 Kibana 服务

 touch /var/log/kibana.log
 chown kibana:kibana /var/log/kibana.log
 ​
 systemctl start kibana.service
 systemctl enable kibana.service
 ​
 netstat -natp | grep 5601

4、验证 Kibana

 浏览器访问 http://192.168.91.112:5601
 第一次登录需要添加一个 Elasticsearch 索引:
 Index name or pattern
 //输入:system-*           #在索引名中输入之前配置的 Output 前缀“system”
 ​
 单击 “create” 按钮创建,单击 “Discover” 按钮可查看图表信息及日志信息。
 数据展示可以分类显示,在“Available Fields”中的“host”,然后单击 “add”按钮,可以看到按照“host”筛选后的结果

5、将 Apache 服务器的日志(访问的、错误的)添加到 Elasticsearch 并通过 Kibana 显示

 vim /etc/logstash/conf.d/apache_log.conf
 input {
     file{
         path => "/etc/httpd/logs/access_log"   #指定访问日志存放位置录
         type => "access"
         start_position => "beginning"    #beginning表示从开头收集,如果只需收集最新的,此处改为latest
     }
     file{
         path => "/etc/httpd/logs/error_log"   #指定错误日志存放位置
         type => "error"
         start_position => "beginning"
     }
 }
 output {
     if [type] == "access" {
         elasticsearch {
             hosts => ["192.168.121.10:9200","192.168.121.20:9200"]
             index => "apache_access-%{+YYYY.MM.dd}"      #索引后缀加上当天的日期
         }
     }
     if [type] == "error" {
         elasticsearch {
             hosts => ["192.168.121.10:9200","192.168.121.20:9200"]
             index => "apache_error-%{+YYYY.MM.dd}"     #索引后缀加上当天的日期
         }  
     }
 }
 ​
 cd /etc/logstash/conf.d/
 /usr/share/logstash/bin/logstash -f apache_log.conf

6、浏览器访问

 浏览器访问 http://192.168.121.10:9100 查看索引是否创建
 ​
 浏览器访问 http://192.168.121.10:5601 登录 Kibana,
 单击“Index Pattern -> Create Index Pattern”按钮添加索引, 在索引名中输入之前配置的 Output 前缀 apache_access-*,并单击“Create”按钮。再用相同的方法添加 apache_error-*索引。
 选择“Discover”选项卡,在中间下拉列表中选择刚添加的 apache_access-* 、apache_error-* 索引, 可以查看相应的图表及日志信息。

image.png

apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
    k8s-app: elasticsearch-logging
    version: v7.4.2
  name: elasticsearch-logging
  namespace: logging
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: elasticsearch-logging
      version: v7.4.2
  serviceName: elasticsearch-logging
  template:
    metadata:
      labels:
        k8s-app: elasticsearch-logging
        version: v7.4.2
    spec:
      nodeSelector:
        log: "true" ## 指定部署在哪个节点。需根据环境来修改
      containers:
      - env:
        - name: NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        - name: cluster.initial_master_nodes
          value: elasticsearch-logging-0
        - name: ES_JAVA_OPTS
          value: "-Xms512m -Xmx512m"
        image: 172.21.32.13:5000/elasticsearch/elasticsearch:7.4.2
        name: elasticsearch-logging
        ports:
        - containerPort: 9200
          name: db
          protocol: TCP
        - containerPort: 9300
          name: transport
          protocol: TCP
        volumeMounts:
        - mountPath: /usr/share/elasticsearch/data
          name: elasticsearch-logging
      dnsConfig:
        options:
        - name: single-request-reopen
      initContainers:
      - command:
        - /sbin/sysctl
        - -w
        - vm.max_map_count=262144
        image: alpine:3.6
        imagePullPolicy: IfNotPresent
        name: elasticsearch-logging-init
        resources: {}
        securityContext:
          privileged: true
      - name: fix-permissions
        image: alpine:3.6
        command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
        securityContext:
          privileged: true
        volumeMounts:
        - name: elasticsearch-logging
          mountPath: /usr/share/elasticsearch/data
  volumeClaimTemplates:
  - metadata:
      name: elasticsearch-logging
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi # Adjust the size as needed
      storageClassName: standard # Change to your desired storage class
---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: elasticsearch-logging
  name: elasticsearch
  namespace: logging
spec:
  ports:
  - port: 9200
    protocol: TCP
    targetPort: db
  selector:
    k8s-app: elasticsearch-logging
  type: ClusterIP

k8s安装efk

es

apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
    app: elasticsearch-logging
  name: elasticsearch-logging
  namespace: logging
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: elasticsearch-logging
  serviceName: elasticsearch-logging
  template:
    metadata:
      labels:
        app: elasticsearch-logging
    spec:
      securityContext:
        fsGroup: 2000
      nodeSelector:
        log: "true" ## 指定部署在哪个节点。需根据环境来修改
      containers:
      - env:
        - name: cluster.name
          value: k8s-logs
        - name: node.name
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: discovery.seed_hosts
          value: "elasticsearch-logging-0"
        - name: network.host
          value: "0.0.0.0"
        - name: cluster.initial_master_nodes
          value: "elasticsearch-logging-0"
        - name: ES_JAVA_OPTS
          value: "-Xms512m -Xmx512m"
        image:  elasticsearch:7.4.2
        name: elasticsearch-logging
        ports:
        - containerPort: 9200
          name: db
          protocol: TCP
        - containerPort: 9300
          name: transport
          protocol: TCP
        resources:
          limits:
            cpu: 1000m
            memory: 1Gi
          requests:
            cpu: 1000m
            memory: 1Gi
        volumeMounts:
        - mountPath: /usr/share/elasticsearch/data
          name: elasticsearch-logging
#      dnsConfig:
#        options:
#        - name: single-request-reopen
      initContainers:
#      - name: fix-permissions
#        image: busybox
#        imagePullPolicy: IfNotPresent
#        command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
#        securityContext:
#          privileged: true
#        volumeMounts:
#        - name: elasticsearch-logging
#          mountPath: /usr/share/elasticsearch/data
      - name: increase-vm-max-map
        image: busybox
        imagePullPolicy: IfNotPresent
        command: ["sysctl", "-w", "vm.max_map_count=262144"]
        securityContext:
          privileged: true
      - name: increase-fd-ulimit
        image: busybox
        imagePullPolicy: IfNotPresent
        command: ["sh", "-c", "ulimit -n 65536"]
        securityContext:
          privileged: true
        volumeMounts:
        - name: elasticsearch-logging
          mountPath: /usr/share/elasticsearch/data
  volumeClaimTemplates:
  - metadata:
      name: elasticsearch-logging
      labels:
        app: elasticsearch-logging
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 30Gi # Adjust the size as needed
      storageClassName: nfs-client-storageclass
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: elasticsearch-logging
  name: elasticsearch
  namespace: logging
spec:
  ports:
  - port: 9200
    protocol: TCP
    targetPort: db
  selector:
    app: elasticsearch-logging
  type: ClusterIP

kubectl label node k8s-node03 log=true

kibana

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kibana
  namespace: logging
  labels:
    app: kibana
spec:
  selector:
    matchLabels:
      app: kibana
  template:
    metadata:
      labels:
        app: kibana
    spec:
      containers:
      - name: kibana
        image: kibana:7.4.2
        resources:
          limits:
            cpu: 1000m
          requests:
            cpu: 100m
        env:
          - name: ELASTICSEARCH_URL
            value: http://elasticsearch:9200
        ports:
        - containerPort: 5601
---
apiVersion: v1
kind: Service
metadata:
  name: kibana
  namespace: logging
  labels:
    app: kibana
spec:
  ports:
  - name: http
    port: 5601
    targetPort: 5601
    nodePort: 30056
  type: NodePort
  selector:
    app: kibana

fluentd

apiVersion: v1
kind: ServiceAccount
metadata:
  name: fluentd-es
  namespace: logging
  labels:
    app: fluentd-es
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: fluentd-es
  labels:
    app: fluentd-es
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
rules:
  - apiGroups:
      - ""
    resources:
      - "namespaces"
      - "pods"
    verbs:
      - "get"
      - "watch"
      - "list"

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: fluentd-es
  labels:
    app: fluentd-es
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
subjects:
  - kind: ServiceAccount
    name: fluentd-es
    namespace: logging
    apiGroup: ""
roleRef:
  kind: ClusterRole
  name: fluentd-es
  apiGroup: ""

---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
    app: fluentd-es
  name: fluentd-es
  namespace: logging
spec:
  selector:
    matchLabels:
      app: fluentd-es
  template:
    metadata:
      labels:
        app: fluentd-es
    spec:
      containers:
        - env:
            - name: FLUENTD_ARGS
              value: --no-supervisor -q
          image: fluent/fluentd-kubernetes-daemonset:v1-debian-elasticsearch
          imagePullPolicy: IfNotPresent
          name: fluentd-es
          resources:
            limits:
              memory: 500Mi
            requests:
              cpu: 100m
              memory: 200Mi
          volumeMounts:
            - mountPath: /var/log
              name: varlog
            - mountPath: /var/lib/docker/containers
              name: varlibdockercontainers
              readOnly: true
            - mountPath: /fluentd/etc/config.d
              name: config-volume
            - mountPath: /fluentd/etc/fluent.conf
              name: config-volume-main
              subPath: fluent.conf
      nodeSelector:
        fluentd: "true"
      securityContext: {}
      serviceAccount: fluentd-es
      serviceAccountName: fluentd-es
      volumes:
        - hostPath:
            path: /var/log
            type: ""
          name: varlog
        - hostPath:
            path: /var/lib/docker/containers
            type: ""
          name: varlibdockercontainers
        - configMap:
            defaultMode: 420
            name: fluentd-config
          name: config-volume
        - configMap:
            defaultMode: 420
            items:
              - key: fluent.conf
                path: fluent.conf
            name: fluentd-es-config-main
          name: config-volume-main

fluentd-es-config-main.yaml

apiVersion: v1
data:
  fluent.conf: |-
    # This is the root config file, which only includes components of the actual configuration
    #
    #  Do not collect fluentd's own logs to avoid infinite loops.
    <match fluent.**>
    @type null
    </match>

    @include /fluentd/etc/config.d/*.conf
kind: ConfigMap
metadata:
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
  name: fluentd-es-config-main
  namespace: logging

fluentd-configmap.yaml

kind: ConfigMap
apiVersion: v1
metadata:
  name: fluentd-config
  namespace: logging
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
data:
  containers.input.conf: |-
    <source>
      @id fluentd-containers.log
      @type tail
      path /var/log/containers/*.log
      pos_file /var/log/es-containers.log.pos
      time_format %Y-%m-%dT%H:%M:%S.%NZ
      localtime
      tag raw.kubernetes.*
      format json
      read_from_head true
    </source>
    # Detect exceptions in the log output and forward them as one log entry.
    # https://github.com/GoogleCloudPlatform/fluent-plugin-detect-exceptions 
    <match raw.kubernetes.**>
      @id raw.kubernetes
      @type detect_exceptions
      remove_tag_prefix raw
      message log
      stream stream
      multiline_flush_interval 5
      max_bytes 500000
      max_lines 1000
    </match>
  output.conf: |-
    # Enriches records with Kubernetes metadata
    <filter kubernetes.**>
      @type kubernetes_metadata
    </filter>
    <match **>
      @id elasticsearch
      @type elasticsearch
      @log_level info
      include_tag_key true
      host elasticsearch
      port 9200
      logstash_format true
      request_timeout    30s
      <buffer>
        @type file
        path /var/log/fluentd-buffers/kubernetes.system.buffer
        flush_mode interval
        retry_type exponential_backoff
        flush_thread_count 2
        flush_interval 5s
        retry_forever
        retry_max_interval 30
        chunk_limit_size 2M
        queue_limit_length 8
        overflow_action block
      </buffer>
    </match>

kibana报错Request Timeout after 30000ms故障解决

方法一:修改elastisearch的内存

方法二:修改kibana的超时时间