背景
当一个程序运行时,为了掌握程序的运行情况,我们需要对程序进行日志采集。无论是传统的机器部署,还是基于 k8s 的服务部署,日志采集的整体逻辑是一样的: ① 日志落盘 ② 日志采集 ③ 日志处理 ④ 日志存储 ⑤ 日志展示 ⑥ 日志归档
本文,我们一起搭建一套简单的日志采集体系。
日志流程
日志落盘
传统服务运行时,可以通过将日志写到一个目录下的文件中。
TODO: 跑通一个日志库的完整使用
stdout 直接输出到容器日志文件
日志采集
日志处理
日志存储
日志展示
日志归档
基于日志的告警
其他
实操
fluentd k8s 实操
由于集群的日志都会在当前机器的文件系统存放,所以实际上只需要起一个 fluentd 进程,并且能够读取日志目录即可。
如果在集群中,则需要以下操作: ① 启动 fluentd 的进程容器 ② 把 k8s 日志目录挂到容器中。 为了解决对 每台机器 的日志采集,需要采用部署中的 daemonset。
另外,由于一些插件可能会用到集群信息,需要给部署集绑定集群角色。
具体可以查看: fluentd 的官方文档
实际的部署文件如下: (参考官方案例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
| --- apiVersion: v1 kind: ServiceAccount metadata: name: fluentd namespace: kube-system labels: k8s-app: fluentd addonmanager.kubernetes.io/mode: Reconcile --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: fluentd labels: k8s-app: fluentd addonmanager.kubernetes.io/mode: Reconcile rules: - apiGroups: - "" resources: - "namespaces" - "pods" verbs: - "get" - "watch" - "list" --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: fluentd labels: k8s-app: fluentd addonmanager.kubernetes.io/mode: Reconcile subjects: - kind: ServiceAccount name: fluentd namespace: kube-system apiGroup: "" roleRef: kind: ClusterRole name: fluentd apiGroup: "" --- kind: ConfigMap apiVersion: v1 metadata: name: fluentd namespace: kube-system labels: addonmanager.kubernetes.io/mode: Reconcile data: input.conf: |- <source> @type tail tag k8s.fluentd.log.* path /var/log/containers/*.log pos_file /var/log/k8s.fluentd.log.pos refresh_interval 3s read_from_head true rotate_wait 30s <parse> @type regexp expression ^(?<time>[^ ]+) (?<stream>stdout|stderr) (?<logtag>[^ ]*) (?<log>.*)$ time_type string time_format %Y-%m-%dT%H:%M:%S.%N%z localtime true keep_time_key true </parse> </source>
output.conf: |- <match k8s.**> @type file path /xxx/log add_path_suffix true path_suffix ".log" append true <format> @type json </format> <buffer tag> @type file path /xx/log/fluentd.log.buffer chunk_limit_size 8MB total_limit_size 64MB flush_mode interval flush_interval 1s retry_max_interval 30 retry_forever true flush_thread_count 4 </buffer> </match> --- apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd namespace: kube-system labels: k8s-app: fluentd addonmanager.kubernetes.io/mode: Reconcile spec: selector: matchLabels: k8s-app: fluentd template: metadata: labels: k8s-app: fluentd annotations: seccomp.security.alpha.kubernetes.io/pod: 'docker/default' spec: priorityClassName: system-node-critical serviceAccountName: fluentd containers: - name: fluentd image: fluent/fluentd-kubernetes-daemonset:v1.15-debian-forward-amd64-1 imagePullPolicy: IfNotPresent env: - name: FLUENTD_ARGS value: --no-supervisor -q resources: limits: cpu: 1 memory: 3Gi requests: cpu: 100m memory: 100Mi volumeMounts: - name: varlog mountPath: /var/log - name: config-volume mountPath: /etc/fluent/config.d - name: outputlog mountPath: {{ EXT_K3S_LOG_PATH }} terminationGracePeriodSeconds: 30 tolerations: - operator: Exists volumes: - name: varlog hostPath: path: /var/log - name: config-volume configMap: name: fluentd - name: outputlog hostPath: path: {{ EXT_K3S_LOG_PATH }}
|
fluentbit k8s 实操
fluentd 是一个 ruby + c 的实现,可能还是有些问题吧,主要是多了一些系统依赖,于是又搞了一个 纯c 写的 fluentbit, 这有官方文档写的两者的关系和差别。 fluentd 的缺点是有 ruby 的环境依赖,优点是拥有 1000+ plugins。 fluentbit 的缺点是目前仅有 70+ 插件,优点是无环境依赖,一个二进制就可以跑。
k8s 使用 helm 部署,可以直接参考 官方文档, 这是默认的 values.yaml
对于一个日志采集器而言,主要就是配置这么几个环节(管道):
- input: 用于配置从何处采集日志,例如文件夹、http、mqtt 等等
- parser: 处理拿到的日志格式,例如 把 docker 日志处理成 json、把 ng 日志处理成 json 等等。
- filter: 过滤操作,可以修改、添加一些信息,例如加 pod name 之类的。
- output: 日志的输出,可以是 kafka、file、es、nats
值得一提的是,fluentbit 支持用 golang build 成 lib 的方式,具体可以参考 官方文档
Life is really simple, but we insist on making it complicated.
— Confucius