• k8s搭建EFK日志系统


    搭建 EFK 日志系统

    前面大家介绍了 Kubernetes 集群中的几种日志收集方案,Kubernetes 中比较流行的日志收集解决方案是 Elasticsearch、Fluentd 和 Kibana(EFK)技术栈,也是官方现在比较推荐的一种方案。

    Elasticsearch 是一个实时的、分布式的可扩展的搜索引擎,允许进行全文、结构化搜索,它通常用于索引和搜索大量日志数据,也可用于搜索许多不同类型的文档。

    Elasticsearch 通常与 Kibana 一起部署,Kibana 是 Elasticsearch 的一个功能强大的数据可视化 Dashboard,Kibana 允许你通过 web 界面来浏览 Elasticsearch 日志数据。

    Fluentd是一个流行的开源数据收集器,我们将在 Kubernetes 集群节点上安装 Fluentd,通过获取容器日志文件、过滤和转换日志数据,然后将数据传递到 Elasticsearch 集群,在该集群中对其进行索引和存储。

    我们先来配置启动一个可扩展的 Elasticsearch 集群,然后在 Kubernetes 集群中创建一个 Kibana 应用,最后通过 DaemonSet 来运行 Fluentd,以便它在每个 Kubernetes 工作节点上都可以运行一个 Pod。

    安装 Elasticsearch 集群

    在创建 Elasticsearch 集群之前,我们先创建一个命名空间,我们将在其中安装所有日志相关的资源对象。

    $ kubectl create ns logging
    

    环境准备

    ElasticSearch 安装有最低安装要求,如果安装后 Pod 无法正常启动,请检查是否符合最低要求的配置,要求如下:

    es 集群要求

    这里我们要安装的 ES 集群环境信息如下所示:

    es 集群环境

    这里我们使用一个 NFS 类型的 StorageClass 来做持久化存储,当然如果你是线上环境建议使用 Local PV 或者 Ceph RBD 之类的存储来持久化 Elasticsearch 的数据。

    此外由于 ElasticSearch 7.x 版本默认安装了 X-Pack 插件,并且部分功能免费,需要我们配置一些安全证书文件。

    1、生成证书文件

    1. # 运行容器生成证书,containerd下面用nerdctl
    2. $ mkdir -p elastic-certs
    3. $ nerdctl run --name elastic-certs -v elastic-certs:/app -it -w /app elasticsearch:7.17.3 /bin/sh -c \
    4. "elasticsearch-certutil ca --out /app/elastic-stack-ca.p12 --pass '' && \
    5. elasticsearch-certutil cert --name security-master --dns \
    6. security-master --ca /app/elastic-stack-ca.p12 --pass '' --ca-pass '' --out /app/elastic-certificates.p12"
    7. # 删除容器
    8. $ nerdctl rm -f elastic-certs
    9. # 将 pcks12 中的信息分离出来,写入文件
    10. $ cd elastic-certs && openssl pkcs12 -nodes -passin pass:'' -in elastic-certificates.p12 -out elastic-certificate.pem

    需要注意 nerdctl 如果是 v0.20.0 版本,需要更新 CNI 插件版本,否则会出现错误 FATA[0000] failed to create shim: OCI runtime create failed: container_linux.go:380: starting container process caused: process_linux.go:545: container init caused: Running hook #0:: error running hook: exit status 1, stdout: , stderr: time="2022-06-06T16:37:03+08:00" level=fatal msg="failed to call cni.Setup: plugin type=\"bridge\" failed (add): incompatible CNI versions; config is \"1.0.0\", plugin supports [\"0.1.0\" \"0.2.0\" \"0.3.0\" \"0.3.1\" \"0.4.0\"]",将 CNI 插件从 https://github.com/containernetworking/plugins/releases/download/v1.1.1/cni-plugins-linux-amd64-v1.1.1.tgz 下载下来覆盖 /opt/cni/bin 目录即可。

    2、添加证书到 Kubernetes

    1. # 添加证书
    2. $ kubectl create secret -n logging generic elastic-certs --from-file=elastic-certificates.p12
    3. # 设置集群用户名密码
    4. $ kubectl create secret -n logging generic elastic-auth --from-literal=username=elastic --from-literal=password=ydzsio321

    安装 ES 集群

    首先添加 ELastic 的 Helm 仓库:

    1. $ helm repo add elastic https://helm.elastic.co
    2. $ helm repo update

    ElaticSearch 安装需要安装三次,分别安装 Master、Data、Client 节点,Master 节点负责集群间的管理工作;Data 节点负责存储数据;Client 节点负责代理 ElasticSearch Cluster 集群,负载均衡。

    首先使用 helm pull 拉取 Chart 并解压:

    1. $ helm pull elastic/elasticsearch --untar --version 7.17.3
    2. $ cd elasticsearch

    在 Chart 目录下面创建用于 Master 节点安装配置的 values 文件:

    1. # values-master.yaml
    2. ## 设置集群名称
    3. clusterName: 'elasticsearch'
    4. ## 设置节点名称
    5. nodeGroup: 'master'
    6. ## 设置角色
    7. roles:
    8. master: 'true'
    9. ingest: 'false'
    10. data: 'false'
    11. # ============镜像配置============
    12. ## 指定镜像与镜像版本
    13. image: 'elasticsearch'
    14. imageTag: '7.17.3'
    15. imagePullPolicy: 'IfNotPresent'
    16. ## 副本数
    17. replicas: 3
    18. # ============资源配置============
    19. ## JVM 配置参数
    20. esJavaOpts: '-Xmx1g -Xms1g'
    21. ## 部署资源配置(生成环境要设置大些)
    22. resources:
    23. requests:
    24. cpu: '2000m'
    25. memory: '2Gi'
    26. limits:
    27. cpu: '2000m'
    28. memory: '2Gi'
    29. ## 数据持久卷配置
    30. persistence:
    31. enabled: true
    32. ## 存储数据大小配置
    33. volumeClaimTemplate:
    34. storageClassName: local-path
    35. accessModes: ['ReadWriteOnce']
    36. resources:
    37. requests:
    38. storage: 5Gi
    39. # ============安全配置============
    40. ## 设置协议,可配置为 http、https
    41. protocol: http
    42. ## 证书挂载配置,这里我们挂入上面创建的证书
    43. secretMounts:
    44. - name: elastic-certs
    45. secretName: elastic-certs
    46. path: /usr/share/elasticsearch/config/certs
    47. defaultMode: 0755
    48. ## 允许您在/usr/share/elasticsearch/config/中添加任何自定义配置文件,例如 elasticsearch.yml、log4j2.properties
    49. ## ElasticSearch 7.x 默认安装了 x-pack 插件,部分功能免费,这里我们配置下
    50. ## 下面注掉的部分为配置 https 证书,配置此部分还需要配置 helm 参数 protocol 值改为 https
    51. esConfig:
    52. elasticsearch.yml: |
    53. xpack.security.enabled: true
    54. xpack.security.transport.ssl.enabled: true
    55. xpack.security.transport.ssl.verification_mode: certificate
    56. xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
    57. xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
    58. # xpack.security.http.ssl.enabled: true
    59. # xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
    60. # xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
    61. ## 环境变量配置,这里引入上面设置的用户名、密码 secret 文件
    62. extraEnvs:
    63. - name: ELASTIC_USERNAME
    64. valueFrom:
    65. secretKeyRef:
    66. name: elastic-auth
    67. key: username
    68. - name: ELASTIC_PASSWORD
    69. valueFrom:
    70. secretKeyRef:
    71. name: elastic-auth
    72. key: password
    73. # ============调度配置============
    74. ## 设置调度策略
    75. ## - hard:只有当有足够的节点时 Pod 才会被调度,并且它们永远不会出现在同一个节点上
    76. ## - soft:尽最大努力调度
    77. antiAffinity: 'soft'
    78. # tolerations:
    79. # - operator: "Exists" ##容忍全部污点

    然后创建用于 Data 节点安装的 values 文件:

    1. # values-data.yaml
    2. # ============设置集群名称============
    3. ## 设置集群名称
    4. clusterName: 'elasticsearch'
    5. ## 设置节点名称
    6. nodeGroup: 'data'
    7. ## 设置角色
    8. roles:
    9. master: 'false'
    10. ingest: 'true'
    11. data: 'true'
    12. # ============镜像配置============
    13. ## 指定镜像与镜像版本
    14. image: 'elasticsearch'
    15. imageTag: '7.17.3'
    16. ## 副本数(建议设置为3,我这里资源不足只用了1个副本)
    17. replicas: 3
    18. # ============资源配置============
    19. ## JVM 配置参数
    20. esJavaOpts: '-Xmx1g -Xms1g'
    21. ## 部署资源配置(生成环境一定要设置大些)
    22. resources:
    23. requests:
    24. cpu: '1000m'
    25. memory: '2Gi'
    26. limits:
    27. cpu: '1000m'
    28. memory: '2Gi'
    29. ## 数据持久卷配置
    30. persistence:
    31. enabled: true
    32. ## 存储数据大小配置
    33. volumeClaimTemplate:
    34. storageClassName: local-path
    35. accessModes: ['ReadWriteOnce']
    36. resources:
    37. requests:
    38. storage: 10Gi
    39. # ============安全配置============
    40. ## 设置协议,可配置为 http、https
    41. protocol: http
    42. ## 证书挂载配置,这里我们挂入上面创建的证书
    43. secretMounts:
    44. - name: elastic-certs
    45. secretName: elastic-certs
    46. path: /usr/share/elasticsearch/config/certs
    47. ## 允许您在/usr/share/elasticsearch/config/中添加任何自定义配置文件,例如 elasticsearch.yml
    48. ## ElasticSearch 7.x 默认安装了 x-pack 插件,部分功能免费,这里我们配置下
    49. ## 下面注掉的部分为配置 https 证书,配置此部分还需要配置 helm 参数 protocol 值改为 https
    50. esConfig:
    51. elasticsearch.yml: |
    52. xpack.security.enabled: true
    53. xpack.security.transport.ssl.enabled: true
    54. xpack.security.transport.ssl.verification_mode: certificate
    55. xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
    56. xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
    57. # xpack.security.http.ssl.enabled: true
    58. # xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
    59. # xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
    60. ## 环境变量配置,这里引入上面设置的用户名、密码 secret 文件
    61. extraEnvs:
    62. - name: ELASTIC_USERNAME
    63. valueFrom:
    64. secretKeyRef:
    65. name: elastic-auth
    66. key: username
    67. - name: ELASTIC_PASSWORD
    68. valueFrom:
    69. secretKeyRef:
    70. name: elastic-auth
    71. key: password
    72. # ============调度配置============
    73. ## 设置调度策略
    74. ## - hard:只有当有足够的节点时 Pod 才会被调度,并且它们永远不会出现在同一个节点上
    75. ## - soft:尽最大努力调度
    76. antiAffinity: 'soft'
    77. ## 容忍配置
    78. # tolerations:
    79. # - operator: "Exists" ##容忍全部污点

    最后一个是用于创建 Client 节点的 values 文件:

    1. # values-client.yaml
    2. # ============设置集群名称============
    3. ## 设置集群名称
    4. clusterName: 'elasticsearch'
    5. ## 设置节点名称
    6. nodeGroup: 'client'
    7. ## 设置角色
    8. roles:
    9. master: 'false'
    10. ingest: 'false'
    11. data: 'false'
    12. # ============镜像配置============
    13. ## 指定镜像与镜像版本
    14. image: 'elasticsearch'
    15. imageTag: '7.17.3'
    16. ## 副本数
    17. replicas: 1
    18. # ============资源配置============
    19. ## JVM 配置参数
    20. esJavaOpts: '-Xmx1g -Xms1g'
    21. ## 部署资源配置(生成环境一定要设置大些)
    22. resources:
    23. requests:
    24. cpu: '1000m'
    25. memory: '2Gi'
    26. limits:
    27. cpu: '1000m'
    28. memory: '2Gi'
    29. ## 数据持久卷配置
    30. persistence:
    31. enabled: false
    32. # ============安全配置============
    33. ## 设置协议,可配置为 http、https
    34. protocol: http
    35. ## 证书挂载配置,这里我们挂入上面创建的证书
    36. secretMounts:
    37. - name: elastic-certs
    38. secretName: elastic-certs
    39. path: /usr/share/elasticsearch/config/certs
    40. ## 允许您在/usr/share/elasticsearch/config/中添加任何自定义配置文件,例如 elasticsearch.yml
    41. ## ElasticSearch 7.x 默认安装了 x-pack 插件,部分功能免费,这里我们配置下
    42. ## 下面注掉的部分为配置 https 证书,配置此部分还需要配置 helm 参数 protocol 值改为 https
    43. esConfig:
    44. elasticsearch.yml: |
    45. xpack.security.enabled: true
    46. xpack.security.transport.ssl.enabled: true
    47. xpack.security.transport.ssl.verification_mode: certificate
    48. xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
    49. xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
    50. # xpack.security.http.ssl.enabled: true
    51. # xpack.security.http.ssl.truststore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
    52. # xpack.security.http.ssl.keystore.path: /usr/share/elasticsearch/config/certs/elastic-certificates.p12
    53. ## 环境变量配置,这里引入上面设置的用户名、密码 secret 文件
    54. extraEnvs:
    55. - name: ELASTIC_USERNAME
    56. valueFrom:
    57. secretKeyRef:
    58. name: elastic-auth
    59. key: username
    60. - name: ELASTIC_PASSWORD
    61. valueFrom:
    62. secretKeyRef:
    63. name: elastic-auth
    64. key: password
    65. # ============Service 配置============
    66. service:
    67. type: NodePort
    68. nodePort: '30200'

    现在用上面的 values 文件来安装:

    1. # 安装 master 节点
    2. $ helm upgrade --install es-master -f values-master.yaml --namespace logging .
    3. # 安装 data 节点
    4. $ helm upgrade --install es-data -f values-data.yaml --namespace logging .
    5. # 安装 client 节点
    6. $ helm upgrade --install es-client -f values-client.yaml --namespace logging .

    在安装 Master 节点后 Pod 启动时候会抛出异常,就绪探针探活失败,这是个正常现象。在执行安装 Data 节点后 Master 节点 Pod 就会恢复正常。

    安装 Kibana

    Elasticsearch 集群安装完成后接下来配置安装 Kibana

    使用 helm pull 命令拉取 Kibana Chart 包并解压:

    1. $ helm pull elastic/kibana --untar --version 7.17.3
    2. $ cd kibana

    创建用于安装 Kibana 的 values 文件:

    1. # values-prod.yaml
    2. ## 指定镜像与镜像版本
    3. image: 'kibana'
    4. imageTag: '7.17.3'
    5. ## 配置 ElasticSearch 地址
    6. elasticsearchHosts: 'http://elasticsearch-client:9200'
    7. # ============环境变量配置============
    8. ## 环境变量配置,这里引入上面设置的用户名、密码 secret 文件
    9. extraEnvs:
    10. - name: 'ELASTICSEARCH_USERNAME'
    11. valueFrom:
    12. secretKeyRef:
    13. name: elastic-auth
    14. key: username
    15. - name: 'ELASTICSEARCH_PASSWORD'
    16. valueFrom:
    17. secretKeyRef:
    18. name: elastic-auth
    19. key: password
    20. # ============资源配置============
    21. resources:
    22. requests:
    23. cpu: '500m'
    24. memory: '1Gi'
    25. limits:
    26. cpu: '500m'
    27. memory: '1Gi'
    28. # ============配置 Kibana 参数============
    29. ## kibana 配置中添加语言配置,设置 kibana 为中文
    30. kibanaConfig:
    31. kibana.yml: |
    32. i18n.locale: "zh-CN"
    33. # ============Service 配置============
    34. service:
    35. type: NodePort
    36. nodePort: '30601'

    使用上面的配置直接安装即可:

    $ helm install kibana -f values-prod.yaml --namespace logging .
    

    下面是安装完成后的 ES 集群和 Kibana 资源:

    1. $ kubectl get pods -n logging
    2. NAME READY STATUS RESTARTS AGE
    3. elasticsearch-client-0 1/1 Running 0 9m25s
    4. elasticsearch-data-0 1/1 Running 0 9m33s
    5. elasticsearch-master-0 1/1 Running 0 8m29s
    6. kibana-kibana-79b9878cd7-7l75v 1/1 Running 0 6m12s
    7. $ kubectl get svc -n logging
    8. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    9. elasticsearch-client NodePort 10.108.226.197 <none> 9200:30200/TCP,9300:32746/TCP 3m25s
    10. elasticsearch-client-headless ClusterIP None <none> 9200/TCP,9300/TCP 3m25s
    11. elasticsearch-data ClusterIP 10.104.121.49 <none> 9200/TCP,9300/TCP 3m33s
    12. elasticsearch-data-headless ClusterIP None <none> 9200/TCP,9300/TCP 3m33s
    13. elasticsearch-master ClusterIP 10.102.72.71 <none> 9200/TCP,9300/TCP 6m8s
    14. elasticsearch-master-headless ClusterIP None <none> 9200/TCP,9300/TCP 6m8s
    15. kibana-kibana NodePort 10.109.35.219 <none> 5601:30601/TCP 12s

    上面我们安装 Kibana 的时候指定了 30601 的 NodePort 端口,所以我们可以从任意节点 http://IP:30601 来访问 Kibana。

    Kibana 登录页面

    我们可以看到会跳转到登录页面,让我们输出用户名、密码,这里我们输入上面配置的用户名 elastic、密码 ydzsio321 进行登录。登录成功后进入如下所示的 Kibana 主页:

    Kibana 主页面

    部署 Fluentd

    Fluentd 是一个高效的日志聚合器,是用 Ruby 编写的,并且可以很好地扩展。对于大部分企业来说,Fluentd 足够高效并且消耗的资源相对较少,另外一个工具 Fluent-bit 更轻量级,占用资源更少,但是插件相对 Fluentd 来说不够丰富,所以整体来说,Fluentd 更加成熟,使用更加广泛,所以这里我们使用 Fluentd 来作为日志收集工具。

    工作原理

    Fluentd 通过一组给定的数据源抓取日志数据,处理后(转换成结构化的数据格式)将它们转发给其他服务,比如 Elasticsearch、对象存储等等。Fluentd 支持超过 300 个日志存储和分析服务,所以在这方面是非常灵活的。主要运行步骤如下:

    • 首先 Fluentd 从多个日志源获取数据
    • 结构化并且标记这些数据
    • 然后根据匹配的标签将数据发送到多个目标服务去

    fluentd 架构

    配置

    一般来说我们是通过一个配置文件来告诉 Fluentd 如何采集、处理数据的,下面简单和大家介绍下 Fluentd 的配置方法。

    日志源配置

    比如我们这里为了收集 Kubernetes 节点上的所有容器日志,就需要做如下的日志源配置:

    1. <source>
    2. @id fluentd-containers.log
    3. @type tail # Fluentd 内置的输入方式,其原理是不停地从源文件中获取新的日志。
    4. path /var/log/containers/*.log # 挂载的宿主机容器日志地址
    5. pos_file /var/log/es-containers.log.pos
    6. tag raw.kubernetes.* # 设置日志标签
    7. read_from_head true
    8. <parse> # 多行格式化成JSON
    9. @type multi_format # 使用 multi-format-parser 解析器插件
    10. <pattern>
    11. format json # JSON 解析器
    12. time_key time # 指定事件时间的时间字段
    13. time_format %Y-%m-%dT%H:%M:%S.%NZ # 时间格式
    14. </pattern>
    15. <pattern>
    16. format /^(?<time>.+) (?<stream>stdout|stderr) [^ ]* (?<log>.*)$/
    17. time_format %Y-%m-%dT%H:%M:%S.%N%:z
    18. </pattern>
    19. </parse>
    20. </source>

    上面配置部分参数说明如下:

    • id:表示引用该日志源的唯一标识符,该标识可用于进一步过滤和路由结构化日志数据
    • type:Fluentd 内置的指令,tail 表示 Fluentd 从上次读取的位置通过 tail 不断获取数据,另外一个是 http 表示通过一个 GET 请求来收集数据。
    • path:tail 类型下的特定参数,告诉 Fluentd 采集 /var/log/containers 目录下的所有日志,这是 docker 在 Kubernetes 节点上用来存储运行容器 stdout 输出日志数据的目录。
    • pos_file:检查点,如果 Fluentd 程序重新启动了,它将使用此文件中的位置来恢复日志数据收集。
    • tag:用来将日志源与目标或者过滤器匹配的自定义字符串,Fluentd 匹配源/目标标签来路由日志数据。
    路由配置

    上面是日志源的配置,接下来看看如何将日志数据发送到 Elasticsearch:

    1. <match **>
    2. @id elasticsearch
    3. @type elasticsearch
    4. @log_level info
    5. include_tag_key true
    6. type_name fluentd
    7. host "#{ENV['OUTPUT_HOST']}"
    8. port "#{ENV['OUTPUT_PORT']}"
    9. logstash_format true
    10. <buffer>
    11. @type file
    12. path /var/log/fluentd-buffers/kubernetes.system.buffer
    13. flush_mode interval
    14. retry_type exponential_backoff
    15. flush_thread_count 2
    16. flush_interval 5s
    17. retry_forever
    18. retry_max_interval 30
    19. chunk_limit_size "#{ENV['OUTPUT_BUFFER_CHUNK_LIMIT']}"
    20. queue_limit_length "#{ENV['OUTPUT_BUFFER_QUEUE_LIMIT']}"
    21. overflow_action block
    22. </buffer>
    23. </match>

    • match:标识一个目标标签,后面是一个匹配日志源的正则表达式,我们这里想要捕获所有的日志并将它们发送给 Elasticsearch,所以需要配置成**
    • id:目标的一个唯一标识符。
    • type:支持的输出插件标识符,我们这里要输出到 Elasticsearch,所以配置成 elasticsearch,这是 Fluentd 的一个内置插件。
    • log_level:指定要捕获的日志级别,我们这里配置成 info,表示任何该级别或者该级别以上(INFO、WARNING、ERROR)的日志都将被路由到 Elsasticsearch。
    • host/port:定义 Elasticsearch 的地址,也可以配置认证信息,我们的 Elasticsearch 不需要认证,所以这里直接指定 host 和 port 即可。
    • logstash_format:Elasticsearch 服务对日志数据构建反向索引进行搜索,将 logstash_format 设置为 true,Fluentd 将会以 logstash 格式来转发结构化的日志数据。
    • Buffer: Fluentd 允许在目标不可用时进行缓存,比如,如果网络出现故障或者 Elasticsearch 不可用的时候。缓冲区配置也有助于降低磁盘的 IO。
    过滤

    由于 Kubernetes 集群中应用太多,也还有很多历史数据,所以我们可以只将某些应用的日志进行收集,比如我们只采集具有 logging=true 这个 Label 标签的 Pod 日志,这个时候就需要使用 filter,如下所示:

    1. # 删除无用的属性
    2. <filter kubernetes.**>
    3. @type record_transformer
    4. remove_keys $.docker.container_id,$.kubernetes.container_image_id,$.kubernetes.pod_id,$.kubernetes.namespace_id,$.kubernetes.master_url,$.kubernetes.labels.pod-template-hash
    5. </filter>
    6. # 只保留具有logging=true标签的Pod日志
    7. <filter kubernetes.**>
    8. @id filter_log
    9. @type grep
    10. <regexp>
    11. key $.kubernetes.labels.logging
    12. pattern ^true$
    13. </regexp>
    14. </filter>

    安装

    要收集 Kubernetes 集群的日志,直接用 DasemonSet 控制器来部署 Fluentd 应用,这样,它就可以从 Kubernetes 节点上采集日志,确保在集群中的每个节点上始终运行一个 Fluentd 容器。当然可以直接使用 Helm 来进行一键安装,为了能够了解更多实现细节,我们这里还是采用手动方法来进行安装。

    可以直接使用官方的对于 Kubernetes 集群的安装文档: Kubernetes - Fluentd

    首先,我们通过 ConfigMap 对象来指定 Fluentd 配置文件,新建 fluentd-configmap.yaml 文件,文件内容如下:

    1. # fluentd-configmap.yaml
    2. kind: ConfigMap
    3. apiVersion: v1
    4. metadata:
    5. name: fluentd-conf
    6. namespace: logging
    7. data:
    8. # 容器日志
    9. containers.input.conf: |-
    10. <source>
    11. @id fluentd-containers.log
    12. @type tail # Fluentd 内置的输入方式,其原理是不停地从源文件中获取新的日志
    13. path /var/log/containers/*.log # Docker 容器日志路径
    14. pos_file /var/log/es-containers.log.pos # 记录读取的位置
    15. tag raw.kubernetes.* # 设置日志标签
    16. read_from_head true # 从头读取
    17. <parse> # 多行格式化成JSON
    18. # 可以使用我们介绍过的 multiline 插件实现多行日志
    19. @type multi_format # 使用 multi-format-parser 解析器插件
    20. <pattern>
    21. format json # JSON解析器
    22. time_key time # 指定事件时间的时间字段
    23. time_format %Y-%m-%dT%H:%M:%S.%NZ # 时间格式
    24. </pattern>
    25. <pattern>
    26. format /^(?<time>.+) (?<stream>stdout|stderr) [^ ]* (?<log>.*)$/
    27. time_format %Y-%m-%dT%H:%M:%S.%N%:z
    28. </pattern>
    29. </parse>
    30. </source>
    31. # 在日志输出中检测异常(多行日志),并将其作为一条日志转发
    32. # https://github.com/GoogleCloudPlatform/fluent-plugin-detect-exceptions
    33. <match raw.kubernetes.**> # 匹配tag为raw.kubernetes.**日志信息
    34. @id raw.kubernetes
    35. @type detect_exceptions # 使用detect-exceptions插件处理异常栈信息
    36. remove_tag_prefix raw # 移除 raw 前缀
    37. message log
    38. multiline_flush_interval 5
    39. </match>
    40. <filter **> # 拼接日志
    41. @id filter_concat
    42. @type concat # Fluentd Filter 插件,用于连接多个日志中分隔的多行日志
    43. key message
    44. multiline_end_regexp /\n$/ # 以换行符“\n”拼接
    45. separator ""
    46. </filter>
    47. # 添加 Kubernetes metadata 数据
    48. <filter kubernetes.**>
    49. @id filter_kubernetes_metadata
    50. @type kubernetes_metadata
    51. </filter>
    52. # 修复 ES 中的 JSON 字段
    53. # 插件地址:https://github.com/repeatedly/fluent-plugin-multi-format-parser
    54. <filter kubernetes.**>
    55. @id filter_parser
    56. @type parser # multi-format-parser多格式解析器插件
    57. key_name log # 在要解析的日志中指定字段名称
    58. reserve_data true # 在解析结果中保留原始键值对
    59. remove_key_name_field true # key_name 解析成功后删除字段
    60. <parse>
    61. @type multi_format
    62. <pattern>
    63. format json
    64. </pattern>
    65. <pattern>
    66. format none
    67. </pattern>
    68. </parse>
    69. </filter>
    70. # 删除一些多余的属性
    71. <filter kubernetes.**>
    72. @type record_transformer
    73. remove_keys $.docker.container_id,$.kubernetes.container_image_id,$.kubernetes.pod_id,$.kubernetes.namespace_id,$.kubernetes.master_url,$.kubernetes.labels.pod-template-hash
    74. </filter>
    75. # 只保留具有logging=true标签的Pod日志
    76. <filter kubernetes.**>
    77. @id filter_log
    78. @type grep
    79. <regexp>
    80. key $.kubernetes.labels.logging
    81. pattern ^true$
    82. </regexp>
    83. </filter>
    84. ###### 监听配置,一般用于日志聚合用 ######
    85. forward.input.conf: |-
    86. # 监听通过TCP发送的消息
    87. <source>
    88. @id forward
    89. @type forward
    90. </source>
    91. output.conf: |-
    92. <match **>
    93. @id elasticsearch
    94. @type elasticsearch
    95. @log_level info
    96. include_tag_key true
    97. host elasticsearch-client
    98. port 9200
    99. user elastic # FLUENT_ELASTICSEARCH_USER | FLUENT_ELASTICSEARCH_PASSWORD
    100. password ydzsio321
    101. logstash_format true
    102. logstash_prefix k8s
    103. request_timeout 30s
    104. <buffer>
    105. @type file
    106. path /var/log/fluentd-buffers/kubernetes.system.buffer
    107. flush_mode interval
    108. retry_type exponential_backoff
    109. flush_thread_count 2
    110. flush_interval 5s
    111. retry_forever
    112. retry_max_interval 30
    113. chunk_limit_size 2M
    114. queue_limit_length 8
    115. overflow_action block
    116. </buffer>
    117. </match>

    上面配置文件中我们只配置了 docker 容器日志目录,收集到数据经过处理后发送到 elasticsearch-client:9200 服务。

    然后新建一个 fluentd-daemonset.yaml 的文件,文件内容如下:

    1. apiVersion: v1
    2. kind: ServiceAccount
    3. metadata:
    4. name: fluentd-es
    5. namespace: logging
    6. labels:
    7. k8s-app: fluentd-es
    8. kubernetes.io/cluster-service: 'true'
    9. addonmanager.kubernetes.io/mode: Reconcile
    10. ---
    11. kind: ClusterRole
    12. apiVersion: rbac.authorization.k8s.io/v1
    13. metadata:
    14. name: fluentd-es
    15. labels:
    16. k8s-app: fluentd-es
    17. kubernetes.io/cluster-service: 'true'
    18. addonmanager.kubernetes.io/mode: Reconcile
    19. rules:
    20. - apiGroups:
    21. - ''
    22. resources:
    23. - 'namespaces'
    24. - 'pods'
    25. verbs:
    26. - 'get'
    27. - 'watch'
    28. - 'list'
    29. ---
    30. kind: ClusterRoleBinding
    31. apiVersion: rbac.authorization.k8s.io/v1
    32. metadata:
    33. name: fluentd-es
    34. labels:
    35. k8s-app: fluentd-es
    36. kubernetes.io/cluster-service: 'true'
    37. addonmanager.kubernetes.io/mode: Reconcile
    38. subjects:
    39. - kind: ServiceAccount
    40. name: fluentd-es
    41. namespace: logging
    42. apiGroup: ''
    43. roleRef:
    44. kind: ClusterRole
    45. name: fluentd-es
    46. apiGroup: ''
    47. ---
    48. apiVersion: apps/v1
    49. kind: DaemonSet
    50. metadata:
    51. name: fluentd
    52. namespace: logging
    53. labels:
    54. app: fluentd
    55. kubernetes.io/cluster-service: 'true'
    56. spec:
    57. selector:
    58. matchLabels:
    59. app: fluentd
    60. template:
    61. metadata:
    62. labels:
    63. app: fluentd
    64. kubernetes.io/cluster-service: 'true'
    65. spec:
    66. tolerations:
    67. - key: node-role.kubernetes.io/master
    68. effect: NoSchedule
    69. serviceAccountName: fluentd-es
    70. containers:
    71. - name: fluentd
    72. image: quay.io/fluentd_elasticsearch/fluentd:v3.4.0
    73. volumeMounts:
    74. - name: fluentconfig
    75. mountPath: /etc/fluent/config.d
    76. - name: varlog
    77. mountPath: /var/log
    78. volumes:
    79. - name: fluentconfig
    80. configMap:
    81. name: fluentd-conf
    82. - name: varlog
    83. hostPath:
    84. path: /var/log

    我们将上面创建的 fluentd-config 这个 ConfigMap 对象通过 volumes 挂载到了 Fluentd 容器中,另外为了能够灵活控制哪些节点的日志可以被收集,还可以添加了一个 nodSelector 属性:

    1. nodeSelector:
    2. beta.kubernetes.io/fluentd-ds-ready: 'true'

    意思就是要想采集节点的日志,那么我们就需要给节点打上上面的标签。

    !!! info "提示" 如果你需要在其他节点上采集日志,则需要给对应节点打上标签,使用如下命令:kubectl label nodes node名 beta.kubernetes.io/fluentd-ds-ready=true

    另外由于我们的集群使用的是 kubeadm 搭建的,默认情况下 master 节点有污点,所以如果要想也收集 master 节点的日志,则需要添加上容忍:

    1. tolerations:
    2. - operator: Exists

    分别创建上面的 ConfigMap 对象和 DaemonSet:

    1. $ kubectl create -f fluentd-configmap.yaml
    2. configmap "fluentd-conf" created
    3. $ kubectl create -f fluentd-daemonset.yaml
    4. serviceaccount "fluentd-es" created
    5. clusterrole.rbac.authorization.k8s.io "fluentd-es" created
    6. clusterrolebinding.rbac.authorization.k8s.io "fluentd-es" created
    7. daemonset.apps "fluentd" created

    创建完成后,查看对应的 Pods 列表,检查是否部署成功:

    1. $ kubectl get pods -n logging
    2. NAME READY STATUS RESTARTS AGE
    3. elasticsearch-client-0 1/1 Running 0 64m
    4. elasticsearch-data-0 1/1 Running 0 65m
    5. elasticsearch-master-0 1/1 Running 0 73m
    6. fluentd-5rqbq 1/1 Running 0 60m
    7. fluentd-l6mgf 1/1 Running 0 60m
    8. fluentd-xmfpg 1/1 Running 0 60m
    9. kibana-66f97964b-mdspc 1/1 Running 0 63m

    Fluentd 启动成功后,这个时候就可以发送日志到 ES 了,但是我们这里是过滤了只采集具有 logging=true 标签的 Pod 日志,所以现在还没有任何数据会被采集。

    下面我们部署一个简单的测试应用, 新建 counter.yaml 文件,文件内容如下:

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: counter
    5. labels:
    6. logging: 'true' # 一定要具有该标签才会被采集
    7. spec:
    8. containers:
    9. - name: count
    10. image: busybox
    11. args:
    12. [
    13. /bin/sh,
    14. -c,
    15. 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done',
    16. ]

    该 Pod 只是简单将日志信息打印到 stdout,所以正常来说 Fluentd 会收集到这个日志数据,在 Kibana 中也就可以找到对应的日志数据了,使用 kubectl 工具创建该 Pod:

    1. $ kubectl create -f counter.yaml
    2. $ kubectl get pods
    3. NAME READY STATUS RESTARTS AGE
    4. counter 1/1 Running 0 9h

    Pod 创建并运行后,回到 Kibana Dashboard 页面,点击左侧最下面的 Management -> Stack Management,进入管理页面,点击左侧 Kibana 下面的 索引模式,点击 创建索引模式 开始导入索引数据:

    create index

    在这里可以配置我们需要的 Elasticsearch 索引,前面 Fluentd 配置文件中我们采集的日志使用的是 logstash 格式,定义了一个 k8s 的前缀,所以这里只需要在文本框中输入 k8s-* 即可匹配到 Elasticsearch 集群中采集的 Kubernetes 集群日志数据,然后点击下一步,进入以下页面:

    index config

    在该页面中配置使用哪个字段按时间过滤日志数据,在下拉列表中,选择@timestamp字段,然后点击 创建索引模式,创建完成后,点击左侧导航菜单中的 Discover,然后就可以看到一些直方图和最近采集到的日志数据了:

    log data

    现在的数据就是上面 Counter 应用的日志,如果还有其他的应用,我们也可以筛选过滤:

    counter log data

    我们也可以通过其他元数据来过滤日志数据,比如您可以单击任何日志条目以查看其他元数据,如容器名称,Kubernetes 节点,命名空间等。

    安装 Kafka

    对于大规模集群来说,日志数据量是非常巨大的,如果直接通过 Fluentd 将日志打入 Elasticsearch,对 ES 来说压力是非常巨大的,我们可以在中间加一层消息中间件来缓解 ES 的压力,一般情况下我们会使用 Kafka,然后可以直接使用 kafka-connect-elasticsearch 这样的工具将数据直接打入 ES,也可以在加一层 Logstash 去消费 Kafka 的数据,然后通过 Logstash 把数据存入 ES,这里我们来使用 Logstash 这种模式来对日志收集进行优化。

    首先在 Kubernetes 集群中安装 Kafka,同样这里使用 Helm 进行安装:

    1. $ helm repo add bitnami https://charts.bitnami.com/bitnami
    2. $ helm repo update

    首先使用 helm pull 拉取 Chart 并解压:

    1. $ helm pull bitnami/kafka --untar --version 17.2.3
    2. $ cd kafka

    这里面我们指定使用一个 StorageClass 来提供持久化存储,在 Chart 目录下面创建用于安装的 values 文件:

    1. # values-prod.yaml
    2. ## @section Persistence parameters
    3. persistence:
    4. enabled: true
    5. storageClass: 'local-path'
    6. accessModes:
    7. - ReadWriteOnce
    8. size: 8Gi
    9. mountPath: /bitnami/kafka
    10. # 配置zk volumes
    11. zookeeper:
    12. enabled: true
    13. persistence:
    14. enabled: true
    15. storageClass: 'local-path'
    16. accessModes:
    17. - ReadWriteOnce
    18. size: 8Gi

    直接使用上面的 values 文件安装 kafka:

    1. $ helm upgrade --install kafka -f values-prod.yaml --namespace logging .
    2. Release "kafka" does not exist. Installing it now.
    3. NAME: kafka
    4. LAST DEPLOYED: Thu Jun 9 14:02:01 2022
    5. NAMESPACE: logging
    6. STATUS: deployed
    7. REVISION: 1
    8. TEST SUITE: None
    9. NOTES:
    10. CHART NAME: kafka
    11. CHART VERSION: 17.2.3
    12. APP VERSION: 3.2.0
    13. ** Please be patient while the chart is being deployed **
    14. Kafka can be accessed by consumers via port 9092 on the following DNS name from within your cluster:
    15. kafka.logging.svc.cluster.local
    16. Each Kafka broker can be accessed by producers via port 9092 on the following DNS name(s) from within your cluster:
    17. kafka-0.kafka-headless.logging.svc.cluster.local:9092
    18. To create a pod that you can use as a Kafka client run the following commands:
    19. kubectl run kafka-client --restart='Never' --image docker.io/bitnami/kafka:3.2.0-debian-10-r4 --namespace logging --command -- sleep infinity
    20. kubectl exec --tty -i kafka-client --namespace logging -- bash
    21. PRODUCER:
    22. kafka-console-producer.sh \
    23. --broker-list kafka-0.kafka-headless.logging.svc.cluster.local:9092 \
    24. --topic test
    25. CONSUMER:
    26. kafka-console-consumer.sh \
    27. --bootstrap-server kafka.logging.svc.cluster.local:9092 \
    28. --topic test \
    29. --from-beginning

    安装完成后我们可以使用上面的提示来检查 Kafka 是否正常运行:

    1. $ kubectl get pods -n logging -l app.kubernetes.io/instance=kafka
    2. kafka-0 1/1 Running 0 7m58s
    3. kafka-zookeeper-0 1/1 Running 0 7m58s

    用下面的命令创建一个 Kafka 的测试客户端 Pod:

    1. $ kubectl run kafka-client --restart='Never' --image docker.io/bitnami/kafka:3.2.0-debian-10-r4 --namespace logging --command -- sleep infinity
    2. pod/kafka-client created

    然后启动一个终端进入容器内部生产消息:

    1. # 生产者
    2. $ kubectl exec --tty -i kafka-client --namespace logging -- bash
    3. I have no name!@kafka-client:/$ kafka-console-producer.sh --broker-list kafka-0.kafka-headless.logging.svc.cluster.local:9092 --topic test
    4. >hello kafka on k8s
    5. >

    启动另外一个终端进入容器内部消费消息:

    1. # 消费者
    2. $ kubectl exec --tty -i kafka-client --namespace logging -- bash
    3. I have no name!@kafka-client:/$ kafka-console-consumer.sh --bootstrap-server kafka.logging.svc.cluster.local:9092 --topic test --from-beginning
    4. hello kafka on k8s

    如果在消费端看到了生产的消息数据证明我们的 Kafka 已经运行成功了。

    Fluentd 配置 Kafka

    现在有了 Kafka,我们就可以将 Fluentd 的日志数据输出到 Kafka 了,只需要将 Fluentd 配置中的  更改为使用 Kafka 插件即可,但是在 Fluentd 中输出到 Kafka,需要使用到 fluent-plugin-kafka 插件,所以需要我们自定义下 Docker 镜像,最简单的做法就是在上面 Fluentd 镜像的基础上新增 kafka 插件即可,Dockerfile 文件如下所示:

    1. FROM quay.io/fluentd_elasticsearch/fluentd:v3.4.0
    2. RUN echo "source 'https://mirrors.tuna.tsinghua.edu.cn/rubygems/'" > Gemfile && gem install bundler
    3. RUN gem install fluent-plugin-kafka -v 0.17.5 --no-document

    使用上面的 Dockerfile 文件构建一个 Docker 镜像即可,我这里构建过后的镜像名为 cnych/fluentd-kafka:v0.17.5。接下来替换 Fluentd 的 Configmap 对象中的  部分,如下所示:

    1. # fluentd-configmap.yaml
    2. kind: ConfigMap
    3. apiVersion: v1
    4. metadata:
    5. name: fluentd-conf
    6. namespace: logging
    7. data:
    8. ......
    9. output.conf: |-
    10. <match **>
    11. @id kafka
    12. @type kafka2
    13. @log_level info
    14. # list of seed brokers
    15. brokers kafka-0.kafka-headless.logging.svc.cluster.local:9092
    16. use_event_time true
    17. # topic settings
    18. topic_key k8slog
    19. default_topic messages # 注意,kafka中消费使用的是这个topic
    20. # buffer settings
    21. <buffer k8slog>
    22. @type file
    23. path /var/log/td-agent/buffer/td
    24. flush_interval 3s
    25. </buffer>
    26. # data type settings
    27. <format>
    28. @type json
    29. </format>
    30. # producer settings
    31. required_acks -1
    32. compression_codec gzip
    33. </match>

    然后替换运行的 Fluentd 镜像:

    1. # fluentd-daemonset.yaml
    2. image: cnych/fluentd-kafka:v0.17.5

    直接更新 Fluentd 的 Configmap 与 DaemonSet 资源对象即可:

    1. $ kubectl apply -f fluentd-configmap.yaml
    2. $ kubectl apply -f fluentd-daemonset.yaml

    更新成功后我们可以使用上面的测试 Kafka 客户端来验证是否有日志数据:

    1. $ kubectl exec --tty -i kafka-client --namespace logging -- bash
    2. I have no name!@kafka-client:/$ kafka-console-consumer.sh --bootstrap-server kafka.logging.svc.cluster.local:9092 --topic messages --from-beginning
    3. {"stream":"stdout","docker":{},"kubernetes":{"container_name":"count","namespace_name":"default","pod_name":"counter","container_image":"busybox:latest","host":"node1","labels":{"logging":"true"}},"message":"43883: Tue Apr 27 12:16:30 UTC 2021\n"}
    4. ......

    安装 Logstash

    虽然数据从 Kafka 到 Elasticsearch 的方式多种多样,比如可以使用 Kafka Connect Elasticsearch Connector 来实现,我们这里还是采用更加流行的 `Logstash`` 方案,上面我们已经将日志从 Fluentd 采集输出到 Kafka 中去了,接下来我们使用 Logstash 来连接 Kafka 与 Elasticsearch 间的日志数据。

    首先使用 helm pull 拉取 Chart 并解压:

    1. $ helm pull elastic/logstash --untar --version 7.17.3
    2. $ cd logstash

    同样在 Chart 根目录下面创建用于安装的 Values 文件,如下所示:

    1. # values-prod.yaml
    2. fullnameOverride: logstash
    3. persistence:
    4. enabled: true
    5. logstashConfig:
    6. logstash.yml: |
    7. http.host: 0.0.0.0
    8. # 如果启用了xpack,需要做如下配置
    9. xpack.monitoring.enabled: true
    10. xpack.monitoring.elasticsearch.hosts: ["http://elasticsearch-client:9200"]
    11. xpack.monitoring.elasticsearch.username: "elastic"
    12. xpack.monitoring.elasticsearch.password: "ydzsio321"
    13. # 要注意下格式
    14. logstashPipeline:
    15. logstash.conf: |
    16. input { kafka { bootstrap_servers => "kafka-0.kafka-headless.logging.svc.cluster.local:9092" codec => json consumer_threads => 3 topics => ["messages"] } }
    17. filter {} # 过滤配置(比如可以删除key、添加geoip等等)
    18. output { elasticsearch { hosts => [ "elasticsearch-client:9200" ] user => "elastic" password => "ydzsio321" index => "logstash-k8s-%{+YYYY.MM.dd}" } stdout { codec => rubydebug } }
    19. volumeClaimTemplate:
    20. accessModes: ['ReadWriteOnce']
    21. storageClassName: nfs-storage
    22. resources:
    23. requests:
    24. storage: 1Gi

    其中最重要的就是通过 logstashPipeline 配置 logstash 数据流的处理配置,通过 input 指定日志源 kafka 的配置,通过 output 输出到 Elasticsearch,同样直接使用上面的 Values 文件安装 logstash 即可:

    1. $ helm upgrade --install logstash -f values-prod.yaml --namespace logging .
    2. Release "logstash" does not exist. Installing it now.
    3. NAME: logstash
    4. LAST DEPLOYED: Thu Jun 9 15:02:49 2022
    5. NAMESPACE: logging
    6. STATUS: deployed
    7. REVISION: 1
    8. TEST SUITE: None
    9. NOTES:
    10. 1. Watch all cluster members come up.
    11. $ kubectl get pods --namespace=logging -l app=logstash -w

    安装启动完成后可以查看 logstash 的日志:

    1. $ logstash kubectl get pods --namespace=logging -l app=logstash
    2. NAME READY STATUS RESTARTS AGE
    3. logstash-0 1/1 Running 0 2m8s
    4. $ kubectl logs -f logstash-0 -n logging
    5. ......
    6. {
    7. "@version" => "1",
    8. "stream" => "stdout",
    9. "@timestamp" => 2022-06-09T07:09:16.889Z,
    10. "message" => "4672: Thu Jun 9 07:09:15 UTC 2022",
    11. "kubernetes" => {
    12. "container_image" => "docker.io/library/busybox:latest",
    13. "container_name" => "count",
    14. "labels" => {
    15. "logging" => "true"
    16. },
    17. "pod_name" => "counter",
    18. "namespace_name" => "default",
    19. "pod_ip" => "10.244.2.118",
    20. "host" => "node2",
    21. "namespace_labels" => {
    22. "kubernetes_io/metadata_name" => "default"
    23. }
    24. },
    25. "docker" => {}
    26. }

    由于我们启用了 debug 日志调试,所以我们可以在 logstash 的日志中看到我们采集的日志消息,到这里证明我们的日志数据就获取成功了。

    现在我们可以登录到 Kibana 可以看到有如下所示的索引数据了:

    索引管理

    然后同样创建索引模式,匹配上面的索引即可:

    创建索引模式

    创建完成后就可以前往发现页面过滤日志数据了:

    过滤日志

    到这里我们就实现了一个使用 Fluentd+Kafka+Logstash+Elasticsearch+Kibana 的 Kubernetes 日志收集工具栈,这里我们完整的 Pod 信息如下所示:

    1. $ kubectl get pods -n logging
    2. NAME READY STATUS RESTARTS AGE
    3. elasticsearch-client-0 1/1 Running 0 128m
    4. elasticsearch-data-0 1/1 Running 0 128m
    5. elasticsearch-master-0 1/1 Running 0 128m
    6. fluentd-6k52h 1/1 Running 0 61m
    7. fluentd-cw72c 1/1 Running 0 61m
    8. fluentd-dn4hs 1/1 Running 0 61m
    9. kafka-0 1/1 Running 3 134m
    10. kafka-client 1/1 Running 0 125m
    11. kafka-zookeeper-0 1/1 Running 0 134m
    12. kibana-kibana-66f97964b-qqjgg 1/1 Running 0 128m
    13. logstash-0 1/1 Running 0 13m

    当然在实际的工作项目中还需要我们根据实际的业务场景来进行参数性能调优以及高可用等设置,以达到系统的最优性能。

    上面我们在配置 logstash 的时候是将日志输出到 "logstash-k8s-%{+YYYY.MM.dd}" 这个索引模式的,可能有的场景下只通过日期去区分索引不是很合理,那么我们可以根据自己的需求去修改索引名称,比如可以根据我们的服务名称来进行区分,那么这个服务名称可以怎么来定义呢?可以是 Pod 的名称或者通过 label 标签去指定,比如我们这里去做一个规范,要求需要收集日志的 Pod 除了需要添加 logging: true 这个标签之外,还需要添加一个 logIndex: <索引名> 的标签。

    比如重新更新我们测试的 counter 应用:

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: counter
    5. labels:
    6. logging: 'true' # 一定要具有该标签才会被采集
    7. logIndex: 'test' # 指定索引名称
    8. spec:
    9. containers:
    10. - name: count
    11. image: busybox
    12. args:
    13. [
    14. /bin/sh,
    15. -c,
    16. 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done',
    17. ]

    然后重新更新 logstash 的配置,修改 values 配置:

    1. # ......
    2. logstashPipeline:
    3. logstash.conf: |
    4. input { kafka { bootstrap_servers => "kafka-0.kafka-headless.logging.svc.cluster.local:9092" codec => json consumer_threads => 3 topics => ["messages"] } }
    5. filter {} # 过滤配置(比如可以删除key、添加geoip等等)
    6. output { elasticsearch { hosts => [ "elasticsearch-client:9200" ] user => "elastic" password => "ydzsio321" index => "k8s-%{[kubernetes][labels][logIndex]}-%{+YYYY.MM.dd}" } stdout { codec => rubydebug } }
    7. # ......

    使用上面的 values 值更新 logstash,正常更新后上面的 counter 这个 Pod 日志会输出到一个名为 k8s-test-2022.06.09 的索引去。

    定制索引名称

    这样我们就实现了自定义索引名称,当然你也可以使用 Pod 名称、容器名称、命名空间名称来作为索引的名称,这完全取决于你自己的需求。

  • 相关阅读:
    华为CSS堆叠技术介绍与实现
    Maven(项目构建管理工具)
    【进阶C语言】编译与链接、预处理符号详解
    2022年前端面试题整理,持续更新中
    C++ 构造函数
    apk组成和Android的打包流程
    51单片机多机通信
    折叠式菜单怎么做编程,初学编程系统化教程初级1上线
    springboot 3.x 之 集成rabbitmq实现动态发送消息给不同的队列
    cf #818 Div.2(A~C)
  • 原文地址:https://blog.csdn.net/Franklin7B/article/details/133442546