Kubernetes 日志采集 | Log-Pilot + ElasticSearch + Kibana


一、Log-Pilot

1. 关于 Log-Pilot

Log-Pilot 是一个智能容器日志采集工具,它不仅能够高效便捷地将容器日志采集输出到多种存储日志后端,同时还能够动态地发现和采集容器内部的日志文件。

开源地址
容器日志采集利器Log-Pilot

2. 采集模式

传统采集模式中需要在每个 Pod 中起一个专门用来采集日志的容器。在集群规模大的情况下,会造成资源的过多占用。
而Log-Pilot 采用的是 Node 采集模式,这个模式中只需要在每个节点上部署一个专门用来采集此节点上所有容器的日志的 Pod,可以避免资源的浪费。

3. Log-Pilot 特性

声明式配置

Log-Pilot 支持声明式日志配置,可以依据容器的 Label 或者 ENV 来动态地生成日志采集配置文件。示例:

  • Label:aliyun.logs.$name=$path
  • ENV:aliyun_logs_$name=$path

含义:

  • $name:自定义的字符串,不同场景下有不同含义,如

  • 输出到 ElasiticSearch 表示 index

  • 输出到 Kafka 表示 topic

  • $path:表示标准输出日志或者日志路径

  • aliyun_logs_$name=stdout 表示采集容器的标准输出日志

  • aliyun_logs_$name=/usr/local/tomcat/logs/* 表示采集容器的内部日志文件

如果不想使用 aliyun 这个前缀,还可以在 Log-Pilot 中配置 PILOT_LOG_PREFIX 环境变量来自定义前缀。

数据自动打标

Log-Pilot 在 Kubernetes 中采集容器日志的时候,同时也会收集容器的元数据信息:

  • k8s_pod
  • k8s_pod_namespace
  • k8s_node_name
  • k8s_container_name

多种解析格式

常用:

  • none:默认格式,指不对日志记录做任何解析,整行采集出来直接输出到日志存储后端
  • json:Log-Pilot 在采集日志的时候同时会将每一行日志以 json 的方式进行解析,解析出多个 KV 对,然后输出到日志存储后端

需要配置 fluentd 插件:

  • csv:主要是针对csv格式的日志采集配置
  • nginx:主要是针对Nginx的日志采集配置
  • apache2:主要是针对Apache的日志采集配置
  • regexp:用户可以通过 format 标签来自定义正则表达式,告诉 Log-Pilot 在解析日志记录的时候以什么样的拆分格式来进行解析拆分

自定义输出 target

格式:aliyun_logs_$name_target=$target
$target 和 前面的 $name 一样,不同的场景下有不同含义,如

  • 输出到 ElasiticSearch 表示 index
  • 输出到 Kafka 表示 topic

使用示例:ElasticSearch 场景下,有一个容器在测试环境中定义了 aliyun_logs_svc=stdout ,表示该容器的标准输出日志被采集到 index=svc中。当该容器应用于生产环境中时,可以添加一条 aliyun_logs_svc_target=svc-pro 定义来使标准输出日志被采集到 index=svc-pro 中,而不用去修改原先每条定义的 $name 。

多插件多后端

目前 Log-Pilot 支持两种采集插件:一个是CNCF社区的Fluentd插件,一个是Elastic的Filebeat插件;其同时其支持对接多种存储后端,目前 Fluentd 和 Filebeat 都支持 Elasticsearch、Kafka、File、Console 作为日志存储后端,而 Fluentd 还支持 Graylog、阿里云日志服务 以及 Mongodb 作为存储后端。

其他特性

  • 自动发现机制
  • 句柄保持机制

二、部署示例

以下部署过程中的集群环境和 YAML 文件仅为展示 Log-Pilot 采集效果,实际部署以具体情况为准。

1. Kubernetes 集群环境

本环境为 Kubernetes 单点集群

[root@node log-test]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
node.master Ready master 40d v1.14.2

2. 部署 ElasticSearch

elasticsearch.yml

apiVersion: v1
kind: Service
metadata:
name: elasticsearch
labels: 
component: elasticsearch
spec:
selector:
component: elasticsearch
ports:
- name: http
port: 9200
targetPort: 9200
nodePort: 30092
protocol: TCP
- name: transport
port: 9300
targetPort: 9300
nodePort: 30093
protocol: TCP
type: NodePort
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: es
labels:
component: elasticsearch
spec:
replicas: 1
serviceName: elasticsearch
template:
metadata:
labels:
component: elasticsearch
spec:
initContainers:
- name: init-sysctl
image: busybox:1.28
imagePullPolicy: IfNotPresent
command: ["sysctl", "-w", "vm.max_map_count=262144"]
securityContext:
privileged: true
containers:
- name: es
securityContext:
capabilities:
add:
- IPC_LOCK
image: elasticsearch:6.8.1
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: ELASTICSEARCH_SERVICE_NAME
value: elasticsearch
- name: "CLUSTER_NAME"
value: "myes"
- name: ES_JAVA_OPTS 
value: "-Xms256m -Xmx256m"
ports:
- containerPort: 9200
protocol: TCP
- containerPort: 9300
protocol: TCP
resources:
limits:
memory: 1Gi
volumeMounts:
- mountPath: /data
name: es-data
volumes:
- name: es-data
hostPath:
path: /es-data
updateStrategy:
type: RollingUpdate

部署 ES

[root@node log-test]# kubectl apply -f elasticsearch.yml 
service/elasticsearch created
statefulset.apps/es created
[root@node log-test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
es-0 1/1 Running 0 16s
[root@node log-test]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch NodePort 10.103.174.133 <none> 9200:30092/TCP,9300:30093/TCP 21s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 40d

检测是否部署成功

3. 部署 Kibana

kibana.yml

apiVersion: v1
kind: Service
metadata:
name: kibana
labels:
component: kibana
spec:
selector:
component: kibana
ports:
- name: http
port: 80
targetPort: http
nodePort: 30156
type: NodePort
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: kibana
labels:
component: kibana
spec:
replicas: 1
selector:
matchLabels:
component: kibana
template:
metadata:
labels:
component: kibana
spec:
containers:
- name: kibana
image: kibana:6.8.1
env:
- name: CLUSTER_NAME
value: docker-cluster
- name: ELASTICSEARCH_URL
value: http://192.168.199.243:30092/ # ES的访问地址
resources:
limits:
memory: 384Mi
ports:
- containerPort: 5601
name: http

部署 Kibana

[root@node log-test]# kubectl apply -f kibana.yml 
service/kibana created
deployment.apps/kibana created
[root@node log-test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
es-0 1/1 Running 0 101s
kibana-66c89cc846-25rrl 1/1 Running 0 8s
[root@node log-test]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch NodePort 10.103.174.133 <none> 9200:30092/TCP,9300:30093/TCP 5m
kibana NodePort 10.106.94.81 <none> 80:30156/TCP 9s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 40d

检测是否成功

4. 部署 Log-Pilot

log-pilot.yml

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: log-pilot
labels:
k8s-app: log-pilot
spec:
template:
metadata:
labels:
k8s-app: log-es
spec:
containers:
- name: log-pilot
image: registry.cn-hangzhou.aliyuncs.com/acs-sample/log-pilot:0.9.5-filebeat
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
env:
- name: "NODE_NAME" #添加后可采集所在 node 信息 
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: "PILOT_LOG_PREFIX" #自定义前缀
value: "mytest"
- name: "FILEBEAT_OUTPUT" #输出到ES
value: "elasticsearch"
- name: "ELASTICSEARCH_HOST" #ES HOST
value: "192.168.199.243"
- name: "ELASTICSEARCH_PORT" #ES PORT
value: "30092"
volumeMounts:
- name: sock
mountPath: /var/run/docker.sock
- name: root
mountPath: /host
readOnly: true
- name: varlib
mountPath: /var/lib/filebeat
- name: varlog
mountPath: /var/log/filebeat
securityContext:
capabilities:
add:
- SYS_ADMIN
terminationGracePeriodSeconds: 30
volumes:
- name: sock
hostPath:
path: /var/run/docker.sock
- name: root
hostPath:
path: /
- name: varlib
hostPath:
path: /var/lib/filebeat
type: DirectoryOrCreate
- name: varlog
hostPath:
path: /var/log/filebeat
type: DirectoryOrCreate

部署 log-pilot

[root@node log-test]# kubectl apply -f log-pilot.yml 
daemonset.extensions/log-pilot created
[root@node log-test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
es-0 1/1 Running 0 2m42s
kibana-66c89cc846-25rrl 1/1 Running 0 69s
log-pilot-tv8mx 1/1 Running 0 3s

5. 使用 tomcat 验证采集效果

tomcat-logs.yml

apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat
labels:
app: tomcat
spec:
replicas: 2
selector:
matchLabels:
app: tomcat
template:
metadata:
labels:
app: tomcat
spec:
containers:
- image: tomcat:alpine
name: tomcat-test
volumeMounts:
- mountPath: /usr/local/tomcat/logs
name: tomcat-logs
env:
- name: mytest_logs_testforstdout #采集标准输出日志
value: "stdout" 
- name: mytest_logs_testforlogdir #采集容器内日志文件
value: "/usr/local/tomcat/logs/*.log"
- name: mytest_logs_testforlogdir_tags #自定义标签
value: "k8s_resource_type=Deployment"
volumes:
- name: tomcat-logs
emptyDir: {}

部署 Tomcat

[root@node log-test]# kubectl apply -f tomcat-logs.yml 
deployment.apps/tomcat created
[root@node log-test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
es-0 1/1 Running 0 10m
kibana-66c89cc846-25rrl 1/1 Running 0 9m14s
log-pilot-tv8mx 1/1 Running 0 8m8s
tomcat-74dc6f785d-jqdb7 1/1 Running 0 5s
tomcat-74dc6f785d-sbhrc 1/1 Running 0 5s

检测采集效果


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM