簡介

Grafana Loki是一個水平可擴充套件,高可用性,多租戶的日誌聚合系統,包含了日誌收集,儲存,視覺化以及報警等功能。

與其他日誌系統不同,Loki的構想是僅對日誌建立標籤索引,而使原始日誌訊息保持未索引狀態。這意味著Loki的運營成本更低,並且效率更高。

Loki特別適合儲存Kubernetes Pod日誌。諸如Pod標籤之類的元資料會自動被抓取並建立索引。

基於Loki打造雲原生分散式日誌系統

與EFK對比

EFK(Elasticsearch,Fluentd,Kibana)技術棧用於收集,視覺化和查詢來自各種來源的日誌。 Elasticsearch中的資料作為非結構化JSON物件儲存在磁碟上。每個物件的鍵和每個鍵的內容都被索引。然後可以使用JSON物件或定義為Lucene的查詢語言來查詢資料。

相比之下,Loki在單二進位制模式下可以將資料儲存在磁碟上,但是在水平可伸縮模式下,資料儲存在雲端儲存系統(例如S3,GCS或Cassandra)中。日誌以純文字格式儲存,並帶有一組標籤名稱和值,其中僅對標籤對進行索引。這種折衷使得它比全索引更具備成本優勢,並且允許開發人員從其應用程式積極地進行日誌記錄。使用LogQL查詢Loki中的日誌。但是,由於這種設計的折衷,基於內容(即日誌行中的文字)進行過濾的LogQL查詢需要載入搜尋視窗中與查詢中定義的標籤匹配的所有塊。

此外,我們知道metrcis和alert只能揭示預定義的問題,未知的問題還得從Log裡邊查詢。日誌和 metric 分在兩個系統,這增加了排查問題的難度。我們的日誌和metrcis系統需要建立聯絡,而靈感來源於prometheus的loki,恰好解決了這個問題。

Loki架構

Loki大體架構如下:

基於Loki打造雲原生分散式日誌系統

接下來我們介紹一些核心元件:

Distributor

—— Distributor 服務負責處理客戶端的寫入流。這是日誌資料寫入路徑中的第一站。Distributor收到一組流後,將驗證每個流的正確性並確保其在配置的租戶(或全域性)限制之內。然後,將有效塊拆分為多個批次,並並行傳送到多個ingester。

Distributor 使用一致性雜湊和可配置的複製因子,以確定ingester服務的哪些例項應接收給定的流。流是與租戶和唯一標籤集關聯的一組日誌。使用租戶ID和標籤集對流進行雜湊,然後使用雜湊查詢將流傳送到的例項。

Ingester

—— Ingester服務負責在寫入路徑上將日誌資料寫入到長期儲存後端(DynamoDB,S3,Cassandra等),並在讀取路徑上返回日誌資料以進行記憶體中查詢。

Ingester包含一個生命週期器,該生命週期器管理雜湊環中ingester的生命週期。每個ingester狀態為以下狀態中的一種:

PENDING

JOINING

ACTIVE

LEAVING

UNHEALTHY

Query frontend

—— Query frontend是一項可選服務,可提供查詢器的API終結點,並可用於加速讀取路徑。當Query frontend就位時,應將傳入的查詢請求定向到Query frontend,而不是Querier。為了執行實際查詢,叢集中仍將需要Querier服務。

Query frontend在內部執行一些查詢調整,並將查詢儲存在內部佇列中。在此設定中,Queriers充當工作人員,將工作從佇列中拉出,執行,然後將其返回到Query frontend進行聚合。Queriers需要配置Query frontend地址(透過-querier。frontend-address CLI標誌),以允許Queriers連線到Query frontend。

Query frontend是無狀態的。但是,由於內部佇列的工作原理,建議執行一些Query frontend副本以充分利用公平排程的好處。在大多數情況下,兩個副本就足夠了。

Querier

——Querier 使用 LogQL 查詢語言處理查詢,同時從ingester和長期儲存中獲取日誌。

Querier將查詢所有記憶體中的記憶體資料,然後回退到針對後端儲存執行相同的查詢。由於副本因素,Querier可能會收到重複的資料。為解決此問題,Querier在內部對具有相同納秒級時間戳,標籤集和日誌訊息的資料進行重複資料刪除。

Chunk Store

—— Chunk Store是Loki的長期資料儲存,旨在支援互動式查詢和持續寫入,而無需後臺維護任務。它包括:

塊的索引。該索引可以透過以下方式支援:

Amazon DynamoDB

Google Bigtable

Apache Cassandra

塊資料本身的鍵值(KV)儲存,可以是:

Amazon DynamoDB

Google Bigtable

Apache Cassandra

Amazon S3

Google Cloud Storage

當然還可以包括做日誌報警的ruler元件以及負責在其時間段開始之前建立週期表,並在其資料時間範圍超出保留期限時將其刪除的table-manager。

部署

Loki微服務部署模式,涉及元件比較多,我們生產環境使用k8s部署,當然涉及到敏感資訊已經去掉。

Chuck 儲存選擇的是s3,index儲存選擇的是Cassandra。

1:建立s3 桶,然後將aksk新增到下面的配置檔案中。Cassandra 叢集搭建我們這裡不再講述。

2:部署loki的配置檔案,

apiVersion: v1

data:

config。yaml: |

chunk_store_config:

chunk_cache_config:

memcached:

batch_size: 100

parallelism: 100

memcached_client:

consistent_hash: true

host: memcached。loki。svc。cluster。local

service: memcached-client

max_look_back_period: 0

write_dedupe_cache_config:

memcached:

batch_size: 100

parallelism: 100

memcached_client:

consistent_hash: true

host: memcached-index-writes。loki。svc。cluster。local

service: memcached-client

auth_enabled: false

distributor:

ring:

kvstore:

store: memberlist

frontend:

compress_responses: true

log_queries_longer_than: 5s

max_outstanding_per_tenant: 200

frontend_worker:

frontend_address: query-frontend。loki。svc。cluster。local:9095

grpc_client_config:

max_send_msg_size: 1。048576e+08

parallelism: 2

ingester:

chunk_block_size: 262144

chunk_idle_period: 15m

lifecycler:

heartbeat_period: 5s

interface_names:

- eth0

join_after: 30s

num_tokens: 512

ring:

kvstore:

store: memberlist

replication_factor: 3

max_transfer_retries: 0

ingester_client:

grpc_client_config:

max_recv_msg_size: 6。7108864e+07

remote_timeout: 1s

limits_config:

enforce_metric_name: false

ingestion_burst_size_mb: 20

ingestion_rate_mb: 10

ingestion_rate_strategy: global

max_cache_freshness_per_query: 10m

max_global_streams_per_user: 10000

max_query_length: 12000h

max_query_parallelism: 16

max_streams_per_user: 0

reject_old_samples: true

reject_old_samples_max_age: 168h

querier:

query_ingesters_within: 2h

query_range:

align_queries_with_step: true

cache_results: true

max_retries: 5

results_cache:

cache:

memcached_client:

consistent_hash: true

host: memcached-frontend。loki。svc。cluster。local

max_idle_conns: 16

service: memcached-client

timeout: 500ms

update_interval: 1m

split_queries_by_interval: 30m

ruler: {}

schema_config:

configs:

- from: “2020-05-15”

index:

period: 168h

prefix: cassandra_table

object_store: s3

schema: v11

store: cassandra

server:

graceful_shutdown_timeout: 5s

grpc_server_max_concurrent_streams: 1000

grpc_server_max_recv_msg_size: 1。048576e+08

grpc_server_max_send_msg_size: 1。048576e+08

http_listen_port: 3100

http_server_idle_timeout: 120s

http_server_write_timeout: 1m

storage_config:

cassandra:

username: loki-superuser

password: xxx

addresses: loki-dc1-all-pods-service。cass-operator。svc。cluster。local

auth: true

keyspace: lokiindex

aws:

bucketnames: xx

endpoint: s3。amazonaws。com

region: ap-southeast-1

access_key_id: xx

secret_access_key: xx

s3forcepathstyle: false

index_queries_cache_config:

memcached:

batch_size: 100

parallelism: 100

memcached_client:

consistent_hash: true

host: memcached-index-queries。loki。svc。cluster。local

service: memcached-client

memberlist:

abort_if_cluster_join_fails: false

bind_port: 7946

join_members:

- loki-gossip-ring。loki。svc。cluster。local:7946

max_join_backoff: 1m

max_join_retries: 10

min_join_backoff: 1s

table_manager:

creation_grace_period: 3h

poll_interval: 10m

retention_deletes_enabled: true

retention_period: 168h

kind: ConfigMap

metadata:

name: loki

namespace: loki

——-

apiVersion: v1

data:

overrides。yaml: |

overrides: {}

kind: ConfigMap

metadata:

name: overrides

namespace: loki

2:部署依賴的4個memcached:

memcached-frontend。yaml如下:

apiVersion: apps/v1

kind: StatefulSet

metadata:

labels:

app: memcached-frontend

name: memcached-frontend

namespace: loki

spec:

replicas: 3

selector:

matchLabels:

app: memcached-frontend

serviceName: memcached-frontend

template:

metadata:

annotations:

prometheus。io/scrape: “true”

prometheus。io/port: “9150”

labels:

app: memcached-frontend

spec:

nodeSelector:

group: loki

tolerations:

- effect: NoExecute

key: app

operator: Exists

affinity:

podAntiAffinity:

requiredDuringSchedulingIgnoredDuringExecution:

- labelSelector:

matchLabels:

app: memcached-frontend

topologyKey: kubernetes。io/hostname

containers:

- args:

- -m 1024

- -I 5m

- -c 1024

- -v

image: memcached:1。5。17-alpine

imagePullPolicy: IfNotPresent

name: memcached

ports:

- containerPort: 11211

name: client

resources:

limits:

cpu: “3”

memory: 1536Mi

requests:

cpu: 500m

memory: 1329Mi

- args:

- ——memcached。address=localhost:11211

- ——web。listen-address=0。0。0。0:9150

image: prom/memcached-exporter:v0。6。0

imagePullPolicy: IfNotPresent

name: exporter

ports:

- containerPort: 9150

name: http-metrics

updateStrategy:

type: RollingUpdate

——-

apiVersion: v1

kind: Service

metadata:

labels:

app: memcached-frontend

name: memcached-frontend

namespace: loki

spec:

ports:

- name: memcached-client

port: 11211

targetPort: 11211

selector:

app: memcached-frontend

memcached-index-queries。yaml 如下:

apiVersion: apps/v1

kind: StatefulSet

metadata:

labels:

app: memcached-index-queries

name: memcached-index-queries

namespace: loki

spec:

replicas: 3

selector:

matchLabels:

app: memcached-index-queries

serviceName: memcached-index-queries

template:

metadata:

annotations:

prometheus。io/scrape: “true”

prometheus。io/port: “9150”

labels:

app: memcached-index-queries

spec:

nodeSelector:

group: loki

tolerations:

- effect: NoExecute

key: app

operator: Exists

affinity:

podAntiAffinity:

requiredDuringSchedulingIgnoredDuringExecution:

- labelSelector:

matchLabels:

app: memcached-index-queries

topologyKey: kubernetes。io/hostname

containers:

- args:

- -m 1024

- -I 5m

- -c 1024

- -v

image: memcached:1。5。17-alpine

imagePullPolicy: IfNotPresent

name: memcached

ports:

- containerPort: 11211

name: client

resources:

limits:

cpu: “3”

memory: 1536Mi

requests:

cpu: 500m

memory: 1329Mi

- args:

- ——memcached。address=localhost:11211

- ——web。listen-address=0。0。0。0:9150

image: prom/memcached-exporter:v0。6。0

imagePullPolicy: IfNotPresent

name: exporter

ports:

- containerPort: 9150

name: http-metrics

updateStrategy:

type: RollingUpdate

——-

apiVersion: v1

kind: Service

metadata:

labels:

app: memcached-index-queries

name: memcached-index-queries

namespace: loki

spec:

clusterIP: None

ports:

- name: memcached-client

port: 11211

targetPort: 11211

selector:

app: memcached-index-queries

memcached-index-writes。yaml 如下:

apiVersion: apps/v1

kind: StatefulSet

metadata:

labels:

app: memcached-index-writes

name: memcached-index-writes

namespace: loki

spec:

replicas: 3

selector:

matchLabels:

app: memcached-index-writes

serviceName: memcached-index-writes

template:

metadata:

annotations:

prometheus。io/scrape: “true”

prometheus。io/port: “9150”

labels:

app: memcached-index-writes

spec:

nodeSelector:

group: loki

tolerations:

- effect: NoExecute

key: app

operator: Exists

affinity:

podAntiAffinity:

requiredDuringSchedulingIgnoredDuringExecution:

- labelSelector:

matchLabels:

app: memcached-index-writes

topologyKey: kubernetes。io/hostname

containers:

- args:

- -m 1024

- -I 1m

- -c 1024

- -v

image: memcached:1。5。17-alpine

imagePullPolicy: IfNotPresent

name: memcached

ports:

- containerPort: 11211

name: client

resources:

limits:

cpu: “3”

memory: 1536Mi

requests:

cpu: 500m

memory: 1329Mi

- args:

- ——memcached。address=localhost:11211

- ——web。listen-address=0。0。0。0:9150

image: prom/memcached-exporter:v0。6。0

imagePullPolicy: IfNotPresent

name: exporter

ports:

- containerPort: 9150

name: http-metrics

updateStrategy:

type: RollingUpdate

——-

apiVersion: v1

kind: Service

metadata:

labels:

app: memcached-index-writes

name: memcached-index-writes

namespace: loki

spec:

clusterIP: None

ports:

- name: memcached-client

port: 11211

targetPort: 11211

selector:

app: memcached-index-writes

memcached。yaml 如下:

apiVersion: apps/v1

kind: StatefulSet

metadata:

labels:

app: memcached

name: memcached

namespace: loki

spec:

replicas: 3

selector:

matchLabels:

app: memcached

serviceName: memcached

template:

metadata:

annotations:

prometheus。io/scrape: “true”

prometheus。io/port: “9150”

labels:

app: memcached

spec:

nodeSelector:

group: loki

tolerations:

- effect: NoExecute

key: app

operator: Exists

affinity:

podAntiAffinity:

requiredDuringSchedulingIgnoredDuringExecution:

- labelSelector:

matchLabels:

app: memcached

topologyKey: kubernetes。io/hostname

containers:

- args:

- -m 4096

- -I 2m

- -c 1024

- -v

image: memcached:1。5。17-alpine

imagePullPolicy: IfNotPresent

name: memcached

ports:

- containerPort: 11211

name: client

resources:

limits:

cpu: “3”

memory: 6Gi

requests:

cpu: 500m

memory: 5016Mi

- args:

- ——memcached。address=localhost:11211

- ——web。listen-address=0。0。0。0:9150

image: prom/memcached-exporter:v0。6。0

imagePullPolicy: IfNotPresent

name: exporter

ports:

- containerPort: 9150

name: http-metrics

updateStrategy:

type: RollingUpdate

——-

apiVersion: v1

kind: Service

metadata:

labels:

app: memcached

name: memcached

namespace: loki

spec:

clusterIP: None

ports:

- name: memcached-client

port: 11211

targetPort: 11211

selector:

app: memcached

對於這4個memcached 的作用,大家可以結合loki的配置檔案和架構圖查閱。

4:在Loki中,ring是由tokens分成較小段的空間。每個段都屬於單個“ ingester”,用於對多個ingester的系列/日誌進行分片。除tokens外,每個例項還具有其ID,地址和定期更新的最新心跳時間戳。這允許其他元件(distributors 和 queriers)發現哪些inester是可用的和有效的。

支援consul ,etcd,memberlist(gossip) 等實現。 我們為了減少不必要的依賴,選擇了memberlist。

所以需要部署一個service:

gossip_ring。yaml 如下:

apiVersion: v1

kind: Service

metadata:

labels:

name: loki-gossip-ring

name: loki-gossip-ring

namespace: loki

spec:

ports:

- name: gossip-ring

port: 7946

targetPort: 7946

protocol: TCP

selector:

gossip_ring_member: ‘true’

5:部署distributor

apiVersion: apps/v1

kind: Deployment

metadata:

name: distributor

namespace: loki

labels:

app: distributor

spec:

minReadySeconds: 10

replicas: 3

revisionHistoryLimit: 10

selector:

matchLabels:

app: distributor

template:

metadata:

annotations:

prometheus。io/path: /metrics

prometheus。io/port: “3100”

prometheus。io/scrape: “true”

labels:

app: distributor

gossip_ring_member: ‘true’

spec:

nodeSelector:

group: loki

tolerations:

- effect: NoExecute

key: app

operator: Exists

affinity:

podAntiAffinity:

requiredDuringSchedulingIgnoredDuringExecution:

- labelSelector:

matchLabels:

app: distributor

topologyKey: kubernetes。io/hostname

containers:

- args:

- -config。file=/etc/loki/config/config。yaml

- -limits。per-user-override-config=/etc/loki/overrides/overrides。yaml

- -target=distributor

image: grafana/loki:1。6。1

imagePullPolicy: IfNotPresent

name: distributor

ports:

- containerPort: 3100

name: http-metrics

- containerPort: 9095

name: grpc

- containerPort: 7946

name: gossip-ring

readinessProbe:

httpGet:

path: /ready

port: 3100

initialDelaySeconds: 15

timeoutSeconds: 1

resources:

limits:

cpu: “1”

memory: 1Gi

requests:

cpu: 500m

memory: 500Mi

volumeMounts:

- mountPath: /etc/loki/config

name: loki

- mountPath: /etc/loki/overrides

name: overrides

volumes:

- configMap:

name: loki

name: loki

- configMap:

name: overrides

name: overrides

——-

apiVersion: v1

kind: Service

metadata:

labels:

name: distributor

name: distributor

namespace: loki

spec:

ports:

- name: distributor-http-metrics

port: 3100

targetPort: 3100

- name: distributor-grpc

port: 9095

targetPort: 9095

selector:

app: distributor

6:部署ingester

apiVersion: apps/v1

kind: StatefulSet

metadata:

name: ingester

namespace: loki

labels:

app: ingester

spec:

updateStrategy:

type: RollingUpdate

replicas: 3

serviceName: ingester

selector:

matchLabels:

app: ingester

strategy:

rollingUpdate:

maxSurge: 0

maxUnavailable: 1

template:

metadata:

annotations:

prometheus。io/path: /metrics

prometheus。io/port: “3100”

prometheus。io/scrape: “true”

labels:

name: ingester

gossip_ring_member: ‘true’

spec:

nodeSelector:

group: loki

tolerations:

- effect: NoExecute

key: app

operator: Exists

securityContext:

fsGroup: 10001

affinity:

podAntiAffinity:

requiredDuringSchedulingIgnoredDuringExecution:

- labelSelector:

matchLabels:

app: ingester

topologyKey: kubernetes。io/hostname

containers:

- args:

- -config。file=/etc/loki/config/config。yaml

- -limits。per-user-override-config=/etc/loki/overrides/overrides。yaml

- -target=ingester

image: grafana/loki:1。6。1

imagePullPolicy: IfNotPresent

name: ingester

ports:

- containerPort: 3100

name: http-metrics

- containerPort: 9095

name: grpc

- containerPort: 7946

name: gossip-ring

readinessProbe:

httpGet:

path: /ready

port: 3100

initialDelaySeconds: 15

timeoutSeconds: 1

resources:

limits:

cpu: “2”

memory: 10Gi

requests:

cpu: “1”

memory: 5Gi

volumeMounts:

- mountPath: /etc/loki/config

name: loki

- mountPath: /etc/loki/overrides

name: overrides

- mountPath: /data

name: ingester-data

terminationGracePeriodSeconds: 4800

volumes:

- configMap:

name: loki

name: loki

- configMap:

name: overrides

name: overrides

volumeClaimTemplates:

- metadata:

labels:

app: querier

name: ingester-data

spec:

accessModes:

- ReadWriteOnce

resources:

requests:

storage: 10Gi

storageClassName: gp2

——-

apiVersion: v1

kind: Service

metadata:

labels:

name: ingester

name: ingester

namespace: loki

spec:

ports:

- name: ingester-http-metrics

port: 3100

targetPort: 3100

- name: ingester-grpc

port: 9095

targetPort: 9095

selector:

app: ingester

7:部署query-frontend

apiVersion: apps/v1

kind: Deployment

metadata:

name: query-frontend

namespace: loki

labels:

app: query-frontend

spec:

minReadySeconds: 10

replicas: 2

revisionHistoryLimit: 10

selector:

matchLabels:

name: query-frontend

template:

metadata:

annotations:

prometheus。io/path: /metrics

prometheus。io/port: “3100”

prometheus。io/scrape: “true”

labels:

app: query-frontend

spec:

nodeSelector:

group: loki

tolerations:

- effect: NoExecute

key: app

operator: Exists

affinity:

podAntiAffinity:

requiredDuringSchedulingIgnoredDuringExecution:

- labelSelector:

matchLabels:

app: query-frontend

topologyKey: kubernetes。io/hostname

containers:

- args:

- -config。file=/etc/loki/config/config。yaml

- -limits。per-user-override-config=/etc/loki/overrides/overrides。yaml

- -log。level=debug

- -target=query-frontend

image: grafana/loki:master-92ace83

imagePullPolicy: IfNotPresent

name: query-frontend

ports:

- containerPort: 3100

name: http-metrics

- containerPort: 9095

name: grpc

readinessProbe:

httpGet:

path: /ready

port: 3100

initialDelaySeconds: 15

timeoutSeconds: 1

resources:

limits:

memory: 1200Mi

requests:

cpu: “2”

memory: 600Mi

volumeMounts:

- mountPath: /etc/loki/config

name: loki

- mountPath: /etc/loki/overrides

name: overrides

volumes:

- configMap:

name: loki

name: loki

- configMap:

name: overrides

name: overrides

——-

apiVersion: v1

kind: Service

metadata:

labels:

name: query-frontend

name: query-frontend

namespace: loki

spec:

clusterIP: None

publishNotReadyAddresses: true

ports:

- name: query-frontend-http-metrics

port: 3100

targetPort: 3100

- name: query-frontend-grpc

port: 9095

targetPort: 9095

selector:

app: query-frontend

8:部署querier

apiVersion: apps/v1

kind: StatefulSet

metadata:

labels:

name: querier

name: querier

namespace: loki

spec:

updateStrategy:

type: RollingUpdate

replicas: 3

serviceName: querier

selector:

matchLabels:

app: querier

template:

metadata:

annotations:

prometheus。io/path: /metrics

prometheus。io/port: “3100”

prometheus。io/scrape: “true”

labels:

app: querier

gossip_ring_member: ‘true’

spec:

nodeSelector:

group: loki

tolerations:

- effect: NoExecute

key: app

operator: Exists

securityContext:

fsGroup: 10001

affinity:

podAntiAffinity:

requiredDuringSchedulingIgnoredDuringExecution:

- labelSelector:

matchLabels:

app: querier

topologyKey: kubernetes。io/hostname

containers:

- args:

- -config。file=/etc/loki/config/config。yaml

- -limits。per-user-override-config=/etc/loki/overrides/overrides。yaml

- -target=querier

image: grafana/loki:1。6。1

imagePullPolicy: IfNotPresent

name: querier

ports:

- containerPort: 3100

name: http-metrics

- containerPort: 9095

name: grpc

- containerPort: 7946

name: gossip-ring

readinessProbe:

httpGet:

path: /ready

port: 3100

initialDelaySeconds: 15

timeoutSeconds: 1

resources:

requests:

cpu: “4”

memory: 2Gi

volumeMounts:

- mountPath: /etc/loki/config

name: loki

- mountPath: /etc/loki/overrides

name: overrides

- mountPath: /data

name: querier-data

volumes:

- configMap:

name: loki

name: loki

- configMap:

name: overrides

name: overrides

volumeClaimTemplates:

- metadata:

labels:

app: querier

name: querier-data

spec:

accessModes:

- ReadWriteOnce

resources:

requests:

storage: 10Gi

storageClassName: gp2

——-

apiVersion: v1

kind: Service

metadata:

labels:

name: querier

name: querier

namespace: loki

spec:

ports:

- name: querier-http-metrics

port: 3100

targetPort: 3100

- name: querier-grpc

port: 9095

targetPort: 9095

selector:

app: querier

9:部署table manager

apiVersion: apps/v1

kind: Deployment

metadata:

name: table-manager

namespace: loki

labels:

app: table-manager

spec:

minReadySeconds: 10

replicas: 1

revisionHistoryLimit: 10

selector:

matchLabels:

app: table-manager

template:

metadata:

annotations:

prometheus。io/path: /metrics

prometheus。io/port: “3100”

prometheus。io/scrape: “true”

labels:

app: table-manager

spec:

nodeSelector:

group: loki

tolerations:

- effect: NoExecute

key: app

operator: Exists

containers:

- args:

- -bigtable。backoff-on-ratelimits=true

- -bigtable。grpc-client-rate-limit=5

- -bigtable。grpc-client-rate-limit-burst=5

- -bigtable。table-cache。enabled=true

- -config。file=/etc/loki/config/config。yaml

- -limits。per-user-override-config=/etc/loki/overrides/overrides。yaml

- -target=table-manager

image: grafana/loki:1。6。1

imagePullPolicy: IfNotPresent

name: table-manager

ports:

- containerPort: 3100

name: http-metrics

- containerPort: 9095

name: grpc

readinessProbe:

httpGet:

path: /ready

port: 3100

initialDelaySeconds: 15

timeoutSeconds: 1

resources:

limits:

cpu: 200m

memory: 200Mi

requests:

cpu: 100m

memory: 100Mi

volumeMounts:

- mountPath: /etc/loki/config

name: loki

volumes:

- configMap:

name: loki

name: loki

——-

apiVersion: v1

kind: Service

metadata:

labels:

app: table-manager

name: table-manager

namespace: loki

spec:

ports:

- name: table-manager-grpc

port: 9095

targetPort: 9095

selector:

app: table-manager

部署完成之後,可以檢視所有pod執行狀態:

kubectl get pods -n loki

NAME READY STATUS RESTARTS AGE

distributor-84747955fb-hhtzl 1/1 Running 0 8d

distributor-84747955fb-pq9wn 1/1 Running 0 8d

distributor-84747955fb-w66hp 1/1 Running 0 8d

ingester-0 1/1 Running 0 8d

ingester-1 1/1 Running 0 8d

ingester-2 1/1 Running 0 8d

memcached-0 2/2 Running 0 3d2h

memcached-1 2/2 Running 0 3d2h

memcached-2 2/2 Running 0 3d2h

memcached-frontend-0 2/2 Running 0 3d2h

memcached-frontend-1 2/2 Running 0 3d2h

memcached-frontend-2 2/2 Running 0 3d2h

memcached-index-queries-0 2/2 Running 0 3d2h

memcached-index-queries-1 2/2 Running 0 3d2h

memcached-index-queries-2 2/2 Running 0 3d2h

memcached-index-writes-0 2/2 Running 0 3d3h

memcached-index-writes-1 2/2 Running 0 3d3h

memcached-index-writes-2 2/2 Running 0 3d3h

querier-0 1/1 Running 0 3d3h

querier-1 1/1 Running 0 3d3h

querier-2 1/1 Running 0 3d3h

query-frontend-6c8ffc8667-qj5zq 1/1 Running 0 8d

table-manager-c4fdf6475-zjzqg 1/1 Running 0 8d

至此,部署工作完成。至於promtail外掛,本文不作介紹,目前支援loki資料來源的外掛比較多,比如fluent bit 等。

視覺化

Grafana已經透過Explore元件支援對loki直接查詢。

基於Loki打造雲原生分散式日誌系統

透過標籤組合來實現查詢。

總結

如果對全文索引不是強需求,那麼loki是k8s 日誌系統的一個比較好的選擇。