From 508dff258f918b9f2a74d70a59b10381c1bdaad6 Mon Sep 17 00:00:00 2001 From: jornshen Date: Mon, 21 Sep 2020 08:02:48 +0800 Subject: [PATCH] Localize /docs/tasks/debug-application-cluster/logging-stackdriver.md --- .../logging-stackdriver.md | 619 ++++++++++++++++++ 1 file changed, 619 insertions(+) create mode 100644 content/zh/docs/tasks/debug-application-cluster/logging-stackdriver.md diff --git a/content/zh/docs/tasks/debug-application-cluster/logging-stackdriver.md b/content/zh/docs/tasks/debug-application-cluster/logging-stackdriver.md new file mode 100644 index 0000000000..0623406b08 --- /dev/null +++ b/content/zh/docs/tasks/debug-application-cluster/logging-stackdriver.md @@ -0,0 +1,619 @@ +--- +title: 使用 Stackdriver 生成日志 +content_type: concept +--- + + + + + + +在阅读这篇文档之前,强烈建议你先熟悉一下 [Kubernetes 日志概况](/zh/docs/concepts/cluster-administration/logging) + + + +{{< note >}} +默认情况下,Stackdriver 日志机制仅收集容器的标准输出和标准错误流。 +如果要收集你的应用程序写入一个文件(例如)的任何日志,请参见 Kubernetes 日志概述中的 [sidecar 方式](/zh/docs/concepts/cluster-administration/logging#sidecar-container-with-a-logging-agent) +{{< /note >}} + + + + + +## 部署 {#deploying} + + +为了接收日志,你必须将 Stackdriver 日志代理部署到集群中的每个节点。 +此代理是一个已配置的 `fluentd`,其配置存在一个 `ConfigMap` 中,且实例使用 Kubernetes 的 `DaemonSet` 进行管理。 +`ConfigMap` 和 `DaemonSet` 的实际部署,取决你的集群设置。 + + + +### 部署到一个新的集群 + +#### Google Kubernetes Engine + + +对于部署在 Google Kubernetes Engine 上的集群,Stackdriver 是默认的日志解决方案。 +Stackdriver 日志机制会默认部署到你的新集群上,除非你明确地不选择。 + + + +#### 其他平台 + + +为了将 Stackdriver 日志机制部署到你正在使用 `kube-up.sh` 创建的*新*集群上,执行如下操作: + + +1. 设置环境变量 `KUBE_LOGGING_DESTINATION` 为 `gcp`。 +1. **如果不是跑在 GCE 上**,在 `KUBE_NODE_LABELS` 变量中包含 `beta.kubernetes.io/fluentd-ds-ready=true`。 + + + +集群启动后,每个节点都应该运行 Stackdriver 日志代理。 +`DaemonSet` 和 `ConfigMap` 作为附加组件进行配置。 +如果你不是使用 `kube-up.sh`,可以考虑不使用预先配置的日志方案启动集群,然后部署 Stackdriver 日志代理到正在运行的集群。 + + + +{{< warning >}} +除了 Google Kubernetes Engine,Stackdriver 日志守护进程在其他的平台有已知的问题。 +请自行承担风险。 +{{< /warning >}} + + +### 部署到一个已知集群 + + +1. 在每个节点上打标签(如果尚未存在) + + + Stackdriver 日志代理部署使用节点标签来确定应该将其分配到给哪些节点。 + 引入这些标签是为了区分 Kubernetes 1.6 或更高版本的节点。 + 如果集群是在配置了 Stackdriver 日志机制的情况下创建的,并且节点的版本为 1.5.X 或更低版本,则它将使用 fluentd 用作静态容器。 + 节点最多只能有一个 fluentd 实例,因此只能将标签打在未分配过 fluentd pod 的节点上。 + 你可以通过运行 `kubectl describe` 来确保你的节点被正确标记,如下所示: + + ``` + kubectl describe node $NODE_NAME + ``` + + 输出应类似于如下内容: + + ``` + Name: NODE_NAME + Role: + Labels: beta.kubernetes.io/fluentd-ds-ready=true + ... + ``` + + 确保输出内容包含 `beta.kubernetes.io/fluentd-ds-ready=true` 标签。 + 如果不存在,则可以使用 `kubectl label` 命令添加,如下所示: + + ``` + kubectl label node $NODE_NAME beta.kubernetes.io/fluentd-ds-ready=true + ``` + + + {{< note >}} + 如果节点发生故障并且必须重新创建,则必须将标签重新打在重新创建了的节点。 + 为了让此操作更便捷,你可以在节点启动脚本中使用 Kubelet 的命令行参数给节点添加标签。 + {{< /note >}} + + +2. 通过运行以下命令,部署一个带有日志代理配置的 `ConfigMap`: + + ``` + kubectl apply -f https://k8s.io/examples/debug/fluentd-gcp-configmap.yaml + ``` + + 该命令在 `default` 命名空间中创建 `ConfigMap`。你可以在创建 `ConfigMap` 对象之前手动下载文件并进行更改。 + + +3. 通过运行以下命令,部署日志代理的 `DaemonSet`: + + ``` + kubectl apply -f https://k8s.io/examples/debug/fluentd-gcp-ds.yaml + ``` + + 你也可以在使用前下载和编辑此文件。 + + +## 验证日志代理部署 + + +部署 Stackdriver `DaemonSet` 之后,你可以通过运行以下命令来查看日志代理的部署状态: + +```shell +kubectl get ds --all-namespaces +``` + + +如果你的集群中有 3 个节点,则输出应类似于如下: + +``` +NAMESPACE NAME DESIRED CURRENT READY NODE-SELECTOR AGE +... +default fluentd-gcp-v2.0 3 3 3 beta.kubernetes.io/fluentd-ds-ready=true 5m +... +``` + + +要了解使用 Stackdriver 进行日志记录的工作方式,请考虑以下具有日志生成的 pod 定义 [counter-pod.yaml](/examples/debug/counter-pod.yaml): + +{{< codenew file="debug/counter-pod.yaml" >}} + + +这个 pod 定义里有一个容器,该容器运行一个 bash 脚本,脚本每秒写一次计数器的值和日期时间,并无限期地运行。 +让我们在默认命名空间中创建此 pod。 + +```shell +kubectl apply -f https://k8s.io/examples/debug/counter-pod.yaml +``` + + +你可以观察到正在运行的 pod: + +```shell +kubectl get pods +``` +``` +NAME READY STATUS RESTARTS AGE +counter 1/1 Running 0 5m +``` + + +在短时间内,你可以观察到 "pending" 的 pod 的状态,因为 kubelet 必须先下载容器镜像。 +当 pod 状态变为 `Running` 时,你可以使用 `kubectl logs` 命令查看此 counter pod 的输出。 + +```shell +kubectl logs counter +``` +``` +0: Mon Jan 1 00:00:00 UTC 2001 +1: Mon Jan 1 00:00:01 UTC 2001 +2: Mon Jan 1 00:00:02 UTC 2001 +... +``` + + +正如日志概览所述,此命令从容器日志文件中获取日志项。 +如果该容器被 Kubernetes 杀死然后重新启动,你仍然可以访问前一个容器的日志。 +但是,如果将 Pod 从节点中驱逐,则日志文件会丢失。让我们通过删除当前运行的 counter 容器来演示这一点: + +```shell +kubectl delete pod counter +``` +``` +pod "counter" deleted +``` + + +然后重建它: + +```shell +kubectl create -f https://k8s.io/examples/debug/counter-pod.yaml +``` +``` +pod/counter created +``` + + +一段时间后,你可以再次从 counter pod 访问日志: + +```shell +kubectl logs counter +``` +``` +0: Mon Jan 1 00:01:00 UTC 2001 +1: Mon Jan 1 00:01:01 UTC 2001 +2: Mon Jan 1 00:01:02 UTC 2001 +... +``` + + +如预期的那样,日志中仅出现最近的日志记录。 +但是,对于实际应用程序,你可能希望能够访问所有容器的日志,特别是出于调试的目的。 +这就是先前启用的 Stackdriver 日志机制可以提供帮助的地方。 + + +## 查看日志 + + +Stackdriver 日志代理为每个日志项关联元数据,供你在后续的查询中只选择感兴趣的消息: +例如,来自某个特定 Pod 的消息。 + + +元数据最重要的部分是资源类型和日志名称。 +容器日志的资源类型为 `container`,在用户界面中名为 `GKE Containers`(即使 Kubernetes 集群不在 Google Kubernetes Engine 上)。 +日志名称是容器的名称,因此,如果你有一个包含两个容器的 pod,在 spec 中名称定义为 `container_1` 和 `container_2`,则它们的日志的名称分别为 `container_1` 和 `container_2`。 + + +系统组件的资源类型为 `compute`,在接口中名为 `GCE VM Instance`。 +系统组件的日志名称是固定的。 +对于 Google Kubernetes Engine 节点,系统组件中的每个日志项都具有以下日志名称之一: + +* docker +* kubelet +* kube-proxy + + +你可以在[专用 Stackdriver 页面](https://cloud.google.com/logging/docs/view/overview)上了解有关查看日志的更多信息。 + + +查看日志的一种可能方法是使用 [Google Cloud SDK]((https://cloud.google.com/sdk/)) 中的 [`gcloud logging`](https://cloud.google.com/logging/docs/reference/tools/gcloud-logging) 命令行接口。 +它使用 Stackdriver 日志机制的[过滤语法](https://cloud.google.com/logging/docs/view/advanced_filters)查询特定日志。 +例如,你可以运行以下命令: + +```none +gcloud beta logging read 'logName="projects/$YOUR_PROJECT_ID/logs/count"' --format json | jq '.[].textPayload' +``` +``` +... +"2: Mon Jan 1 00:01:02 UTC 2001\n" +"1: Mon Jan 1 00:01:01 UTC 2001\n" +"0: Mon Jan 1 00:01:00 UTC 2001\n" +... +"2: Mon Jan 1 00:00:02 UTC 2001\n" +"1: Mon Jan 1 00:00:01 UTC 2001\n" +"0: Mon Jan 1 00:00:00 UTC 2001\n" +``` + + +如你所见,尽管 kubelet 已经删除了第一个容器的日志,日志中仍会包含 counter 容器第一次和第二次运行时输出的消息。 + + +### 导出日志 + + +你可以将日志导出到 [Google Cloud Storage](https://cloud.google.com/storage/) 或 +[BigQuery](https://cloud.google.com/bigquery/) 进行进一步的分析。 +Stackdriver 日志机制提供了接收器(Sink)的概念,你可以在其中指定日志项的存放地。 +可在 Stackdriver [导出日志页面](https://cloud.google.com/logging/docs/export/configure_export_v2)上获得更多信息。 + + +## 配置 Stackdriver 日志代理 + + +有时默认的 Stackdriver 日志机制安装可能无法满足你的需求,例如: + + +* 你可能需要添加更多资源,因为默认的行为表现无法满足你的需求。 +* 你可能需要引入额外的解析机制以便从日志消息中提取更多元数据,例如严重性或源代码引用。 +* 你可能想要将日志不仅仅发送到 Stackdriver 或仅将部分日志发送到 Stackdriver。 + + +在这种情况下,你需要更改 `DaemonSet` 和 `ConfigMap` 的参数。 + + +### 先决条件 + + +如果使用的是 GKE,并且集群中启用了 Stackdriver 日志机制,则无法更改其配置,因为它是由 GKE 管理和支持的。 +但是,你可以禁用默认集成的日志机制并部署自己的。 + + + +{{< note >}} +你将需要自己支持和维护新部署的配置了:更新映像和配置、调整资源等等。 +{{< /note >}} + + +若要禁用默认的日志记录集成,请使用以下命令: + +``` +gcloud beta container clusters update --logging-service=none CLUSTER +``` + + +你可以在[部署部分](#deploying)中找到有关如何将 Stackdriver 日志代理安装到正在运行的集群中的说明​​。 + + +### 更改 `DaemonSet` 参数 {#changing-daemonset-parameters} + + +当集群中有 Stackdriver 日志机制的 `DaemonSet` 时,你只需修改其 spec 中的 `template` 字段,daemonset 控制器将为你更新 pod。 +例如,假设你按照上面的描述已经安装了 Stackdriver 日志机制。 +现在,你想更改内存限制,来给 fluentd 提供的更多内存,从而安全地处理更多日志。 + + +获取集群中运行的 `DaemonSet` 的 spec: + +```shell +kubectl get ds fluentd-gcp-v2.0 --namespace kube-system -o yaml > fluentd-gcp-ds.yaml +``` + + +然后在 spec 文件中编辑资源需求,并使用以下命令更新 apiserver 中的 `DaemonSet` 对象: + +```shell +kubectl replace -f fluentd-gcp-ds.yaml +``` + + +一段时间后,Stackdriver 日志代理的 pod 将使用新配置重新启动。 + + +### 更改 fluentd 参数 + + +Fluentd 的配置存在 `ConfigMap` 对象中。 +它实际上是一组合并在一起的配置文件。 +你可以在[官方网站](https://docs.fluentd.org)上了解 fluentd 的配置。 + + +假设你要向配置添加新的解析逻辑,以便 fluentd 可以理解默认的 Python 日志记录格式。 +一个合适的 fluentd 过滤器类似如下: + +``` + + type parser + format /^(?\w):(?\w):(?.*)/ + reserve_data true + suppress_parse_error_log true + key_name log + +``` + + +现在,你需要将其放入配置中,并使 Stackdriver 日志代理感知它。 +通过运行以下命令,获取集群中当前版本的 Stackdriver 日志机制的 `ConfigMap`: + +```shell +kubectl get cm fluentd-gcp-config --namespace kube-system -o yaml > fluentd-gcp-configmap.yaml +``` + + +然后在 `containers.input.conf` 键的值中,在 `source` 部分之后插入一个新的过滤器。 + + + +{{< note >}} +顺序很重要。 +{{< /note >}} + + +在 apiserver 中更新 `ConfigMap` 比更新 `DaemonSet` 更复杂。 +最好考虑 `ConfigMap` 是不可变的。 +如果是这样,要更新配置,你应该使用新名称创建 `ConfigMap`,然后使用 +[上面的指南](#changing-daemonset-parameters)将 `DaemonSet` 更改为指向它。 + + +### 添加 fluentd 插件 + + +Fluentd 用 Ruby 编写,并允许使用 [plugins](https://www.fluentd.org/plugins) 扩展其功能。 +如果要使用默认的 Stackdriver 日志机制容器镜像中未包含的插件,则必须构建自定义镜像。 +假设你要为来自特定容器添加 Kafka 信息接收器,以进行其他处理。 +你可以复用默认的[容器镜像源](https://git.k8s.io/contrib/fluentd/fluentd-gcp-image),并仅添加少量更改: + + +* 将 Makefile 更改为指向你的容器仓库,例如 `PREFIX=gcr.io/`。 +* 将你的依赖项添加到 Gemfile 中,例如 `gem 'fluent-plugin-kafka'`。 + + +然后在该目录运行 `make build push`。在更新 `DaemonSet` 以使用新镜像后,你就可以使用在 fluentd 配置中安装的插件了。