日志之Loki详细讲解
文章目录
- 1 Loki
- 1.1 引言
- 1.2 Loki工作方式
- 1.2.1 日志解析格式
- 1.2.2 日志搜集架构模式
- 1.2.3 Loki部署模式
- 1.3 服务端部署
- 1.3.1 AllInOne部署模式
- 1.3.1.1 k8s部署
- 1.3.1.2 创建configmap
- 1.3.1.3 创建持久化存储
- 1.3.1.4 创建应用
- 1.3.1.5 验证部署结果
- 1.3.2 裸机部署
- 1.4 Promtail部署
- 1.4.1 k8s部署
- 1.4.1.1 创建配置文件
- 1.4.1.2 创建DaemonSet文件
- 1.4.1.3 创建promtail应用
- 1.4.2 裸机部署
- 1.5 数据源
- 1.6 其他客户端配置
- 1.6.1 Logstash作为日志收集客户端
- 1.7 Helm安装
- 1.8 故障解决方案
- 1.8.1 502 BadGateWay
- 1.8.2 Ingester not ready: instance xx:9095 in state JOINING
- 1.8.3 too many unhealthy instances in the ring
- 1.8.4 Data source connected
1 Loki
1.1 引言
Loki
是一个轻量级的日志收集、分析的应用,采用的是promtail
的方式来获取日志内容并送到loki里面进行存储,最终在grafana
的datasource
里面添加数据源进行日志的展示、查询。
官方文档:https://kubernetes.io/docs/concepts/security/pod-security-policy
loki
的持久化存储支持azure、gcs、s3、swift、local
这5中类型,其中常用的是s3、local
。另外,它还支持很多种日志搜集类型,像最常用的logstash、fluentbit
也在官方支持的列表中。
优点:
- 支持的客户端,如
Promtail,Fluentbit,Fluentd,Vector,Logstash和Grafana Agent
- 首选代理
Promtail
,可以多来源提取日志,包括本地日志文件,systemd,Windows
事件日志,Docker
日志记录驱动程序等 - 没有日志格式要求,包括
JSON,XML,CSV,logfmt
,非结构化文本 - 使用与查询指标相同的语法查询日志
- 日志查询时允许动态筛选和转换日志行
- 可以轻松地计算日志中的需要的指标
- 引入时的最小索引意味着您可以在查询时动态地对日志进行切片和切块,以便在出现新问题时回答它们
- 云原生支持,使用
Prometheus
形式抓取数据
各日志收集组件简单对比
名称 | 安装的组件 | 优点 |
---|---|---|
ELK/EFK | elasticsearch、logstash, kibana、filebeat、kafka/redis | 支持自定义grok正则解析复杂日志内容;dashboard支持主富的可视化展示 |
Loki | grafana、loki、promtail | 占用资源小;grafana原生支持;查询速度快 |
1.2 Loki工作方式
1.2.1 日志解析格式
从上面的图中我们可以看到,它在解析日志的时候是以index
为主的,index
包括时间戳和pod
的部分label
(其他label
为filename
、containers
等),其余的是日志内容。具体查询效果如下:
{app="loki",namespace="kube-public"}
为索引
1.2.2 日志搜集架构模式
在使用过程中,官方推荐使用promtail
做为agent
以DaemonSet
方式部署在kubernetes
的worker
节点上搜集日志。另外也可以用上面提到的其他日志收集工具来收取,这篇文章在结尾处会附上其他工具的配置方式。
1.2.3 Loki部署模式
Loki
由许多组件微服务构建而成,微服务组件有5个。在这5个里面添加缓存用来把数据放起来加快查询。数据放在共享存储里面配置memberlist_config
部分并在实例之间共享状态,将Loki
进行无限横向扩展。
在配置完memberlist_config
部分后采用轮询的方式查找数据。为了使用方便官方把所有的微服务编译成一个二进制,可以通过命令行参数-target
控制,支持all、read、write
,我们在部署时根据日志量的大小可以指定不同模式
all
(读写模式)
服务启动后,我们做的数据查询、数据写入都是来自这一个节点
read/write
(读写分离模式)
在读写分离模式下运行时fronted-query
查询会将流量转发到read
节点上。读节点上保留了querier、ruler、fronted
,写节点上保留了distributor、ingester
- 微服务模式运行
微服务模式运行下,通过不同的配置参数启动为不同的角色,每一个进程都引用它的目标角色服务。
组件名称 | 功能 |
---|---|
分发器/调度器(distributor) | 验证数据合规:数据排序; hash一致性, QPS限制, 转发,数据副本保证不丢失 |
收集器(ingester) | 时间戳排序: 文件系统支持: WAL预写 |
查询前端 (query frontend) | 提供页面操作,向后端存储发出数据查询;查询队列 (query-queueing) 能够防止大数据量查询时触发0OM;查询分割 (query-split) 可以分割大批量查询最后进行数据聚台 |
查询器Querier | 使用loggl语言在后端存储中查询日志 |
缓存 | 将查询到的日志缓存起来共后续使用,如果数据不完整重新查询缺失的数据 |
1.3 服务端部署
在部署之前需要准备好一个k8s集群才行哦
应用 | 镜像 |
---|---|
loki | grafana/loki:2.5.0 |
promtail | grafana/promtail:2.5.0 |
1.3.1 AllInOne部署模式
1.3.1.1 k8s部署
我们从github上下载的程序是没有配置文件的,需要提前将文件准备一份。这里提供了一份完整的allInOne
配置文件,部分内容进行了优化。
配置文件内容如下所示
auth_enabled: false
target: all
ballast_bytes: 20480
server:grpc_listen_port: 9095http_listen_port: 3100graceful_shutdown_timeout: 20sgrpc_listen_address: "0.0.0.0"grpc_listen_network: "tcp"grpc_server_max_concurrent_streams: 100grpc_server_max_recv_msg_size: 4194304grpc_server_max_send_msg_size: 4194304http_server_idle_timeout: 2mhttp_listen_address: "0.0.0.0"http_listen_network: "tcp"http_server_read_timeout: 30shttp_server_write_timeout: 20slog_source_ips_enabled: true# http_path_prefix如果需要更改,在推送日志的时候前缀都需要加指定的内容# http_path_prefix: "/"register_instrumentation: truelog_format: jsonlog_level: info
distributor:ring:heartbeat_timeout: 3skvstore:prefix: collectors/store: memberlist# 需要提前创建好consul集群# consul:# http_client_timeout: 20s# consistent_reads: true# host: 127.0.0.1:8500# watch_burst_size: 2# watch_rate_limit: 2
querier:engine:max_look_back_period: 20s timeout: 3m0s extra_query_delay: 100ms max_concurrent: 10 multi_tenant_queries_enabled: truequery_ingester_only: falsequery_ingesters_within: 3h0m0squery_store_only: falsequery_timeout: 5m0stail_max_duration: 1h0s
query_scheduler:max_outstanding_requests_per_tenant: 2048grpc_client_config:max_recv_msg_size: 104857600max_send_msg_size: 16777216grpc_compression: gziprate_limit: 0rate_limit_burst: 0backoff_on_ratelimits: falsebackoff_config:min_period: 50msmax_period: 15smax_retries: 5 use_scheduler_ring: truescheduler_ring:kvstore:store: memberlistprefix: "collectors/"heartbeat_period: 30sheartbeat_timeout: 1m0s# 默认第一个网卡的名称# instance_interface_names# instance_addr: 127.0.0.1# 默认server.grpc-listen-portinstance_port: 9095
frontend:max_outstanding_per_tenant: 4096querier_forget_delay: 1h0scompress_responses: truelog_queries_longer_than: 2m0smax_body_size: 104857600query_stats_enabled: truescheduler_dns_lookup_period: 10s scheduler_worker_concurrency: 15
query_range:align_queries_with_step: truecache_results: trueparallelise_shardable_queries: truemax_retries: 3results_cache:cache:enable_fifocache: falsedefault_validity: 30s background:writeback_buffer: 10000redis:endpoint: 127.0.0.1:6379timeout: 1sexpiration: 0s db: 9pool_size: 128 password: 1521Qyx6^tls_enabled: falsetls_insecure_skip_verify: trueidle_timeout: 10s max_connection_age: 8h
ruler:enable_api: trueenable_sharding: truealertmanager_refresh_interval: 1mdisable_rule_group_label: falseevaluation_interval: 1m0sflush_period: 3m0sfor_grace_period: 20m0sfor_outage_tolerance: 1h0snotification_queue_capacity: 10000notification_timeout: 4spoll_interval: 10m0squery_stats_enabled: trueremote_write:config_refresh_period: 10senabled: falseresend_delay: 2m0srule_path: /rulerssearch_pending_for: 5m0sstorage:local:directory: /data/loki/rulerstype: configdbsharding_strategy: defaultwal_cleaner:period: 240hmin_age: 12h0m0swal:dir: /data/loki/ruler_walmax_age: 4h0m0smin_age: 5m0struncate_frequency: 1h0m0sring:kvstore:store: memberlistprefix: "collectors/"heartbeat_period: 5sheartbeat_timeout: 1m0s# instance_addr: "127.0.0.1"# instance_id: "miyamoto.en0"# instance_interface_names: ["en0","lo0"]instance_port: 9500num_tokens: 100
ingester_client:pool_config:health_check_ingesters: falseclient_cleanup_period: 10s remote_timeout: 3sremote_timeout: 5s
ingester:autoforget_unhealthy: truechunk_encoding: gzipchunk_target_size: 1572864max_transfer_retries: 0sync_min_utilization: 3.5sync_period: 20sflush_check_period: 30s flush_op_timeout: 10m0schunk_retain_period: 1m30schunk_block_size: 262144chunk_idle_period: 1h0smax_returned_stream_errors: 20concurrent_flushes: 3index_shards: 32max_chunk_age: 2h0m0squery_store_max_look_back_period: 3h30m30swal:enabled: truedir: /data/loki/wal flush_on_shutdown: truecheckpoint_duration: 15mreplay_memory_ceiling: 2GBlifecycler:ring:kvstore:store: memberlistprefix: "collectors/"heartbeat_timeout: 30s replication_factor: 1num_tokens: 128heartbeat_period: 5s join_after: 5s observe_period: 1m0s# interface_names: ["en0","lo0"]final_sleep: 10s min_ready_duration: 15s
storage_config:boltdb:directory: /data/loki/boltdb boltdb_shipper:active_index_directory: /data/loki/active_indexbuild_per_tenant_index: truecache_location: /data/loki/cache cache_ttl: 48hresync_interval: 5mquery_ready_num_days: 5index_gateway_client:grpc_client_config:filesystem:directory: /data/loki/chunks
chunk_store_config:chunk_cache_config:enable_fifocache: truedefault_validity: 30sbackground:writeback_buffer: 10000redis:endpoint: 192.168.3.56:6379timeout: 1sexpiration: 0s db: 8 pool_size: 128 password: 1521Qyx6^tls_enabled: falsetls_insecure_skip_verify: trueidle_timeout: 10s max_connection_age: 8hfifocache:ttl: 1hvalidity: 30m0smax_size_items: 2000max_size_bytes: 500MBwrite_dedupe_cache_config:enable_fifocache: truedefault_validity: 30s background:writeback_buffer: 10000redis:endpoint: 127.0.0.1:6379timeout: 1sexpiration: 0s db: 7pool_size: 128 password: 1521Qyx6^tls_enabled: falsetls_insecure_skip_verify: trueidle_timeout: 10s max_connection_age: 8hfifocache:ttl: 1hvalidity: 30m0smax_size_items: 2000max_size_bytes: 500MBcache_lookups_older_than: 10s
# 压缩碎片索引
compactor:shared_store: filesystemshared_store_key_prefix: index/working_directory: /data/loki/compactorcompaction_interval: 10m0sretention_enabled: trueretention_delete_delay: 2h0m0sretention_delete_worker_count: 150delete_request_cancel_period: 24h0m0smax_compaction_parallelism: 2# compactor_ring:
frontend_worker:match_max_concurrent: trueparallelism: 10dns_lookup_duration: 5s
# runtime_config 这里没有配置任何信息
# runtime_config:
common:storage:filesystem:chunks_directory: /data/loki/chunksfules_directory: /data/loki/rulersreplication_factor: 3persist_tokens: false# instance_interface_names: ["en0","eth0","ens33"]
analytics:reporting_enabled: false
limits_config:ingestion_rate_strategy: globalingestion_rate_mb: 100ingestion_burst_size_mb: 18max_label_name_length: 2096max_label_value_length: 2048max_label_names_per_series: 60enforce_metric_name: truemax_entries_limit_per_query: 5000reject_old_samples: truereject_old_samples_max_age: 168hcreation_grace_period: 20m0smax_global_streams_per_user: 5000unordered_writes: truemax_chunks_per_query: 200000max_query_length: 721hmax_query_parallelism: 64 max_query_series: 700cardinality_limit: 100000max_streams_matchers_per_query: 1000 max_concurrent_tail_requests: 10 ruler_evaluation_delay_duration: 3s ruler_max_rules_per_rule_group: 0ruler_max_rule_groups_per_tenant: 0retention_period: 700hper_tenant_override_period: 20s max_cache_freshness_per_query: 2m0smax_queriers_per_tenant: 0per_stream_rate_limit: 6MBper_stream_rate_limit_burst: 50MBmax_query_lookback: 0ruler_remote_write_disabled: falsemin_sharding_lookback: 0ssplit_queries_by_interval: 10m0smax_line_size: 30mbmax_line_size_truncate: falsemax_streams_per_user: 0# memberlist_conig模块配置gossip用于在分发服务器、摄取器和查询器之间发现和连接。
# 所有三个组件的配置都是唯一的,以确保单个共享环。
# 至少定义了1个join_members配置后,将自动为分发服务器、摄取器和ring 配置memberlist类型的kvstore
memberlist:randomize_node_name: truestream_timeout: 5s retransmit_factor: 4join_members:- 'loki-memberlist'abort_if_cluster_join_fails: trueadvertise_addr: 0.0.0.0advertise_port: 7946bind_addr: ["0.0.0.0"]bind_port: 7946compression_enabled: truedead_node_reclaim_time: 30sgossip_interval: 100msgossip_nodes: 3gossip_to_dead_nodes_time: 3# join:leave_timeout: 15sleft_ingesters_timeout: 3m0s max_join_backoff: 1m0smax_join_retries: 5message_history_buffer_bytes: 4096min_join_backoff: 2s# node_name: miyamotopacket_dial_timeout: 5spacket_write_timeout: 5s pull_push_interval: 100msrejoin_interval: 10stls_enabled: falsetls_insecure_skip_verify: true
schema_config:configs:- from: "2020-10-24"index:period: 24hprefix: index_object_store: filesystemschema: v11store: boltdb-shipperchunks:period: 168hrow_shards: 32
table_manager:retention_deletes_enabled: falseretention_period: 0sthroughput_updates_disabled: falsepoll_interval: 3m0screation_grace_period: 20mindex_tables_provisioning:provisioned_write_throughput: 1000provisioned_read_throughput: 500inactive_write_throughput: 4inactive_read_throughput: 300inactive_write_scale_lastn: 50 enable_inactive_throughput_on_demand_mode: trueenable_ondemand_throughput_mode: trueinactive_read_scale_lastn: 10 write_scale:enabled: truetarget: 80# role_arn:out_cooldown: 1800min_capacity: 3000max_capacity: 6000in_cooldown: 1800inactive_write_scale:enabled: truetarget: 80out_cooldown: 1800min_capacity: 3000max_capacity: 6000in_cooldown: 1800read_scale:enabled: truetarget: 80out_cooldown: 1800min_capacity: 3000max_capacity: 6000in_cooldown: 1800inactive_read_scale:enabled: truetarget: 80out_cooldown: 1800min_capacity: 3000max_capacity: 6000in_cooldown: 1800chunk_tables_provisioning:enable_inactive_throughput_on_demand_mode: trueenable_ondemand_throughput_mode: trueprovisioned_write_throughput: 1000provisioned_read_throughput: 300inactive_write_throughput: 1inactive_write_scale_lastn: 50inactive_read_throughput: 300inactive_read_scale_lastn: 10write_scale:enabled: truetarget: 80out_cooldown: 1800min_capacity: 3000max_capacity: 6000in_cooldown: 1800inactive_write_scale:enabled: truetarget: 80out_cooldown: 1800min_capacity: 3000max_capacity: 6000in_cooldown: 1800read_scale:enabled: truetarget: 80out_cooldown: 1800min_capacity: 3000max_capacity: 6000in_cooldown: 1800inactive_read_scale:enabled: truetarget: 80out_cooldown: 1800min_capacity: 3000max_capacity: 6000in_cooldown: 1800
tracing:enabled: true
注意
:
ingester.lifecycler.ring.replication_factor
的值在单实例的情况下为1ingester.lifecycler.min_ready_duration
的值为15s,在启动后默认会显示15秒将状态变为ready
memberlist.node_name
的值可以不用设置,默认是当前主机的名称memberlist.join_members
是一个列表,在有多个实例的情况下需要添加各个节点的主机名/IP地址
。在k8s
里面可以设置成一个service绑定到StatefulSets
query_range.results_cache.cache.enable_fifocache
建议设置为false,我这里设置成了trueinstance_interface_names
是一个列表,默认的为["en0","eth0"]
,可以根据需要设置对应的网卡名称,一般不需要进行特殊设置。
1.3.1.2 创建configmap
将上面的内容写入到一个文件——>loki-all.yaml
,把它作为一个configmap
写入k8s
集群。可以使用如下命令创建:
kubectl create configmap --from-file ./loki-all.yaml loki-all
可以通过命令查看到已经创建好的configmap
,具体操作详见下图
1.3.1.3 创建持久化存储
在k8s里面我们的数据是需要进行持久化的。Loki
收集起来的日志信息对于业务来说是至关重要的,因此需要在容器重启的时候日志能够保留下来。
那么就需要用到pv、pvc
,后端存储可以使用nfs、glusterfs、hostPath、azureDisk、cephfs
等20种支持类型,这里因为没有对应的环境就采用了hostPath
方式。
apiVersion: v1
kind: PersistentVolume
metadata:name: lokinamespace: default
spec:hostPath:path: /glusterfs/lokitype: DirectoryOrCreatecapacity:storage: 1GiaccessModes:- ReadWriteMany
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: lokinamespace: default
spec:accessModes:- ReadWriteManyresources:requests:storage: 1GivolumeName: loki
1.3.1.4 创建应用
准备好k8s的StatefulSet
部署文件后就可以直接在集群里面创建应用了。
apiVersion: apps/v1
kind: StatefulSet
metadata:labels:app: lokiname: lokinamespace: default
spec:podManagementPolicy: OrderedReadyreplicas: 1selector:matchLabels:app: lokitemplate:metadata:annotations:prometheus.io/port: http-metricsprometheus.io/scrape: "true"labels:app: lokispec:containers:- args:- -config.file=/etc/loki/loki-all.yamlimage: grafana/loki:2.5.0imagePullPolicy: IfNotPresentlivenessProbe:failureThreshold: 3httpGet:path: /readyport: http-metricsscheme: HTTPinitialDelaySeconds: 45periodSeconds: 10successThreshold: 1timeoutSeconds: 1name: lokiports:- containerPort: 3100name: http-metricsprotocol: TCP- containerPort: 9095name: grpcprotocol: TCP- containerPort: 7946name: memberlist-portprotocol: TCPreadinessProbe:failureThreshold: 3httpGet:path: /readyport: http-metricsscheme: HTTPinitialDelaySeconds: 45periodSeconds: 10successThreshold: 1timeoutSeconds: 1resources:requests:cpu: 500mmemory: 500Milimits:cpu: 500mmemory: 500MisecurityContext:readOnlyRootFilesystem: truevolumeMounts:- mountPath: /etc/lokiname: config- mountPath: /dataname: storagerestartPolicy: AlwayssecurityContext:fsGroup: 10001runAsGroup: 10001runAsNonRoot: truerunAsUser: 10001serviceAccount: lokiserviceAccountName: lokivolumes:- emptyDir: {}name: tmp- name: configconfigMap:name: loki- persistentVolumeClaim:claimName: lokiname: storage
---
kind: Service
apiVersion: v1
metadata:name: loki-memberlistnamespace: default
spec:ports:- name: loki-memberlistprotocol: TCPport: 7946targetPort: 7946selector:kubepi.org/name: loki
---
kind: Service
apiVersion: v1
metadata:name: lokinamespace: default
spec:ports:- name: lokiprotocol: TCPport: 3100targetPort: 3100selector:kubepi.org/name: loki
在上面的配置文件中我添加了一些pod
级别的安全策略,这些安全策略还有集群级别的PodSecurityPolicy
,防止因为漏洞的原因造成集群的整个崩溃
1.3.1.5 验证部署结果
当看到上面的Running
状态时可以通过API的方式看一下分发器是不是正常工作,当显示Active
时正常才会正常分发日志流到收集器(ingester
)
1.3.2 裸机部署
将loki
放到系统的/bin/
目录下,准备grafana-loki.service
控制文件重载系统服务列表
[Unit]
Description=Grafana Loki Log Ingester
Documentation=https://grafana.com/logs/
After=network-online.target[Service]
ExecStart=/bin/loki --config.file /etc/loki/loki-all.yaml
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID[Install]
WantedBy=multi-user.target
重载系统列表命令,可以直接系统自动管理服务:
systemctl daemon-reload
# 启动服务
systemctl start grafana-loki
# 停止服务
systemctl stop grafana-loki
# 重载应用
systemctl reload grafana-loki
1.4 Promtail部署
部署客户端收集日志时也需要创建一个配置文件,按照上面创建服务端的步骤创建。不同的是需要把日志内容push
到服务端
1.4.1 k8s部署
1.4.1.1 创建配置文件
server:log_level: infohttp_listen_port: 3101
clients:- url: http://loki:3100/loki/api/v1/push
positions:filename: /run/promtail/positions.yaml
scrape_configs:- job_name: kubernetes-podspipeline_stages:- cri: {}kubernetes_sd_configs:- role: podrelabel_configs:- source_labels:- __meta_kubernetes_pod_controller_nameregex: ([0-9a-z-.]+?)(-[0-9a-f]{8,10})?action: replacetarget_label: __tmp_controller_name- source_labels:- __meta_kubernetes_pod_label_app_kubernetes_io_name- __meta_kubernetes_pod_label_app- __tmp_controller_name- __meta_kubernetes_pod_nameregex: ^;*([^;]+)(;.*)?$action: replacetarget_label: app- source_labels:- __meta_kubernetes_pod_label_app_kubernetes_io_instance- __meta_kubernetes_pod_label_releaseregex: ^;*([^;]+)(;.*)?$action: replacetarget_label: instance- source_labels:- __meta_kubernetes_pod_label_app_kubernetes_io_component- __meta_kubernetes_pod_label_componentregex: ^;*([^;]+)(;.*)?$action: replacetarget_label: component- action: replacesource_labels:- __meta_kubernetes_pod_node_nametarget_label: node_name- action: replacesource_labels:- __meta_kubernetes_namespacetarget_label: namespace- action: replacereplacement: $1separator: /source_labels:- namespace- apptarget_label: job- action: replacesource_labels:- __meta_kubernetes_pod_nametarget_label: pod- action: replacesource_labels:- __meta_kubernetes_pod_container_nametarget_label: container- action: replacereplacement: /var/log/pods/*$1/*.logseparator: /source_labels:- __meta_kubernetes_pod_uid- __meta_kubernetes_pod_container_nametarget_label: __path__- action: replaceregex: true/(.*)replacement: /var/log/pods/*$1/*.logseparator: /source_labels:- __meta_kubernetes_pod_annotationpresent_kubernetes_io_config_hash- __meta_kubernetes_pod_annotation_kubernetes_io_config_hash- __meta_kubernetes_pod_container_nametarget_label: __path__
用上面的内容创建一个configMap,方法同上
1.4.1.2 创建DaemonSet文件
Promtail
是一个无状态应用不需要进行持久化存储只需要部署到集群里面就可以了,还是同样的准备DaemonSets
创建文件。
kind: DaemonSet
apiVersion: apps/v1
metadata:name: promtailnamespace: defaultlabels:app.kubernetes.io/instance: promtailapp.kubernetes.io/name: promtailapp.kubernetes.io/version: 2.5.0
spec:selector:matchLabels:app.kubernetes.io/instance: promtailapp.kubernetes.io/name: promtailtemplate:metadata:labels:app.kubernetes.io/instance: promtailapp.kubernetes.io/name: promtailspec:volumes:- name: configconfigMap:name: promtail- name: runhostPath:path: /run/promtail- name: containershostPath:path: /var/lib/docker/containers- name: podshostPath:path: /var/log/podscontainers:- name: promtailimage: docker.io/grafana/promtail:2.3.0args:- '-config.file=/etc/promtail/promtail.yaml'ports:- name: http-metricscontainerPort: 3101protocol: TCPenv:- name: HOSTNAMEvalueFrom:fieldRef:apiVersion: v1fieldPath: spec.nodeNamevolumeMounts:- name: configmountPath: /etc/promtail- name: runmountPath: /run/promtail- name: containersreadOnly: truemountPath: /var/lib/docker/containers- name: podsreadOnly: truemountPath: /var/log/podsreadinessProbe:httpGet:path: /readyport: http-metricsscheme: HTTPinitialDelaySeconds: 10timeoutSeconds: 1periodSeconds: 10successThreshold: 1failureThreshold: 5imagePullPolicy: IfNotPresentsecurityContext:capabilities:drop:- ALLreadOnlyRootFilesystem: falseallowPrivilegeEscalation: falserestartPolicy: AlwaysserviceAccountName: promtailserviceAccount: promtailtolerations:- key: node-role.kubernetes.io/masteroperator: Existseffect: NoSchedule- key: node-role.kubernetes.io/control-planeoperator: Existseffect: NoSchedule
1.4.1.3 创建promtail应用
kubectl apply -f promtail.yaml
使用上面这个命令创建后就可以看到服务已经创建好了。接下来就是在Grafana
里面添加DataSource
查看数据了。
1.4.2 裸机部署
如果是裸机部署的情况下,需要对上面的配置文件做一下稍微的改动,更改clients
的地址就可以,文件存放到/etc/loki/
下,例如改成:
clients:- url: http://ipaddress:port/loki/api/v1/push
添加系统开机启动配置,service配置文件存放位置/usr/lib/systemd/system/loki-promtail.service
内容如下
[Unit]
Description=Grafana Loki Log Ingester
Documentation=https://grafana.com/logs/
After=network-online.target[Service]
ExecStart=/bin/promtail --config.file /etc/loki/loki-promtail.yaml
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID[Install]
WantedBy=multi-user.target
启动方式同上面服务端部署内容
1.5 数据源
添加数据源,具体步骤: Grafana->Setting->DataSources->AddDataSource->Loki
注意
:http
的URL
地址,应用、服务部署在哪个namespace
下,就需要指定它的FQDN
地址,它的格式是ServiceName.namespace
。如果默认在default
下、创建的端口号是3100,就需要填写为http://loki:3100,这里为什么不写IP地址而写成服务的名字,是因为在k8s集群里面有个dns服务器会自动解析这个地址。
查找日志信息
1.6 其他客户端配置
1.6.1 Logstash作为日志收集客户端
在启动Logstash
后我们需要安装一个插件,可以通过这个命令安装loki
的输出插件,安装完成之后可以在logstash
的output
中添加信息。
bin/logstash-plugin install logstash-output-loki
添加配置进行测试
完整的logstash
配置信息,可以参考官网给出的内容LogstashConfigFile
output {loki {[url => "" | default = none | required=true][tenant_id => string | default = nil | required=false][message_field => string | default = "message" | required=false][include_fields => array | default = [] | required=false][batch_wait => number | default = 1(s) | required=false][batch_size => number | default = 102400(bytes) | required=false][min_delay => number | default = 1(s) | required=false][max_delay => number | default = 300(s) | required=false][retries => number | default = 10 | required=false][username => string | default = nil | required=false][password => secret | default = nil | required=false][cert => path | default = nil | required=false][key => path | default = nil| required=false][ca_cert => path | default = nil | required=false][insecure_skip_verify => boolean | default = false | required=false]}
}
或者采用logstash
的http
输出模块,配置如下:
output {http {format => "json"http_method => "post"content_type => "application/json"connect_timeout => 10url => "http://loki:3100/loki/api/v1/push"message => '"message":"%{message}"}'}
}
1.7 Helm安装
如果想简便安装的话,可以采用helm
来安装。helm
将所有的安装步骤都进行了封装,简化了安装步骤。
对于想详细了解k8s的人来说,helm不太适合。因为它封装后自动执行,k8s
管理员不知道各组件之间是如何依赖的,可能会造成误区。
废话不多说,下面开始helm安装:
- 添加repo源
helm repo add grafana https://grafana.github.io/helm-charts
- 更新源
helm repo update
- 部署
默认配置
helm upgrade --install loki grafana/loki-simple-scalable
自定义namespace
helm upgrade --install loki --namespace=loki grafana/loki-simple-scalable
自定义配置信息
helm upgrade --install loki grafana/loki-simple-scalable --set "key1=val1,key2=val2,..."
1.8 故障解决方案
1.8.1 502 BadGateWay
loki的地址填写不正确
在k8s里面,地址填写错误造成了502。检查一下loki的地址是否是以下内容:
http://LokiServiceName
http://LokiServiceName.namespace
http://LokiServiceName.namespace:ServicePort
grafana和loki
在不同的节点上,检查一下节点间网络通信状态、防火墙策略
1.8.2 Ingester not ready: instance xx:9095 in state JOINING
耐心等待一会,因为是allInOne
模式程序启动需要一定的时间。
1.8.3 too many unhealthy instances in the ring
将ingester.lifecycler.replication_factor
改为1,是因为这个设置不正确造成的。这个在启动的时候会设置为多个复制源,但当前只部署了一个所以在查看label
的时候提示这个
1.8.4 Data source connected
Data source connected, but no labels received. Verify that Loki and Promtail is configured properly
promtail
无法将收集到的日志发送给loki,许可检查一下promtail
的输出是不是正常promtail
在loki还没有准备就绪的时候把日志发送过来了,但loki没有接收到。如果需要重新接收日志,需要删除positions.yaml文件,具体路径可以用find查找一下位置promtail
忽略了目标日志文件或者配置文件错误造成的无法正常启动promtail
无法在指定的位置发现日志文件
相关文章:

日志之Loki详细讲解
文章目录 1 Loki1.1 引言1.2 Loki工作方式1.2.1 日志解析格式1.2.2 日志搜集架构模式1.2.3 Loki部署模式 1.3 服务端部署1.3.1 AllInOne部署模式1.3.1.1 k8s部署1.3.1.2 创建configmap1.3.1.3 创建持久化存储1.3.1.4 创建应用1.3.1.5 验证部署结果 1.3.2 裸机部署 1.4 Promtail…...
Mongodb投射中的$slice,正向反向跳过要搞清楚
在投射中,使用$操作符和$elemMatch返回数组中第一个符合查询条件的元素。而在投射中使用$slice, 能够返回指定数量的数组元素。 定义 投射中使用$slice命令,指定查询结果中返回数组元素的数量。 语法 db.collection.find(<query>,{<arrayFi…...

类和对象 第六部分 继承 第一部分:继承的语法
一.继承的概念 继承是面向对象的三大特性之一 有些类与类之间存在特殊的关系,例如下图: 我们可以发现,下级别的成员除了拥有上一级的共性,还有自己的特性,这个时候,我们可以讨论利用继承的技术,…...

githacker安装详细教程,linux添加环境变量详细教程(见标题三)
笔者是ctf小白,这两天也是遇到.git泄露的题目,需要工具来解决问题,在下载和使用的过程中也是遇到很多问题,写此篇记录经验,以供学习 在本篇标题三中有详细介绍了Linux系统添加环境变量的操作教程,以供学习 …...

2401Idea用GradleKotlin编译Java控制台中文出乱码解决
解决方法 解决方法1 在项目 build.gradle.kts 文件中加入 tasks.withType<JavaCompile> {options.encoding "UTF-8" } tasks.withType<JavaExec> {systemProperty("file.encoding", "utf-8") }经测试, 只加 tasks.withType<…...

Day39 62不同路径 63不同路径II 343整数拆分 96不同的二叉搜索树
62 不同路径 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径&#…...

JavaScript 的 ~~ 运算和floor 的性能差异
在JavaScript中,~~(双波浪号)和Math.floor()都可以用于向下取整,但它们在行为和性能上有一些差异。要测试这两者之间的性能差异,你可以使用JavaScript的performance.now()方法来进行基准测试。 行为差异 Math.floor()…...
AtCoder Beginner Contest 338F - Negative Traveling Salesman【floyd+状态压缩dp】
原题链接:https://atcoder.jp/contests/abc338/tasks/abc338_f Time Limit: 6 sec / Memory Limit: 1024 MB Score: 500 points、 问题陈述 有一个有N个顶点和M条边的加权简单有向图。顶点的编号为 1 到 N,i/th 边的权重为 Wi,从顶点 U…...

UDP/TCP协议特点
1.前置知识 定义应用层协议 1.确定客户端和服务端要传递哪些信息 2.约定传输格式 网络上传输的一般是二进制数据/字符串 结构化数据转二进制/字符串 称为序列化 反之称之为反序列化 下面就是传输层了 在TCP/IP协议中,我们以 目的端口,目的IP 源端口 源IP 协议号这样一个五…...
编程笔记 html5cssjs 059 css多列
编程笔记 html5&css&js 059 css多列 一、CSS3 多列属性二、实例小结 CSS3 可以将文本内容设计成像报纸一样的多列布局. 一、CSS3 多列属性 下表列出了所有 CSS3 的多列属性: 属性 描述 column-count 指定元素应该被分割的列数。 column-fill 指定如何填充…...

Facebook的元宇宙探索:虚拟社交的新时代
近年来,科技的飞速发展推动着人类社交方式的翻天覆地的改变。在这场数字化革命的浪潮中,社交媒体巨头Facebook正积极探索并引领着一个被誉为“元宇宙”的全新领域,试图为用户打造更为真实、丰富的虚拟社交体验。 元宇宙的崛起 元宇宙这个概念…...

用React给XXL-JOB开发一个新皮肤(四):实现用户管理模块
目录 一. 简述二. 模块规划 2.1. 页面规划2.2. 模型实体定义 三. 模块实现 3.1. 用户分页搜索3.2. Modal 配置3.3. 创建用户表单3.4. 修改用户表单3.5. 删除 四. 结束语 一. 简述 上一篇文章我们实现登录页面和管理页面的 Layout 骨架,并对接登录和登出接口。这篇…...
某赛通电子文档安全管理系统 hiddenWatermark/uploadFile 文件上传漏洞复现
0x01 产品简介 某赛通电子文档安全管理系统(简称:CDG)是一款电子文档安全加密软件,该系统利用驱动层透明加密技术,通过对电子文档的加密保护,防止内部员工泄密和外部人员非法窃取企业核心重要数据资产,对电子文档进行全生命周期防护,系统具有透明加密、主动加密、智能…...

Redis五种数据类型及应用场景
1、数据类型 String(字符串,整数,浮点数):做简单的键值对缓存 List(列表):储存一些列表类型的数据结构 Hash(哈希):包含键值对的无序散列表,结构化的数据 Set(无序集合):交集,并集…...

测试环境搭建整套大数据系统(一:基础配置,修改hostname,hosts,免密)
一:使用服务器配置。 二:修改服务器名称hostname,hosts。 在 Linux 系统中,hostname 和 /etc/hosts 文件分别用于管理主机名和主机名解析。 在三台服务器上,分别执行以下命令。 vim /etc/hostnamexdso-hadoop-test-0…...

maven helper 解决jar包冲突方法
一 概要说明 1.1 说明 首先,解决idea中jar包冲突,使用maven的插件:maven helper插件,它能够给我们罗列出来同一个jar包的不同版本,以及他们的来源,但是对不同jar包中同名的类没有办法。 1.2 依赖顺序 …...
AppSrv-文件共享(23国赛真题)
2023全国职业院校技能大赛网络系统管理赛项–模块B:服务部署(WindowServer2022) 文章目录 AppSrv-文件共享题目配置步骤创建用户主目录共享文件夹:本地目录为d:\share\users\,允许所有域用户可读可写。在本目录下为所有用户添加一个以名称命名的文件夹,该文件夹将设置为所…...

AsyncLocal是如何实现在Thread直接传值的?
一:背景 1. 讲故事 这个问题的由来是在.NET高级调试训练营第十期分享ThreadStatic底层玩法的时候,有朋友提出了AsyncLocal是如何实现的,虽然做了口头上的表述,但总还是会不具体,所以觉得有必要用文字图表的方式来系统…...

Flask 入门1:一个简单的 Web 程序
1. 关于 Flask Flask诞生于2010年, Armin Ronacher的一个愚人节玩笑。不过现在已经是一个用python语言基于Werkzeug工具箱编写的轻量级web开发框架,它主要面向需求简单,项目周期短的小应用。 Flask本身相当于一个内核,其他几乎所…...

维护管理Harbor,docker容器的重启策略
维护管理Harbor 通过HarborWeb创建项目 在 Harbor 仓库中,任何镜像在被 push 到 regsitry 之前都必须有一个自己所属的项目。 单击“项目”,填写项目名称,项目级别若设置为"私有",则不勾选。如果设置为公共仓库&#…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...