背景介绍
作为线上定位问题和排查故障的重要手段,日志在可观测领域有着不可替代的作用。因此,日志系统需要追求稳定性、性能、成本、易用性、可扩展性等关键点。
目前公司的日志系统是基于ELK的,支持云主机日志采集、容器日志采集和特殊分类日志的综合采集等功能。但是随着公司的业务发展,日志应用场景逐渐遇到了一些瓶颈:
数据增长和处理需求增加:业务的不断扩张和数据量的增加,原有的日志系统无法满足现有的数据处理需求。数据处理速度变慢,存储空间不足等问题。
数据质量和可靠性要求提高:日志数据对于公司业务和运维至关重要,因此数据质量和可靠性要求越来越高。原有的日志系统存在日志丢失、日志收集慢等问题,需要进行改进。
现状: 运行了多套ES 集群,需要的硬件和维护成本很高,通过扩容的方法去满足业务场景,ES集群会太大会变动不稳定,创建独立集群,也需要更高成本,两者都会使得成本和维护工作量剧增。
鉴于这些问题,开始探索新的日志系统架构,以彻底解决上面的问题。
关键需求
- 功能
高效支持聚合查询
支持多区域和跨租户查询 - 效率和维护
降低成本,并能处理 10 倍规模的问题
提高可靠性,简化操作 - 从 ELK 平台透明迁移
兼容性:能够无缝迁移现有的ELK平台的数据,无需进行大量修改
最好用户可以继续使用类Kibana 来交互分析日志 - 增强日志系统的完整性
高性能采集器:采用高性能的采集器,提高日志收集的速度,降低数据采集延迟。
并行处理:采用并行处理的方式,同时处理多个日志数据流,提高数据处理速度和效率。
新架构体系
日志存储选择clickhouse的原因
- 具有高写入吞吐量
- 具有高吞吐量的单个大查询能力
- 服务器成本更低
- 更稳定,运维成本更低
- ClickHouse 采用 SQL 语法,比 ES 的 DSL 更加简单,学习成本更低。
在原生Kibana跟ElasticSearch之间新增一层Proxy,该Proxy来做ElasticSearch跟ClickHouse的语法转换,如图:
CKibana 该Proxy负责将图表请求转换成ClickHouse语法查询到ClickHouse结果后模拟成ElasticSearch响应返回给Kibana,这样就可以直接在原生Kibana上面展示ClickHouse中的数据
CKibana: github.com/TongchengOp…
K8S on CKibana部署
准备环境
- Kibana: 用来提供给业务做UI展示
- ElasticSearch: 用来做kibana元数据存储+查询缓存等高级特性
- ClickHouse: 日志数据存储
- CKibana: 提供Proxy等高级功能,实现让用户直接在原生Kibana上查询ClickHouse数据
部署ElasticSearch
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch
spec:
serviceName: elasticsearch
replicas: 1
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
containers:
- name: elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
env:
- name: discovery.type
value: single-node
- name: cluster.name
value: my-cluster
- name: xpack.security.enabled
value: "true"
- name: network.host
value: "0.0.0.0"
- name: ES_JAVA_OPTS
value: "-Xms512m -Xmx512m"
ports:
- containerPort: 9200
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
spec:
type: NodePort
ports:
- port: 9200
targetPort: 9200
nodePort: 30200
selector:
app: elasticsearch
部署 elasticsearch:
kubectl apply -f elasticsearch.yaml
部署完之后通过如下命令查看 pod 启动情况:
kubectl get pod -n default
查找到 pod 后,通过如下命令进入 elasticsearch 的 pod:
kubectl exec -it elasticsearch-0 -n default -- bash
部署完成后进入 pod 后执行如下命令,根据提示设置初始密码
/usr/share/elasticsearch/bin/elasticsearch-setup-passwords interactive
部署ckibana
apiVersion: apps/v1
kind: Deployment
metadata:
name: ckibana
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: ckibana
template:
metadata:
labels:
app: ckibana
spec:
containers:
- name: ckibana
image: ting001/ckibana:1.0.5
args: [ "java", "-jar","-Dspring.config.location=/wd/application.yaml","app.jar" ]
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: "5"
memory: 5Gi
requests:
cpu: "1"
memory: 1Gi
volumeMounts:
- name: ckibana-application-config
mountPath: /wd/application.yaml
subPath: application.yaml
volumes:
- name: ckibana-application-config
configMap:
name: ckibana-application-config
tolerations:
- effect: NoSchedule
key: log
operator: Exists
---
apiVersion: v1
kind: Service
metadata:
name: ckibana
namespace: default
labels:
app: ckibana
spec:
selector:
app: ckibana
ports:
- port: 8080
protocol: TCP
targetPort: 8080
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ckibana-application-config
namespace: default
data:
application.yaml: |-
spring:
application:
name: ckibana
server:
port: 8080
logging:
config: classpath:logback-spring.xml
file:
path: logs
metadata-config:
hosts: http://elasticsearch.default.svc:9200
headers:
Authorization: Basic ZWxhc3RpYzpwYXNzd29yZA== # echo -ne "elastic:password" | base64
部署 ckibana:
kubectl apply -f ckibana.yaml
部署完之后通过如下命令查看 pod 启动情况:
kubectl get pod -n default
查找到 pod 后,通过如下命令进入 ckibana 的 pod:
kubectl exec -it ckibana-5fb6dc98fb-kp5zl -n default -- bash
部署完成后进入 pod 后配置ck连接信息
全量更新配置接口
curl --location 'localhost:8080/config/all' \
--header 'Content-Type: application/json' \
--data '{
"proxy":{
"roundAbleMinPeriod":120000,
"maxTimeRange":86400000,
"enableMonitoring":true,
"blackIndexList":[],
"whiteIndexList":[
"index1"
],
"es":{
"host": "http://elasticsearch.default.svc:9200",
"headers": {
"Authorization": "yourEsClusterAuthorization"
}
},
"ck":{
"url": "ip:Port",
"user": "yourUserName",
"pass": "yourPass",
"defaultCkDatabase": "yourCkDatabaseName"
}
}
}'
获取配置接口
curl --location 'localhost:8080/config/all'
部署kibana
apiVersion: apps/v1
kind: Deployment
metadata:
name: kibana
spec:
replicas: 1
selector:
matchLabels:
app: kibana
template:
metadata:
labels:
app: kibana
spec:
containers:
- name: kibana
image: docker.elastic.co/kibana/kibana:8.12.0
env:
- name: ELASTICSEARCH_HOSTS
value: "http://ckibana.default.svc:8080"
- name: NODE_OPTIONS
value: "--max-old-space-size=1800"
volumeMounts:
- name: kibana-config
mountPath: /usr/share/kibana/config/kibana.yml
readOnly: true
subPath: kibana.yml
ports:
- containerPort: 5601
volumes:
- name: kibana-config
configMap:
name: kibana
---
kind: Service
apiVersion: v1
metadata:
name: kibana
spec:
selector:
app: kibana
ports:
- protocol: TCP
port: 5601
targetPort: 5601
nodePort: 30011
type: NodePort
---
apiVersion: v1
kind: ConfigMap
metadata:
name: kibana
labels:
k8s-app: kibana
data:
kibana.yml: |-
server.name: kibana
server.host: "0.0.0.0"
elasticsearch.hosts: [ "http://ckibana.default.svc:8080" ]
elasticsearch.username: "kibana"
elasticsearch.password: "password"
elasticsearch.ssl.verificationMode: none
monitoring.ui.container.elasticsearch.enabled: true
部署 kibana:
kubectl apply -f kibana.yaml
部署完之后通过如下命令查看 pod 启动情况:
kubectl get pod -n default