【51CTO.com快译】人们需要了解生产Kubernetes集群的可扩展日志记录模式,以用于自己的集群级日志记录。
传统上,在单体架构中,日志直接存储在裸机或虚拟机上,并且从来没有离开过服务器磁盘,运营团队将会根据需要检查每个磁盘的日志。
这适用于内部部署的服务器,而云中的日志是短暂的。随着越来越多的企业在容器上运行他们的服务,并使用Kubernetes编排部署,日志不必再存储在服务器上,因此实施日志管理策略至关重要。
日志是调试和监控应用程序的有效方法,它们需要存储在单独的后端,以便在Pod或节点故障时进行查询和分析。这些独立的后端包括Elasticsearch、谷歌云平台的Stackdriver和AWS的Cloudwatch等系统。
将集群的日志存储在存储后端中称为集群级日志记录。本文将讨论企业如何在自己的Kubernetes集群中实现这种方法。
日志架构
在Kubernetes集群中有两个主要的日志源:应用程序和系统组件。
应用程序作为Kubernetes集群中的容器运行,容器运行时负责获取应用程序的日志,而Docker将这些日志重定向到stdout( 标准输出流)和 stderr( 标准输入流)。在Kubernetes集群中,这两个流都被写入集群节点上的JSON文件。
可以使用以下命令随时获取这些容器日志:
- kubectl logs podname
日志的另一个来源是系统组件。一些系统组件(即kube-scheduler和kube-proxy)作为容器运行,并遵循与应用程序相同的日志记录原则。
其他系统组件(kubelet和容器运行时本身)作为原生服务运行。如果机器上的systemd可用,组件会在journald中写入日志,否则它们会在/var/log目录中写入.log文件。
现在已经了解了应用程序和集群的哪些组件生成日志以及它们的存储位置,接下来看看将这些日志卸载到不同存储系统的一些常见模式。
日志记录模式
收集日志的两个最突出的模式是DaemonSet模式和Sidecar模式。
(1)DaemonSet模式
在DaemonSet模式中,日志代理通过Kubernetes中的DaemonSet资源部署为Pod。部署DaemonSet可确保集群中的每个节点都有一个运行日志代理的Pod。这个日志代理被配置为从/var/logs目录读取日志并将它们发送到存储后端。
(2)Sidecar模式
而在Sidecar模式中,一个专用容器与同一个Pod中的每个应用程序容器一起运行。Sidecar模式可以有两种类型:Streaming Sidecar或日志代理Sidecar (Logging Agent Sidecar)。
当运行将日志写入文件而不是stdout/stderr流的应用程序,或以非标准格式写入日志的应用程序时,将使用流Streaming Sidecar。在这种情况下,可以使用Streaming Sidecar容器将文件中的日志发布到其自己的stdout/stderr流,然后Kubernetes本身可以获取stdout/stderr流。
Streaming Sidecar还可以通过将日志消息转换为标准日志格式来为日志结构带来奇偶校验。
另一种方法是日志代理Sidecar,Sidecar本身将日志发送到存储后端。每个Pod都包含一个日志代理,例如Fluentd或Filebeat,它从应用程序容器中捕获日志并将它们直接发送到存储后端。
DaemonSet和Sidecar的优缺点
现在已经讨论了DaemonSet和Sidecar方法,以下了解每种方法的优缺点。
(1)DaemonSet(节点级)
优点:
- 节点级日志更容易实现,因为它与现有的基于文件的日志相关,并且由于每个节点运行的容器较少,因此比Sidecar方法占用的资源更少。
- 日志可通过kubectl命令用于调试,因为日志文件可用于返回日志文件内容的kubelet。
缺点:
- 支持写入日志文件而不是流的不同日志结构或应用程序的灵活性较低。需要修改应用程序日志结构以实现奇偶校验,或者处理存储后端中的差异。
- 由于它们作为JSON文件存储在节点磁盘上,因此日志不能永久保存。需要有一个日志轮换机制来回收旧日志。如果使用的是容器运行时接口,kubelet会负责轮换日志,不需要实施明确的解决方案。
(2)Sidecar
优点:
- 可以灵活地为每个应用程序容器定制Sidecar。例如,应用程序可能无法写入stdout/stderr,或者它可能具有某些不同的日志记录格式。在这些情况下,Sidecar容器可以为系统带来奇偶校验。
- 如果没有使用流式传输的日志代理Sidecar,则不需要轮换日志,因为节点磁盘上没有存储任何日志。
缺点:
- 与节点级别的Pod相比,为每个应用程序容器运行一个Sidecar非常耗费资源。
- 为每个部署添加一个Sidecar会增加额外的复杂性。
- 如果将Streaming Sidecar用于将其日志写入文件的应用程序,将使用两倍的存储空间来存储相同的日志,因为将会复制条目。
- 如果没有使用流式传输的日志代理Sidecar,将无法通过kubectl访问日志。这是因为kubelet不再有权访问JSON日志。
- 使用日志代理Sidecar,还需要一个节点级代理,否则将无法收集系统组件日志。
将理论付诸实践
现在已经了解了登录Kubernetes集群的可能模式,可以付诸实践,部署生成日志的虚拟容器,并创建Kubernetes资源来实现上面讨论的日志记录模式。
在这个例子中,将使用Fluentd作为日志代理,将安装Elasticsearch用于日志记录后端和Kibana用于可视化目的。将使用Helm图表将Elasticsearch和Kibana安装到同一个集群中。但是需要注意的是,存储后端不应位于同一个集群上,这样做仅用于演示目的。由于Fluentd的可插拔架构,它支持各种不同的接收器。这就是Elasticsearch后端可以被任何云原生解决方案替换的原因,包括Stackdriver或Cloudwatch。
(1)安装Elasticsearch和Kibana
将使用找到的官方Helm图表部署Elasticsearch和Kibana(Elasticsearch、Kibana)。要通过Helm安装,在路径上需要一个Helm二进制文件,但Helm的安装不在本文讨论范围之内。
让我们从添加helm repos开始。
Properties files
1 helm repo add elastic https://helm.elastic.co
接下来,将把Elasticsearch和Kibana图表安装到集群中。
Properties files
1 helm install elasticsearch elastic/elasticsearch
2 helm install kibana elastic/kibana
这将在集群中安装最新版本的Elasticsearch和Kibana,然后可以将其用作日志的存储后端。
在图表中使用了默认值,但是在生产中安装它时,可以根据需要更改任何参数。
(2)DaemonSet
在这里将Fluentd部署为DaemonSet,而不会创建单独的Service Account和ClusterRole。但在生产环境中,Fluentdpod应该使用访问受限的单独服务帐户运行。
可以使用以下Kubernetes资源将Fluentd部署为DaemonSet:
Go
- api Version: extensions/v1beta1
- kind: DaemonSet
- metadata:
- name: fluentd
- namespace: kube-system
- labels:
- k8s-app: fluentd-logger
- spec:
- template:
- metadata:
- labels:
- k8s-app: fluentd-logger
- spec:
- containers:
- - name: fluentd
- image: fluent/fluentd-kubernetes-daemonset:elasticsearch
- env:
- - name: FLUENT\_ELASTICSEARCH\_HOST
- value: "elasticsearch-master"
- - name: FLUENT\_ELASTICSEARCH\_PORT
- value: "9200"
- volumeMounts:
- - name: varlog
- mountPath: /var/log
- - name: dockerlogs
- mountPath: /var/lib/docker/containers
- readOnly: true
- volumes:
- - name: varlog
- hostPath:
- path: /var/log
- - name: dockerlogs
- hostPath:
- path: /var/lib/docker/containers
在这个例子中,挂载了两个卷:一个在/var/log,另一个在/var/log/docker/containers,系统组件和Docker运行时分别放置日志。
正在使用的映像已经配置了智能默认值以与DaemonSet一起使用,但可以更改配置。
将上述YAML资源保存在名为fluentd-ds.yaml的文件中,并通过以下命令应用该资源:
Properties files
- kubectl apply -f fluentd-ds.yaml
这将在Kubernetes集群中的每个节点上启动一个Fluentdpod。
现在将看到如何实现流和日志代理Sidecar模式。
(3)Sidecar
首先,看看当应用程序将日志写入文件而不是数据流时的Streaming Sidecar模式。可以运行一个Sidecar来读取这些日志,并将其写回stdout/stderr流。
Go
- apiVersion: v1
- kind: Pod
- metadata:
- name: my-app
- spec:
- containers:
- - name: legacy-app
- image: busybox
- args:
- - /bin/sh
- - -c
- - >
- i=0;
- while true;
- do
- echo "$i: $(date)" >> /var/log/output.log;
- i=$((i+1));
- sleep 1;
- done
- volumeMounts:
- - name: varlog
- mountPath: /var/log
- - name: streaming-Sidecar
- image: busybox
- args: \[/bin/sh, -c, 'tail -n+1 -f /var/log/output.log'\]
- volumeMounts:
- - name: varlog
- mountPath: /var/log
- volumes:
- - name: varlog
- emptyDir: {}
在这个例子中,有一个虚拟容器将日志写入容器的/var/log目录中的文件。现在,容器运行时无法获取这些日志,这就是实现了一个Streaming Sidecar来从/var/log位置跟踪日志并将其重定向到stdout流。
这一日志流将由容器运行时获取并作为JSON文件存储在节点上的/var/log目录中,节点级日志代理然后将获取该文件。
现在看看日志代理Sidecar。在这种模式中,将Fluentd部署为Sidecar,它将直接写入Elasticsearch存储后端。
在此没有安装Elasticsearch插件的预构建镜像,而创建自定义Docker镜像超出了本文讨论的范围。与其相反,将使用在DaemonSet示例中使用的相同Fluentd映像。
Go
- apiVersion: v1
- kind: Pod
- metadata:
- name: my-app
- spec:
- containers:
- - name: count
- image: busybox
- args:
- - /bin/sh
- - -c
- - >
- i=0;
- while true;
- do
- echo "$i: $(date)" >> /var/log/output.log;
- i=$((i+1));
- sleep 1;
- done
- volumeMounts:
- - name: varlog
- mountPath: /var/log
- - name: logging-agent
- image: fluent/fluentd-kubernetes-daemonset:elasticsearch
- env:
- - name: FLUENT\_ELASTICSEARCH\_HOST
- value: "elastisearch-master"
- - name: FLUENT\_ELASTICSEARCH\_PORT
- value: "9200"
- volumeMounts:
- - name: varlog
- mountPath: /var/log
- volumes:
- - name: varlog
- emptyDir: {}
结论
鉴于Pod和节点的短暂性,将来自Kubernetes集群的日志存储在单独的存储后端中非常重要。可以使用多种模式来设置在本文中讨论的日志记录架构。
在此建议为生产系统混合使用Sidecar和节点级模式。这包括使用DaemonSet模式设置集群范围的节点级日志记录,以及为不支持将日志写入流(stdout/stderr)或不以标准日志格式写入的应用程序实现Streaming Sidecar容器。这个流容器将自动显示要选取的节点级代理的日志。
对于存储后端的选择,可以选择自托管的开源解决方案,例如Elasticsearch,或者可以使用云托管的Elasticsearch、Stackdriver以及Cloudwatch等选项选择托管服务路线。选择适合后端将取决于希望在架构中实现的成本、查询和日志分析要求。
原文标题:Kubernetes Logging in Production,作者:Kentaro Wakayama
【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】