本文超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否未变得不正确。
使用Kubernetes进行集群级日志记录
Kubernetes集群通常会嗡嗡作响地运行许多系统和应用程序Pod。系统管理员如何收集、管理和查询系统Pod的日志?用户如何查询其应用程序的日志,该应用程序由许多Pod组成,这些Pod可能由Kubernetes系统重新启动或自动生成?Kubernetes集群级日志记录服务解决了这些问题。
Kubernetes的集群级日志记录允许我们收集超出Pod的容器镜像的生命周期、Pod的生命周期甚至集群的生命周期的日志。在本文中,我们假设已经创建了一个Kubernetes集群,该集群具有将日志发送到Google Cloud Logging的集群级日志记录支持。这是在创建Google Container Engine (GKE) 集群时的选项,并且默认情况下为开源Google Compute Engine (GCE) Kubernetes发行版启用。创建集群后,您将拥有一组运行的系统Pod,这些Pod支持对Kubernetes服务的名称进行监控、日志记录和DNS解析
$ kubectl get pods
NAME READY REASON RESTARTS AGE
fluentd-cloud-logging-kubernetes-minion-0f64 1/1 Running 0 32m
fluentd-cloud-logging-kubernetes-minion-27gf 1/1 Running 0 32m
fluentd-cloud-logging-kubernetes-minion-pk22 1/1 Running 0 31m
fluentd-cloud-logging-kubernetes-minion-20ej 1/1 Running 0 31m
kube-dns-v3-pk22 3/3 Running 0 32m
monitoring-heapster-v1-20ej 0/1 Running 9 32m
这是一张图片中的相同信息,显示了Pod可能如何放置在特定节点上。
这是每个节点上运行内容的特写。
第一个图表显示了在GCE集群上创建的四个节点,每个虚拟机节点的名称位于紫色背景上。每个节点的内部和公共IP显示在灰色框中,每个节点中运行的Pod显示在绿色框中。每个Pod框显示Pod的名称及其运行的命名空间、Pod的IP地址以及作为Pod执行的一部分运行的镜像。在这里,我们看到每个节点都运行一个fluentd-cloud-logging Pod,该Pod收集在同一节点上运行的容器的日志输出并将它们发送到Google Cloud Logging。提供集群DNS服务的Pod运行在其中一个节点上,提供监控支持的Pod运行在另一个节点上。
为了帮助解释集群级日志记录的工作原理,让我们从一个综合日志生成器Pod规范counter-pod.yaml开始
apiVersion : v1
kind : Pod
metadata :
name : counter
spec :
containers :
- name : count
image : ubuntu:14.04
args : [bash, -c,
'for ((i = 0; ; i++)); do echo "$i: $(date)"; sleep 1; done']
此Pod规范具有一个容器,该容器在容器诞生时运行bash脚本。此脚本只是每秒写出一次计数器的值和日期,并且无限期地运行。让我们创建Pod。
$ kubectl create -f counter-pod.yaml
pods/counter
我们可以观察正在运行的Pod
$ kubectl get pods
NAME READY REASON RESTARTS AGE
counter 1/1 Running 0 5m
fluentd-cloud-logging-kubernetes-minion-0f64 1/1 Running 0 55m
fluentd-cloud-logging-kubernetes-minion-27gf 1/1 Running 0 55m
fluentd-cloud-logging-kubernetes-minion-pk22 1/1 Running 0 55m
fluentd-cloud-logging-kubernetes-minion-20ej 1/1 Running 0 55m
kube-dns-v3-pk22 3/3 Running 0 55m
monitoring-heapster-v1-20ej 0/1 Running 9 56m
此步骤可能需要几分钟时间下载ubuntu:14.04镜像,在此期间Pod状态将显示为“Pending(待处理)”。
其中一个节点现在正在运行计数器Pod
当Pod状态更改为“Running(运行中)”时,我们可以使用kubectl logs命令查看此计数器Pod的输出。
$ kubectl logs counter
0: Tue Jun 2 21:37:31 UTC 2015
1: Tue Jun 2 21:37:32 UTC 2015
2: Tue Jun 2 21:37:33 UTC 2015
3: Tue Jun 2 21:37:34 UTC 2015
4: Tue Jun 2 21:37:35 UTC 2015
5: Tue Jun 2 21:37:36 UTC 2015
此命令从正在此容器中运行的镜像的Docker日志文件中获取日志文本。我们可以连接到正在运行的容器并观察正在运行的计数器bash脚本。
$ kubectl exec -i counter bash
ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 17976 2888 ? Ss 00:02 0:00 bash -c for ((i = 0; ; i++)); do echo "$i: $(date)"; sleep 1; done
root 468 0.0 0.0 17968 2904 ? Ss 00:05 0:00 bash
root 479 0.0 0.0 4348 812 ? S 00:05 0:00 sleep 1
root 480 0.0 0.0 15572 2212 ? R 00:05 0:00 ps aux
如果由于某种原因此Pod中的镜像被终止,然后由Kubernetes重新启动,会发生什么情况?我们仍然会看到先前调用容器的日志行,然后是已启动容器的日志行吗?或者我们会丢失原始容器执行的日志行,而只看到新容器的日志行?让我们来看看。首先,让我们停止当前正在运行的计数器。
$ kubectl stop pod counter
pods/counter
Now let’s restart the counter.
$ kubectl create -f counter-pod.yaml
pods/counter
让我们等待容器重新启动并再次获取日志行。
$ kubectl logs counter
0: Tue Jun 2 21:51:40 UTC 2015
1: Tue Jun 2 21:51:41 UTC 2015
2: Tue Jun 2 21:51:42 UTC 2015
3: Tue Jun 2 21:51:43 UTC 2015
4: Tue Jun 2 21:51:44 UTC 2015
5: Tue Jun 2 21:51:45 UTC 2015
6: Tue Jun 2 21:51:46 UTC 2015
7: Tue Jun 2 21:51:47 UTC 2015
8: Tue Jun 2 21:51:48 UTC 2015
哦不!我们丢失了此Pod中容器第一次调用的日志行!理想情况下,我们希望保留Pod中每个容器每次调用的所有日志行。此外,即使Pod重新启动,我们仍然希望保留Pod中容器发出的所有日志行。但不要担心,这是Kubernetes中集群级日志记录提供的功能。创建集群时,可以使用在每个节点上运行的Fluentd代理将每个容器的标准输出和标准错误输出提取到Google Cloud Logging或Elasticsearch中,并使用Kibana查看。这篇博文侧重于Google Cloud Logging。
启用日志记录到Google Cloud Logging后创建Kubernetes集群时,系统会在集群的每个节点上创建一个名为fluentd-cloud-logging的Pod来收集Docker容器日志。这些Pod在这篇博文的开头显示在第一个get pods命令的响应中。
此日志收集Pod的规范类似于fluentd-gcp.yaml
apiVersion: v1
kind: Pod
metadata:
name: fluentd-cloud-logging
spec:
containers:
- name: fluentd-cloud-logging
image: gcr.io/google\_containers/fluentd-gcp:1.6
env:
- name: FLUENTD\_ARGS
value: -qq
volumeMounts:
- name: containers
mountPath: /var/lib/docker/containers
volumes:
- name: containers
hostPath:
path: /var/lib/docker/containers
此Pod规范将主机上包含Docker日志文件的目录/var/lib/docker/containers映射到容器内具有相同路径的目录。Pod运行一个镜像gcr.io/google_containers/fluentd-gcp:1.6,该镜像配置为从logs目录收集Docker日志文件并将其提取到Google Cloud Logging中。此Pod的一个实例在集群的每个节点上运行。Kubernetes会注意到此Pod是否发生故障并自动重新启动它。
我们可以点击Google Developer Console的“Monitoring(监控)”部分下的“Logs(日志)”项,然后选择计数器容器的日志,该容器将被称为kubernetes.counter_default_count。这标识了发生日志收集的Pod的名称(counter)、命名空间(default)和容器的名称(count)。使用此名称,我们可以从下拉菜单中选择仅针对计数器容器的日志
(image-counter-new-logs.png)
当我们在Developer Console中查看日志时,我们会观察到容器两次调用的日志。
(image-screenshot-2015-06-02)
请注意,第一个容器计数到108,然后终止。当下一个容器镜像重新启动时,计数过程从0开始恢复。同样,如果我们删除Pod并重新启动它,我们将在Pod运行时捕获Pod中所有容器实例的日志。
提取到Google Cloud Logging的日志可以导出到各种其他目的地,包括Google Cloud Storage存储桶和BigQuery。使用Cloud Logging控制台中的“Exports(导出)”选项卡指定日志应流式传输到的位置(或点击此链接进入设置”选项卡)。
我们可以使用SQL查询从BigQuery查询提取的日志,该查询报告显示最新行的计数器日志行。
SELECT metadata.timestamp, structPayload.log FROM [mylogs.kubernetes_counter_default_count_20150611] ORDER BY metadata.timestamp DESC
以下是一些示例输出
(image-bigquery-log-new.png)
我们还可以将Google Cloud Storage存储桶中的日志提取到我们的台式机或笔记本电脑,然后在本地搜索它们。以下命令提取在集群中运行的计数器Pod的日志,该集群本身位于名为myproject的GCE项目中。仅提取日期为2015-06-11的日志。
$ gsutil -m cp -r gs://myproject/kubernetes.counter\_default\_count/2015/06/11 .
现在我们可以在提取的日志上运行查询。下面的示例使用jq程序仅提取日志行。
$ cat 21\:00\:00\_21\:59\:59\_S0.json | jq '.structPayload.log'
"0: Thu Jun 11 21:39:38 UTC 2015\n"
"1: Thu Jun 11 21:39:39 UTC 2015\n"
"2: Thu Jun 11 21:39:40 UTC 2015\n"
"3: Thu Jun 11 21:39:41 UTC 2015\n"
"4: Thu Jun 11 21:39:42 UTC 2015\n"
"5: Thu Jun 11 21:39:43 UTC 2015\n"
"6: Thu Jun 11 21:39:44 UTC 2015\n"
"7: Thu Jun 11 21:39:45 UTC 2015\n"
本文简要介绍了支持在Kubernetes部署上收集集群级日志的底层机制。这里的方法仅适用于收集Pod容器中运行的进程的标准输出和标准错误输出。要收集存储在文件中的其他日志,可以使用sidecar容器来收集所需的文件,如页面使用Fluentd收集容器内的日志文件并将它们发送到Google Cloud Logging服务中所述。