K8S 日志收集ELK
收集日志可以用于分析用户行为,监控服务器状态,增强系统或应用安全性等。
1 常见的日志收集方案
ELK简介:ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana。
Elasticsearch:是个开源分布式搜索引擎,提供搜集、分析、存储数据三大功能。
Logstash:主要是用来做日志的分析、过滤等处理工作。
Kibana:可以为 Logstash 和 ElasticSearch 提供的日志提供友好的 Web 界面,可以帮助汇总、分析和搜索重要数据日志。
新增了一个FileBeat,它是一个轻量级的日志收集处理工具(Agent),Filebeat占用资源少,适合于在各个服务器上搜集日志后传输给Logstash。
传统服务日志收集方案:Elasticsearch、Logstash、Kibana(ELKB) + Filebeat
传统服务日志收集与K8s服务日志收集区别:
传统日志收集:传统服务部署在固定的服务器,而日志也固定服务器中的具体目录中,即便服务器重启,应用依然在固定的节点,对日志收集系统来讲,也不需要重新指定日志的所在位置。
K8s日志收集:在K8s集群中,服务通常不会固定在某一个节点,如果服务重启、弹性伸缩,那么服务可能会漂移到其他的节点,所以对于K8s中日志的收集与传统的方式不太一样。
容器日志收集方案:Elasticsearch、fluentd、Kibana(EFK)
Fluentd这种需要我们在每个 Pod 中都附带一个Agent容器来进行本 Pod 内部容器的日志采集,
一般采用共享卷的方式,但是对于这一种模式来说,很明显的一个问题就是占用的资源比较多,尤其是在集群规模比较大的情况下,或者说单个节点上容器特别多的情况下,它会占用过多的系统资源,同时也对日志存储后端占用过多的连接数。当我们的集群规模越大,这种部署模式引发的潜在问题就越大。
2 破解利器 Log-Pilot
轻量级:Log-Pilot采用节点模式(每个Node节点仅会部署一个Agent)进行日志采集,对比与上述fluentd(每个Pod中部署一个Agent)更加的节约资源,同样在集群规模比较大的情况下表现出的优势越明显。
自动检测:Log-Pilot 能够自动感知宿主机上容器的创建删除事件,进而动态配置容器日志采集配置文件。
句柄保持机制:Log-Pilot 内部会实时跟踪日志采集偏移量,然后维持日志文件信息与偏移量的映射关系,最后定期地持久化到磁盘中。采用偏移量的方式我们可以避免日志采集丢失和重复的问题,同时即使当采集工具宕掉再起来,它可以通过加载持久化在磁盘上的元数据信息,然后从指定的日志偏移位置上继续采集日志。
自动数据打标:Log-Pilot 在采集容器日志的时候,同时也会收集容器的元数据信息,包括容器的名称,容器所属的服务名称以及容器所属的应用名称,同时在 Kubernetes 里面也会采集容器所属的 Pod 信息,包括 Pod 的名称,Pod 所属的 namespace 以及 Pod 所在的节点信息。这样我们排查问题时,就可以很方便地知道这个日志数据是来源于哪个节点上的哪个应用容器。
支持高级特性:Log-Pilot 除了提供前面的几个特性外,还支持一些其他的高级特性,比如低资源消耗,支持自定义 tag,支持多种日志解析格式,支持自定义日志输出 target 以及支持 fluentd 和 filebeat 等插件,最后支持对接到多种日志存储后端。
支持自定义Tag:我们可以在容器的标签或者环境变量里配置 aliyun.logs.$name.tags: k=v
那么在采集日志的时候也会将k=v
采集到容器的日志输出中。
比如我们有一种场景,有一个开发环境和测试环境,应用日志都会被采集到统一的一个日志存储后端,假设是一个 ElasticSearch 集群,但是我们在 ElasticSearch 中查询日志的时候又想区分出来,具体某条日志记录到底来源于生产环境,还是测试环境。那么我们就可以通过给测试环境的容器打上
stage=dev 的 tag
给生产环境的容器打上stage=pro
的 tag,Log-Pilot 在采集容器日志的时候,同时会将这些 tag 随容器日志一同采集到日志存储后端中,那么当我们在查询日志的时候,就可以通过stage=dev
或者stage=pro
能明确地区分出某条日志是来源于生产环境的应用容器所产生,还是测试环境应用容器所产生的。另外通过自定义 tag 的方式我们还可以进行日志统计、日志路由和日志过滤。
3 Log-Pilot 环境准备
本案例在K8s集群内部署日志收集系统ELK,所有节点先增加2G内存。
4 创建 Service Account
创建es的Service Account,ServiceAccount在K8s中可用于存储服务的账号信息,用于给运行在Pod里面的进程提供必要的身份证明。
[root@master01 ~]# kubectl create sa es-admin -n kube-system
[root@master01 ~]# kubectl create clusterrolebinding es-admin --clusterrole=cluster-admin --serviceaccount=kube-system:es-admin
当serviceaccout创建时K8s会默认创建对应的secret用于存储账号的token信息
[root@master01 ~]# kubectl get secrets -n kube-system | grep es-admin
5 部署 Elasticsearch 集群
es集群采用StatefulSet控制器部署,StatefulSet本质上是Deployment的一种变体,用于部署有状态服务,它所管理的Pod拥有固定的Pod名称,启停顺序。
[root@master01 logs]# kubectl create -f elasticsearch.yaml
查看StatefulSet信息(缩写:sts)
[root@master01 logs]# kubectl get sts -n kube-system
查看es的Pod
[root@master01 ~]# kubectl get pod -n kube-system -o wide | grep elastic
查看es的svc端口
[root@master01 logs]# kubectl get svc -n kube-system
elasticsearch-0 1/1 Running 0 22m
elasticsearch-1 1/1 Running 0 22m
elasticsearch-2 1/1 Running 0 21m
6 部署 Log-Pilot
为了保证集群每个节点都能够采集到日志信息,Log-Pilot采用DaemonSet控制器创建,DaemonSet可以保证集群的每个节点都存在一个相同的副本。
[root@master01 logs]# kubectl apply -f log-pilot.yaml
[root@master01 ~]# kubectl get pod -n kube-system | grep log-pilot
log-pilot-c4kvk 1/1 Running 0 2m32s
log-pilot-s78h8 1/1 Running 0 2m32s
log-pilot-xlclz 1/1 Running 0 2m32s
log-pilot-xzwps 1/1 Running 0 2m32s
7 部署 Kibana
kibana提供web页面展示,采用Deploy控制器部署。
[root@master01 logs]# kubectl apply -f kibana.yaml
[root@master01 logs]# kubectl get deploy -n kube-system
kibana 1/1 1 1 82s
[root@master01 logs]# kubectl get ing -n kube-system
NAME CLASS HOSTS ADDRESS PORTS AGE
kibana <none> www.kibana.com 192.168.0.13 80 4m2s
配置域名解析:C:\Windows\System32\drivers\etc
192.168.0.13 www.kibana.com
访问测试:在访问测试时,通过域名与ingress对外暴露的端口进行访问
查看ingress-nginx暴露的端口
[root@master01 logs]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP
ingress-nginx-controller NodePort 10.111.226.197 <none> 80:31681/TCP,443:31150/TCP 22m
访问测试:注意80对应的是HTTP端口,443对应的是HTTPS端口
部署应用并采集日志
[root@master01 ~]# vim elk.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
ports:
- containerPort: 80
env:
- name: aliyun_logs_nginx #变量名称开头固定为aliyun_logs(变量名称用于创建kibana索引)
value: "stdout"
- name: aliyun_logs_nginxlogs #变量名称开头固定为aliyun_logs(变量名称用于创建kibana索引)
value: "/var/log/nginx/*"
volumeMounts:
- mountPath: /var/log/nginx/
name: nginxlogs
volumes:
- name: nginxlogs
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: svc-nginx
namespace: test
spec:
selector:
app: deploy-nginx
clusterIP: None
type: ClusterIP #service类型
ports:
- port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-tomcat
namespace: test
spec:
selector:
matchLabels:
app: deploy-tomcat
template:
metadata:
labels:
app: deploy-tomcat
spec:
containers:
- name: tomcat
image: tomcat:8.5-jre10-slim
ports:
- containerPort: 8080
env:
- name: aliyun_logs_tomcat #变量名称开头固定为aliyun_logs(变量名称用于创建kibana索引)
value: "stdout"
- name: aliyun_logs_tomcatlogs #变量名称开头固定为aliyun_logs(变量名称用于创建kibana索引)
value: "/usr/local/tomcat/logs/*"
volumeMounts:
- mountPath: /usr/local/tomcat/logs
name: tomcatlogs
volumes:
- name: tomcatlogs
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: svc-tomcat
namespace: test
spec:
selector:
app: deploy-tomcat
clusterIP: None
type: ClusterIP #service类型
ports:
- port: 8080
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-http #自定义ingress名称
namespace: test
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
kubernetes.io/ingress.class: nginx #注释名称需为nginx(不可省略)
spec:
rules: #定义主机列表
- host: www.nginx.com #自定义域名
http:
paths:
- pathType: Prefix #路径类型
path: "/" #定义站点路径
backend: #定义后端引用的服务
service: #关联service
name: svc-nginx #对应上面创建的service名称
port:
number: 80 #service端口
- host: www.tomcat.com #自定义域名
http:
paths:
- pathType: Prefix #路径类型
path: "/" #定义站点路径
backend: #定义后端引用的服务
service: #关联service
name: svc-tomcat #对应上面创建的service名称
port:
number: 8080 #service端口
创建Pod
[root@master01 ~]# kubectl create -f elk.yml
添加索引:索引名称对应环境变量名称
评论区