作者:来自 Elastic Muhammad Sulaman Sarwar
在 Kubernetes 中监控 Windows 工作负载面临独特的挑战:IIS 访问日志在进入 Elasticsearch 时被包裹在容器元数据中,导致无法搜索。由于缺少结构化字段,要排查 500 错误激增或响应时间变慢的问题,就只能在数 GB 的非结构化文本中用 grep 查找。业务影响是什么?更长的 MTTR、沮丧的工程师,以及对应用性能的可见性受限。
解决方案不需要新的 agent 或日志传输程序。它是一个 ingest pipeline —— Elasticsearch 在索引过程中转换数据的方式 —— 能检测流中的 IIS 日志,去除包裹层,并将其路由到结构化解析中。
简而言之:使用 ingest pipeline 通过站点标识符(W3SVC1、W3SVC2)检测 IIS 日志,移除 Kubernetes 元数据,并将其路由到 IIS 集成中,以实现自动 ECS 字段映射。结果:可查询的仪表板、更快的故障排查、无需基础设施更改。
问题
在 Kubernetes 上运行 IIS 的 Windows 容器会将 W3C 访问日志输出到 stdout。Kubernetes 集成会摄取这些日志,但它们会被容器元数据包裹。
`2025-01-15T10:23:45.123Z stdout F 2025-01-15 10:23:45 W3SVC1 WEBSERVER01 10.0.1.5 GET /api/users - 443 - 192.168.1.100 HTTP/1.1 - - 200 0 0 125` AI写代码
IIS 日志数据位于 stdout F 之后。如果不进行解析,你无法根据状态码、URI、响应时间或其他结构化字段进行查询。
前提条件
你需要 Elasticsearch 9.x+、用于收集容器日志的 Kubernetes 集成,以及已安装的 IIS 集成。IIS 集成提供 logs-iis.access@custom pipeline,用于处理 W3C 解析和 ECS 字段映射。
验证 IIS 集成是否已安装:
`GET _ingest/pipeline/logs-iis.access@custom` AI写代码
如果出现 404,通过 Kibana → Management → Integrations → IIS 安装 IIS 集成。
确认 Kubernetes 日志正在流入:
`1. GET logs-kubernetes.*/_search
2. {
3. "size": 5,
4. "sort": [{ "@timestamp": "desc" }]
5. }` AI写代码
检查 IIS 日志是否出现在 Kubernetes 流中:
`1. GET logs-kubernetes.*/_search
2. {
3. "query": { "match": { "message": "W3SVC" }},
4. "size": 5
5. }` AI写代码
如果没有返回结果,说明你的 IIS 容器没有将日志输出到 stdout,或者日志没有到达 Elasticsearch。使用 kubectl logs 检查容器日志。
创建路由 pipeline
此 pipeline 通过匹配站点标识符(W3SVC1、W3SVC2 等)检测 IIS 访问日志,移除 Kubernetes 包裹层,并将其路由到 IIS 数据流:
`1. PUT _ingest/pipeline/k8s-iis-router
2. {
3. "description": "Route IIS logs from Kubernetes to IIS data stream",
4. "processors": [
5. {
6. "set": {
7. "if": "ctx.message != null && /W3SVC\\d+/.matcher(ctx.message).find()",
8. "field": "iis_log_detected",
9. "value": true
10. }
11. },
12. {
13. "gsub": {
14. "if": "ctx.iis_log_detected == true",
15. "field": "message",
16. "pattern": "^[0-9TZ:\\.\\-]+\\s+stdout\\s+F\\s+",
17. "replacement": ""
18. }
19. },
20. {
21. "pipeline": {
22. "if": "ctx.iis_log_detected == true",
23. "name": "logs-iis.access@custom"
24. }
25. },
26. {
27. "set": {
28. "if": "ctx.iis_log_detected == true",
29. "field": "data_stream.dataset",
30. "value": "iis.access"
31. }
32. },
33. {
34. "set": {
35. "if": "ctx.iis_log_detected == true",
36. "field": "data_stream.type",
37. "value": "logs"
38. }
39. },
40. {
41. "set": {
42. "if": "ctx.iis_log_detected == true",
43. "field": "data_stream.namespace",
44. "value": "default"
45. }
46. },
47. {
48. "remove": {
49. "if": "ctx.iis_log_detected == true",
50. "field": ["iis_log_detected"],
51. "ignore_missing": true
52. }
53. }
54. ],
55. "on_failure": [
56. {
57. "set": {
58. "field": "error.message",
59. "value": "IIS routing failed: {{ _ingest.on_failure_message }}"
60. }
61. }
62. ]
63. }` AI写代码收起代码块
该 pipeline 通过匹配 W3SVC\d+ 检测 IIS 日志,去除 Kubernetes 时间戳和 stdout F 前缀,调用 IIS 集成 pipeline 进行 W3C 解析,并设置数据流字段,将文档路由到 logs-iis.access-default。非 IIS 日志将原样通过。
测试 Pipeline
在应用到生产前,使用 simulate API 进行测试:
`1. POST _ingest/pipeline/k8s-iis-router/_simulate
2. {
3. "docs": [
4. {
5. "_source": {
6. "message": "2025-01-15T10:23:45.123Z stdout F 2025-01-15 10:23:45 W3SVC1 WEBSERVER01 10.0.1.5 GET /api/users - 443 - 192.168.1.100 HTTP/1.1 - - 200 0 0 125"
7. }
8. }
9. ]
10. }` AI写代码
响应结果应显示 data_stream.dataset: iis.access 以及已解析的字段,如 http.response.status_code、url.path 和 client.ip。
使用非 IIS 日志进行测试以确保其能正常通过:
`1. POST _ingest/pipeline/k8s-iis-router/_simulate
2. {
3. "docs": [
4. {
5. "_source": {
6. "message": "2025-01-15T10:23:45.123Z stdout F Some other container log"
7. }
8. }
9. ]
10. }` AI写代码
该文档不应被路由到 IIS 数据流。
应用到 Kubernetes 日志
更新你的 Kubernetes 日志索引模板以使用路由 pipeline:
`1. PUT _index_template/kubernetes-logs
2. {
3. "index_patterns": ["logs-kubernetes.*"],
4. "priority": 250,
5. "template": {
6. "settings": {
7. "index.default_pipeline": "k8s-iis-router"
8. }
9. }
10. }` AI写代码
如果使用 Fleet 管理的 Kubernetes 集成,请在集成设置中 Advanced options → Custom pipeline 下添加该 pipeline。
验证
等待 1–2 分钟以便新日志到达。该 pipeline 仅处理新文档,不会处理现有文档。
检查文档是否到达 IIS 数据流:
`GET logs-iis.access-*/_count` AI写代码
如果 count 为 0,请验证 pipeline 是否已附加:
`GET logs-kubernetes.*/_settings` AI写代码
在响应中查找 "index.default_pipeline": "k8s-iis-router"。
查看带有结构化字段的已解析日志:
`1. GET logs-iis.access-*/_search
2. {
3. "size": 5,
4. "sort": [{ "@timestamp": "desc" }]
5. }` AI写代码
你应能看到 ECS 字段:
- http.response.status_code(整数:200、404、500)
- http.request.method(GET、POST、PUT、DELETE)
- url.path(如 /api/users)
- client.ip(客户端 IP 地址)
- event.duration(响应时间,单位纳秒)
验证 Kubernetes 流中 IIS 日志是否减少:
`1. GET logs-kubernetes.*/_search
2. {
3. "query": { "match": { "message": "W3SVC" }},
4. "size": 5
5. }` AI写代码
如果 IIS 日志仍出现在此处,说明未被路由。检查 pipeline 错误:
故障排查
如果日志未出现在 IIS 数据流中:确认 IIS 集成 pipeline 存在(GET _ingest/pipeline/logs-iis.access@custom)。检查 IIS 日志是否包含 W3SVC(GET logs-kubernetes.*/_search?q=W3SVC)。使用 kubectl exec -- iisreset /status 验证 IIS 容器中日志记录是否启用。
如果解析失败:IIS 集成要求默认 W3C 字段顺序:date time s-sitename s-computername s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs-version cs(Referer) cs(X-Forwarded-For) sc-status sc-substatus sc-win32-status time-taken。若你的格式不同,需要在 IIS pipeline 中自定义 grok 模式。
性能问题:正则 W3SVC\d+ 会在每个 Kubernetes 日志文档上运行。为减少开销,可将检测范围限定到特定容器:
`"if": "ctx.kubernetes?.container?.name == 'iis-app' && /W3SVC\\d+/.matcher(ctx.message).find()"` AI写代码
可选增强
在 gsub 步骤后添加此处理器,根据 Kubernetes 命名空间将日志路由到不同的数据流命名空间:
`1. {
2. "set": {
3. "if": "ctx.iis_log_detected == true && ctx.kubernetes?.namespace != null",
4. "field": "data_stream.namespace",
5. "value": "{{ kubernetes.namespace }}"
6. }
7. }` AI写代码
这会创建独立的数据流,如 logs-iis.access-production 和 logs-iis.access-staging,使得按环境管理保留策略和访问控制更容易。
结果:工程团队可以按状态码查询日志,构建显示响应时间分位数的仪表板,并设置错误率警报。过去需要手动解析日志的操作现在在摄取阶段自动完成。当生产事件发生时,你搜索的是结构化数据,而非原始文本。
这种方法不仅适用于 IIS。任何在单个流中包含多种日志格式的情况——无论是应用日志与系统日志混合,还是一个容器中有多个服务——模式都是相同的:在摄取阶段检测、去除包裹层、路由到专用 pipeline。摄取层成为日志解析器,下游系统获得干净、结构化的数据。