.NET Core + K8S + Loki 玩转日志聚合

1. Intro
最近在了解日志聚合系统,正好前几天看到一篇文章《用了日志系统新贵Loki,ELK突然不香了!》,所以就决定动手体验一下。本文就带大家快速了解下Loki,并简单介绍.NET Core如何集成Loki。
2. What's Loki Stack
Grafana Loki like Prometheus, but for logs。其是一个水平可扩展,高可用性,多租户的日志聚合系统,基于Apatch 2.0开源。其有三部分组成:
- Loki 是主服务器,负责存储日志和处理查询。对标ELK中的ElasticSearch。
- Promtail 是代理,负责收集日志并将其发送给loki。对标ELK中的Logstash。
- Grafana提供用户界面。对标ELK中的Kibana。

3. Why Use Loki
日志聚合系统的目的是为了方便我们进行日志跟踪和故障排查,尤其在云原生的环境之下。目前主流的日志聚合系统,当数ELK、EFK和Loki。Loki相较于ELK Stack有以下优势:
Elasticsearch中的数据作为非结构化JSON对象存储在磁盘上,Loki以二进制的形式存储。
Elasticsearch采用全文索引,倒排索引的切分和共享的成本较高。Loki仅索引元数据,比如标签。
和Prometheus无缝集成。
4. How Use Loki
首先我们先来基于Heml安装Loki到本地K8S集群。
1. 添加Loki Chart 仓库:
PS C:\Users\Shengjie> helm repo add loki https://grafana.github.io/loki/charts
"loki" has been added to your repositories
PS C:\Users\Shengjie> helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "stable" chart repository
...Successfully got an update from the "loki" chart repository
Update Complete. ⎈ Happy Helming!⎈
2. 安装Loki Stack
PS C:\Users\Shengjie> helm search hub loki-stack
URL CHART VERSION APP VERSION DESCRIPTION
https://hub.helm.sh/charts/loki/loki-stack 0.38.3 v1.5.0 Loki: like Prometheus, but for logs.
PS C:\Users\Shengjie> helm show values loki/loki-stack
loki:
enabled: true
promtail:
enabled: true
fluent-bit:
enabled: false
grafana:
enabled: false
sidecar:
datasources:
enabled: true
image:
tag: 6.7.0
prometheus:
enabled: false
filebeat:
enabled: false
filebeatConfig:
filebeat.yml: |
# logging.level: debug
filebeat.inputs:
- type: container
paths:
- /var/log/containers/*.log
processors:
- add_kubernetes_metadata:
host: ${NODE_NAME}
matchers:
- logs_path:
logs_path: "/var/log/containers/"
output.logstash:
hosts: ["logstash-loki:5044"]
logstash:
enabled: false
image:
repository: grafana/logstash-output-loki
tag: 1.0.1
filters:
main: |-
filter {
if [kubernetes] {
mutate {
add_field => {
"container_name" => "%{[kubernetes][container][name]}"
"namespace" => "%{[kubernetes][namespace]}"
"pod" => "%{[kubernetes][pod][name]}"
}
replace => { "host" => "%{[kubernetes][node][name]}"}
}
}
mutate {
remove_field => ["tags"]
}
}
outputs:
main: |-
output {
loki {
url => "http://loki:3100/loki/api/v1/push"
#username => "test"
#password => "test"
}
# stdout { codec => rubydebug }
}
从上面的Values中,可以看出,可以自定义启用fluent-bit、grafana、filebeat、prometheus、logstash组件。这里我们仅启用grafana日志界面。
PS C:\Users\Shengjie> helm install loki-stack loki/loki-stack --set grafana.enabled=true
coalesce.go:165: warning: skipped value for filters: Not a table.
coalesce.go:165: warning: skipped value for filters: Not a table.
NAME: loki-stack
LAST DEPLOYED: Sun Jul 26 11:58:11 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
The Loki stack has been deployed to your cluster. Loki can now be added as a datasource in Grafana.
See http://docs.grafana.org/features/datasources/loki/ for more detail.
3. 登录Grafana
首先确认Loki是否成功部署:
PS C:\Users\Shengjie> helm list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
loki-stack default 1 2020-07-26 11:58:11.022896 +0800 CST deployed loki-stack-0.38.3 v1.5.0
PS C:\Users\Shengjie> kubectl get pod -w
NAME READY STATUS RESTARTS AGE
loki-stack-0 1/1 Running 0 2m33s
loki-stack-grafana-c447cfbd-z6tbg 1/1 Running 0 2m33s
loki-stack-promtail-j47hl 1/1 Running 0 2m33s
PS C:\Users\Shengjie> kubectl get svc -w
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 56d
loki-stack ClusterIP 10.110.83.209 <none> 3100/TCP 2m52s
loki-stack-grafana ClusterIP 10.111.24.26 <none> 80/TCP 2m52s
loki-stack-headless ClusterIP None <none> 3100/TCP 2m52s
从上面可知,已经成功启动,其中loki暴露的容器端口为3100,grafana暴露的端口为80。
因此我们下一步需要进行端口转发,才能访问grafana。
PS C:\Users\Shengjie> kubectl port-forward svc/loki-stack-grafana 3000:80
Forwarding from 127.0.0.1:3000 -> 3000
Forwarding from [::1]:3000 -> 3000
然后本地浏览器打开http://localhost:3000/就可以访问了。
其默认用户是admin,默认密码在哪里呢,别慌,我们去看下loki-stack chart 的readme:
PS C:\Users\Shengjie> helm show readme loki/loki-stack
# Loki-Stack Helm Chart
## Prerequisites
Make sure you have Helm [installed](https://helm.sh/docs/using_helm/#installing-helm) and
[deployed](https://helm.sh/docs/using_helm/#installing-tiller) to your cluster. Then add
Loki's chart repository to Helm:
$ helm repo add loki https://grafana.github.io/loki/charts
You can update the chart repository by running:
$ helm repo update
## Deploy Loki and Promtail to your cluster
### Deploy with default config
$ helm upgrade --install loki loki/loki-stack
### Deploy in a custom namespace
$ helm upgrade --install loki --namespace=loki-stack loki/loki-stack
### Deploy with custom config
$ helm upgrade --install loki loki/loki-stack --set "key1=val1,key2=val2,..."
## Deploy Loki and Fluent Bit to your cluster
$ helm upgrade --install loki loki/loki-stack \
--set fluent-bit.enabled=true,promtail.enabled=false
## Deploy Grafana to your cluster
The chart loki-stack contains a pre-configured Grafana, simply use `--set grafana.enabled=true`
To get the admin password for the Grafana pod, run the following command:
$ kubectl get secret --namespace <YOUR-NAMESPACE> loki-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
To access the Grafana UI, run the following command:
$ kubectl port-forward --namespace <YOUR-NAMESPACE> service/loki-grafana 3000:80
Navigate to http://localhost:3000 and login with `admin` and the password output above.
Then follow the [instructions for adding the loki datasource](/docs/getting-started/grafana.md), using the URL `http://loki:3100/`
上面已经说了很清楚了,可以从secret中获取。
如果在windows powersheel中执行,需要分两步:
1. 先获取base64加密的密码
PS C:\Users\Shengjie> $pwd= kubectl get secret --namespace default loki-stack-grafana -o jsonpath="{.data.admin-password}"
2. decode base64
PS C:\Users\Shengjie> [Text.Encoding]::Utf8.GetString([Convert]::FromBase64String($pwd))
CjnbkkQmwQynZ96gCsynSf0elYQLOp4dyuDnp9jJ
------------------------
Linux命令行执行:
shengjie@Thinkpad:/mnt/c/Users/Shengjie$ kubectl get secret --namespace default loki-stack-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
CjnbkkQmwQynZ96gCsynSf0elYQLOp4dyuDnp9jJ
然后使用admin/CjnbkkQmwQynZ96gCsynSf0elYQLOp4dyuDnp9jJ即可成功登录http://localhost:3000/。

5. Use Loki With .NET Core
下一步,我们就来创建一个ASP.NET Core Web 应用,将日志记录到Loki,并通过Grafana进行聚合分析。
PS C:\Users\Shengjie> dotnet new web -n Loki.K8s.Demo
The template "ASP.NET Core Empty" was created successfully.
Processing post-creation actions...
Running 'dotnet restore' on Loki.K8s.Demo\Loki.K8s.Demo.csproj...
Determining projects to restore...
Restored C:\Users\Shengjie\Loki.K8s.Demo\Loki.K8s.Demo.csproj (in 150 ms).
Restore succeeded.
PS C:\Users\Shengjie> cd .\Loki.K8s.Demo\
# 添加Serilog.AspNetCore和Serilog.Sinks.Loki Nuget包。
PS C:\Users\Shengjie\Loki.K8s.Demo> dotnet add package Serilog.AspNetCore
PS C:\Users\Shengjie\Loki.K8s.Demo> dotnet add package Serilog.Sinks.Loki
从上可知,日志组件选用的是Serilog,因为其支持持久化日志到Loki。
修改Program.cs如下:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
}).UseSerilog((ctx, cfg) =>
{
//cfg.MinimumLevel.Override("Microsoft", LogEventLevel.Warning);//Microsoft框架本身的日志,仅输出Warning以上级别
cfg.Enrich.FromLogContext()
.Enrich.WithProperty("App", ctx.HostingEnvironment.ApplicationName)
.Enrich.WithProperty("ENV", ctx.HostingEnvironment.EnvironmentName)
.WriteTo.LokiHttp(new NoAuthCredentials("http://localhost:3100"))//配置Loki Url和认证方式
.WriteTo.Console();
});
修改Startup.cs的Configure方法如下:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,ILogger<Startup> logger)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
logger.LogInformation("start handle request!");
await context.Response.WriteAsync("Hello World!");
logger.LogInformation("end handle request!");
});
});
}
因为不想把应用打包成镜像运行到K8S中,所以我们需要把K8S的Loki服务做一次端口转发暴露到本机,转发后,就可以使用http://localhost:3100作为Loki的Url进行日志写入啦。
PS C:\Users\Shengjie\Loki.K8s.Demo> kubectl port-forward svc/loki-stack 3100:3100
Forwarding from 127.0.0.1:3100 -> 3100
Forwarding from [::1]:3100 -> 3100
运行项目后,重新打开Grafana,添加过滤条件,就可以查看应用日志了。

参考资料:
.NET Core + K8S + Loki 玩转日志聚合的更多相关文章
- .Net Core with 微服务 - Seq 日志聚合
上一次我们介绍并演示了如果使用 Consul 做为我们微服务的注册中心,来实现服务的注册与发现.那么本次我们讲会演示如何做日志聚合.日志聚合比较常用的有 ELK 等,但是这次我想要介绍的是一款比较小众 ...
- .NET Core + K8S + Apollo 玩转配置中心
1.引言 Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置管理 ...
- Kubernetes-20:日志聚合分析系统—Loki的搭建与使用
日志聚合分析系统--Loki 什么是Loki? Loki 是 Grafana Labs 团队最新的开源项目,是一个水平可扩展,高可用性,多租户的日志聚合系统.它的设计非常经济高效且易于操作,因为它不会 ...
- 日志聚合工具loki
目录 1.loki是什么 2.loki特点 3.loki组成 4.loki安装 4.1.添加helm的chart库 4.2.安装loki及promtail 4.3.安装grafana 5.配置和使用 ...
- 记录这两年是如何一步一步转型到.net core+k8s
2017年12月份,我离开北京,回到了武汉,开始在现在这家公司担任架构师工作.经过2年的时间,逐步完成以.net core+k8s为核心的技术架构.文末有彩蛋. 以下整理这两年的主要时间节点: 201 ...
- asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程
最近在学习张善友老师的NanoFabric 框架的时了解到Exceptionless : https://exceptionless.com/ !因此学习了一下这个开源框架!下面对Exceptionl ...
- Net Core平台灵活简单的日志记录框架NLog+SqlServer初体验
Net Core平台灵活简单的日志记录框架NLog+SqlServer初体验 前几天分享的"[Net Core平台灵活简单的日志记录框架NLog+Mysql组合初体验][http://www ...
- Net Core平台灵活简单的日志记录框架NLog+Mysql组合初体验
Net Core平台灵活简单的日志记录框架NLog初体验 前几天分享的"[Net Core集成Exceptionless分布式日志功能以及全局异常过滤][https://www.cnblog ...
- yarn配置日志聚合
[原文地址] 日志聚集是YARN提供的日志中央化管理功能,它能将运行完成的Container/任务日志上传到HDFS上,从而减轻NodeManager负载,且提供一个中央化存储和分析机制.默认情况下, ...
随机推荐
- dart快速入门教程 (2)
2.变量和数据类型 2.1.变量和常量 变量通俗的说就是可以变化的量,作用就是用来存储数据,你可以把一个变量看作是一个水果篮,里面可以装苹果.梨.香蕉等,常量就是一个固定的值,和变量是相对的,变量可以 ...
- jQurey zTree API 3.5
https://jeesite.gitee.io/front/jquery-ztree/3.5/api/API_cn.html
- nginx配置奇怪问题记录
执行 nginx -t 检查配置报了如下错误: 下面是配置信息 遇到个很奇怪的问题,plm-api-stage 这么配置就可以正常校验过,但是改成 plm-stage-api,就会上面的警告信息: ...
- Android详细介绍MPAndroidChart-LineChart
在开发当中曲线图用的时候太多了,之前都是自己手写,之后发现太累还丑不符合需求 MPAndroidChart 先介绍LineChart 0.效果图 首先依赖 1. implementation 'co ...
- 关于前端数据&逻辑的思考
最近重构了一个项目,一个基于redux模型的react-native项目,目标是在混乱的代码中梳理出一个清晰的结构来,为了实现这个目标,首先需要对项目的结构做分层处理,将各个逻辑分离出来,这里我是基于 ...
- 面试必杀技,讲一讲Spring中的循环依赖
本系列文章: 听说你还没学Spring就被源码编译劝退了?30+张图带你玩转Spring编译 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configu ...
- appium升级操作
在app自动化测试中经常会碰到,因为appium版本低而导致,appium客户端连接不到appium服务端等一系列错误~ 其实appium升级很简单的哦~ 打开cmd命令行终端,键入npm updat ...
- 微信小程序开发中遇到的几个小问题
本地图片不显示,开发工具运行是没问题的,但真机调试却显示不了 item.img = '/goods/img/图片.png' <image src="{{item.img}}" ...
- JVM 专题二十二:垃圾回收(六)垃圾回收器 (三)
4. GC日志分析 4.1 日志分析 通过阅读GC日志,我们可以了解Java虚拟机内存分配与回收策略. 内存分配与垃圾回收的参数列表-XX:+PrintGC:输出GC日志.类似-verbose: gc ...
- vue axios接口封装、Promise封装、简单的axios方法封装、vue接口方法封装、vue post、get、patch、put方法封装
相信大家在做前后端数据交互的时候都会给请求做一些简单的封装就像之前封装ajax方法一样axios的封装也是一样的简单下面这个就是封装的axios的方法,require.js import axios ...