一、Log-Pilot
1. 关于 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
检测采集效果