kubernetes(二十二)addons-EFK日志处理
前言
kubernetes官方默认给我们提供了很多addons,其中就包括了日志处理套件EFK,包括 Elasticsearch, Fluentd 和 Kibana三个组件。其中Elasticsearch是搜索引擎,负责存储日志并对外提供日志的查询功能;Fluentd是一个日志收集组件,负责收集集群中的日志、并发送给Elasticsearch;Kibana是一个图形化展示组件,负责从Elasticsearch中查询日志,并以适当的形式展示出来
部署EFK
-
下载对应的启动文件
$ cd /opt/k8s/work/efk $ for file in es-service.yaml es-statefulset.yaml fluentd-es-configmap.yaml fluentd-es-ds.yaml kibana-deployment.yaml kibana-service.yaml; do wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/fluentd-elasticsearch/$file done
-
Elasticsearch 以statefulset形式启动。对应的镜像中不包含Es的安全插件 X-Pack。因为es要求
vm.max_map_count
的值不能小于262144,所以对应的启动文件es-statefulset.yaml中有一个init container,在es容器启动前设置vm.max_map_count
。如果系统中这个值已经设置过,可以把这个init container相关的配置去掉,通过以下命令可以查看vm.max_map_count
的值$ more /proc/sys/vm/max_map_count
-
Storage es-statefulset.yaml启动文件中es的存储配置的是EmptyDir,所以在es重启时存储的数据会丢失,因此直接下载的文件只使用于测试,如果想在生产环境使用,要替换成永久存性的存储卷。
-
Fluentd 以DaemonSet形式启动,会在所有节点上启动一个pod,依据fluentd-es-configmap.yaml中的配置会读取kubelet、container的日志,发送给es。
-
此addon中启动文件,不要直接在生产环境中使用,如果想在生产环境中使用,推荐用 Helm来安装这些组件,对应的helm地址如下
-
-
修改启动文件中对应的镜像地址
启动文件中默认的镜像Registry是quay.io,国内无法直接下载,此处用微软的Registry代替
$ sed -i -e 's_quay.io_quay.azk8s.cn_' es-statefulset.yaml $ sed -i -e 's_quay.io_quay.azk8s.cn_' fluentd-es-ds.yaml
-
启动EFK
$ kubectl apply -f .
以上通过Kubernetes提供的EFK进行日志收集的部署就完成了。不过由于我在自己测试环境执行时由于资源限制,ES无法同时启动两个,而Kubernetes提供的这个ES镜像,至少需要两个组建成集群才能正常使用,所以,只能采用ES官方的镜像自己搭建EFK环境。
单节点ElasticSearch部署EFK
部署Elasticsearch
-
编辑启动文件
-
es配置文件
$ cat >docker.es.co-configmap.yaml<<EOF kind: ConfigMap apiVersion: v1 metadata: name: es-config-v7.6.1 namespace: kube-system labels: addonmanager.kubernetes.io/mode: Reconcile data: elasticsearch.yml: |- cluster.name: kubernetes-logging node.name: elasticsearch-logging-0 path.data: /data discovery.type: single-node network.host: 0.0.0.0 EOF
- discovery.type: single-node,代表对应的es是单节点集群
- network.host: 0.0.0.0 任意IP都可以访问
-
es启动文件
$ cat >docker.es.co-statefulset.yml<<EOF # Elasticsearch deployment itself apiVersion: apps/v1 kind: StatefulSet metadata: name: elasticsearch-logging namespace: kube-system labels: k8s-app: elasticsearch-logging version: v7.4.2 addonmanager.kubernetes.io/mode: Reconcile spec: serviceName: elasticsearch-logging replicas: 1 selector: matchLabels: k8s-app: elasticsearch-logging version: v7.4.2 template: metadata: labels: k8s-app: elasticsearch-logging version: v7.4.2 spec: #serviceAccountName: elasticsearch-logging containers: - image: elasticsearch:7.6.1 name: elasticsearch-logging #imagePullPolicy: Always resources: # need more cpu upon initialization, therefore burstable class limits: cpu: 1000m memory: 4Gi requests: cpu: 100m memory: 1Gi ports: - containerPort: 9200 name: db protocol: TCP - containerPort: 9300 name: transport protocol: TCP #livenessProbe: #tcpSocket: # port: transport #initialDelaySeconds: 5 #timeoutSeconds: 10 # readinessProbe: #tcpSocket: # port: transport #initialDelaySeconds: 5 #timeoutSeconds: 10 volumeMounts: - name: elasticsearch-logging mountPath: /data - name: config-volume mountPath: /usr/share/elasticsearch/config/elasticsearch.yml subPath: elasticsearch.yml env: - name: "NAMESPACE" valueFrom: fieldRef: fieldPath: metadata.namespace volumes: - name: elasticsearch-logging emptyDir: {} - name: config-volume configMap: name: es-config-v7.6.1 EOF
相比较kubernetes给我们提供的启动文件,此处主要做了两点改变
- 删除了权限相关部分,不需要进行服务发现组件集群了。
- 镜像文件换成了elasticsearch:7.6.1,是es官方发布在docker hub上的镜像
-
es service文件
$ cat >es-service.yaml<<EOF apiVersion: v1 kind: Service metadata: name: elasticsearch-logging namespace: kube-system labels: k8s-app: elasticsearch-logging kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile kubernetes.io/name: "Elasticsearch" spec: ports: - port: 9200 protocol: TCP targetPort: db selector: k8s-app: elasticsearch-logging EOF
-
-
启动服务
$ kubectl create -f docker.es.co-configmap.yaml $ kubectl create -f docker.es.co-statefulset.yml $ kubectl create -f es-service.yaml
部署fluentd服务
fluentd启动文件和kubernetes给我们提供的没有什么变化,我本地启动时唯一修改的地方是docker日志的目录。在默认情况下,docker日志采用json-file这个日志driver,存储在docker工作目录下的containers目录中,默认的工作目录是/var/lib/docker,所以默认的docker 日志目录是/var/lib/docker/containers,我自己的环境在安装docker时将工作目录修改成了/data/k8s/docker/data,所以需要修改启动中的挂载目录
-
编辑启动文件
-
DaemonSet文件
$ cat>fluentd-es-ds.yaml<<EOF apiVersion: v1 kind: ServiceAccount metadata: name: fluentd-es namespace: kube-system labels: k8s-app: fluentd-es addonmanager.kubernetes.io/mode: Reconcile --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: fluentd-es labels: k8s-app: fluentd-es addonmanager.kubernetes.io/mode: Reconcile rules: - apiGroups: - "" resources: - "namespaces" - "pods" verbs: - "get" - "watch" - "list" --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: fluentd-es labels: k8s-app: fluentd-es addonmanager.kubernetes.io/mode: Reconcile subjects: - kind: ServiceAccount name: fluentd-es namespace: kube-system apiGroup: "" roleRef: kind: ClusterRole name: fluentd-es apiGroup: "" --- apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd-es-v3.0.0 namespace: kube-system labels: k8s-app: fluentd-es version: v3.0.0 addonmanager.kubernetes.io/mode: Reconcile spec: selector: matchLabels: k8s-app: fluentd-es version: v3.0.0 template: metadata: labels: k8s-app: fluentd-es version: v3.0.0 # This annotation ensures that fluentd does not get evicted if the node # supports critical pod annotation based priority scheme. # Note that this does not guarantee admission on the nodes (#40573). annotations: seccomp.security.alpha.kubernetes.io/pod: 'docker/default' spec: priorityClassName: system-node-critical serviceAccountName: fluentd-es containers: - name: fluentd-es image: quay.azk8s.cn/fluentd_elasticsearch/fluentd:v3.0.0 env: - name: FLUENTD_ARGS value: --no-supervisor -q resources: limits: memory: 500Mi requests: cpu: 100m memory: 200Mi volumeMounts: - name: varlog mountPath: /var/log - name: varlibdockercontainers mountPath: /data/k8s/docker/data/containers readOnly: true - name: config-volume mountPath: /etc/fluent/config.d ports: - containerPort: 24231 name: prometheus protocol: TCP #livenessProbe: #tcpSocket: # port: prometheus #initialDelaySeconds: 5 #timeoutSeconds: 10 #readinessProbe: #tcpSocket: # port: prometheus #initialDelaySeconds: 5 #timeoutSeconds: 10 terminationGracePeriodSeconds: 30 volumes: - name: varlog hostPath: path: /var/log - name: varlibdockercontainers hostPath: path: /data/k8s/docker/data/containers - name: config-volume configMap: name: fluentd-es-config-v0.2.0 EOF
- 将对应的varlibdockercontainers挂载的hostPath修改成了/data/k8s/docker/data/containers,并且挂载到fluentd容器内的路径也要是/data/k8s/docker/data/containers,要保持一致
-
配置文件,因为配置文件和kubernetes给我们提供的没有做变更,此处不全部贴出,具体内容参考fluentd-es-configmap.yaml,此处只给出source部分的内容,来讲解下前一步为什么我们挂载到fluentd容器内的日志目录要和宿主机保持一致
... <source> @id fluentd-containers.log @type tail path /var/log/containers/*.log pos_file /var/log/es-containers.log.pos tag raw.kubernetes.* read_from_head true <parse> @type multi_format <pattern> format json time_key time time_format %Y-%m-%dT%H:%M:%S.%NZ </pattern> <pattern> format /^(?<time>.+) (?<stream>stdout|stderr) [^ ]* (?<log>.*)$/ time_format %Y-%m-%dT%H:%M:%S.%N%:z </pattern> </parse> </source> ...
这个source部分的配置中,fluentd并不是从我们挂载的容器中的docker日志目录直接拿数据的,而是从/var/log/containers目录下拉取日志数据的(/var/log/是我们将宿主机的/var/log目录挂载进去的),这个是因为,Kubernetes 的kubelet组件在/var/log/目录下创建了一个软链接,并且将pod名称,和container名称也放到这个软连接名称中了,例如
/var/log/containers/fluentd-es-v3.0.0-hvbw7_kube-system_fluentd-es-ef645a4009163b41d596b68d32dbcc921f032549fa168b630d10d0ea2f98eacb.log -> /var/log/pods/kube-system_fluentd-es-v3.0.0-hvbw7_c5269d8e-8543-470a-8599-8ae3a7242a46/fluentd-es/0.log
/var/log/pods/kube-system_fluentd-es-v3.0.0-hvbw7_c5269d8e-8543-470a-8599-8ae3a7242a46/fluentd-es/0.log -> /data/k8s/docker/data/containers/ef645a4009163b41d596b68d32dbcc921f032549fa168b630d10d0ea2f98eacb/ef645a4009163b41d596b68d32dbcc921f032549fa168b630d10d0ea2f98eacb-json.log
kubelet通过这样的链接,读取/var/log/containers下的日志,实际上就会读取到容器内的日志,因为链接的路径信息已经固定,所以在容器内的路径一定要和宿主机中保持一致。
这样做的好处也比较好理解,因为日志文件名称中包含了pod名称,命名空间等kubernetes的信息,在flutented中通过插件很容易就可将这些信息解析出来,便于使用者在kibana中对特定应用的日志进行检索过滤。
-
-
启动fluentd
$ kubectl create -f fluentd-es-configmap.yaml $ kubectl create -f fluentd-es-ds.yaml
部署kibana
-
编辑启动文件
-
deployment文件
cat >cat kibana-deployment.yaml<<EOF apiVersion: apps/v1 kind: Deployment metadata: name: kibana-logging namespace: kube-system labels: k8s-app: kibana-logging addonmanager.kubernetes.io/mode: Reconcile spec: replicas: 1 selector: matchLabels: k8s-app: kibana-logging template: metadata: labels: k8s-app: kibana-logging annotations: seccomp.security.alpha.kubernetes.io/pod: 'docker/default' spec: containers: - name: kibana-logging image: elastic/kibana:7.2.0 resources: # need more cpu upon initialization, therefore burstable class limits: cpu: 1000m requests: cpu: 100m env: - name: ELASTICSEARCH_HOSTS value: http://elasticsearch-logging:9200 - name: SERVER_NAME value: kibana-logging - name: SERVER_BASEPATH value: /api/v1/namespaces/kube-system/services/kibana-logging/proxy - name: SERVER_REWRITEBASEPATH value: "false" ports: - containerPort: 5601 name: ui protocol: TCP EOF
-
service文件
cat >kibana-service.yaml<<EOF apiVersion: v1 kind: Service metadata: name: kibana-logging namespace: kube-system labels: k8s-app: kibana-logging kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile kubernetes.io/name: "Kibana" spec: ports: - port: 5601 protocol: TCP targetPort: ui selector: k8s-app: kibana-logging EOF
-
-
启动kibana
$ kubectl create -f kibana-deployment.yaml $ kubectl create -f kibana-service.yaml
启动kubecrl proxy访问kibana
$ kubectl proxy --accept-hosts='^*$' --address=192.168.0.107
通过界面访问,在浏览器中输入 http://192.168.0.107:8001/api/v1/namespaces/kube-system/services/kibana-logging/proxy/
访问kibana。
初次访问需要先配置index pattern
稍等片刻,之后在Discover界面就可以查看相应的日志
可以看到,除了容器中的日志,还额外追加了许多kubernetes的信息。
原文地址:https://www.cnblogs.com/gaofeng-henu/p/12678901.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ubuntu下利用expect实现screen多窗口开机运行
- hetzner服务器购买和安装debian系统
- 安全通告 | Apache SkyWalking SQL注入漏洞安全风险公告(CVE-2020-13921)
- Cmd Markdown 迁移备份的流程
- PyTorch3:计算图torch.autograph
- spark shell 配置 Kryo 序列化
- Mac里捣腾Kerberos(一)
- Spark on K8S 访问 Kerberized HDFS
- Apache Beam的Docker Demo
- docker login 报错了...
- Spark-Submit 和 K8S Operation For Spark
- Spark的Dockerfile分析
- Spark on Kubernetes在Mac的Demo
- Python的Wand模块
- 机器学习第4天:预测1立方米混凝土抗压强度