kubernetes運維之使用elk Stack收集k8s平臺日誌
目錄:php
1、收集哪些日誌
• k8s系統的組件日誌 好比kubectl get cs下面的組件
master節點上的controller-manager,scheduler,apiserver
node節點上的kubelet,kube-proxy
• k8s Cluster裏面部署的應用程序日誌 java
這裏就造成一個數據流,首選呢就是Beats,後面是Logstach,後面是ES,後面是kibana,因此這個技術棧是很是完善的。而beats系列的組件也不少,好比對網絡數據的採集,對日誌文件的採集,對windos事件的採集,運行時間的採集,而elk這個棧呢,不只僅能夠採集數據日誌,還能採集性能資源的指標,好比CPU,內存,網絡,這裏呢主要使用Filebeat收集日誌文件。監控呢就找專業的去作,好比prometheus。node
話說回來,容器的日誌怎麼收集?mysql
方案一:Node上部署一個日誌收集程序
• DaemonSet方式部署日誌收集程序
• 對本節點/var/log和 /var/lib/docker/containers/
兩個目錄下的日誌進行採集
• Pod中容器日誌目錄掛載到宿主機統一目錄上nginx
也就是my-pod是容器,而後標準輸入輸出到控制檯了,時間上這裏是被docker接管了,落地到一個具體的文件中了,docker會接管標準輸出與標準錯誤輸出,而後寫到一個日誌裏,這裏會起一個日誌採集的agent,去採集這個日誌,而這個張圖,大概意思就是在你每一個的node上部署一個日誌採集器,而後採集pod日誌,標準輸入輸出的目錄,默認是在 /var/lib/docker/containers/ 下面,這個下面是運行當前的容器的讀寫層,裏面就包含了一個日誌,通常就是掛載到分佈式存儲上,要是掛載到宿主機的目錄,也不是很太方便,還要去區別全部的容器。要是使用分佈式存儲,好比器一個pod,直接讓存儲專門存儲日誌這個卷,
掛載到容器中的啓動容器中,每起一個都掛這個卷,最終都會落到上面去,這樣會好一點。web
方案二:Pod中附加專用日誌收集的容器
• 每一個運行應用程序的Pod中增長一個日誌
收集容器,使用emtyDir共享日誌目錄讓
日誌收集程序讀取到。sql
第二種呢就是一種sidecar的模式,就是在你sidecar模式中再增長一個專門去處理那就想要的事情的容器,這就稱爲一個旁路,也就是當前你業務旁邊,給你增長一個容器,處理你業務的日誌的,也就是使用emtyDir讓容器A寫日誌目錄,給共享到這個目錄裏,也就是共享目錄,也就是在宿主機的目錄裏,而後容器B讀取也是掛載這個數據卷,它也能天然讀取當前數據卷內的內容,因此這種狀況呢就附加個Pod就能獲取到日誌了。docker
方案三:應用程序直接推送日誌
• 超出Kubernetes範圍
這個小公司會有些,不過也很少,就是應用程序在代碼裏去修改,直接推送到你遠程的存儲上,再也不輸出到控制檯,本地文件了,直接推,這個就再也不k8s範圍以內了,這種方案用的有很少,用的最多的就是前兩種數據庫
這兩種方案有什麼優缺點?
像方案一就是須要在每臺node節點上去部署一個日誌採集的agent,資源消耗少,通常不須要應用程序的介入,可是它須要經過應用程序寫到標準輸出和標準錯誤輸出,好比tomcat,日誌裏面都是不少行,須要合併成一行才能進行採集,須要轉換成json格式,json在docker方面已經多行分開了,因此不能使用多行匹配了,因此很尷尬。json
像方案二就是在pod中附加專用日誌收集的容器,附加到每一個應用裏面,每一個pod再加一個容器,就加一個鏡像,這種方式低耦合,缺點呢,顯而易見,你部署一個應用,加一個採集器,部署又一個又加一個採集器,就是你要啓動一套項目,須要加一個容器,就是須要資源的消耗了,並增長運維的維護成本,不過運維維護成本也還好,主要增長資源的消耗比較大一點。
第三種方案,就是讓開發去改就好了。
咱們使用的是方案二的,附加一個,這個仍是比較好實現的
目前呢咱們使用fileBeat去作日誌的採集,早期呢都是使用logstach去採集,logstach採集呢佔用資源也比較大,自己呢是java寫的,filebeat是Go寫的,資源佔用比較小,java它採集的量一大了,以後消耗槓槓的,因此後面官方將logstach採集功能剝離出來,使用GO重寫了一個filebeat,全部如今用建議使用fileBeat。
這個fek裏面是filebeat,就是部署filebeat,這裏面啓動用對k8s的支持,目前這個適合比較小的數據量,本身寫的yaml,若是你的數據量達到20-30g以上,這個單機的es確定是很難知足的,若是你的日誌量比較大,不建議你把elk部署到k8s中,建議把你的logstack,es,存儲部署到k8s以外,特別是es,建議部署到集羣以外,物理機去組件集羣,kibana能夠部署在k8s 中,可是es是有狀態的部署
[root@k8s-master elk]# ls fek k8s-logs.yaml nginx-deployment.yaml tomcat-deployment.yaml [root@k8s-master elk]# ls fek k8s-logs.yaml nginx-deployment.yaml tomcat-deployment.yaml [root@k8s-master elk]# cd fek/ [root@k8s-master fek]# ls elasticsearch.yaml filebeat-kubernetes.yaml kibana.yaml
[root@k8s-master fek]# cat filebeat-kubernetes.yaml --- apiVersion: v1 kind: ConfigMap metadata: name: filebeat-config namespace: kube-system labels: k8s-app: filebeat data: filebeat.yml: |- filebeat.config: inputs: path: ${path.config}/inputs.d/*.yml reload.enabled: false modules: path: ${path.config}/modules.d/*.yml reload.enabled: false output.elasticsearch: hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}'] --- apiVersion: v1 kind: ConfigMap metadata: name: filebeat-inputs namespace: kube-system labels: k8s-app: filebeat data: kubernetes.yml: |- - type: docker containers.ids: - "*" processors: - add_kubernetes_metadata: in_cluster: true --- apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: filebeat namespace: kube-system labels: k8s-app: filebeat spec: template: metadata: labels: k8s-app: filebeat spec: serviceAccountName: filebeat terminationGracePeriodSeconds: 30 containers: - name: filebeat image: elastic/filebeat:7.3.1 args: [ "-c", "/etc/filebeat.yml", "-e", ] env: - name: ELASTICSEARCH_HOST value: elasticsearch - name: ELASTICSEARCH_PORT value: "9200" securityContext: runAsUser: 0 resources: limits: memory: 200Mi requests: cpu: 100m memory: 100Mi volumeMounts: - name: config mountPath: /etc/filebeat.yml readOnly: true subPath: filebeat.yml - name: inputs mountPath: /usr/share/filebeat/inputs.d readOnly: true - name: data mountPath: /usr/share/filebeat/data - name: varlibdockercontainers mountPath: /var/lib/docker/containers readOnly: true volumes: - name: config configMap: defaultMode: 0600 name: filebeat-config - name: varlibdockercontainers hostPath: path: /var/lib/docker/containers - name: inputs configMap: defaultMode: 0600 name: filebeat-inputs - name: data hostPath: path: /var/lib/filebeat-data type: DirectoryOrCreate --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: filebeat subjects: - kind: ServiceAccount name: filebeat namespace: kube-system roleRef: kind: ClusterRole name: filebeat apiGroup: rbac.authorization.k8s.io --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: filebeat labels: k8s-app: filebeat rules: - apiGroups: [""] # "" indicates the core API group resources: - namespaces - pods verbs: - get - watch - list --- apiVersion: v1 kind: ServiceAccount metadata: name: filebeat namespace: kube-system labels: k8s-app: filebeat ---
[root@k8s-master fek]# cat elasticsearch.yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: elasticsearch namespace: kube-system labels: k8s-app: elasticsearch spec: serviceName: elasticsearch selector: matchLabels: k8s-app: elasticsearch template: metadata: labels: k8s-app: elasticsearch spec: containers: - image: elasticsearch:7.3.1 name: elasticsearch resources: limits: cpu: 1 memory: 2Gi requests: cpu: 0.5 memory: 500Mi env: - name: "discovery.type" value: "single-node" - name: ES_JAVA_OPTS value: "-Xms512m -Xmx2g" ports: - containerPort: 9200 name: db protocol: TCP volumeMounts: - name: elasticsearch-data mountPath: /usr/share/elasticsearch/data volumeClaimTemplates: - metadata: name: elasticsearch-data spec: storageClassName: "managed-nfs-storage" accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 20Gi --- apiVersion: v1 kind: Service metadata: name: elasticsearch namespace: kube-system spec: clusterIP: None ports: - port: 9200 protocol: TCP targetPort: db selector: k8s-app: elasticsearch
[root@k8s-master fek]# cat kibana.yaml apiVersion: apps/v1 kind: Deployment metadata: name: kibana namespace: kube-system labels: k8s-app: kibana spec: replicas: 1 selector: matchLabels: k8s-app: kibana template: metadata: labels: k8s-app: kibana spec: containers: - name: kibana image: kibana:7.3.1 resources: limits: cpu: 1 memory: 500Mi requests: cpu: 0.5 memory: 200Mi env: - name: ELASTICSEARCH_HOSTS value: http://elasticsearch:9200 ports: - containerPort: 5601 name: ui protocol: TCP --- apiVersion: v1 kind: Service metadata: name: kibana namespace: kube-system spec: ports: - port: 5601 protocol: TCP targetPort: ui selector: k8s-app: kibana --- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: kibana namespace: kube-system spec: rules: - host: kibana.ctnrs.com http: paths: - path: / backend: serviceName: kibana servicePort: 5601
[root@k8s-master fek]# kubectl create -f . [root@k8s-master fek]# kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE alertmanager-5d75d5688f-xw2qg 2/2 Running 0 6h32m coredns-bccdc95cf-kqxwv 1/1 Running 2 6d6h coredns-bccdc95cf-nwkbp 1/1 Running 2 6d6h elasticsearch-0 1/1 Running 0 7m15s etcd-k8s-master 1/1 Running 1 6d6h filebeat-8s9cx 1/1 Running 0 7m14s filebeat-xgdj7 1/1 Running 0 7m14s grafana-0 1/1 Running 0 21h kibana-b7d98644-cmg9k 1/1 Running 0 7m15s kube-apiserver-k8s-master 1/1 Running 1 6d6h kube-controller-manager-k8s-master 1/1 Running 2 6d6h kube-flannel-ds-amd64-dc5z9 1/1 Running 1 6d6h kube-flannel-ds-amd64-jm2jz 1/1 Running 1 6d6h kube-flannel-ds-amd64-z6tt2 1/1 Running 1 6d6h kube-proxy-9ltx7 1/1 Running 2 6d6h kube-proxy-lnzrj 1/1 Running 1 6d6h kube-proxy-v7dqm 1/1 Running 1 6d6h kube-scheduler-k8s-master 1/1 Running 2 6d6h kube-state-metrics-6474469878-lkphv 2/2 Running 0 8h prometheus-0 2/2 Running 0 5h6m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/elasticsearch ClusterIP None <none> 9200/TCP 46m service/kibana ClusterIP 10.1.185.95 <none> 5601/TCP 46m service/kube-dns ClusterIP 10.1.0.10 <none> 53/UDP,53/TCP,9153/TCP 6d7h NAME HOSTS ADDRESS PORTS AGE ingress.extensions/kibana kibana.ctnrs.com 80 46m
而後咱們去訪問一下,這裏我是作的測試因此把它的域名寫到了本地的hosts文件進行解析
這裏選擇Explore導入本身的數據
如今數據已經收集到了,看一下它的索引有沒有寫入成功
也就是建立的三個yaml文件以後,默認的建立filebeat索引,這就像數據庫,索引呢查詢到ES裏面的數據庫,索引匹配呢就是讓kibana拿這個索引匹配查看裏面的數據。
建立索引的匹配filebeat,這裏會幫你去匹配因此有filebeat開頭的,由於它是按天天去存儲這個索引的,也就是每一天都有一個命名,因此打個星就能匹配全部,你訪問這個模式就能查看以這個開頭的數據這裏還要點一下保存
這裏添加一個過濾時間的字段,通常使用這個時間戳
而後點最上面的按鈕就能看到數據了。這裏默認的就是使用這個filebeat,要是多個的話,這裏會有一個選擇框,下面的輸出是全部控制檯輸出的
這裏會能夠看一些相關的日誌,好比命名空間,不少
好比看容器的保存路徑下的容器的日誌
還有messages輸出總體的日誌內容,能看出它採用的哪一個命名空間,能看出pod的名稱,node的名稱,也能看出採集的日誌
好比單獨看一些想要的日誌,經過過濾條件去篩選
咱們如今要收集k8s的日誌,也就是你的ELK平臺部署起來了,它是一個獨立的系統部署起來了,要是使用set car方式去收集這個日誌。
要是採集k8s日誌,須要採集
[root@k8s-master elk]# tail /var/log/messages
這個文件,收集這個,咱們先編寫一個filebeat,這裏就指定你要收集那些文件,這個filebeat這個pod,是不能訪問到宿主機的,因此咱們要經過數據卷掛載這個文件,es的索引至關於mysql 的db,因此要根據es裏要建立不一樣的索引,也就是按天,記錄某一個日誌,這一天產生的日誌放到這個索引中,這個索引呢要自定義名稱,根據你當前部署的業務寫一個名稱,這樣爲了方面後面作查詢,作必定的分類,別到時候幾個項目了,k8s項目了,php項目了,Tomcat項目了,都在一個索引裏面,當去查詢也比較困難,因此把他們分紅不一樣的索引,要指定這些的話就須要加這三個參數
setup.ilm.enabled: false setup.template.name: "k8s-module" setup.template.pattern: "k8s-module-*"
下面是經過deemonset部署的filebeat到每一個節點上,經過hostpath將宿主機上的/var/log/messages/掛載到容器中的/var/log/messages,這樣容器中就有這個日誌文件了,就能讀取到了,這就是收集k8s的日誌。
[root@k8s-master elk]# cat k8s-logs.yaml apiVersion: v1 kind: ConfigMap metadata: name: k8s-logs-filebeat-config namespace: kube-system data: filebeat.yml: | filebeat.inputs: - type: log paths: - /var/log/messages fields: app: k8s type: module fields_under_root: true setup.ilm.enabled: false setup.template.name: "k8s-module" setup.template.pattern: "k8s-module-*" output.elasticsearch: hosts: ['elasticsearch.kube-system:9200'] index: "k8s-module-%{+yyyy.MM.dd}" --- apiVersion: apps/v1 kind: DaemonSet metadata: name: k8s-logs namespace: kube-system spec: selector: matchLabels: project: k8s app: filebeat template: metadata: labels: project: k8s app: filebeat spec: containers: - name: filebeat image: elastic/filebeat:7.3.1 args: [ "-c", "/etc/filebeat.yml", "-e", ] resources: requests: cpu: 100m memory: 100Mi limits: cpu: 500m memory: 500Mi securityContext: runAsUser: 0 volumeMounts: - name: filebeat-config mountPath: /etc/filebeat.yml subPath: filebeat.yml - name: k8s-logs mountPath: /var/log/messages volumes: - name: k8s-logs hostPath: path: /var/log/messages - name: filebeat-config configMap: name: k8s-logs-filebeat-config
[root@k8s-master elk]# kubectl create -f k8s-logs.yaml [root@k8s-master elk]# kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE coredns-bccdc95cf-kqxwv 1/1 Running 2 6d8h coredns-bccdc95cf-nwkbp 1/1 Running 2 6d8h elasticsearch-0 1/1 Running 0 94m etcd-k8s-master 1/1 Running 1 6d8h filebeat-8s9cx 1/1 Running 0 94m filebeat-xgdj7 1/1 Running 0 94m k8s-logs-5s9kl 1/1 Running 0 37s k8s-logs-txz4q 1/1 Running 0 37s kibana-b7d98644-cmg9k 1/1 Running 0 94m kube-apiserver-k8s-master 1/1 Running 1 6d8h kube-controller-manager-k8s-master 1/1 Running 2 6d8h kube-flannel-ds-amd64-dc5z9 1/1 Running 1 6d7h kube-flannel-ds-amd64-jm2jz 1/1 Running 1 6d7h kube-flannel-ds-amd64-z6tt2 1/1 Running 1 6d8h kube-proxy-9ltx7 1/1 Running 2 6d8h kube-proxy-lnzrj 1/1 Running 1 6d7h kube-proxy-v7dqm 1/1 Running 1 6d7h kube-scheduler-k8s-master 1/1 Running 2 6d8h
仍是原來的步驟,最後的一個按鈕索引管理這裏
這是咱們自定義採集的日誌
而後在建立一個索引
選擇這個而後保存
建立索引
選擇module-這裏就能看到咱們var/log/messages的日誌
作一個簡單的測試好比這樣
[root@k8s-node1 ~]# echo hello > /var/log/messages
而後接收一下tomcat的日誌
通常須要看的話,tomcat前面由nginx去作反向代理,而Tomcat須要看的日誌是catalina
jc日誌主要調試的時候須要看。
[root@k8s-master elk]# cat tomcat-deployment.yaml apiVersion: apps/v1beta1 kind: Deployment metadata: name: tomcat-java-demo namespace: test spec: replicas: 3 selector: matchLabels: project: www app: java-demo template: metadata: labels: project: www app: java-demo spec: imagePullSecrets: - name: registry-pull-secret containers: - name: tomcat image: 192.168.30.24/test/tomcat-java-demo:latest imagePullPolicy: Always ports: - containerPort: 8080 name: web protocol: TCP resources: requests: cpu: 0.5 memory: 1Gi limits: cpu: 1 memory: 2Gi livenessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 60 timeoutSeconds: 20 readinessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 60 timeoutSeconds: 20 volumeMounts: - name: tomcat-logs mountPath: /usr/local/tomcat/logs - name: filebeat image: elastic/filebeat:7.3.1 args: [ "-c", "/etc/filebeat.yml", "-e", ] resources: limits: memory: 500Mi requests: cpu: 100m memory: 100Mi securityContext: runAsUser: 0 volumeMounts: - name: filebeat-config mountPath: /etc/filebeat.yml subPath: filebeat.yml - name: tomcat-logs mountPath: /usr/local/tomcat/logs volumes: - name: tomcat-logs emptyDir: {} - name: filebeat-config configMap: name: filebeat-config --- apiVersion: v1 kind: ConfigMap metadata: name: filebeat-config namespace: test data: filebeat.yml: |- filebeat.inputs: - type: log paths: - /usr/local/tomcat/logs/catalina.* fields: app: www type: tomcat-catalina fields_under_root: true multiline: pattern: '^\[' negate: true match: after setup.ilm.enabled: false setup.template.name: "tomcat-catalina" setup.template.pattern: "tomcat-catalina-*" output.elasticsearch: hosts: ['elasticsearch.kube-system:9200'] index: "tomcat-catalina-%{+yyyy.MM.dd}"
滾動更新一下,通常要是錯誤日誌的話,日誌量會增長,確定須要去解決,又不是訪問日誌。另外滾動更新須要一分鐘時間
[root@k8s-master elk]# kubectl get pod -n test [root@k8s-master elk]# kubectl get pod -n test NAME READY STATUS RESTARTS AGE tomcat-java-demo-7ffd4dc7c5-26xjf 2/2 Running 0 5m19s tomcat-java-demo-7ffd4dc7c5-lwfgr 2/2 Running 0 7m31s tomcat-java-demo-7ffd4dc7c5-pwj77 2/2 Running 0 8m50s
咱們的日誌收集到了
而後在建立一個索引而後也能夠去測試一下去容器,好比訪問日誌等等,和剛纔的測試同樣。