ELK:收集k8s容器日志最佳实践

简介


  • 关于日志收集这个主题,这已经是第三篇了,为什么一再研究这个课题,因为这个课题实在太重要,而当今优秀的开源解决方案还不是很明朗;

  • 就docker微服务化而言,研发有需求标准输出,也有需求文件输出,每次登录到服务器上去查看日志又多有不妥;现有的解决方案ELK,每次收集新应用日志都要更改配置文件重新适配日志路径足以让我们崩溃;

  • 对于k8s,没有日志系统推行工作就无法进行,总不能让开发小伙伴登录到k8s上去找日志吧,鬼知道在哪个pod里;当然,k8s官方提供了解决方案efk,efk最大的问题就是无法对日志有效分组,所有日志都在一个索引里,影响查询速度不说,对于研发小伙伴查找属于自己应用的日志也很困难,不得不说,这个解决方案很鸡肋;

  • 综上三条,能够统筹普通应用、docker微服务、k8s的日志收集方案迫在眉睫,今天就将能解决这些问题的日志收集方案的最佳实践分享给大家;

  • 该实践采用的是阿里云的开源工具 log-pilot 采集日志,采集的过程中就将各种日志打标分类,类似最近比较火的垃圾分类,逻辑结构图如下:
    img-w500

  • 三种节点类型:

    • k8s使用daemonset类型的副本集,使每个节点运行一个 log-pilot 来收集日志,该日志会含有 k8s_container_name、k8s_pod、k8s_node_name、 k8s_pod_namespace 等打标数据,输出到相应的 logstash 来做索引
    • 运行docker微服务的主机上运行一个 log-pilot 来收集日志,该日志会含有 docker_container、topic、index 等打标数据,输出到相应的 logstash 来做索引
    • 普通非容器程序的日志可以采用 filebeat 收集,日志中可以自定义标签和字段,输出到对应的 logstash 来做索引

log-pilot 说明和配置


  • 容器日志采集模式现在流行的方式有 SideCar模式和 Node模式,SideCar模式会占用大量资源,而Node模式需要智能的 logging agent 配合,而 log-pilot 就是那个智能的agent
  • log-pilot 可同时支持stdout和容器内文件日志采集,支持声明式日志配置,同时拥有自动感知(发现)机制、自动checkpoint及具柄保持机制和自动日志数据打标
  • log-pilot 除拥有上述功能,还支持多插件多后端,低消耗,高性能,具体情况请看 K8S 日志实践

log-pilot 插件支持

img-w500

log-pilot 工作模式

img-w500

log-pilot 配置方法

  • Kubernetes 下,Log-Pilot 可以依据环境变量 aliyun_logs_$name = $path 动态地生成日志采集配置文件,其中包含两个变量:
    • $name 是我们自定义的一个字符串,它在不同的场景下指代不同的含义,在本场景中,将日志采集到 ElasticSearch 的时候,这个 $name 表示的是 Index
    • 另一个是 $path,支持两种输入形式,stdout 和容器内部日志文件的路径,对应日志标准输出和容器内的日志文件。
    • 第一种约定关键字 stdout 表示的是采集容器的标准输出日志,如本例中我们要采集 tomcat 容器日志,那么我们通过配置标签 aliyun.logs.catalina=stdout 来采集 tomcat 标准输出日志。
    • 第二种是容器内部日志文件的路径,也支持通配符的方式,通过配置环境变量 aliyun_logs_access=/usr/local/tomcat/logs/*.log 来采集 tomcat 容器内部的日志。当然如果你不想使用 aliyun 这个关键字,Log-Pilot 也提供了环境变量 PILOT_LOG_PREFIX 可以指定自己的声明式日志配置前缀,比如 PILOT_LOG_PREFIX: "aliyun,custom"
  • 此外,Log-Pilot 还支持多种日志解析格式,通过 aliyun_logs_$name_format=<format> 标签就可以告诉 Log-Pilot 在采集日志的时候,同时以什么样的格式来解析日志记录,支持的格式包括:none、json、csv、nginx、apache2regxp
  • Log-Pilot 同时支持自定义 tag,我们可以在环境变量里配置 aliyun_logs_$name_tags="K1=V1,K2=V2",那么在采集日志的时候也会将 K1=V1K2=V2 采集到容器的日志输出中。自定义 tag 可帮助您给日志产生的环境打上 tag,方便进行日志统计、日志路由和日志过滤。

log-pilot 在k8s上的配置

cat > ops-log-pilot-filebeat-ds.yaml << EOF
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: ops-log-pilot-filebeat-ds
  namespace: ops
spec:
  selector:
    matchLabels:
      app: log-pilot-filebeat
      release: stable
  template:
    metadata:
      labels:
        app: log-pilot-filebeat
        release: stable
    spec:
      containers:
      - name: log-pilot-filebeat
        image: registry.cn-hangzhou.aliyuncs.com/acs/log-pilot:0.9.6-filebeat
        env:
        - name: "NODE_NAME"
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: "PILOT_LOG_PREFIX"
          value: "glinux"
        - name: "LOGGING_OUTPUT"
          value: "logstash"
        # 请确保集群到ES网络可达
        - name: "LOGSTASH_HOST"
          value: "logstash.glinux.top"
        - name: "LOGSTASH_PORT"
          value: "5053"
        volumeMounts:
        - name: sock
          mountPath: /var/run/docker.sock
        - name: root
          mountPath: /host
          readOnly: true
        - name: varlib
          mountPath: /var/lib/filebeat
        - name: varlog
          mountPath: /var/log/filebeat
        - name: localtime
          mountPath: /etc/localtime
          readOnly: true
        livenessProbe:
          failureThreshold: 3
          exec:
            command:
            - /pilot/healthz
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 2
        securityContext:
          capabilities:
            add:
            - SYS_ADMIN
      volumes:
      - name: sock
        hostPath:
          path: /var/run/docker.sock
      - name: root
        hostPath:
          path: /
      - name: varlib
        hostPath:
          path: /var/lib/filebeat
          type: DirectoryOrCreate
      - name: varlog
        hostPath:
          path: /var/log/filebeat
          type: DirectoryOrCreate
      - name: localtime
        hostPath:
          path: /etc/localtime
EOF
# 调用方法
kubectl apply -f ops-log-pilot-filebeat-ds.yaml

log-pilot 在docker主机上配置

docker run -d \
   --name log-pilot-filebeat \
   -v /var/run/docker.sock:/var/run/docker.sock \
   -v /etc/localtime:/etc/localtime \
   -v /:/host:ro \
   --cap-add SYS_ADMIN \
   -e PILOT_LOG_PREFIX=glinux \
   -e LOGGING_OUTPUT=logstash \
   -e LOGSTASH_HOST=logstash..glinux.top \
   -e LOGSTASH_PORT=5063 \
   --restart=always \
   registry.cn-hangzhou.aliyuncs.com/acs/log-pilot:0.9.5-filebeat

logstash 配置方法


  • logstash的三个实例,我是运行在同一台机器上,同时kibana也是运行在这台机器上
  • 当然也可以通过一个logstash实例,配置中采用判断条件建立不同索引,但会影响性能,所以这里我起了三个实例
  • logstash的主要功能是将收集到的日志进行拆分,采用某些字段建成索引,传递给 elasticsearch 集群
  • 这里强烈建议使用阿里云的 elasticsearch 集群,可以先使用免费版 1核2G内存20G SSD 三组,原因是阿里云和elastic有合作,es有授权,很多功能可以使用,比如用户管理,监控等,后面会说到

logstash 处理k8s日志

  • logstash 监控配置文件,监控信息会体现在kibana中
cat > /data/logslogstash.yml << EOF
xpack.monitoring.elasticsearch.url: http://xxxxxxxxxxxxxxxx.es.aliyuncs.com:9200
xpack.monitoring.elasticsearch.username: "user"
xpack.monitoring.elasticsearch.password: "pass"
EOF

配置文件

cat > /data/conf/logstash-k8s.conf << EOF
input {
  beats {
    host => "0.0.0.0"
    port => "5043"
  }
}
filter {
  grok {
    match => { "message" => "%{TIMESTAMP_ISO8601:log-timestamp} %{LOGLEVEL:log-level} %{JAVALOGMESSAGE:log-msg}" }
  }
  mutate {
#    remove_field => ["message"]
    remove_field => ["beat"]
   }
}
output {
  stdout { codec => rubydebug }
  elasticsearch {
        hosts => ["http://xxxxxxxxxxxxxxxx.es.aliyuncs.com:9200"]
        user => ["user"]
        password => ["pass"]
        index => "%{k8s_container_name}-%{+YYYY.MM.dd}"
  }
}
EOF

启动命令

docker run -p 5053:5043 -d \
    --user root \
    --log-driver json-file \
    --log-opt max-size=10m \
    --log-opt max-file=3 \
    --name logstash-k8s \
    --restart=always \
    -v /data/conf/logstash-k8s.conf:/usr/share/logstash/pipeline/logstash.conf \
    -v /data/conf/logstash.yml:/usr/share/logstash/config/logstash.yml \
    logstash:6.6.2

logstash 处理docker日志

配置文件

cat > /data/conf/logstash-docker.conf << EOF
input {
  beats {
    host => "0.0.0.0"
    port => "5043"
  }
}
filter {
  grok {
    match => { "message" => "%{TIMESTAMP_ISO8601:log-timestamp} %{LOGLEVEL:log-level} %{JAVALOGMESSAGE:log-msg}" }
  }
  mutate {
#    remove_field => ["message"]
    remove_field => ["beat"]
   }
}
output {
  stdout { codec => rubydebug }
  elasticsearch {
        hosts => ["xxxxxxxxxxxxxxxx.es.aliyuncs.com:9200"]
        user => ["uesr"]
        password => ["pass"]
        index => "%{docker_container}-%{+YYYY.MM.dd}"
  }
}
EOF

启动命令

docker run -p 5063:5043 -d \
    --user root \
    --log-driver json-file \
    --log-opt max-size=10m \
    --log-opt max-file=3 \
    --name logstash-docker \
    --restart=always \
    -v /data/conf/logstash-docker.conf:/usr/share/logstash/pipeline/logstash.conf \
    -v /data/conf/logstash.yml:/usr/share/logstash/config/logstash.yml \
    logstash:6.6.2

elasticsearch 说明


  • 如上所述,elasticsearch 使用阿里云的产品 阿里云 · Elasticsearch
  • 可以先使用免费版 1核2G内存20G SSD 三组
  • 开通后会有 地址、用户名、密码等信息,这些是要填写在logstash的输出配置文件中
  • 阿里云和elastic有合作,es有授权,用户管理、用户登录、索引监控、节点监控、logstash监控等功能均可正常使用
  • 除以上外,定期清理es的索引也很有必要,可以参考我之前的博客 ELK:收集Docker容器日志 中 定时删除过期日志索引文件 章节
  • 使用阿里云的es后,kibana上会有授权体现,这里贴两张图展示一下功能

kibana 的监控

img-w500

kibana 的管理

img-w500

kibana 说明和配置


  • 下面步骤操作完毕启动后,此处访问 http://IP:5603,用户名和密码同 elasticserach 的,输入即可登录kibana,如此建立索引,就可以正常的玩耍了

kibana 配置文件

  • 如下的配置文件会屏蔽掉许多没用的插件功能模块,如上图显示的清爽界面
cat > /data/conf/kibana-es-aliyun.yml << EOF
# Default Kibana configuration from kibana-docker.
server.name: kibana
server.host: "0"
elasticsearch.hosts: http://xxxxxx.es.aliyuncs.com:9200
elasticsearch.username: user
elasticsearch.password: pass
xpack.monitoring.ui.container.elasticsearch.enabled: true
timelion.enabled: false
console.enabled: false
xpack.grokdebugger.enabled: false
xpack.searchprofiler.enabled: false
xpack.canvas.enabled: false
xpack.ml.enabled: false
xpack.infra.enabled: false
xpack.apm.enabled: false
xpack.graph.enabled: false
EOF

kibana 启动命令

docker run -p 5603:5601 -d \
    --user root \
    --log-driver json-file \
    --log-opt max-size=10m \
    --log-opt max-file=3 \
    --name kibana-es-aliyun \
    --restart=always \
    -e ELASTICSEARCH_URL=http://xxxxxx.es.aliyuncs.com:9200 \
    kibana:6.6.2
  • 下面来看下优秀的登录界面
    img-w500

日志收集效果验证


docker日志收集案例 tomcat

  • 注意 label 的配置
   docker run -it -d --name tomcat -p 10080:8080 \
    -v /var/logs/:/usr/local/tomcat/logs \
    --label glinux.logs.catalina=stdout \
    --label glinux.logs.access=/usr/local/tomcat/logs/localhost_access_log.*.txt \
    tomcat
  • 日志收集效果如下图:
    img-w500

k8s日志收集案例 tomcat

  • 注意env的配置
cat > tomcat-pod.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
  name: tomcat
spec:
  containers:
  - name: tomcat
    image: "tomcat:7.0"
    env:
# 1、stdout为约定关键字,表示采集标准输出日志
# 2、配置标准输出日志采集到ES的catalina索引下
    - name: glinux_logs_catalina
      value: "stdout"
# 1、配置采集容器内文件日志,支持通配符
# 2、配置该日志采集到ES的access索引下
    - name: glinux_logs_access
      value: "/usr/local/tomcat/logs/catalina.*.log"
# 容器内文件日志路径需要配置emptyDir
    volumeMounts:
    - name: tomcat-log
      mountPath: /usr/local/tomcat/logs
  volumes:
  - name: tomcat-log
    emptyDir: {}
EOF
# 调用
kubectl apply -f tomcat-pod.yaml -n ops
  • 日志收集效果如下图:
    img-w500

参考文档


posted @ 2019-07-06 00:39  Williams_Guozi  阅读(15931)  评论(20编辑  收藏  举报
本站总访问量 本站总访客量人次 本博客总访问量