带你玩转kubernetes-k8s(第63篇-Kubernetes之集群统一日志管理)

释放双眼,带上耳机,听听看~!

在Kubernetes集群环境中,一个完整的应用或服务都会涉及为数众多的组件运行,各组件所在的Node及实例数量都是可变的。日志子系统如果不做集中化管理,则会给系统的运维支撑造成很大的困难,因此有必要在集群层面对日志进行统一收集和检索等工作。

在容器中输出到控制台的日志,都会以*-json.log的命名方式保存在/var/lib/docker/containers/目录下,这就为日志采集和后续处理奠定了基础。

Kubernetes推荐采用Fluentd+Elasticsearch+Kibana完成对系统和容器日志的采集、查询和展现工作。

部署统一的日志管理系统,需要以下两个前提条件。

       ◎ API Server正确配置了CA证书。

       ◎ DNS服务启动、运行。

系统部署架构

该系统的逻辑架构如下图:

带你玩转kubernetes-k8s(第63篇-Kubernetes之集群统一日志管理)

在各Node上都运行了一个Fluentd容器,采集本节点/var/log和/var/lib/docker/containers两个目录下的日志进程,将其汇总到Elasticsearch集群,最终通过Kibana完成和用户的交互工作。

这里有一个特殊的需求:Fluentd必须在每个Node上运行,为了满足这一需求,我们通过下面几种方式部署Fluentd。

◎ 直接在Node主机上部署Fluentd。
◎ 利用kubelet的–config参数,为每个Node都加载Fluentd Pod。
◎ 利用DaemonSet让Fluentd Pod在每个Node上运行。

创建Elasticsearch RC和Service

Elasticsearch的RC和Service定义如下:


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
1---
2apiVersion: v1
3kind: ReplicationController
4metadata:
5  name: elasticsearch-logging-v1
6  namespace: kube-system
7  labels:
8    k8s-app: elasticsearch-logging
9    version: v1
10    kubernetes.io/cluster-service: "true"
11spec:
12  replicas: 2
13  selector:
14    k8s-app: elasticsearch-logging
15    version: v1
16  template:
17    metadata:
18      labels:
19        k8s-app: elasticsearch-logging
20        version: v1
21        kubernetes.io/cluster-service: "true"
22    spec:
23      containers:
24      - image: gcr.io/google_containers/elasticsearch:1.8
25        name: elasticsearch-logging
26        resources:
27          # keep request = limit to keep this container in guaranteed class
28          limits:
29            cpu: 100m
30          requests:
31            cpu: 100m
32        ports:
33        - containerPort: 9200
34          name: db
35          protocol: TCP
36        - containerPort: 9300
37          name: transport
38          protocol: TCP
39        volumeMounts:
40        - name: es-persistent-storage
41          mountPath: /data
42      volumes:
43      - name: es-persistent-storage
44      emptyDir: {}
45---
46apiVersion: v1
47kind: Service
48metadata:
49  name: elasticsearch-logging
50  namespace: kube-system
51  labels:
52    k8s-app: elasticsearch-logging
53    kubernetes.io/cluster-service: "true"
54    kubernetes.io/name: "Elasticsearch"
55spec:
56  ports:
57  - port: 9200
58    protocol: TCP
59    targetPort: db
60  selector:
61    k8s-app: elasticsearch-logging
62

执行kubectl create -f elastic-search.yml命令完成创建。
在命令成功执行后,首先验证Pod的运行情况。通过kubectl get pods–namespaces=kube-system获取运行中的Pod。

接下来通过Elasticsearch页面验证其功能。

首先,执行# kubectl cluster-info命令获取Elasticsearch服务的地址。带你玩转kubernetes-k8s(第63篇-Kubernetes之集群统一日志管理)

然后,使用# kubectl proxy命令对API Server进行代理,在成功执行后输出如下内容:

这样就可以在浏览器上访问URL地址https://20.0.40.51:12567/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy,来验证Elasticsearch的运行情况了,返回的内容是一个JSON文档。

在每个Node上启动Fluentd

Fluentd的DaemonSet定义如下:


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
1apiVersion: extensions/v1beta1
2kind: DaemonSet
3metadata:
4  name: fluentd-cloud-logging
5  namespace: kube-system
6  labels:
7    k8s-app: fluentd-cloud-logging
8spec:
9  template:
10    metadata:
11      namespace: kube-system
12      labels:
13        k8s-app: fluentd-cloud-logging
14    spec:
15      containers:
16      - name: fluentd-cloud-logging
17        image: gcr.io/google_containers/fluentd-elasticsearch:1.17
18        resources:
19          limits:
20            cpu: 100m
21            memory: 200Mi
22        env:
23        - name: FLUENTD_ARGS
24          value: -q
25        volumeMounts:
26        - name: varlog
27          mountPath: /var/log
28          readOnly: false
29        - name: containers
30          mountPath: /var/lib/docker/containers
31          readOnly: false
32      volumes:
33      - name: containers
34        hostPath:
35          path: /var/lib/docker/containers
36      - name: varlog
37        hostPath:
38          path: /var/log
39
40

通过kubectl create命令创建Fluentd容器:

查看创建的结果:

结果显示Fluentd DaemonSet正常运行,还启动了3个Pod,与集群中的Node数量一致。

接下来使用# kubectl logs fluentd-cloud-logging-7tw9z命令查看Pod的日志,在Elasticsearch正常工作的情况下,我们会看到类似下面这样的日志内容:


1
2
3
4
5
1# kubectl logs fluentd-cloud-logging-7tw9z
2
3    Connection opened to Elasticsearch cluster =>
4{:host => "elasticsearch-logging", :port=>9200, :scheme=>"http"}
5

运行Kibana

至此已经运行了Elasticsearch和Fluentd,数据的采集和汇聚已经完成,接下来使用Kibana展示和操作数据。

Kibana的RC和Service定义如下:


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
1---
2apiVersion: v1
3kind: ReplicationController
4metadata:
5  name: kibana-logging-v1
6  namespace: kube-system
7  labels:
8    k8s-app: kibana-logging
9    version: v1
10    kubernetes.io/cluster-service: "true"
11spec:
12  replicas: 1
13  selector:
14    k8s-app: kibana-logging
15    version: v1
16  template:
17    metadata:
18      labels:
19        k8s-app: kibana-logging
20        version: v1
21        kubernetes.io/cluster-service: "true"
22    spec:
23      containers:
24      - name: kibana-logging
25        image: gcr.io/google_containers/kibana:1.3
26        resources:
27          # keep request = limit to keep this container in guaranteed class
28          limits:
29            cpu: 100m
30          requests:
31            cpu: 100m
32        env:
33          - name: "ELASTICSEARCH_URL"
34            value: "http://elasticsearch-logging:9200"
35        ports:
36        - containerPort: 5601
37          name: ui
38          protocol: TCP
39---
40apiVersion: v1
41kind: Service
42metadata:
43  name: kibana-logging
44  namespace: kube-system
45  labels:
46    k8s-app: kibana-logging
47    kubernetes.io/cluster-service: "true"
48    kubernetes.io/name: "Kibana"
49spec:
50  ports:
51  - port: 5601
52    protocol: TCP
53    targetPort: ui
54  selector:
55    k8s-app: kibana-logging
56

通过kubectl create -f kibana-rc-svc.yml命令创建Kibana的RC和Service。

查看Kibana的运行情况。

结果表明运行均已成功。通过kubectl cluster-info命令获取Kibana服务的URL地址。

同样通过kubectl proxy命令启动代理,在出现“Starting to serve on 127.0.0.1:8001”字样之后,用浏览器访问URL地址http://ip:port/api/v1/proxy/namespaces/kube-system/services/kibana-logging即可访问Kibana页面。

第1次进入页面时需要进行一些设置,选择所需选项后单击create按钮。

然后单击discover按钮,就可以正常查询日志了。

在搜索栏输入“error”关键字,可以搜索出包含该关键字的日志记录。

同时,通过左边菜单中Fields相关的内容对查询的内容进行限定。

至此,Kubernetes集群范围内的统一日志收集和查询系统就搭建完成了。

Kubernetes的审计机制

Kubernetes为了加强对集群操作的安全监管,从1.4版本开始引入审计机制,主要体现为审计日志(Audit Log)。审计日志按照时间顺序记录了与安全相关的各种事件,这些事件有助于系统管理员快速、集中了解以下问题:

◎ 发生了什么事情?
◎ 作用于什么对象?
◎ 在什么时间发生?
◎ 谁(从哪儿)触发的?
◎ 在哪儿观察到的?
◎ 活动的后继处理行为是怎样的?

下面是两条Pod操作的审计日志示例。

第一条:

带你玩转kubernetes-k8s(第63篇-Kubernetes之集群统一日志管理)

第二条:

带你玩转kubernetes-k8s(第63篇-Kubernetes之集群统一日志管理)

API Server把客户端的请求(Request)的处理流程视为一个“链条”,这个链条上的每个“节点”就是一个状态(Stage),从开始到结束的所有Request Stage如下。

◎ RequestReceived:在Audit Handler收到请求后生成的状态。
◎ ResponseStarted:响应的Header已经发送但Body还没有发送的状态,仅对长期运行的请求(Long-running Requests)有效,例如Watch。
◎ ResponseComplete:Body已经发送完成。
◎ Panic:严重错误(Panic)发生时的状态。
Kubernets从1.7版本开始引入高级审计特性(AdvancedAuditing),可以自定义审计策略(选择记录哪些事件)和审计存储后端(日志和Webhook)等,开启方法为增加kube-apiserver的启动参数–feature-gates=AdvancedAuditing=true。注意:在开启AdvancedAuditing后,日志的格式有一些修改,例如新增了上述Stage信息;从Kubernets 1.8版本开始,该参数默认为true。
kube-apiserver在收到一个请求后(如创建Pod的请求),会根据Audit Policy(审计策略)对此请求做出相应的处理。
我们可以将Audit Policy视作一组规则,这组规则定义了有哪些事件及数据需要记录(审计)。当一个事件被处理时,规则列表会依次尝试匹配该事件,第1个匹配的规则会决定审计日志的级别(Audit Level),目前定义的几种级别如下(按级别从低到高排列)。
◎ None:不生成审计日志。
◎ Metadata:只记录Request请求的元数据如requesting user、timestamp、resource、verb等,但不记录请求及响应的具体内容。
◎ Request:记录Request请求的元数据及请求的具体内容。
◎ RequestResponse:记录事件的元数据,以及请求与应答的具体内容。

None以上的级别会生成相应的审计日志并将审计日志输出到后端,当前的后端实现如下。

(1)Log backend:以本地日志文件记录保存,为JSON日志格式,我们需要对API Server的启动命令设置下列参数。

◎ –audit-log-path:指定日志文件的保存路径。
◎ –audit-log-maxage:设定审计日志文件保留的最大天数。
◎ –audit-log-maxbackup:设定审计日志文件最多保留多少个。
◎ –audit-log-maxsize:设定审计日志文件的单个大小,单位为MB,默认为100MB。

审计日志文件以audit-log-maxsize设置的大小为单位,在写满后,kube-apiserver将以时间戳重命名原文件,然后继续写入audit-log-path指定的审计日志文件;audit-log-maxbackup和audit-log-maxage参数则用于kube-apiserver自动删除旧的审计日志文件。

(2)Webhook backend:回调外部接口进行通知,审计日志以JSON格式发送(POST方式)给Webhook Server,支持batch和blocking这两种通知模式,相关配置参数如下。
◎ –audit-webhook-config-file:指定Webhook backend的配置文件。

◎ –audit-webhook-mode:确定采用哪种模式回调通知。
◎ –audit-webhook-initial-backoff:指定回调失败后第1次重试的等待时间,后继重试等待时间则呈指数级递增。

Webhook backend的配置文件采用了kubeconfig格式,主要内容包括远程审计服务的地址和相关鉴权参数,配置示例如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1# clusters refers to the remote service.
2clusters:
3  - name: name-of-remote-audit-service
4    cluster:
5      certificate-authority: /path/to/ca.pem  # CA for verifying the remote service.
6      server: https://audit.example.com/audit # URL of remote service to query. Must use 'https'.
7
8# users refers to the API server's webhook configuration.
9users:
10  - name: name-of-api-server
11    user:
12      client-certificate: /path/to/cert.pem # cert for the webhook plugin to use
13      client-key: /path/to/key.pem          # key matching the cert
14
15# kubeconfig files require a context. Provide one for the API server.
16current-context: webhook
17contexts:
18- context:
19    cluster: name-of-remote-audit-service
20    user: name-of-api-sever
21  name: webhook
22

–audit-webhook-mode则包括以下选项。
◎ batch:批量模式,缓存事件并以异步批量方式通知,是默认的工作模式。
◎ blocking:阻塞模式,事件按顺序逐个处理,这种模式会阻塞API Server的响应,可能导致性能问题。
◎ blocking-strict:与阻塞模式类似,不同的是当一个Request在RequestReceived阶段发生审计失败时,整个Request请求会被认为失败。

(3)Batching Dynamic backend:一种动态配置的Webhook backend,是通过AuditSink API 动态配置的,在Kubernetes 1.13版本中引入。
需要注意的是,开启审计功能会增加API Server的内存消耗量,因为此时需要额外的内存来存储每个请求的审计上下文数据,而增加的内存量与审计功能的配置有关,比如更详细的审计日志所需的内存更多。我们可以通过kube-apiserver中的–audit-policy-file参数指定一个Audit Policy文件名来开启API Server的审计功能。

通常审计日志可以以本地日志文件方式保存,然后使用Fluentd作为Agent采集该日志并存储到Elasticsearch,用Kibana等UI界面对日志进行展示和查询。

 

小结: 今天的内容到此结束

           谢谢大家的浏览。

 

 

给TA打赏
共{{data.count}}人
人已打赏
安全运维

故障复盘的简洁框架-黄金三问

2021-9-30 19:18:23

安全运维

OpenSSH-8.7p1离线升级修复安全漏洞

2021-10-23 10:13:25

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索