零、EFK架构及参考文章
注:这个教程只在aws或者本地自己搭建的k8s集群有效,如果使用的是serverless的k8s,例如:阿里云,腾讯云购买的K8s集群的话,并不适用,因为serverless的集群并没有node的概念,无法部署daemonset。
1.EFK架构
我们将 Kubernetes 集群作为一个整体,那么我们将需要统一收集日志。但是 Kubernetes 并不提供任何日志收集功能,因此您需要设置一个集中的日志后端(例如: Elasticsearch) ,并将所有日志发送到日志后端。下面的图像描绘了一个 high-level 的 Kubernetes Logging 架构。
我最后将EFK中的Fluentd替换成了Fluent-bit,理由如下:
Fluentd和Fluent Bit都可以用作聚合器或转发器,它们可以相互补充或用作独立解决方案。近年来,出于性能和兼容性原因,云提供商从 Fluentd 转向 Fluent Bit。Fluent Bit 现在被认为是下一代解决方案。
2.参考文章
K8S日志通过fluent-bit采集到ES并在Kibana上查询:https://mafgwo.cn/2021/07/09/2028_k8s-fluent-bit/
ElasticSearch+Kibana on K8s 讲解与实战操作(版本7.17.3):https://juejin.cn/post/7276675247597617163#heading-19
这篇文章最主要的是讲解了ElasticSearch常见API实例讲解
es对日志数据进行索引生命周期管理:https://blog.csdn.net/w1014074794/article/details/120670909
ELK入门——解决:Kibana的Stack Monitoring显示节点offline:https://blog.csdn.net/Netceor/article/details/113616029
Kubernetes 集群日志 和 EFK 架构日志方案:https://www.cnblogs.com/whuanle/p/15893923.html
FK-ELK日志架构系列3:Kibana用户角色权限之配置用户访问指定日志:https://blog.csdn.net/welcome66/article/details/107224840
kibana 开发工具常用命令:http://t.csdnimg.cn/ruaSF
3.日志采集方式
日志作为任一系统不可或缺的部分,在K8S的官方文档中也介绍了多种的日志采集形式,总结起来主要有下述3种:原生方式、DaemonSet方式和Sidecar方式。
-
原生方式:使用 kubectl logs 直接在查看本地保留的日志,或者通过docker engine的 log driver 把日志重定向到文件、syslog、fluentd等系统中。
-
DaemonSet方式:在K8S的每个node上部署日志agent,由agent采集所有容器的日志到服务端。
-
Sidecar方式:一个POD中运行一个sidecar的日志agent容器,用于采集该POD主容器产生的日志
DaemonSet确保全部(或者某些)节点上运行一个Pod副本。当有新节点加入集群时,也会为它们新增一个Pod。当节点从集群中移除时,这些Pod也会被回收,删除DaemonSet将会删除它创建的所有Pod
使用DaemonSet的一些典型用法:
运行集群存储daemon(守护进程),例如在每个节点上运行Glusterd、Ceph等
在每个节点运行日志收集daemon,例如Fluentd、Logstash、Fluent-bit
在每个节点运行监控daemon,比如Prometheus Node Exporter等
简单来说,原生方式和DaemonSet属于非侵入式采集,而Sidecar属于侵入式采集
一、部署elasticsearch
1.介绍
Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎,能够解决不断涌现出的各种用例。 作为Elastic Stack 的核心,Elasticsearch 会集中存储您的数据,让您飞快完成搜索,微调相关性,进行强大的分析,并轻松缩放规模。
2.部署流程
-
拉取Elastic的helm
# 添加 Elastic Helm charts repo helm repo add elastic https://helm.elastic.co # 拉取 helm pull elastic/elasticsearch --version=7.17.3 --untar
-
如果是在本地部署的话,需要提前创建pv和pvc
### 创建pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: pv-logging-efk-1 spec: capacity: storage: 20Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: logging-efk hostPath: path: "/mnt/data1" --- apiVersion: v1 kind: PersistentVolume metadata: name: pv-logging-efk-2 spec: capacity: storage: 20Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: logging-efk hostPath: path: "/mnt/data2" --- apiVersion: v1 kind: PersistentVolume metadata: name: pv-logging-efk-3 spec: capacity: storage: 20Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: logging-efk hostPath: path: "/mnt/data3" ### 创建pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: logging-efk-v1 spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi storageClassName: logging-efk
-
修改values.yaml
clusterName: "elasticsearch" nodeGroup: "master" masterService: "elasticsearch-master" roles: master: "true" ingest: "true" data: "true" remote_cluster_client: "true" ml: "true" replicas: 3 minimumMasterNodes: 2 esMajorVersion: "" clusterDeprecationIndexing: "false" esConfig: { } esJvmOptions: { } extraEnvs: [] envFrom: [] secret: enabled: true password: "novastar" secretMounts: [] hostAliases: [] image: "docker.elastic.co/elasticsearch/elasticsearch" imageTag: "7.17.3" imagePullPolicy: "IfNotPresent" podAnnotations: { } labels: { } esJavaOpts: "-Xmx1g -Xms1g" # example: "-Xmx1g -Xms1g" resources: requests: cpu: "1000m" memory: "2Gi" limits: cpu: "1000m" memory: "2Gi" initResources: { } networkHost: "0.0.0.0" volumeClaimTemplate: accessModes: ["ReadWriteOnce"] resources: requests: storage: 20Gi storageClassName: "logging-efk" rbac: create: false serviceAccountAnnotations: { } serviceAccountName: "" automountToken: true podSecurityPolicy: create: false name: "" spec: privileged: true fsGroup: rule: RunAsAny runAsUser: rule: RunAsAny seLinux: rule: RunAsAny supplementalGroups: rule: RunAsAny volumes: - secret - configMap - persistentVolumeClaim - emptyDir # 开启持久化存储 persistence: enabled: true existingClaim: "logging-efk-v1" labels: enabled: false annotations: { } extraVolumes: [] extraVolumeMounts: [] extraContainers: [] extraInitContainers: [] priorityClassName: "" antiAffinityTopologyKey: "kubernetes.io/hostname" antiAffinity: "hard" nodeAffinity: { } podManagementPolicy: "Parallel" enableServiceLinks: true protocol: http httpPort: 9200 transportPort: 9300 # type这里使用的是LoadBalancer, service: enabled: true labels: { } labelsHeadless: { } type: LoadBalancer publishNotReadyAddresses: false nodePort: "" annotations: { } httpPortName: http transportPortName: transport loadBalancerIP: "" loadBalancerSourceRanges: [] externalTrafficPolicy: "" updateStrategy: RollingUpdate maxUnavailable: 1 podSecurityContext: fsGroup: 1000 runAsUser: 1000 securityContext: capabilities: drop: - ALL runAsNonRoot: true runAsUser: 1000