使用 Fluentd 记录日志

此任务说明了如何配置 Istio 以创建自定义日志条目并将它们输出到一个 Fluentd 守护程序。Fluentd 是一个开源日志收集器,支持许多数据输出方式,而且是可插拔架构。一种流行的日志后端是 Elasticsearch,以及作为展示的 Kibana。在此任务结束时,将会实现一个新的日志流,把日志发送到一个示例 Fluentd / Elasticsearch / Kibana 工具栈。

Bookinfo 示例应用程序被用作贯穿全文的例子。

开始之前

  • 在您的集群中安装 Istio 并部署一个应用程序。此任务假设 Mixer 使用默认配置(—configDefaultNamespace=istio-system)进行设置。如果你使用不同的配置值,请更新此任务中的配置和命令以匹配该值。

安装 Fluentd

在您的集群中可能已经运行了一个 Fluentd 守护程序,例如通过这里这里描述的 add-on 进行安装,或者由您的集群提供商安装。这很可能会将日志配置为发送到 Elasticsearch 系统或日志提供者。

您可以使用这些 Fluentd 守护程序,或者您配置的其他 Fluentd。只要他们能够监听转发日志,Istio 的 Mixer 就可以连接他们。要使 Istio 的 Mixer 连接到一个运行的 Fluentd 守护程序,您需要为 Fluentd 添加一个 service。监听转发日志的 Fluentd 配置为:

  1. <source>
  2. type forward
  3. </source>

将 Mixer 连接到所有可能的 Fluentd 的全部配置细节超出了此任务的范围。

示例 Fluentd、Elasticsearch、Kibana 工具栈

为了此任务的目标,您可以部署提供的示例工具栈。此栈在一个非生产就绪的 ServicesDeployments 集合中包含了 Fluentd、Elasticsearch 和 Kibana,它们都位于一个名为 logging 的新 Namespace 中。

将下面的内容保存为 logging-stack.yaml

  1. # Logging Namespace。下列内容都在此 namespace 中.
  2. apiVersion: v1
  3. kind: Namespace
  4. metadata:
  5. name: logging
  6. ---
  7. # Elasticsearch Service
  8. apiVersion: v1
  9. kind: Service
  10. metadata:
  11. name: elasticsearch
  12. namespace: logging
  13. labels:
  14. app: elasticsearch
  15. spec:
  16. ports:
  17. - port: 9200
  18. protocol: TCP
  19. targetPort: db
  20. selector:
  21. app: elasticsearch
  22. ---
  23. # Elasticsearch Deployment
  24. apiVersion: extensions/v1beta1
  25. kind: Deployment
  26. metadata:
  27. name: elasticsearch
  28. namespace: logging
  29. labels:
  30. app: elasticsearch
  31. annotations:
  32. sidecar.istio.io/inject: "false"
  33. spec:
  34. template:
  35. metadata:
  36. labels:
  37. app: elasticsearch
  38. spec:
  39. containers:
  40. - image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.1.1
  41. name: elasticsearch
  42. resources:
  43. # 在初始化时需要更多的 cpu,因此使用 burstable 级别。
  44. limits:
  45. cpu: 1000m
  46. requests:
  47. cpu: 100m
  48. env:
  49. - name: discovery.type
  50. value: single-node
  51. ports:
  52. - containerPort: 9200
  53. name: db
  54. protocol: TCP
  55. - containerPort: 9300
  56. name: transport
  57. protocol: TCP
  58. volumeMounts:
  59. - name: elasticsearch
  60. mountPath: /data
  61. volumes:
  62. - name: elasticsearch
  63. emptyDir: {}
  64. ---
  65. # Fluentd Service
  66. apiVersion: v1
  67. kind: Service
  68. metadata:
  69. name: fluentd-es
  70. namespace: logging
  71. labels:
  72. app: fluentd-es
  73. spec:
  74. ports:
  75. - name: fluentd-tcp
  76. port: 24224
  77. protocol: TCP
  78. targetPort: 24224
  79. - name: fluentd-udp
  80. port: 24224
  81. protocol: UDP
  82. targetPort: 24224
  83. selector:
  84. app: fluentd-es
  85. ---
  86. # Fluentd Deployment
  87. apiVersion: extensions/v1beta1
  88. kind: Deployment
  89. metadata:
  90. name: fluentd-es
  91. namespace: logging
  92. labels:
  93. app: fluentd-es
  94. annotations:
  95. sidecar.istio.io/inject: "false"
  96. spec:
  97. template:
  98. metadata:
  99. labels:
  100. app: fluentd-es
  101. spec:
  102. containers:
  103. - name: fluentd-es
  104. image: gcr.io/google-containers/fluentd-elasticsearch:v2.0.1
  105. env:
  106. - name: FLUENTD_ARGS
  107. value: --no-supervisor -q
  108. resources:
  109. limits:
  110. memory: 500Mi
  111. requests:
  112. cpu: 100m
  113. memory: 200Mi
  114. volumeMounts:
  115. - name: config-volume
  116. mountPath: /etc/fluent/config.d
  117. terminationGracePeriodSeconds: 30
  118. volumes:
  119. - name: config-volume
  120. configMap:
  121. name: fluentd-es-config
  122. ---
  123. # Fluentd ConfigMap,包含配置文件。
  124. kind: ConfigMap
  125. apiVersion: v1
  126. data:
  127. forward.input.conf: |-
  128. # 采用 TCP 发送的消息
  129. <source>
  130. type forward
  131. </source>
  132. output.conf: |-
  133. <match **>
  134. type elasticsearch
  135. log_level info
  136. include_tag_key true
  137. host elasticsearch
  138. port 9200
  139. logstash_format true
  140. # 设置 chunk limits.
  141. buffer_chunk_limit 2M
  142. buffer_queue_limit 8
  143. flush_interval 5s
  144. # 重试间隔绝对不要超过 5 分钟。
  145. max_retry_wait 30
  146. # 禁用重试次数限制(永远重试)。
  147. disable_retry_limit
  148. # 使用多线程。
  149. num_threads 2
  150. </match>
  151. metadata:
  152. name: fluentd-es-config
  153. namespace: logging
  154. ---
  155. # Kibana Service
  156. apiVersion: v1
  157. kind: Service
  158. metadata:
  159. name: kibana
  160. namespace: logging
  161. labels:
  162. app: kibana
  163. spec:
  164. ports:
  165. - port: 5601
  166. protocol: TCP
  167. targetPort: ui
  168. selector:
  169. app: kibana
  170. ---
  171. # Kibana Deployment
  172. apiVersion: extensions/v1beta1
  173. kind: Deployment
  174. metadata:
  175. name: kibana
  176. namespace: logging
  177. labels:
  178. app: kibana
  179. annotations:
  180. sidecar.istio.io/inject: "false"
  181. spec:
  182. template:
  183. metadata:
  184. labels:
  185. app: kibana
  186. spec:
  187. containers:
  188. - name: kibana
  189. image: docker.elastic.co/kibana/kibana-oss:6.1.1
  190. resources:
  191. # need more cpu upon initialization, therefore burstable class
  192. limits:
  193. cpu: 1000m
  194. requests:
  195. cpu: 100m
  196. env:
  197. - name: ELASTICSEARCH_URL
  198. value: http://elasticsearch:9200
  199. ports:
  200. - containerPort: 5601
  201. name: ui
  202. protocol: TCP
  203. ---

创建资源:

  1. $ kubectl apply -f logging-stack.yaml
  2. namespace "logging" created
  3. service "elasticsearch" created
  4. deployment "elasticsearch" created
  5. service "fluentd-es" created
  6. deployment "fluentd-es" created
  7. configmap "fluentd-es-config" created
  8. service "kibana" created
  9. deployment "kibana" created

配置 Istio

现在已经有了一个运行的 Fluentd 守护程序,接下来使用新的日志类型配置 Istio,并将日志发送到监听的守护程序。创建一个新的用于保存日志流配置 YAML 文件,Istio 将自动生成和收集这些日志流。

将下列内容保存为 fluentd-istio.yaml

  1. # logentry 实例配置
  2. apiVersion: "config.istio.io/v1alpha2"
  3. kind: logentry
  4. metadata:
  5. name: newlog
  6. namespace: istio-system
  7. spec:
  8. severity: '"info"'
  9. timestamp: request.time
  10. variables:
  11. source: source.labels["app"] | source.workload.name | "unknown"
  12. user: source.user | "unknown"
  13. destination: destination.labels["app"] | destination.workload.name | "unknown"
  14. responseCode: response.code | 0
  15. responseSize: response.size | 0
  16. latency: response.duration | "0ms"
  17. monitored_resource_type: '"UNSPECIFIED"'
  18. ---
  19. # Fluentd handler 配置
  20. apiVersion: "config.istio.io/v1alpha2"
  21. kind: fluentd
  22. metadata:
  23. name: handler
  24. namespace: istio-system
  25. spec:
  26. address: "fluentd-es.logging:24224"
  27. ---
  28. # 将 logentry 示例发送到 Fluentd handler 的 rule
  29. apiVersion: "config.istio.io/v1alpha2"
  30. kind: rule
  31. metadata:
  32. name: newlogtofluentd
  33. namespace: istio-system
  34. spec:
  35. match: "true" # 匹配所有请求
  36. actions:
  37. - handler: handler.fluentd
  38. instances:
  39. - newlog.logentry
  40. ---

创建资源:

  1. $ kubectl apply -f fluentd-istio.yaml
  2. Created config logentry/istio-system/newlog at revision 22374
  3. Created config fluentd/istio-system/handler at revision 22375
  4. Created config rule/istio-system/newlogtofluentd at revision 22376

请注意,handler 配置中的 address: "fluentd-es.logging:24224" 一行指向我们在示例工具栈中配置的 Fluentd 守护程序。

查看新的日志

  • 发送流量到示例应用程序。

对于 Bookinfo 示例,请在您的浏览器中访问 http://$GATEWAY_URL/productpage,或执行以下命令:

  1. $ curl http://$GATEWAY_URL/productpage
  • 在 Kubernetes 环境中,通过以下命令为 Kibana 设置端口转发:
  1. $ kubectl -n logging port-forward $(kubectl -n logging get pod -l app=kibana -o jsonpath='{.items[0].metadata.name}') 5601:5601 &

保持命令运行。在结束对 Kibana UI 的访问时,使用 Ctrl-C 退出。

  • 导航到 Kibana UI 并点击右上角的 “Set up index patterns”。

  • 使用 * 作为索引模式,并点击 “Next step”。

  • 选择 @timestamp 作为 Time Filter 字段名称,并点击 “Create index pattern”。

  • 现在点击左侧目录中的 “Discover”,开始探索生成的日志。

清理

  • 删除新的遥测配置:
  1. $ kubectl delete -f fluentd-istio.yaml
  • 删除示例 Fluentd、Elasticsearch、Kibana 工具栈:
  1. $ kubectl delete -f logging-stack.yaml
  • 删除任何可能还在运行的 kubectl port-forward 进程:
  1. $ killall kubectl
  • 如果您不打算探索任何后续任务,请参考 Bookinfo 清理中的指示停止应用程序。