介绍
在 Kubernetes 集群上运行多个服务和应用程序时,集中的集群级日志堆可以帮助您快速分类和分析您的 Pods 产生的大量日志数据。
Elasticsearch是一个实时、分布式和可扩展的搜索引擎,允许全文本和结构化搜索以及分析,通常用于索引和搜索大量日志数据,但也可以用于搜索许多不同类型的文档。
Elasticsearch 通常与 Kibana一起部署,它是 Elasticsearch 的强大的数据可视化前端和仪表板,Kibana 允许您通过 Web 界面探索您的 Elasticsearch 日志数据,并构建仪表板和查询,以快速回答问题并深入了解您的 Kubernetes 应用程序。
在本教程中,我们将使用 Fluentd 来收集、转换和将日志数据发送到 Elasticsearch 后端. Fluentd 是一个受欢迎的开源数据收集器,我们将在我们的 Kubernetes 节点上设置以收集容器日志文件,过滤和转换日志数据,并将其发送到 Elasticsearch 集群,在那里它将被索引和存储。
首先,我们将配置和启动可扩展的 Elasticsearch 集群,然后创建 Kibana Kubernetes 服务和部署。
如果您正在寻找一个管理的Kubernetes托管服务,请查看我们的简单的,用于增长的管理的Kubernetes服务(https://www.digitalocean.com/products/kubernetes)。
前提条件
在您开始使用本指南之前,请确保您有以下内容:
- 具有基于角色访问控制(RBAC)的 Kubernetes 1.10+ 集群启用
- 确保您的集群具有足够的资源来部署 EFK 堆栈,如果不能通过添加工人节点来扩展您的集群,我们将部署一个 3-Pod Elasticsearch 集群(如果需要的话,您可以扩展到 1),以及一个单一的 Kibana Pod. 每个工人节点也将运行一个 Fluentd Pod. 本指南中的集群由 3 个工人节点和一个受管理的控制平面组成。
一旦您设置了这些组件,您已经准备好开始使用本指南。
步骤 1 - 创建一个名称空间
在我们部署一个 Elasticsearch 集群之前,我们首先将创建一个 Namespace,在其中我们将安装我们的所有日志仪器。Kubernetes 允许您使用名称空间的虚拟集群
抽象来分离运行在您的集群中的对象。
首先,使用kubectl
来调查群集中的现有名称空间:
1kubectl get namespaces
您应该看到以下三个初始名称空间,这些名称空间在您的 Kubernetes 集群中预先安装:
1[secondary_label Output]
2NAME STATUS AGE
3default Active 5m
4kube-system Active 5m
5kube-public Active 5m
默认
Namespace 包含没有指定 Namespace 创建的对象。 cube-system
Namespace 包含 Kubernetes 系统创建和使用的对象,如 cube-dns
, cube-proxy
和 kubernetes-dashboard
。
公用
名称空间是另一个自动创建的名称空间,可用于存储您想要在整个群集中可读和可访问的对象,即使是未经身份验证的用户。
要创建cube-logging
的名称空间,首先打开并编辑名为cube-logging.yaml
的文件,使用您最喜欢的编辑器,如 nano:
1nano kube-logging.yaml
在您的编辑器中,粘贴以下的 Namespace 对象 YAML:
1[label kube-logging.yaml]
2kind: Namespace
3apiVersion: v1
4metadata:
5 name: kube-logging
然后保存并关闭文件。
在这里,我们将Kubernetes对象的类型
指定为Namespace
对象。 要了解有关Namespace
对象的更多信息,请参阅官方Kubernetes文档中的Namespaces Walkthrough
(https://kubernetes.io/docs/tasks/administer-cluster/namespaces-walkthrough/)。
一旦您创建了kube-logging.yaml
Namespace 对象文件,请使用kubectl create
创建使用-f
文件名旗的 Namespace:
1kubectl create -f kube-logging.yaml
你应该看到以下结果:
1[secondary_label Output]
2namespace/kube-logging created
然后您可以确认 Namespace 已成功创建:
1kubectl get namespaces
在此时刻,你应该看到新的cube-logging
名称空间:
1[secondary_label Output]
2NAME STATUS AGE
3default Active 23m
4kube-logging Active 1m
5kube-public Active 23m
6kube-system Active 23m
我们现在可以部署一个Elasticsearch集群到这个孤立的日志命名空间中。
步骤 2 — 创建 Elasticsearch StatefulSet
现在我们已经创建了一个名称空间来容纳我们的日志堆栈,我们可以开始部署它的各种组件。
在本指南中,我们使用 3 个 Elasticsearch Pods 来避免在高可用性多节点集群中出现的分裂大脑
问题。在高层次上,分裂大脑
是当一个或多个节点无法与其他节点进行通信时产生的,并选出多个分裂
大师时产生的问题。在 3 个节点中,如果一个节点暂时脱离集群,其他两个节点可以选择一个新的大师,而集群可以继续运作,而最后一个节点试图重新连接。 有关更多信息,请参阅 Elasticsearch 中的集群协调的新时代和 [投票配置(INKL1))。
创造无头无头的服务
首先,我们将创建一个名为elasticsearch
的无头Kubernetes服务,该服务将为3Pod定义一个DNS域。
使用您最喜欢的编辑器打开名为 elasticsearch_svc.yaml
的文件:
1nano elasticsearch_svc.yaml
粘贴在以下Kubernetes服务YAML:
1[label elasticsearch_svc.yaml]
2kind: Service
3apiVersion: v1
4metadata:
5 name: elasticsearch
6 namespace: kube-logging
7 labels:
8 app: elasticsearch
9spec:
10 selector:
11 app: elasticsearch
12 clusterIP: None
13 ports:
14 - port: 9200
15 name: rest
16 - port: 9300
17 name: inter-node
然后保存并关闭文件。
我们在cube-logging
Namespace 中定义一个名为elasticsearch
的服务
,并给它一个app:elasticsearch
标签,然后将.spec.selector
设置为app:elasticsearch
,使服务选择具有app:elasticsearch
标签的Pods。
最后,我们定义了用于与REST API互动的端口9200
和9300
,分别用于节点间通信。
使用kubectl
创建服务:
1kubectl create -f elasticsearch_svc.yaml
你应该看到以下结果:
1[secondary_label Output]
2service/elasticsearch created
最后,双重检查是否使用kubectl get
成功创建了服务:
1kubectl get services --namespace=kube-logging
你应该看到以下:
1[secondary_label Output]
2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
3elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 26s
现在,我们已经为我们的 Pods 设置了无头服务和稳定的 .elasticsearch.kube-logging.svc.cluster.local
域名,我们可以继续创建 StatefulSet。
创建国家实体
Kubernetes StatefulSet 允许您将稳定的身份分配给 Pods,并赋予它们稳定的、持久的存储空间。Elasticsearch 需要稳定的存储空间,以便在整个 Pod 进行重新安排和重新启动。
在您最喜爱的编辑器中打开名为 elasticsearch_statefulset.yaml
的文件:
1nano elasticsearch_statefulset.yaml
我们将通过StatefulSet对象定义部分按部分移动,将块粘贴到这个文件中。
开始通过粘贴到以下块:
1[label elasticsearch_statefulset.yaml]
2apiVersion: apps/v1
3kind: StatefulSet
4metadata:
5 name: es-cluster
6 namespace: kube-logging
7spec:
8 serviceName: elasticsearch
9 replicas: 3
10 selector:
11 matchLabels:
12 app: elasticsearch
13 template:
14 metadata:
15 labels:
16 app: elasticsearch
在这个区块中,我们在cube-logging
名称空间中定义了一个名为es-cluster
的StatefulSet,然后使用serviceName
字段将其与我们先前创建的elasticsearch
服务相关联。
我们指定3个复印件
(Pods)并将matchLabels
选项设置为app: elasticseach
,然后在.spec.template.metadata
部分中反映。
现在我们可以转到对象 spec. 粘贴在前一个区块下面的YAML下面的下一个区块:
1[label elasticsearch_statefulset.yaml]
2. . .
3 spec:
4 containers:
5 - name: elasticsearch
6 image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
7 resources:
8 limits:
9 cpu: 1000m
10 requests:
11 cpu: 100m
12 ports:
13 - containerPort: 9200
14 name: rest
15 protocol: TCP
16 - containerPort: 9300
17 name: inter-node
18 protocol: TCP
19 volumeMounts:
20 - name: data
21 mountPath: /usr/share/elasticsearch/data
22 env:
23 - name: cluster.name
24 value: k8s-logs
25 - name: node.name
26 valueFrom:
27 fieldRef:
28 fieldPath: metadata.name
29 - name: discovery.seed_hosts
30 value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch"
31 - name: cluster.initial_master_nodes
32 value: "es-cluster-0,es-cluster-1,es-cluster-2"
33 - name: ES_JAVA_OPTS
34 value: "-Xms512m -Xmx512m"
在这里,我们在 StatefulSet 中定义了 Pods。我们将容器命名为elasticsearch
,然后选择docker.elasticsearch.co/elasticsearch:7.2.0
Docker 图像。 在此时,您可以更改此图像标签以匹配您的内部 Elasticsearch 图像或其他版本。
然后,我们使用资源
字段来指定容器需要至少保证 0.1 vCPU,并且可以爆发高达 1 vCPU(在执行初始大摄入或处理负载峰值时限制了Pod的资源使用)。
然后,我们分别打开并命名 REST API 和节点间通信的端口9200
和9300
。我们指定一个名为数据
的volumeMount
,将名为数据
的 PersistentVolume 安装在路径/usr/share/elasticsearch/data
的容器上。
最后,我们在容器中设置了一些环境变量:
- `集群.名': 弹性搜索集群的名称,在本指南中为"k8s-logs".
- 节点. name: 节点名称,我们设定为
.元数据
。 这将决定s-croup-[0,1,2]
,取决于指定节点的正文。 *`发现.种子_宿主': 此字段会设置一个集群中可种子出节点发现过程的硕士合格节点列表. 在本指南中,由于我们先前配置的无头服务,我们的Pods有"es-cluster-[0, 1,2].elasticsearch.kube-logb.svc.croup.local"的域,因此我们据此设定了这个变量. 利用本地命名空间Kubernetes DNS分辨率,我们可以将它缩短为'es-cluster-[0, 1,2].elasticsearch'. 欲多了解弹性研究发现,请查阅官方弹性研究文件. 集群
。初始_master_节点: 本领域还具体列出参加总选举过程的合格主节点. 请注意,对于此字段,您应当用其node.name
而不是其主机名来识别节点。 *ES_JAVA_OPTS':我们在此设定为
-Xms512m-Xmx512m',它告诉JVM使用最小和最大堆积大小为512 MB. 您应该根据您的集群资源可用性和需求来调整这些参数 。 要多学多学,请参考确定堆积大小. (英语)
我们将粘贴的下一个块看起来如下:
1[label elasticsearch_statefulset.yaml]
2. . .
3 initContainers:
4 - name: fix-permissions
5 image: busybox
6 command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
7 securityContext:
8 privileged: true
9 volumeMounts:
10 - name: data
11 mountPath: /usr/share/elasticsearch/data
12 - name: increase-vm-max-map
13 image: busybox
14 command: ["sysctl", "-w", "vm.max_map_count=262144"]
15 securityContext:
16 privileged: true
17 - name: increase-fd-ulimit
18 image: busybox
19 command: ["sh", "-c", "ulimit -n 65536"]
20 securityContext:
21 privileged: true
在这个块中,我们定义了几种在主要的elasticsearch
应用程序容器之前运行的Init容器,这些Init容器在它们定义的顺序下完成,以便了解更多有关Init容器的信息,请参阅官方的Kubernetes文件(https://kubernetes.io/docs/concepts/workloads/pods/init-containers/)。
第一个命名为fix-permissions
,运行一个chown
命令,将 Elasticsearch 数据目录的所有者和组更改为1000:1000
,即 Elasticsearch 用户的 UID。
第二个命名为increase-vm-max-map
,运行命令来增加操作系统对mmap数的限制,默认情况下可能太低,导致内存错误。
接下来要运行的 Init 容器是 increase-fd-ulimit
,它运行了 ulimit
命令,以增加最大限度的开放文件描述器。
<$>[注] 注: Elasticsearch Notes for Production Use也提到了因性能原因而禁用交换。 根据您的 Kubernetes 安装或提供商,交换可能已经禁用了。 要检查这一点,‘exec’ 进入运行容器并运行‘cat /proc/swaps’ 列出活跃的交换设备。 如果您在那里看不到任何东西,交换将被禁用。
现在我们已经定义了我们的主要应用程序容器和运行在其前面的Init容器来调节容器操作系统,我们可以将最后一块添加到我们的StatefulSet对象定义文件中:volumeClaimTemplates。
粘贴到以下volumeClaimTemplate
块中:
1[label elasticsearch_statefulset.yaml]
2. . .
3 volumeClaimTemplates:
4 - metadata:
5 name: data
6 labels:
7 app: elasticsearch
8 spec:
9 accessModes: [ "ReadWriteOnce" ]
10 storageClassName: do-block-storage
11 resources:
12 requests:
13 storage: 100Gi
在这个块中,我们定义了StatefulSet的volumeClaimTemplates
。Kubernetes将使用此来为Pods创建持久体积.在上面的块中,我们将其命名为data
(这是我们在以前定义的volumeMount
中所指的名称
),并给它与我们的StatefulSet相同的app:elasticsearch
标签。
然后我们将其访问模式指定为ReadWriteOnce
,这意味着它只能通过单个节点进行读写装配。我们在本指南中将存储类定义为Do-block-storage
,因为我们使用的是DigitalOcean Kubernetes集群用于演示目的。您应该根据您正在运行Kubernetes集群的位置改变此值。 有关更多信息,请参阅 持久卷文档。
最后,我们指明,我们希望每个 PersistentVolume 尺寸为 100GiB. 您应根据您的生产需求调整此值。
完整的StatefulSet spec应该看起来像这样:
1[label elasticsearch_statefulset.yaml]
2apiVersion: apps/v1
3kind: StatefulSet
4metadata:
5 name: es-cluster
6 namespace: kube-logging
7spec:
8 serviceName: elasticsearch
9 replicas: 3
10 selector:
11 matchLabels:
12 app: elasticsearch
13 template:
14 metadata:
15 labels:
16 app: elasticsearch
17 spec:
18 containers:
19 - name: elasticsearch
20 image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
21 resources:
22 limits:
23 cpu: 1000m
24 requests:
25 cpu: 100m
26 ports:
27 - containerPort: 9200
28 name: rest
29 protocol: TCP
30 - containerPort: 9300
31 name: inter-node
32 protocol: TCP
33 volumeMounts:
34 - name: data
35 mountPath: /usr/share/elasticsearch/data
36 env:
37 - name: cluster.name
38 value: k8s-logs
39 - name: node.name
40 valueFrom:
41 fieldRef:
42 fieldPath: metadata.name
43 - name: discovery.seed_hosts
44 value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch"
45 - name: cluster.initial_master_nodes
46 value: "es-cluster-0,es-cluster-1,es-cluster-2"
47 - name: ES_JAVA_OPTS
48 value: "-Xms512m -Xmx512m"
49 initContainers:
50 - name: fix-permissions
51 image: busybox
52 command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
53 securityContext:
54 privileged: true
55 volumeMounts:
56 - name: data
57 mountPath: /usr/share/elasticsearch/data
58 - name: increase-vm-max-map
59 image: busybox
60 command: ["sysctl", "-w", "vm.max_map_count=262144"]
61 securityContext:
62 privileged: true
63 - name: increase-fd-ulimit
64 image: busybox
65 command: ["sh", "-c", "ulimit -n 65536"]
66 securityContext:
67 privileged: true
68 volumeClaimTemplates:
69 - metadata:
70 name: data
71 labels:
72 app: elasticsearch
73 spec:
74 accessModes: [ "ReadWriteOnce" ]
75 storageClassName: do-block-storage
76 resources:
77 requests:
78 storage: 100Gi
一旦您对 Elasticsearch 配置满意,请保存并关闭文件。
现在,使用kubectl
部署 StatefulSet:
1kubectl create -f elasticsearch_statefulset.yaml
你应该看到以下结果:
1[secondary_label Output]
2statefulset.apps/es-cluster created
您可以使用kubectl 部署状态
来监控 StatefulSet 发布时:
1kubectl rollout status sts/es-cluster --namespace=kube-logging
您应该看到下面的输出,因为集群被滚动:
1[secondary_label Output]
2Waiting for 3 pods to be ready...
3Waiting for 2 pods to be ready...
4Waiting for 1 pods to be ready...
5partitioned roll out complete: 3 new pods have been updated...
一旦所有 Pods 都部署了,您可以通过对 REST API 执行请求来检查您的 Elasticsearch 集群是否正常运作。
要做到这一点,先将本地端口9200
转发到Elasticsearch节点中的一个端口9200
上(es-cluster-0
)使用kubectl port-forward
:
1kubectl port-forward es-cluster-0 9200:9200 --namespace=kube-logging
然后,在单独的终端窗口中,对 REST API 执行一个弯曲
请求:
1curl http://localhost:9200/_cluster/state?pretty
你应该看到以下结果:
1[secondary_label Output]
2{
3 "cluster_name" : "k8s-logs",
4 "compressed_size_in_bytes" : 348,
5 "cluster_uuid" : "QD06dK7CQgids-GQZooNVw",
6 "version" : 3,
7 "state_uuid" : "mjNIWXAzQVuxNNOQ7xR-qg",
8 "master_node" : "IdM5B7cUQWqFgIHXBp0JDg",
9 "blocks" : { },
10 "nodes" : {
11 "u7DoTpMmSCixOoictzHItA" : {
12 "name" : "es-cluster-1",
13 "ephemeral_id" : "ZlBflnXKRMC4RvEACHIVdg",
14 "transport_address" : "10.244.8.2:9300",
15 "attributes" : { }
16 },
17 "IdM5B7cUQWqFgIHXBp0JDg" : {
18 "name" : "es-cluster-0",
19 "ephemeral_id" : "JTk1FDdFQuWbSFAtBxdxAQ",
20 "transport_address" : "10.244.44.3:9300",
21 "attributes" : { }
22 },
23 "R8E7xcSUSbGbgrhAdyAKmQ" : {
24 "name" : "es-cluster-2",
25 "ephemeral_id" : "9wv6ke71Qqy9vk2LgJTqaA",
26 "transport_address" : "10.244.40.4:9300",
27 "attributes" : { }
28 }
29 },
30...
这表明我们的Elasticsearch集群k8s-logs
已成功创建了3个节点:es-cluster-0
,es-cluster-1
和es-cluster-2
。
现在您的 Elasticsearch 集群已启动并运行,您可以继续为其设置 Kibana 前端。
步骤 3 – 创建Kibana部署和服务
要在 Kubernetes 上启动 Kibana,我们将创建一个名为kibana
的服务,以及一个由一个Pod复制件组成的部署。
这一次,我们将创建服务和部署在同一个文件中. 在你最喜欢的编辑器中打开名为 kibana.yaml
的文件:
1nano kibana.yaml
点击下面的服务spec:
1[label kibana.yaml]
2apiVersion: v1
3kind: Service
4metadata:
5 name: kibana
6 namespace: kube-logging
7 labels:
8 app: kibana
9spec:
10 ports:
11 - port: 5601
12 selector:
13 app: kibana
14---
15apiVersion: apps/v1
16kind: Deployment
17metadata:
18 name: kibana
19 namespace: kube-logging
20 labels:
21 app: kibana
22spec:
23 replicas: 1
24 selector:
25 matchLabels:
26 app: kibana
27 template:
28 metadata:
29 labels:
30 app: kibana
31 spec:
32 containers:
33 - name: kibana
34 image: docker.elastic.co/kibana/kibana:7.2.0
35 resources:
36 limits:
37 cpu: 1000m
38 requests:
39 cpu: 100m
40 env:
41 - name: ELASTICSEARCH_URL
42 value: http://elasticsearch:9200
43 ports:
44 - containerPort: 5601
然后保存并关闭文件。
在这个规格中,我们在cube-logging
名称空间中定义了一个名为kibana
的服务,并给了它app: kibana
标签。
我们还规定,它应该在端口5601
上可访问,并使用app: kibana
标签来选择服务的目标Pod。
在部署
规格中,我们定义了一个名为kibana
的部署,并指定我们希望 1 Pod 复制。
我们使用docker.elastic.co/kibana/kibana:7.2.0
图像,在此时,您可以替代您自己的私人或公共Kibana图像来使用。
我们指出,我们希望至少为 Pod 保证 0.1 vCPU,最大限度为 1 vCPU. 您可以根据预期负载和可用的资源来更改这些参数。
接下来,我们使用ELASTICSEARCH_URL
环境变量为 Elasticsearch 集群设置端点和端口。 使用 Kubernetes DNS,该端点与其服务名称elasticsearch
相符。 该域将分解为 3 个 Elasticsearch Pods 的 IP 地址列表。 有关 Kubernetes DNS 的更多信息,请参阅 DNS for Services and Pods。
最后,我们将Kibana的集装箱端口设置为5601
,Kibana服务将向其发送请求。
一旦你对Kibana配置感到满意,你可以使用kubectl
启动服务和部署:
1kubectl create -f kibana.yaml
你应该看到以下结果:
1[secondary_label Output]
2service/kibana created
3deployment.apps/kibana created
您可以通过运行以下命令来验证是否成功部署:
1kubectl rollout status deployment/kibana --namespace=kube-logging
你应该看到以下结果:
1[secondary_label Output]
2deployment "kibana" successfully rolled out
要访问Kibana接口,我们将再次将本地端口转发到运行Kibana的Kubernetes节点。
1kubectl get pods --namespace=kube-logging
1[secondary_label Output]
2NAME READY STATUS RESTARTS AGE
3es-cluster-0 1/1 Running 0 55m
4es-cluster-1 1/1 Running 0 54m
5es-cluster-2 1/1 Running 0 54m
6kibana-6c9fb4b5b7-plbg2 1/1 Running 0 4m27s
在这里,我们观察到我们的Kibana Pod被称为kibana-6c9fb4b5b7-plbg2
。
将本地端口5601
向本地端口5601
前进:
1kubectl port-forward kibana-6c9fb4b5b7-plbg2 5601:5601 --namespace=kube-logging
你应该看到以下结果:
1[secondary_label Output]
2Forwarding from 127.0.0.1:5601 -> 5601
3Forwarding from [::1]:5601 -> 5601
现在,在您的 Web 浏览器中,访问以下 URL:
1http://localhost:5601
如果您看到以下Kibana欢迎页面,您已成功部署Kibana到您的Kubernetes集群中:
现在您可以继续部署EFK堆栈的最终组件:日志收集器,Fluentd。
步骤 4 — 创建 Fluentd DaemonSet
在本指南中,我们将将Fluentd设置为DaemonSet,这是一种Kubernetes工作负载类型,在Kubernetes集群中的每个节点上运行一个特定的Pod副本。 使用这个DaemonSet控制器,我们将在集群中的每个节点上部署一个Fluentd日志代理Pod。 有关此日志架构的更多信息,请参阅[使用节点日志代理](https://kubernetes.io/docs/concepts/cluster-administration/logging/#using-a-node-logging-agent)
从官方Kubernetes文件中。
在Kubernetes中,登录到stdout
和stderr
的容器化应用程序将其日志流捕获并重定向到节点上的JSON文件中。
除了集装箱日志外,Fluentd 代理还会跟踪 Kubernetes 系统组件日志,如 kubelet、kube-proxy 和 Docker 日志. 若要查看由 Fluentd 日志代理收集的完整来源列表,请参阅用于配置日志代理的 kubernetes.conf
文件。
首先,在您最喜欢的文本编辑器中打开名为 'fluentd.yaml' 的文件:
1nano fluentd.yaml
在本指南中,我们将使用由 Fluentd 维护者提供的 Fluentd DaemonSet spec。
首先,粘贴下面的 ServiceAccount 定义:
1[label fluentd.yaml]
2apiVersion: v1
3kind: ServiceAccount
4metadata:
5 name: fluentd
6 namespace: kube-logging
7 labels:
8 app: fluentd
在这里,我们创建了一个名为fluentd
的服务帐户,Fluentd Pods 将使用它来访问 Kubernetes API. 我们在cube-logging
Namespace 中创建一个服务帐户,并再次标记为app: fluentd
。
接下来,粘贴到以下ClusterRole
块:
1[label fluentd.yaml]
2. . .
3---
4apiVersion: rbac.authorization.k8s.io/v1
5kind: ClusterRole
6metadata:
7 name: fluentd
8 labels:
9 app: fluentd
10rules:
11- apiGroups:
12 - ""
13 resources:
14 - pods
15 - namespaces
16 verbs:
17 - get
18 - list
19 - watch
在这里,我们定义了一个名为fluentd
的集群角色,我们在pods
和namespaces
对象上授予get
、list
和watch
权限。集群角色允许您授予访问集群覆盖的Kubernetes资源,如节点。
现在,粘贴到以下ClusterRoleBinding
块:
1[label fluentd.yaml]
2. . .
3---
4kind: ClusterRoleBinding
5apiVersion: rbac.authorization.k8s.io/v1
6metadata:
7 name: fluentd
8roleRef:
9 kind: ClusterRole
10 name: fluentd
11 apiGroup: rbac.authorization.k8s.io
12subjects:
13- kind: ServiceAccount
14 name: fluentd
15 namespace: kube-logging
在这个区块中,我们定义了一个名为fluentd
的ClusterRoleBinding
,该区块将fluentd
ClusterRole 绑定到fluentd
服务帐户,从而授予fluentd
服务帐户在fluentd
集群角色中列出的权限。
在此时刻,我们可以开始粘贴实际的DaemonSet spec:
1[label fluentd.yaml]
2. . .
3---
4apiVersion: apps/v1
5kind: DaemonSet
6metadata:
7 name: fluentd
8 namespace: kube-logging
9 labels:
10 app: fluentd
在这里,我们在cube-logging
名称空间中定义一个名为fluentd
的DaemonSet,并给它一个app:fluentd
标签。
接下来,粘贴在下一节:
1[label fluentd.yaml]
2. . .
3spec:
4 selector:
5 matchLabels:
6 app: fluentd
7 template:
8 metadata:
9 labels:
10 app: fluentd
11 spec:
12 serviceAccount: fluentd
13 serviceAccountName: fluentd
14 tolerations:
15 - key: node-role.kubernetes.io/master
16 effect: NoSchedule
17 containers:
18 - name: fluentd
19 image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1
20 env:
21 - name: FLUENT_ELASTICSEARCH_HOST
22 value: "elasticsearch.kube-logging.svc.cluster.local"
23 - name: FLUENT_ELASTICSEARCH_PORT
24 value: "9200"
25 - name: FLUENT_ELASTICSEARCH_SCHEME
26 value: "http"
27 - name: FLUENTD_SYSTEMD_CONF
28 value: disable
在这里,我们匹配在.metadata.labels
中定义的app:fluentd
标签,然后将fluentd
服务帐户分配给DaemonSet。
接下来,我们将定义一个NoSchedule
容量,以匹配Kubernetes主节点上的相应污点。这将确保DaemonSet也被部署到Kubernetes主节点上。如果您不想在主节点上运行Fluentd Pod,请删除此容量。 有关Kubernetes污点和容量的更多信息,请从官方Kubernetes文件中查看[色彩和容量](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/)
。
接下来,我们开始定义Pod容器,我们称之为fluentd
。
如果您想使用自己的私人或公共Fluentd图像,或使用不同的图像版本,请在容器规格中修改图像
标签。
接下来,我们使用一些环境变量来配置 Fluentd:
FLUENT_ELASTICSEARCH_HOST
:我们将此设置为先前定义的 Elasticsearch 无头服务地址:elasticsearch.kube-logging.svc.cluster.local
. 这将解决为 3 个 Elasticsearch Pods 的 IP 地址列表。 实际 Elasticsearch 主机很可能会是本列表中返回的第一个 IP 地址。 要在集群中分发日志,您需要更改 Fluentd 的 Elasticsearch 输出插件的配置。 要了解更多有关该插件的信息,请参阅 Elasticsearch Output Plugin。FLUENT_ELASTICSEARCH_PORT
:我们将此
最后,粘贴在以下部分:
1[label fluentd.yaml]
2. . .
3 resources:
4 limits:
5 memory: 512Mi
6 requests:
7 cpu: 100m
8 memory: 200Mi
9 volumeMounts:
10 - name: varlog
11 mountPath: /var/log
12 - name: varlibdockercontainers
13 mountPath: /var/lib/docker/containers
14 readOnly: true
15 terminationGracePeriodSeconds: 30
16 volumes:
17 - name: varlog
18 hostPath:
19 path: /var/log
20 - name: varlibdockercontainers
21 hostPath:
22 path: /var/lib/docker/containers
在这里,我们在FluentD Pod上指定 512 MB 内存限制,并保证其 0.1vCPU 和 200MiB 内存,您可以根据预期日志量和可用资源来调整这些资源限制和请求。
接下来,我们将/var/log
和/var/lib/docker/containers
的主机路径安装到容器中,使用varlog
和varlibdockercontainers``volumeMounts
。
我们在这个块中定义的最后参数是terminationGracePeriodSeconds
,在收到SIGTERM
信号后,Fluentd 可在 30 秒内优雅关闭。30 秒后,容器会发送一个SIGKILL
信号。对于terminationGracePeriodSeconds
的默认值为 30 秒,所以在大多数情况下,该参数可以被省略。 有关优雅终止 Kubernetes 工作负载的更多信息,请参阅 Google 的[Kubernetes 最佳实践:终止与 Grace](https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-terminating-with-grace)
。
整个 Fluentd 规格应该看起来像这样:
1[label fluentd.yaml]
2apiVersion: v1
3kind: ServiceAccount
4metadata:
5 name: fluentd
6 namespace: kube-logging
7 labels:
8 app: fluentd
9---
10apiVersion: rbac.authorization.k8s.io/v1
11kind: ClusterRole
12metadata:
13 name: fluentd
14 labels:
15 app: fluentd
16rules:
17- apiGroups:
18 - ""
19 resources:
20 - pods
21 - namespaces
22 verbs:
23 - get
24 - list
25 - watch
26---
27kind: ClusterRoleBinding
28apiVersion: rbac.authorization.k8s.io/v1
29metadata:
30 name: fluentd
31roleRef:
32 kind: ClusterRole
33 name: fluentd
34 apiGroup: rbac.authorization.k8s.io
35subjects:
36- kind: ServiceAccount
37 name: fluentd
38 namespace: kube-logging
39---
40apiVersion: apps/v1
41kind: DaemonSet
42metadata:
43 name: fluentd
44 namespace: kube-logging
45 labels:
46 app: fluentd
47spec:
48 selector:
49 matchLabels:
50 app: fluentd
51 template:
52 metadata:
53 labels:
54 app: fluentd
55 spec:
56 serviceAccount: fluentd
57 serviceAccountName: fluentd
58 tolerations:
59 - key: node-role.kubernetes.io/master
60 effect: NoSchedule
61 containers:
62 - name: fluentd
63 image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1
64 env:
65 - name: FLUENT_ELASTICSEARCH_HOST
66 value: "elasticsearch.kube-logging.svc.cluster.local"
67 - name: FLUENT_ELASTICSEARCH_PORT
68 value: "9200"
69 - name: FLUENT_ELASTICSEARCH_SCHEME
70 value: "http"
71 - name: FLUENTD_SYSTEMD_CONF
72 value: disable
73 resources:
74 limits:
75 memory: 512Mi
76 requests:
77 cpu: 100m
78 memory: 200Mi
79 volumeMounts:
80 - name: varlog
81 mountPath: /var/log
82 - name: varlibdockercontainers
83 mountPath: /var/lib/docker/containers
84 readOnly: true
85 terminationGracePeriodSeconds: 30
86 volumes:
87 - name: varlog
88 hostPath:
89 path: /var/log
90 - name: varlibdockercontainers
91 hostPath:
92 path: /var/lib/docker/containers
完成配置 Fluentd DaemonSet 后,保存并关闭文件。
现在,使用kubectl
来滚动DaemonSet:
1kubectl create -f fluentd.yaml
你应该看到以下结果:
1[secondary_label Output]
2serviceaccount/fluentd created
3clusterrole.rbac.authorization.k8s.io/fluentd created
4clusterrolebinding.rbac.authorization.k8s.io/fluentd created
5daemonset.extensions/fluentd created
確認您的 DaemonSet 是否使用「kubectl」成功部署:
1kubectl get ds --namespace=kube-logging
您应该看到以下状态输出:
1[secondary_label Output]
2NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
3fluentd 3 3 3 3 3 <none> 58s
这表明有3个流动的Pod运行,这相当于我们Kubernetes集群中的节点数量。
现在我们可以检查Kibana,以验证日志数据是否被正确收集并发送到Elasticsearch。
隨著「kubectl 端口前進」仍然開放,前往「http://localhost:5601」。
在左边的导航菜单中点击 Discover:
您应该看到下面的配置窗口:
这允许您定义您想在Kibana中探索的Elasticsearch索引。 要了解更多信息,请参阅Defining your index patterns在官方的Kibana文件中。 目前,我们只需使用logstash-*
wildcard 模式来捕捉我们Elasticsearch集群中的所有日志数据。 在文本框中输入logstash-*
并点击Next step**
。
然后你会被带到以下页面:
这允许您配置 Kibana 将使用哪个字段按时间过滤日志数据. 在下载中,选择 @timestamp 字段,然后点击 Create index pattern。
现在,在左手导航菜单中点击发现
。
您应该看到一个 histogram 图表和一些最近的日志条目:
此时,您已成功配置并在您的 Kubernetes 集群中部署 EFK 堆栈. 若要了解如何使用 Kibana 来分析您的日志数据,请参阅 Kibana 用户指南。
在下一个可选的部分中,我们将部署一个简单的计数Pod,它打印数字到stdout,并在Kibana中找到其日志。
步骤 5 (可选) — 测试集装箱仓库
为了演示一个基本的Kibana使用案例,探索给定的Pod的最新日志,我们将部署一个最小的计数Pod,以打印序列数字。
让我们从创建Pod开始,在你最喜欢的编辑器中打开名为counter.yaml
的文件:
1nano counter.yaml
然后,粘贴在以下Pod spec中:
1[label counter.yaml]
2apiVersion: v1
3kind: Pod
4metadata:
5 name: counter
6spec:
7 containers:
8 - name: count
9 image: busybox
10 args: [/bin/sh, -c,
11 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
保存并关闭文件。
这是一个名为计数
的最小Pod,运行一个同时
循环,连续打印数字。
使用kubectl
部署反对
Pod:
1kubectl create -f counter.yaml
一旦 Pod 创建并运行,请返回您的 Kibana 仪表板。
从发现
页面,在搜索栏中输入kubernetes.pod_name:counter
。
然后你应该看到一个列表的日志列表的反对
Pod:
您可以点击任何日志条目以查看其他元数据,如容器名称、Kubernetes节点、Nameespace 等。
结论
在本指南中,我们展示了如何在 Kubernetes 集群上设置和配置 Elasticsearch、Fluentd 和 Kibana。
在部署此日志堆栈到您的 Kubernetes 生产集群之前,最好根据本指南所示调整资源要求和限制,您还可能想要设置 X-Pack以启用内置的监控和安全功能。
我们在这里使用的日志架构包括3个Elasticsearch Pod,一个单一的Kibana Pod(不负荷均衡),以及一组作为DaemonSet部署的Fluentd Pod。
Kubernetes 还允许更复杂的记录代理架构,这些架构可能更适合您的使用情况。 有关更多信息,请参阅 Kubernetes 文档中的 Logging Architecture。