一、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
檢測采集效果


