日志源解析|自建Kubernetes集群部署CLS日志服务原理及场景实现

2021-12-14 16:14:00 浏览数 (2)

作者:kahing、willyi

导语:云原生日志服务(Cloud Log Service,CLS)是腾讯云提供的一站式日志数据解决平台,提供了从日志采集、日志存储到日志检索,图表分析、监控告警、日志投递等多项服务,协助用户通过日志来解决业务运维、服务监控、日志审计等场景问题。

简介

日志服务CLS支持采集自建K8s集群上的日志,在进行日志采集前,需要在K8s自建集群上通过CRD定义日志采集配置(LogConfig),并部署安装Log-Provisoner,Log-Agent,以及LogListener。针对使用腾讯云容器服务(Tencent Kubernetes Engine , TKE)的用户, 可参见TKE开启日志采集文档,通过控制台快速接入并使用日志服务。

腾讯云容器服务(Tencent Kubernetes Engine ,TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务。腾讯云容器服务完全兼容原生 kubernetes API ,扩展了腾讯云的云硬盘、负载均衡等 kubernetes 插件,为容器化的应用提供高效部署、资源调度。

前提条件

  1. Kubernetes 1.10 及以上版本集群;
  2. 开通日志服务, 创建日志集与日志主题, 并获取日志主题ID(topicId),详细配置请参见 创建日志主题 文档;
  3. 获取日志主题所在地域的域名(CLS_HOST),详细CLS域名列表请参见 可用地域 文档;
  4. 获取访问CLS侧鉴权所需的API密钥ID(TmpSecretId)以及API密钥Key(TmpSecretKey),请前往 API密钥管理 查看。

K8s日志采集原理

K8s集群上部署日志采集主要涉及Log-Provisoner,Log-Agent,LogListener三个组件,以及一个LogConfig采集配置。

  • LogConfig:日志采集配置,定义了日志从哪里被采集, 采集后如何解析, 解析后投递至CLS侧的哪个日志主题。
  • Log-Provisoner: 将LogConfig中定义日志采集配置信息同步至CLS侧。
  • Log-Agent:监听LogConfig和节点上容器的变化, 动态计算容器中的日志文件在节点宿主机上的实际位置。
  • LogListener:采集节点宿主机上的相应日志文件内容,解析并上传至CLS侧。

部署步骤

定义LogConfig资源类型

定义LogConfig对象

创建LogConfig对象

配置CLS鉴权ConfigMap

部署cls-provisione

部署log-agent与loglistener

1. 定义LogConfig资源类型

使用K8s中的Custom Resource Definition(CRD)定义 LogConfig资源类型。

以Master节点路径/usr/local/为例:wget下载CRD.yaml声明文件,使用kubectl定义LogConfig资源类型。操作命令如下:

代码语言:javascript复制
# wget https://mirrors.tencent.com/install/cls/k8s/CRD.yaml
# kubectl create -f /usr/local/CRD.yaml

2. 定义LogConfig对象

通过创建LogConfig对象定义日志采集配置,即日志从哪里被采集, 采集后如何解析, 解析后投递至CLS侧的哪个日志主题。

以Master节点路径/usr/local/为例:wget下载LogConfig.yaml声明文件

代码语言:javascript复制
# wget https://mirrors.tencent.com/install/cls/k8s/LogConfig.yaml

LogConfig.yaml声明文件主要分为两个部分:

  • clsDetail:定义日志解析格式,以及目标日志主题ID(topicId)
  • inputDetail:定义采集日志源,即日志从哪里被采集

注意:需将clsDetail中的topicId项配置为您创建的日志主题ID

以下将对日志解析格式以及日志源的配置进行说明:

日志解析格式

CLS支持以下几种日志解析格式:

单行全文格式

多行全文格式

完全正则格式

JSON格

分隔符格式

1. 单行全文格式

单行全文日志是指一行日志内容为一条完整的日志。日志服务在采集的时候,将使用换行符n来作为一条日志日志的结束符。为了统一结构化管理,每条日志都会存在一个默认的键值CONTENT,但日志数据本身不再进行日志结构化处理,也不会提取日志字段,日志属性的时间项由日志采集的时间决定。

假设一条日志原始数据为:

代码语言:javascript复制
Tue Jan 22 12:08:15 CST 2019 Installed: libjpeg-turbo-static-1.2.90-6.el7.x86_64

LogConfig配置参考示例如下:

代码语言:javascript复制
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
clsDetail:
  topicId: xxxxxx-xx-xx-xx-xxxxxxxx
   # 单行日志
  logType: minimalist_log

采集到日志服务的数据为:

代码语言:javascript复制
__CONTENT__:Tue Jan 22 12:08:15 CST 2019 Installed: libjpeg-turbo-static-1.2.90-6.el7.x86_64

2. 多行全文格式

多行全文日志是指一条完整的日志数据可能跨占多行(例如 Java  stacktrace)。在这种情况下,以换行符n 为日志的结束标识符就显得有些不合理,为了能让日志系统明确区分开每条日志,采用首行正则的方式进行匹配,当某行日志匹配上预先设置的正则表达式,就认为是一条日志的开头,而下一个行首出现作为该条日志的结束标识符。

多行全文也会设置一个默认的键值CONTENT,但日志数据本身不再进行日志结构化处理,也不会提取日志字段,日志属性的时间项由日志采集的时间决定。

假设一条多行日志原始数据为:

代码语言:javascript复制
2019-12-15 17:13:06,043 [main] ERROR com.test.logging.FooFactory:
java.lang.NullPointerException
    at com.test.logging.FooFactory.createFoo(FooFactory.java:15)
    at com.test.logging.FooFactoryTest.test(FooFactoryTest.java:11)

LogConfig配置的参考如下:

代码语言:javascript复制
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
  clsDetail:
    topicId: xxxxxx-xx-xx-xx-xxxxxxxx
    # 多行日志
    logType: multiline_log
    extractRule:
      # 只有以日期时间开头的行才被认为是新一条日志的开头,否则就添加换行符n并追加到当前日志的尾部
      beginningRegex: d{4}-d{2}-d{2}sd{2}:d{2}:d{2},d{3}s. 

采集到日志服务的数据为:

代码语言:javascript复制
__CONTENT__:2019-12-15 17:13:06,043 [main] ERROR com.test.logging.FooFactory:njava.lang.NullPointerExceptionn    at com.test.logging.FooFactory.createFoo(FooFactory.java:15)n    at com.test.logging.FooFactoryTest.test(FooFactoryTest.java:11)

3. 单行-完全正则格式

单行完全正则格式通常用来处理结构化的日志,指将一条完整日志按正则方式提取多个 key-value 的日志解析模式。

假设一条日志原始数据为:

代码语言:javascript复制
10.135.46.111 - - [22/Jan/2019:19:19:30  0800] "GET /my/course/1 HTTP/1.1" 127.0.0.1 200 782 9703 "http://127.0.0.1/course/explore?filter[type]=all&filter[price]=all&filter[currentLevelId]=all&orderBy=studentNum" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0"  0.354 0.354

LogConfig配置的参考如下:

代码语言:javascript复制
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
  clsDetail:
    topicId: xxxxxx-xx-xx-xx-xxxxxxxx
    # 完全正则格式
    logType: fullregex_log
    extractRule:
      # 正则表达式,会根据()捕获组提取对应的value
      logRegex: (S )[^[] ([[^:] :d :d :d sS )s"(w )s(S )s([^"] )"s(S )s(d )s(d )s(d )s"([^"] )"s"([^"] )"s (S )s(S ).*
      beginningRegex: (S )[^[] ([[^:] :d :d :d sS )s"(w )s(S )s([^"] )"s(S )s(d )s(d )s(d )s"([^"] )"s"([^"] )"s (S )s(S ).*
      # 提取的key列表,与提取的value的一一对应
      keys:  ['remote_addr','time_local','request_method','request_url','http_protocol','http_host','status','request_length','body_bytes_sent','http_referer','http_user_agent','request_time','upstream_response_time']

采集到日志服务的数据为:

代码语言:javascript复制
body_bytes_sent: 9703
http_host: 127.0.0.1
http_protocol: HTTP/1.1
http_referer: http://127.0.0.1/course/explore?filter[type]=all&filter[price]=all&filter[currentLevelId]=all&orderBy=studentNum
http_user_agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0
remote_addr: 10.135.46.111
request_length: 782
request_method: GET
request_time: 0.354
request_url: /my/course/1
status: 200
time_local: [22/Jan/2019:19:19:30  0800]
upstream_response_time: 0.354

4. 多行-完全正则格式

多行-完全正则模式适用于日志文本中一条完整的日志数据跨占多行(例如 Java 程序日志),可按正则表达式提取为多个 key-value 键值的日志解析模式。若不需要提取 key-value,请参阅多行全文格式进行配置。假设一条日志原始数据为:

代码语言:javascript复制
[2018-10-01T10:30:01,000] [INFO] java.lang.Exception: exception happened
   at TestPrintStackTrace.f(TestPrintStackTrace.java:3)
   at TestPrintStackTrace.g(TestPrintStackTrace.java:7)
   at TestPrintStackTrace.main(TestPrintStackTrace.java:16)

LogConfig 配置的参考如下:

代码语言:javascript复制
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec: 
  clsDetail: 
    topicId: xxxxxx-xx-xx-xx-xxxxxxxx
        #多行-完全正则格式
        logType: multiline_fullregex_log
        extractRule: 
      #行首完全正则表达式,只有以日期时间开头的行才被认为是新一条日志的开头,否则就添加换行符n并追加到当前日志的尾部
            beginningRegex: [d -d -w :d :d ,d ]s[w ]s.*
      #正则表达式,会根据()捕获组提取对应的value
      logRegex: [(d -d -w :d :d ,d )]s[(w )]s(.*)
            # 提取的 key 列表,与提取的 value 的一一对应
            keys: 
      - time 
      - level 
      - msg

根据提取的 key,采集到日志服务的数据为:

代码语言:javascript复制
time: 2018-10-01T10:30:01,000`
level: INFO`
msg:java.lang.Exception: exception happened
   at TestPrintStackTrace.f(TestPrintStackTrace.java:3)
   at TestPrintStackTrace.g(TestPrintStackTrace.java:7)
   at TestPrintStackTrace.main(TestPrintStackTrace.java:16)

5. JSON格式

JSON 格式日志会自动提取首层的 key 作为对应字段名,首层的 value 作为对应的字段值,以该方式将整条日志进行结构化处理,每条完整的日志以换行符n为结束标识符。

假设一条 JSON 日志原始数据为:

代码语言:javascript复制
{"remote_ip":"10.135.46.111","time_local":"22/Jan/2019:19:19:34  0800","body_sent":23,"responsetime":0.232,"upstreamtime":"0.232","upstreamhost":"unix:/tmp/php-cgi.sock","http_host":"127.0.0.1","method":"POST","url":"/event/dispatch","request":"POST /event/dispatch HTTP/1.1","xff":"-","referer":"http://127.0.0.1/my/course/4","agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0","response_code":"200"}

LogConfig配置的参考如下:

代码语言:javascript复制
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
  clsDetail:
    topicId: xxxxxx-xx-xx-xx-xxxxxxxx
    # JSON格式日志
    logType: json_log

采集到日志服务的数据为:

代码语言:javascript复制
agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0
body_sent: 23
http_host: 127.0.0.1
method: POST
referer: http://127.0.0.1/my/course/4
remote_ip: 10.135.46.111
request: POST /event/dispatch HTTP/1.1
response_code: 200
responsetime: 0.232
time_local: 22/Jan/2019:19:19:34  0800
upstreamhost: unix:/tmp/php-cgi.sock
upstreamtime: 0.232
url: /event/dispatch
xff: -

6. 分隔符格式

分隔符日志是指一条日志数据可以根据指定的分隔符将整条日志进行结构化处理,每条完整的日志以换行符n为结束标识符。日志服务在进行分隔符格式日志处理时,您需要为每个分开的字段定义唯一的 key。

假设您的一条日志原始数据为:

代码语言:javascript复制
10.20.20.10 ::: [Tue Jan 22 14:49:45 CST 2019  0800] ::: GET /online/sample HTTP/1.1 ::: 127.0.0.1 ::: 200 ::: 647 ::: 35 ::: http://127.0.0.1/

LogConfig配置的参考如下:

代码语言:javascript复制
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
  clsDetail:
    topicId: xxxxxx-xx-xx-xx-xxxxxxxx
    # 分隔符日志
    logType: delimiter_log
    extractRule:
      # 分隔符
      delimiter: ':::'
      # 提取的key列表,与被分割的字段一一对应
      keys: ['IP','time','request','host','status','length','bytes','referer']

采集到日志服务的数据为:

代码语言:javascript复制
IP: 10.20.20.10
bytes: 35
host: 127.0.0.1
length: 647
referer: http://127.0.0.1/
request: GET /online/sample HTTP/1.1
status: 200
time: [Tue Jan 22 14:49:45 CST 2019  0800]

日志源

CLS支持一下几种集群日志源:

容器标准输出

容器文件

主机文件

1. 容器标准输出

示例1:采集default命名空间中的所有容器的标准输出

代码语言:javascript复制
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
  inputDetail:
    type: container_stdout
    containerStdout:
      namespace: default
      allContainers: true
 ...

示例2: 采集production命名空间中属于ingress-gateway deployment的pod中的容器的标准输出

代码语言:javascript复制
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
  inputDetail:
    type: container_stdout
    containerStdout:
      allContainers: false
      workloads:
      - namespace: production
        name: ingress-gateway
        kind: deployment
  ...

示例3: 采集production命名空间中pod标签中包含“k8s-app=nginx”的pod中的容器的标准输出

代码语言:javascript复制
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
  inputDetail:
    type: container_stdout
    containerStdout:
      namespace: production
      allContainers: false
      includeLabels:
        k8s-app: nginx
  ...

2. 容器文件

示例1: 采集production命名空间中属于ingress-gateway deployment的pod中的nginx容器中/data/nginx/log/路径下名为access.log的文件

代码语言:javascript复制
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
  topicId: xxxxxx-xx-xx-xx-xxxxxxxx
  inputDetail:
    type: container_file
    containerFile:
      namespace: production
      workload:
        name: ingress-gateway
        type: deployment
      container: nginx
      logPath: /data/nginx/log
      filePattern: access.log
  ...

示例2: 采集production命名空间中pod标签包含“k8s-app=ingress-gateway“的pod中的nginx容器中/data/nginx/log/路径下名为access.log的文件

代码语言:javascript复制
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
  inputDetail:
    type: container_file
    containerFile:
      namespace: production
      includeLabels:
        k8s-app: ingress-gateway
      container: nginx
      logPath: /data/nginx/log
      filePattern: access.log
  ...

3. 主机文件

示例: 采集主机/data/路径下所有.log文件

代码语言:javascript复制
apiVersion: cls.cloud.tencent.com/v1
kind: LogConfig
spec:
  inputDetail:
    type: host_file
    hostFile:
      logPath: /data
      filePattern: *.log
  ...

3. 创建LogConfig对象

基于您的需求,参见 步骤2 配置说明,定义LogConfig.yaml声明文件,并使用kubect创建LogConfig对象。操作命令如下:

代码语言:javascript复制
# kubectl create -f /usr/local/LogConfig.yaml

4. 配置CLS鉴权ConfigMap

将日志从自建K8s集群上传至CLS侧涉及鉴权, 需要创建ConfigMap用于存储API密钥IDAPI密钥KEY。

以Master节点路径/usr/local/为例:wget下载ConfigMap.yaml声明文件

代码语言:javascript复制
# wget https://mirrors.tencent.com/install/cls/k8s/ConfigMap.yaml

注意:需将ConfigMap.yaml中的TmpSecretId以及TmpSecretKey的值配置为您的API密钥IDAPI密钥KEY

使用kubect创建ConfigMap对象。操作命令如下:

代码语言:javascript复制
# kubectl create -f /usr/local/ConfigMap.yaml

5. 部署Log-Provinsioner

Log-Provisioner负责发现并监听LogConfig资源中日志主题ID, 日志采集规则,日志文件路径,并同步至CLS侧。 

以Master节点路径/usr/local/为例:wget下载Log-Provisioner.yaml声明文件

代码语言:javascript复制
# wget https://mirrors.tencent.com/install/cls/k8s/Log-Provisioner.yaml

注意:需将Log-Provisioner.yaml中环境变量env下的CLS_HOST字段配置为目标日志主题所在地域的域名。 不同地域的域名请参见 这里

使用kubect以Deployment的方式部署Log-Provinsioner。操作命令如下:

代码语言:javascript复制
# kubectl create -f /usr/local/Log-Provinsioner.yaml

6. 部署Log-Agent和Loglistener

集群的日志采集主要分为两个部分, 一个是Log-Agent,一个是Loglistener:

  • Log-Agent负责拉取集群中LogConfig中的日志源信息,并计算容器日志在宿主机上映射的绝对路径。
  • Loglistener负责采集与解析宿主机日志文件路径下的日志文件,并上传至CLS侧

以Master节点路径/usr/local/为例:wget下载Log-Agent和Loglistener的声明文件

代码语言:javascript复制
# wget https://mirrors.tencent.com/install/cls/k8s/Log—Agent.yaml

注意:如果宿主机的docker根目录不在/var/lib/docker(这是在宿主机的根目录)下,需要在Log—Agent.yaml声明文件中把docker的根目录映射到容器中,如下图,将/data/docker挂载到容器中。

docker根目录映射到容器docker根目录映射到容器

使用kubect以DaemonSet的方式部署Log-Agent和Loglistener。操作命令如下:

代码语言:javascript复制
# kubectl create -f /usr/local/Log—Agent.yaml

CLS控制台查看日志

至此, 就完成了集群日志采集的所有部署,您可以到CLS侧检索页查看采集上来的日志。

CLS检索页CLS检索页

其他资料

[1] TKE开启日志采集:https://cloud.tencent.com/document/product/457/56751

[2] 创建日志主题:https://cloud.tencent.com/document/product/614/41035

[3] 可用地域:https://cloud.tencent.com/document/product/614/18940

[4] API密钥管理:https://console.cloud.tencent.com/cam/capi

[5] CLS 日志服务检索页:https://console.cloud.tencent.com/cls/search

[6] CLS 日志服务免费额度领取:https://cloud.tencent.com/document/product/614/47116


以上就是本期自建K8s集群部署CLS日志服务的分享,如果您有更多有意思的日志实践,欢迎投稿~

一站式日志数据解决方案平台一站式日志数据解决方案平台

往期文章:

【日志服务CLS】免费体验Demo日志:一键开启,CLS全功能开箱即用

【日志服务CLS】容器服务TKE审计日志运维场景体验

【日志服务CLS】Nginx日志数据全方位大解析

对象存储COS访问日志场景体验

【日志服务CLS】腾讯云日志服务CLS接入内容分发网络CDN

0 人点赞