本文主要是介绍日志之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详细讲解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!