Promtail
Promtail 是用来将容器日志发送到 Loki 或者 Grafana 服务上的日志收集工具,该工具主要包括发现采集目标以及给日志流添加上 Label 标签,然后发送给 Loki,另外 Promtail 的服务发现是基于 Prometheus 的服务发现机制实现的。
以下在k8s集群中安装并配置promtail的例子:
为了更好的理解,我创建了两个yaml文件,promtail-daemonset.yaml负责拉取promtail镜像,映射卷,配置k8s认证文件等,promtail以daemonset的方式存在每个node节点;promtail-configmap.yaml负责配置promtail抓取日志的配置文件。
配置如下:
[root@kubeadm loki]# cat promtail-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: promtail-daemonset
spec:
selector:
matchLabels:
name: promtail
template:
metadata:
labels:
name: promtail
spec:
hostNetwork: true #开启hostnetwork映射configmap定义的端口到node节点方便在浏览器调试
serviceAccount: SERVICE_ACCOUNT
serviceAccountName: promtail-serviceaccount #这里的名称要跟下面ServiceAccount定义的一样
volumes:
- name: logs
hostPath:
path: /var/log
- name: varlibdockercontainers #注意,不加这个卷映射的,在抓取pod日志文件时会报promtail logs no such file or directory
hostPath:
path: /var/lib/docker/containers
- name: promtail-config
configMap:
name: promtail-config #这里的name要跟promtail-configmap.yaml定义的name一样
containers:
- name: promtail-container
image: grafana/promtail
args:
- -config.file=/etc/promtail/promtail.yaml #指定从configmap定义的promtail配置文件在pod的存放位置
- -client.url=http://192.168.37.202:3100/loki/api/v1/push
volumeMounts:
- name: logs
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: promtail-config
mountPath: /etc/promtail
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: promtail-clusterrole
rules: #选择了给予cluster-admin的权限,解决启动时pod报权限警告
- apiGroups:
- '*'
resources:
- '*'
verbs:
- '*'
- nonResourceURLs:
- '*'
verbs:
- '*'
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: promtail-serviceaccount
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: promtail-clusterrolebinding
subjects:
- kind: ServiceAccount
name: promtail-serviceaccount
namespace: default
roleRef:
kind: ClusterRole
name: promtail-clusterrole
apiGroup: rbac.authorization.k8s.io
抓取pod容器内的日志configmap配置:
[root@kubeadm loki]# cat promtail-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: promtail-config
data:
promtail.yaml: |
clients:
- url: http://192.168.37.202:3100/loki/api/v1/push #定义loki的clients
positions:
filename: /tmp/positions.yaml #存放promtail位置信息的yaml文件在pod里的位置,目录路径必须是pod存在的
server:
http_listen_port: 8088 #开放promtail的http端口,方便浏览器查看调试
target_config:
sync_period: 10s
scrape_configs:
- job_name: kubernetes-pods-name
pipeline_stages:
- docker: {}
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels:
- __meta_kubernetes_pod_label_name
target_label: __service__ #前后带__表示隐藏不显示这个标签,但loki中可以搜索到
- source_labels:
- __meta_kubernetes_pod_node_name
target_label: __host__
- action: drop
regex: ^$
source_labels:
- __service__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- action: replace
replacement: $1
separator: /
source_labels:
- __meta_kubernetes_namespace
- __service__
target_label: job
- action: replace
source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- action: replace
source_labels:
- __meta_kubernetes_pod_name
target_label: instance
- action: replace
source_labels:
- __meta_kubernetes_pod_container_name
target_label: container_name
- replacement: /var/log/pods/*$1/*.log
separator: /
source_labels:
- __meta_kubernetes_pod_uid
- __meta_kubernetes_pod_container_name
target_label: __path__
- job_name: kubernetes-pods-app
pipeline_stages:
- docker: {}
kubernetes_sd_configs:
- role: pod
relabel_configs:
- action: drop
regex: .+
source_labels:
- __meta_kubernetes_pod_label_name
- source_labels:
- __meta_kubernetes_pod_label_app
target_label: __service__
- source_labels:
- __meta_kubernetes_pod_node_name
target_label: __host__
- action: drop
regex: ^$
source_labels:
- __service__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- action: replace
replacement: $1
separator: /
source_labels:
- __meta_kubernetes_namespace
- __service__
target_label: job
- action: replace
source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- action: replace
source_labels:
- __meta_kubernetes_pod_name
target_label: instance
- action: replace
source_labels:
- __meta_kubernetes_pod_container_name
target_label: container_name
- replacement: /var/log/pods/*$1/*.log
separator: /
source_labels:
- __meta_kubernetes_pod_uid
- __meta_kubernetes_pod_container_name
target_label: __path__
- job_name: kubernetes-pods-direct-controllers
pipeline_stages:
- docker: {}
kubernetes_sd_configs:
- role: pod
relabel_configs:
- action: drop
regex: .+
separator: ''
source_labels:
- __meta_kubernetes_pod_label_name
- __meta_kubernetes_pod_label_app
- action: drop
regex: ^([0-9a-z-.]+)(-[0-9a-f]{8,10})$
source_labels:
- __meta_kubernetes_pod_controller_name
- source_labels:
- __meta_kubernetes_pod_controller_name
target_label: __service__
- source_labels:
- __meta_kubernetes_pod_node_name
target_label: __host__
- action: drop
regex: ^$
source_labels:
- __service__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- action: replace
replacement: $1
separator: /
source_labels:
- __meta_kubernetes_namespace
- __service__
target_label: job
- action: replace
source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- action: replace
source_labels:
- __meta_kubernetes_pod_name
target_label: instance
- action: replace
source_labels:
- __meta_kubernetes_pod_container_name
target_label: container_name
- replacement: /var/log/pods/*$1/*.log
separator: /
source_labels:
- __meta_kubernetes_pod_uid
- __meta_kubernetes_pod_container_name
target_label: __path__
- job_name: kubernetes-pods-indirect-controller
pipeline_stages:
- docker: {}
kubernetes_sd_configs:
- role: pod
relabel_configs:
- action: drop
regex: .+
separator: ''
source_labels:
- __meta_kubernetes_pod_label_name
- __meta_kubernetes_pod_label_app
- action: keep
regex: ^([0-9a-z-.]+)(-[0-9a-f]{8,10})$
source_labels:
- __meta_kubernetes_pod_controller_name
- action: replace
regex: ^([0-9a-z-.]+)(-[0-9a-f]{8,10})$
source_labels:
- __meta_kubernetes_pod_controller_name
target_label: __service__
- source_labels:
- __meta_kubernetes_pod_node_name
target_label: __host__
- action: drop
regex: ^$
source_labels:
- __service__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- action: replace
replacement: $1
separator: /
source_labels:
- __meta_kubernetes_namespace
- __service__
target_label: job
- action: replace
source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- action: replace
source_labels:
- __meta_kubernetes_pod_name
target_label: instance
- action: replace
source_labels:
- __meta_kubernetes_pod_container_name
target_label: container_name
- replacement: /var/log/pods/*$1/*.log
separator: /
source_labels:
- __meta_kubernetes_pod_uid
- __meta_kubernetes_pod_container_name
target_label: __path__
- job_name: kubernetes-pods-static
pipeline_stages:
- docker: {}
kubernetes_sd_configs:
- role: pod
relabel_configs:
- action: drop
regex: ^$
source_labels:
- __meta_kubernetes_pod_annotation_kubernetes_io_config_mirror
- action: replace
source_labels:
- __meta_kubernetes_pod_label_component
target_label: __service__
- source_labels:
- __meta_kubernetes_pod_node_name
target_label: __host__
- action: drop
regex: ^$
source_labels:
- __service__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- action: replace
replacement: $1
separator: /
source_labels:
- __meta_kubernetes_namespace
- __service__
target_label: job
- action: replace
source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- action: replace
source_labels:
- __meta_kubernetes_pod_name
target_label: instance
- action: replace
source_labels:
- __meta_kubernetes_pod_container_name
target_label: container_name
- replacement: /var/log/pods/*$1/*.log
separator: /
source_labels:
- __meta_kubernetes_pod_annotation_kubernetes_io_config_mirror
- __meta_kubernetes_pod_container_name
target_label: __path__
上面的配置不太好理解,请参考一下官网关于loki-promtail的配置文档,部分解说原文翻译中文如下:
regex是任何有效的 RE2正则表达式。这是必需的replace,keep,drop,labelmap,labeldrop和 labelkeep行动。正则表达式固定在两端。
- replace:regex与串联的匹配source_labels。然后,设置 target_label于replacement与匹配组的引用(${1},${2},…)中replacement可以通过值取代。如果regex 不匹配,则不进行替换。
- keep:删除regex与串联不匹配的目标source_labels。
- drop:删除regex与串联的匹配的目标source_labels。
- hashmod:设置target_label为的modulus哈希值的source_labels。
- labelmap:regex与所有标签名称匹配。然后匹配标签的值复制到由给定的标签名称replacement与匹配组的参考(${1},${2},…)在replacement由他们的价值取代。
- labeldrop:regex与所有标签名称匹配。任何匹配的标签将从标签集中删除。
- labelkeep:regex与所有标签名称匹配。任何不匹配的标签都将从标签集中删除
抓取pod内应用程序指定日志目录如下:
前提:pod应用程序日志目录有做持久卷映射到node节点主机目录
[root@kubeadm loki]# cat promtail-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: promtail-config
data:
promtail.yaml: |
clients:
- url: http://192.168.37.202:3100/loki/api/v1/push
positions:
filename: /var/log/positions.yaml
server:
http_listen_port: 8088
target_config:
sync_period: 10s
scrape_configs:
- job_name: service
static_configs:
- targets:
- localhost
labels:
job: web01
__path__: /var/log/web01/*/*.log #抓取node节点/var/log/web01/*/下的所有日志
- targets:
- localhost
labels:
job: web02
__path__: /var/log/web02/*/*.log
执行:
[root@kubeadm loki]# kubectl apply -f promtail-daemonset.yaml
[root@kubeadm loki]# kubectl apply -f promtail-configmap.yaml
[root@kubeadm loki]# kubectl get pod
NAME READY STATUS RESTARTS AGE
promtail-daemonset-7j88j 1/1 Running 0 4h4m
promtail-daemonset-j5jps 1/1 Running 0 4h4m
promtail-daemonset-lxdtq 1/1 Running 0 4h4m
排错:
查看报错,按照相应提示解决问题
[root@kubeadm loki]# kubectl describe pod/promtail-daemonset-7j88j
[root@kubeadm loki]# kubectl logs pod/promtail-daemonset-7j88j
注意:promtail-daemonset.yaml读取promtail-configmap.yaml文件中内容是首次启动就读进了,promtail-configmap.yaml内容有更新的,需要kubectl delete -f promtail-daemonset.yaml后再重新apply promtail-daemonset.yaml文件。
附:测试环境中的实例:
[root@kubemaster01 yaml]# cat promtail.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: promtail-serviceaccount
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: promtail-clusterrole
rules:
- apiGroups:
- '*'
resources:
- '*'
verbs:
- '*'
- nonResourceURLs:
- '*'
verbs:
- '*'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: promtail-clusterrolebinding
subjects:
- kind: ServiceAccount
name: promtail-serviceaccount
namespace: default
roleRef:
kind: ClusterRole
name: promtail-clusterrole
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: ConfigMap
metadata:
name: promtail-config
data:
promtail.yaml: |
clients:
- url: http://192.168.19.44:31000/loki/api/v1/push
positions:
filename: /var/log/positions.yaml
server:
http_listen_port: 8088
target_config:
sync_period: 10s
scrape_configs:
- job_name: service
static_configs:
- targets:
- localhost
labels:
job: contract
__path__: /ubox/logs/contract/*/*.log
pipeline_stages:
- match:
selector: '{job=~".*"}'
stages:
- regex:
expression: '^(?P<time>\S+ \S+) (?P<content>.*)$'
- timestamp:
source: time
format: 2006-01-02 15:04:05
location: 'Asia/Shanghai'
- match:
selector: '{job=~".*"}'
stages:
- regex:
expression: '(?P<IP>\S+?) - (?P<user>\S+?) \[(?P<time>\S+? \+\d{4})\] (?P<content>.*)$'
- timestamp:
source: time
format: 02/Jan/2006:15:04:05 -0700
location: 'Asia/Shanghai'
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: promtail-daemonset
spec:
selector:
matchLabels:
name: promtail
template:
metadata:
labels:
name: promtail
spec:
hostNetwork: true
serviceAccount: SERVICE_ACCOUNT
serviceAccountName: promtail-serviceaccount
volumes:
- name: logs
hostPath:
path: /var/log
- name: servicelog
hostPath:
path: /ubox/logs
- name: promtail-config
configMap:
name: promtail-config
containers:
- name: promtail-container
image: harbor.dev.uboxol.com/library/promtail:8809de6
args:
- -config.file=/etc/promtail/promtail.yaml
- -client.url=http://192.168.19.44:31000/loki/api/v1/push
volumeMounts:
- name: logs
mountPath: /var/log
- name: servicelog
mountPath: /ubox/logs
readOnly: true
- name: promtail-config
mountPath: /etc/promtail
imagePullSecrets:
- name: registry-harbor
注:这个文件写了两个配置时间格式的正则,下面是日志的实例:
#日志1:
2020-07-27 13:18:38 Date-info: REQUEST_ID:5f1a6a7e27520:.......
#时间截匹配正则:
expression: '^(?P<time>\S+ \S+) (?P<content>.*)$'
#日志2:
172.16.214.64 - - [27/Jul/2020:12:00:00 +0800] "GET /contracts/index?sdfsdsdfsfsdfsd......
#时间截匹配正则:
expression: '(?P<IP>\S+?) - (?P<user>\S+?) \[(?P<time>\S+? \+\d{4})\] (?P<content>.*)$'