全栈监控的软件
商业的监控软件:阿里云  ARMS  
全球做监控最好的公司:Datadog  SAAS    all-in-one  agent(将复杂性整合,直接安装就可以全部监控),收费贵,不做国内市场。

日志统一采集

ELK
Logstash             Elasticsearch       Kibana
采集端                 存储端               展示端
EFK
Filebeat             Elasticsearch       Kibana
Fluentd

Logstash + Filebeat 联合使用,实现集群内日志拆分方便检索;在k8s中 Filebeat 使用 DaemonSet 部署,Logstash 使用 Deployment 部署。
Fluentd 和 Loki 适合k8s内使用
部署 EFK

1、传统架构 rpm 日志输出文件

cd efk-rpm/
rpm -ivh elasticsearch-7.17.16-x86_64.rpm	#自己带了JDK
cd /etc/elasticsearch/
vim elasticsearch.yml	#注意前面不能有空格
----------------------- Cluster -------------------------
cluster.name: cluster-01	# 打开注释并修改
------------------------ Node ---------------------------
node.name: node-1
------------------------ Paths --------------------------
path.data: /data/elasticsearch
----------------------- Network -------------------------
network.host: 0.0.0.0
http.port: 9200
---------------------- Discovery ------------------------
discovery.seed_hosts: ["192.168.118.132"]		#这里用主机名或者IP
cluster.initial_master_nodes: ["192.168.118.132"]

chown -R elasticsearch:elasticsearch elasticsearch
id elasticsearch

vim jvm.options
-Xms2g	#分的最小内存
-Xmx2g	#分的最大内存

systemctl start elasticsearch.service
netstat -lnpt

检查集群状态

# 列出节点健康状态
curl -XGET 127.0.0.1:9200/_cat/health?v
# 显示cluster状态
curl -XGET 127.0.0.1:9200/_cluster/health\?pretty
# 列出 master节点
curl -XGET 127.0.0.1:9200/_cat/master?v
# 列出节点及利用率
curl -XGET 127.0.0.1:9200/_cat/nodes?v
# 显示索引 
curl localhost:9200/_cat/indices?v

安装前端

rpm -ivh kibana-7.17.16-x86_64.rpm	#展示用的
cd /etc/kibana/
vim kibana.yml
server.port: 5601
server.host: "0.0.0.0"
elasticsearch.hosts: ["http://192.168.118.132:9200"]	#若是有多个,可以加逗号隔开["",""]这样的

systemctl start kibana.service	# 监听5601
ps -ef | grep node
http://192.168.118.132:5601/ 
INPUT  输入   日志来自文件
filestream   日志文件
container    容器中日志

OUTPUT   
Elasticsearch

rpm -ivh filebeat-7.17.15-x86_64.rpm
cd /etc/filebeat/
vim filebeat.yml
...
enabled: true
- /var/log/message*			# 添加需要收集的日志,日志有变化就会把新的日志采集上来
- /var/log/elasticsearch/*
...
output.elasticsearch:
  # Array of hosts to connect to.
  hosts: ["192.168.118.132:9200"]

systemctl start filebeat.service

索引  index   
索引是 Elasticsearch 中用于存储和管理相关数据的逻辑容器。索引可以看作数据库中的一个表,它包含了一组具有相似结构的文档
分片  shard	# 可以做高可用
分片包含索引数据的一个子集,并且其本身具有完整的功能和独立性,可以将分片近似看作“独立索引“,分片是Elasticsearch 分布式存储的基石,是底层的基本读写单元。
Harvester	收割日志
Index  索引  建议按天创建索引

2. Kubernetes 架构下如何采集日志,应用在容器中、Pod 中
应用被放到 Pod 中如何输出日志,不建议日志输出时生成为文件,建议应用日志直接输出为 stdout
以下为容器运行时真正存放日志目录:
- container log: /var/log/containers/*.log
- Pod log:/var/log/pods

使用边车容器运行日志代理 sidecar	# 容器可以挂一些容器,这些容器是做辅助功能的,这种容器就叫做边车容器

从应用中直接暴露日志目录

使用节点级日志代理(建议)

cd 20-log/elk/elasticsearch/

# 添加镜像
helm repo add elastic https://helm.elastic.co
# 使用7.17.3版本
helm pull elastic/elasticsearch --version=7.17.3

helm upgrade --install els -n logging -f elasticsearch/els-values.yaml  ./elasticsearch --create-namespace --namespace logging

# 部署kibana 
helm search repo  elastic/kibana -l
helm -n logging upgrade --install  kibana -f kibana/kibana-values.yaml  ./kibana
# 验证
curl 10.109.192.69:9200/_cluster/health\?pretty

# 部署filebeat 
helm -n logging install filebeat  -f filebeat/filebeat-values-1.yaml  ./filebeat

# 可以去访问网站了
192.168.118.18:31523	# 这个端口号是随机的,记得查看svc

# 配置是在filebeat中定义的
vim filebeat-values-2.yaml

helm -n logging upgrade filebeat -f filebeat/filebeat-values-2.yaml filebeat

日志方案之Loki

Log-agent (采集器)   Alloy 或 Promtail #Alloy是新出的,推荐使用这个
	Log-agent 是 Loki 日志代理(agent)的重要组件。它的功能是从系统中收集每个日志,标记它,然后将其发送给 Loki。

Distributor (分发器) 
	Distributor 是一个无状态组件,负责处理和验证从日志代理(如 Promtail)接收的日志,并将日志分发到 ingester。
	当 Distributor 收到日志时,它首先验证日志是否符合配置,例如有效标签、不是较旧的时间戳以及日志是否太长。验证完成后,Distributor 会根据一致性哈希将日志分发到每个 ingester,以确保平均分配给每个可用的 ingester。

Ingester (接收器)
	Ingester 负责在其文件系统上存储和索引从 Distributor 收到的日志,并定期将日志传输到持久性存储(长期存储),如 S3。
Ingester 根据配置设置保留策略(自动日志删除时间)。
	它使用时间序列数据库以一定的结构格式存储日志,这简化了高效查询和日志过期的过程。

Ruler (规则器)
	Ruler 是 Loki 的监控和告警组件,其作用是记录指标并根据收到的日志数据触发告警。它不是直接衡量指标,而是将日志数据转换为指标。
	Ruler 监控日志并在检测到任何问题时发出通知,并通过电子邮件或 Slack 发送通知。

Querier  (查询器)
	Querier 负责使用 LogQL 查询语言从存储和 ingester 中查询日志。它根据用户查询(如时间戳、标签等)过滤和聚合日志。
	查询器缓存之前的查询,以防止一次又一次地查询相同的日志,它只查询一次具有相同时间戳、标签和日志消息的日志。

Query Frontend (查询前端) 
	Query Frontend 是一个与用户交互的无状态组件,它负责处理查询请求、执行查询以及通过 Grafana 仪表板可视化日志。
	Query Frontend 将大型查询拆分为多个较小的查询,并同时运行所有查询,这可以防止大型查询在单个查询中导致内存问题,并有助于加快执行速度。

Grafana (前端展示)
	Grafana 是一个开源工具,可帮助查询、可视化和监控日志。我们可以将 Loki 与 Grafana 集成,并在仪表板、图表等方式可视化日志数据。
	Grafana 使用查询语言 LogQL 与 Grafana 集成,我们也可以在 Grafana 中编写 LogQL 查询来过滤和查询日志。

Log Storage (后端存储)
	Loki 存储日志数据,提高查询和接收日志的效率。将日志数据压缩成块,根据时间进行组织,并为其提供标签和时间戳。然后,它以键值对格式为每个块创建一个索引,包含块时间戳和标签等。
例如,将块的索引视为一本书的索引。
	Chunks 和 Index 可以存储在各种后端对象存储或文件系统中。
一旦存储了块,它就会为数据创建一个保留期,并根据保留期自动删除。
如果使用文件系统作为存储,则块和索引的默认存储路径是 /var/lib/loki/chunks 和 /var/lib/loki/index。

部署案例:

- Flog: 日志生成器,模拟应用程序产生日志。 
- Alloy:日志代理,用来抓取日志并把日志发给Loki,类似 filebeat 的角色。 
- Gateway: 接收请求并根据请求的URL 转发给后端应用。 
- Loki read component:  运行  Query Frontend 和 Querier。 
- Loki write component:  运行 Distributor 和 Ingester。
- Loki backend component:   Index Gateway、Compactor 和 Ruler。
- Minio: 存储日志  index and chunks	#开源的对象存储,内网部署优选
- Grafana: 展示和搜索日志

vim docker-compose.yaml
---
networks:
  loki:

services:
  read:
    image: grafana/loki:3.5
    command: "-config.file=/etc/loki/config.yaml -target=read"
    ports:
      - 3101:3100
      - 7946
      - 9095
    volumes:
      - ./loki-config.yaml:/etc/loki/config.yaml
    depends_on:
      - minio
    healthcheck:
      test: [ "CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3100/ready || exit 1" ]
      interval: 10s
      timeout: 5s
      retries: 5
    networks: &loki-dns
      loki:
        aliases:
          - loki

  write:
    image: grafana/loki:3.5
    command: "-config.file=/etc/loki/config.yaml -target=write"
    ports:
      - 3102:3100
      - 7946
      - 9095
    volumes:
      - ./loki-config.yaml:/etc/loki/config.yaml
    healthcheck:
      test: [ "CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3100/ready || exit 1" ]
      interval: 10s
      timeout: 5s
      retries: 5
    depends_on:
      - minio
    networks:
      <<: *loki-dns

  alloy:
    image: grafana/alloy:v1.8.2
    volumes:
      - ./alloy-local-config.yaml:/etc/alloy/config.alloy:ro
      - /var/run/docker.sock:/var/run/docker.sock
    command:  run --server.http.listen-addr=0.0.0.0:12345 --storage.path=/var/lib/alloy/data /etc/alloy/config.alloy
    ports:
      - 12345:12345
    depends_on:
      - gateway
    networks:
      - loki

  minio:
    image: minio/minio:RELEASE.2025-04-08T15-41-24Z
    entrypoint:
      - sh
      - -euc
      - |
        mkdir -p /data/loki-data && \
        mkdir -p /data/loki-ruler && \
        minio server /data
    environment:
      - MINIO_ROOT_USER=loki
      - MINIO_ROOT_PASSWORD=supersecret
      - MINIO_PROMETHEUS_AUTH_TYPE=public
      - MINIO_UPDATE=off
    ports:
      - 9000
    volumes:
      - ./.data/minio:/data
    healthcheck:
      test: [ "CMD", "curl", "-f", "http://localhost:9000/minio/health/live" ]
      interval: 15s
      timeout: 20s
      retries: 5
    networks:
      - loki

  grafana:
    image: grafana/grafana:11.4.4
    environment:
      - GF_PATHS_PROVISIONING=/etc/grafana/provisioning
      - GF_AUTH_ANONYMOUS_ENABLED=true
      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
    depends_on:
      - gateway
    entrypoint:
      - sh
      - -euc
      - |
        mkdir -p /etc/grafana/provisioning/datasources
        cat <<EOF > /etc/grafana/provisioning/datasources/ds.yaml
        apiVersion: 1
        datasources:
          - name: Loki
            type: loki
            access: proxy
            url: http://gateway:3100
            jsonData:
              httpHeaderName1: "X-Scope-OrgID"
            secureJsonData:
              httpHeaderValue1: "tenant1"
        EOF
        /run.sh
    ports:
      - "3000:3000"
    healthcheck:
      test: [ "CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1" ]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - loki

  backend:
    image: grafana/loki:3.5
    volumes:
      - ./loki-config.yaml:/etc/loki/config.yaml
    ports:
      - "3100"
      - "7946"
    command: "-config.file=/etc/loki/config.yaml -target=backend -legacy-read-mode=false"
    depends_on:
      - gateway
    networks:
      - loki 

  gateway:
    image: nginx:1.27.5
    depends_on:
      - read
      - write
    entrypoint:
      - sh
      - -euc
      - |
        cat <<EOF > /etc/nginx/nginx.conf
        user  nginx;
        worker_processes  5;  ## Default: 1

        events {
          worker_connections   1000;
        }

        http {
          resolver 127.0.0.11;

          server {
            listen             3100;

            location = / {
              return 200 'OK';
              auth_basic off;
            }

            location = /api/prom/push {
              proxy_pass       http://write:3100\$$request_uri;	#发给写的Loki
            }

            location = /api/prom/tail {
              proxy_pass       http://read:3100\$$request_uri;		#发给读的Loki
              proxy_set_header Upgrade \$$http_upgrade;
              proxy_set_header Connection "upgrade";
            }

            location ~ /api/prom/.* {
              proxy_pass       http://read:3100\$$request_uri;
            }

            location = /loki/api/v1/push {
              proxy_pass       http://write:3100\$$request_uri;
            }

            location = /loki/api/v1/tail {
              proxy_pass       http://read:3100\$$request_uri;
              proxy_set_header Upgrade \$$http_upgrade;
              proxy_set_header Connection "upgrade";
            }

            location ~ /loki/api/.* {
              proxy_pass       http://read:3100\$$request_uri;
            }
          }
        }
        EOF
        /docker-entrypoint.sh nginx -g "daemon off;"
    ports:
      - "3100:3100"
    healthcheck:
      test: ["CMD", "service", "nginx", "status"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - loki

  flog:
    image: mingrammer/flog:0.4.3
    command: -f json -d 200ms -l
    networks:
      - loki

# 然后就可以通过ip:3000访问grafana了
侧导航栏选择Explore ——> Loki
用logQL语法查日志
例如:
查询容器 loki-flog-1 产生的所有日志  {container="loki-flog-1"} 
查询包含 status 的日志行  {container="loki-flog-1"} |= `status`
查询 status=404 的日志行   {container="loki-flog-1"} | json | status=`404`   

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐