目錄
一、安裝存儲日志組件 Elasticsearch
1.1 創(chuàng)建名稱空間
1.2 安裝 elasticsearch 組件
1)創(chuàng)建 headless service 服務(wù)
2)通過 statefulset 創(chuàng)建 elasticsearch 集群
二、安裝 kibana 可視化 UI 界面
本篇文章所用到的資料文件下載地址:
kibana-v7.2.0-kubernetes文檔類資源-CSDN下載
https://download.csdn.net/download/weixin_46560589/87391396
一、安裝存儲日志組件 Elasticsearch
1.1 創(chuàng)建名稱空間
????????在安裝 Elasticsearch 集群之前,我們先創(chuàng)建一個名稱空間,在這個名稱空間下安裝日志收工具 elasticsearch、fluentd、kibana。我們創(chuàng)建一個 kube-logging 名稱空間,將 EFK 組件安裝到該名稱空間中。
[root@k8s-master1 ~]# mkdir efk
[root@k8s-master1 ~]# cd efk/
[root@k8s-master1 efk]# kubectl create namespace kube-logging
namespace/kube-logging created
# 查看 kube-logging 名稱空間是否創(chuàng)建成功
[root@k8s-master1 efk]# kubectl get ns
NAME STATUS AGE
default Active 8d
kube-logging Active 7s
kube-node-lease Active 8d
kube-public Active 8d
kube-system Active 8d
1.2 安裝 elasticsearch 組件
????????通過上面步驟已經(jīng)創(chuàng)建了一個名稱空間 kube-logging,在這個名稱空間下去安裝日志收集組件 efk。首先,我們需要部署一個有 3 個節(jié)點(diǎn)的 Elasticsearch 集群,我們使用 3 個 Elasticsearch Pods 可以避免高可用中的多節(jié)點(diǎn)群集中發(fā)生的“裂腦”的問題。
Elasticsearch 腦裂參考地址:Node | Elasticsearch Guide [8.6] | Elastic
-
1)創(chuàng)建 headless service 服務(wù)
????????創(chuàng)建一個 headless service 的 Kubernetes 服務(wù),服務(wù)名稱是 elasticsearch,這個服務(wù)將為 3 個 Pod 定義一個 DNS 域。headless service 不具備負(fù)載均衡也沒有 IP。
要了解有關(guān) headless service 的更多信息,可參考:服務(wù)(Service) | Kubernetes
[root@k8s-master1 efk]# vim elasticsearch_svc.yaml
kind: Service
apiVersion: v1
metadata:
name: elasticsearch
namespace: kube-logging
labels:
app: elasticsearch
spec:
selector:
app: elasticsearch
clusterIP: None
ports:
- port: 9200
name: rest
- port: 9300
name: inter-node
????????在 kube-logging 名稱空間定義了一個名為 elasticsearch 的 Service服務(wù),帶有app=elasticsearch 標(biāo)簽,當(dāng)我們將 Elasticsearch StatefulSet 與此服務(wù)關(guān)聯(lián)時,服務(wù)將返回帶有標(biāo)簽 app=elasticsearch 的 Elasticsearch Pods 的 DNS 記錄,然后設(shè)置 clusterIP=None,將該服務(wù)設(shè)置成無頭服務(wù)。最后,我們分別定義端口 9200、9300,分別用于與 REST API 交互,以及用于節(jié)點(diǎn)間通信。
[root@k8s-master1 efk]# kubectl apply -f elasticsearch_svc.yaml
service/elasticsearch created
[root@k8s-master1 efk]# kubectl get svc -n kube-logging
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 7s
????????現(xiàn)在我們已經(jīng)為 Pod 設(shè)置了無頭服務(wù)和一個穩(wěn)定的域名 .elasticsearch.kube-logging.svc.cluster.local,接下來我們通過 StatefulSet 來創(chuàng)建具體的 Elasticsearch 的 Pod 應(yīng)用。
-
2)通過 statefulset 創(chuàng)建 elasticsearch 集群
- 創(chuàng)建 Storageclass,實(shí)現(xiàn)存儲類動態(tài)供給:
1、安裝 nfs 服務(wù)
# 在各個節(jié)點(diǎn)安裝 nfs 服務(wù)
yum install nfs-utils -y
# 啟動 nfs 服務(wù)
systemctl enable nfs --now
# 在 master1 上創(chuàng)建一個 nfs 共享目錄
[root@k8s-master1 efk]# mkdir -pv /data/v1
# 編輯 /etc/exports 文件
[root@k8s-master1 efk]# vim /etc/exports
/data/v1 192.168.78.0/24(rw,no_root_squash)
# 加載配置,使配置生效
[root@k8s-master1 efk]# exportfs -arv
exporting 192.168.78.0/24:/data/v1
[root@k8s-master1 efk]# systemctl restart nfs
2、創(chuàng)建 nfs 作為存儲的供應(yīng)商
# 創(chuàng)建 sa
[root@k8s-master1 efk]# kubectl create serviceaccount nfs-provisioner
serviceaccount/nfs-provisioner created
[root@k8s-master1 efk]# kubectl get sa
NAME SECRETS AGE
default 1 8d
nfs-provisioner 1 4s
# 對 sa 做 rbac 授權(quán)
[root@k8s-master1 efk]# vim rbac.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get"]
- apiGroups: ["extensions"]
resources: ["podsecuritypolicies"]
resourceNames: ["nfs-provisioner"]
verbs: ["use"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-provisioner
subjects:
- kind: ServiceAccount
name: nfs-provisioner
namespace: default
roleRef:
kind: ClusterRole
name: nfs-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-provisioner
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-provisioner
subjects:
- kind: ServiceAccount
name: nfs-provisioner
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-provisioner
apiGroup: rbac.authorization.k8s.io
[root@k8s-master1 efk]# kubectl apply -f rbac.yaml
注意:k8s-v1.20+ 版本通過 nfs provisioner 動態(tài)生成 pv 會報錯,信息如下:
Unexpected error getting claim reference to claim "default/test-claim1": selfLink was empty, can't make reference
報錯原因是 1.20 版本啟用了 selfLink,解決方法如下:
[root@k8s-master1 efk]# vim /etc/kubernetes/manifests/kube-apiserver.yaml
······
spec:
containers:
- command:
- kube-apiserver
- --feature-gates=RemoveSelfLink=false # 添加這一行內(nèi)容
······
[root@k8s-master1 efk]# kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
[root@k8s-master1 efk]# kubectl get pods -n kube-system | grep apiserver
kube-apiserver 0/1 CrashLoopBackOff 1 (14s ago) 16s
kube-apiserver-k8s-master1 1/1 Running 0 117s
# 重新更新 apiserver.yaml 會有生成一個新的 pod:kube-apiserver,這個 pod 狀態(tài)是 CrashLoopBackOff,需要刪除
[root@k8s-master1 efk]# kubectl delete pods -n kube-system kube-apiserver
把 nfs-client-provisioner.tar.gz 上傳到? node1、node2 節(jié)點(diǎn),手動解壓
[root@k8s-node1 ~]# docker load -i nfs-client-provisioner.tar.gz
[root@k8s-node2 ~]# docker load -i nfs-client-provisioner.tar.gz
# 通過 deployment 創(chuàng)建 pod 用來運(yùn)行 nfs-provisioner
[root@k8s-master1 efk]# vim deployment.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-provisioner
spec:
selector:
matchLabels:
app: nfs-provisioner
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-provisioner
spec:
serviceAccount: nfs-provisioner
containers:
- name: nfs-provisioner
image: registry.cn-hangzhou.aliyuncs.com/open-ali/xianchao/nfs-client-provisioner:v1
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: example.com/nfs
- name: NFS_SERVER
value: 192.168.78.143 # 這個需要寫 nfs 服務(wù)端所在的 ip 地址,即安裝了 nfs 服務(wù)的機(jī)器 ip
- name: NFS_PATH
value: /data/v1 # 這個是 nfs 服務(wù)端共享的目錄
volumes:
- name: nfs-client-root
nfs:
server: 192.168.78.143
path: /data/v1
[root@k8s-master1 efk]# kubectl apply -f deployment.yaml
deployment.apps/nfs-provisioner created
[root@k8s-master1 efk]# kubectl get pods | grep nfs
nfs-provisioner-6988f7c774-nk8x5 1/1 Running 0 7s
# 創(chuàng)建 stoorageclass
[root@k8s-master1 efk]# vim class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: do-block-storage
provisioner: example.com/nfs # 該值需要和 nfs provisioner 配置的 PROVISIONER_NAME 的 value 值保持一致
[root@k8s-master1 efk]# kubectl apply -f class.yaml
[root@k8s-master1 efk]# kubectl get storageclasses
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
do-block-storage example.com/nfs Delete Immediate false 65s
-
安裝 elasticsearch 集群
把 elasticsearch_7_2_0.tar.gz 和 busybox.tar.gz 文件上傳到 node1、node2,手動解壓:
[root@k8s-node1 ~]# docker load -i elasticsearch_7_2_0.tar.gz
[root@k8s-node1 ~]# docker load -i busybox.tar.gz
[root@k8s-node2 ~]# docker load -i elasticsearch_7_2_0.tar.gz
[root@k8s-node2 ~]# docker load -i busybox.tar.gz
elasticsearch-statefulset.yaml 文件解釋說明:
[root@k8s-master1 efk]# vim elasticsearch-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: es-cluster
namespace: kube-logging
spec:
serviceName: elasticsearch
replicas: 3
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
·····
????????上面內(nèi)容的解釋:在 kube-logging 的名稱空間中定義了一個 es-cluste r的 StatefulSet。然后,我們使用 serviceName?字段與我們之前創(chuàng)建的 headless ElasticSearch 服務(wù)相關(guān)聯(lián)。這樣可以確??梢允褂靡韵?DNS 地址訪問 StatefulSet 中的每個 Pod:
????????es-cluster-[0,1,2].elasticsearch.kube-logging.svc.cluster.local,其中 [0,1,2] 與 Pod 分配的序號數(shù)相對應(yīng)。我們指定 3 個 replicas(3 個 Pod 副本),將 selector matchLabels?設(shè)置為 app: elasticseach。該 .spec.selector.matchLabels 和 .spec.template.metadata.labels 字段必須匹配。
# statefulset 中定義 pod 模板,內(nèi)容如下:
·····
spec:
containers:
- name: elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 1000m
requests:
cpu: 100m
ports:
- containerPort: 9200
name: rest
protocol: TCP
- containerPort: 9300
name: inter-node
protocol: TCP
volumeMounts:
- name: data
mountPath: /usr/share/elasticsearch/data
env:
- name: cluster.name
value: k8s-logs
- name: node.name
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: discovery.seed_hosts
value: "es-cluster-0.elasticsearch.kube-logging.svc.cluster.local,es-cluster-1.elasticsearch.kube-logging.svc.cluster.local,es-cluster-2.elasticsearch.kube-logging.svc.cluster.local"
- name: cluster.initial_master_nodes
value: "es-cluster-0,es-cluster-1,es-cluster-2"
- name: ES_JAVA_OPTS
value: "-Xms512m -Xmx512m"
······
????????上面內(nèi)容解釋:在 statefulset 中定義了 pod,容器的名字是 elasticsearch,鏡像是docker.elastic.co/elasticsearch/elasticsearch:7.2.0。使用 resources 字段來指定容器至少需要 0.1個 vCPU,并且容器最多可以使用 1 個 vC??PU 了解有關(guān)資源請求和限制。
可參考Resource Management for Pods and Containers | Kubernetes。
????????容器暴露了 9200 和 9300 兩個端口,名稱要和上面定義的 Service 保持一致,通過volumeMount 聲明了數(shù)據(jù)持久化目錄,定義了一個 data 數(shù)據(jù)卷,通過 volumeMount 把它掛載到容器里的 /usr/share/elasticsearch/data 目錄。
容器中設(shè)置了一些環(huán)境變量:
-
cluster.name:Elasticsearch 集群的名稱,我們這里是 k8s-logs。
-
node.name:節(jié)點(diǎn)的名稱,通過 metadata.name 來獲取。這將解析為 es-cluster-[0,1,2],取決于節(jié)點(diǎn)的指定順序。
-
discovery.seed_hosts:此字段用于設(shè)置在 Elasticsearch 集群中節(jié)點(diǎn)相互連接的發(fā)現(xiàn)方法,它為我們的集群指定了一個靜態(tài)主機(jī)列表。由于我們之前配置的是無頭服務(wù),我們的 Pod 具有唯一的 DNS 地址 es-cluster-[0,1,2].elasticsearch.kube-logging.svc.cluster.local,因此我們相應(yīng)地設(shè)置此地址變量即可。由于都在同一個 namespace 下面,所以我們可以將其縮短為 es-cluster-[0,1,2].elasticsearch。要了解有關(guān) Elasticsearch 發(fā)現(xiàn)的更多信息,請參閱 Elasticsearch 官方文檔:Discovery and cluster formation | Elasticsearch Guide [8.6] | Elastic
-
ES_JAVA_OPTS:這里我們設(shè)置為-Xms512m -Xmx512m,告訴JVM使用512 MB的最小和最大堆。這個值應(yīng)該根據(jù)群集的資源可用性和需求調(diào)整這些參數(shù)。要了解更多信息,請參閱設(shè)置堆大小的相關(guān)文檔:Heap size settings | Elasticsearch Guide [8.6] | Elastic。
# initcontainer 內(nèi)容
······
initContainers:
- name: fix-permissions
image: busybox
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
securityContext:
privileged: true
volumeMounts:
- name: data
mountPath: /usr/share/elasticsearch/data
- name: increase-vm-max-map
image: busybox
imagePullPolicy: IfNotPresent
command: ["sysctl", "-w", "vm.max_map_count=262144"]
securityContext:
privileged: true
- name: increase-fd-ulimit
image: busybox
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "ulimit -n 65536"]
securityContext:
privileged: true
······
????????這里我們定義了幾個在主應(yīng)用程序之前運(yùn)行的 Init 容器,這些初始容器按照定義的順序依次執(zhí)行,執(zhí)行完成后才會啟動主應(yīng)用容器。
????????第一個名為 fix-permissions 的容器用來運(yùn)行 chown 命令,將 Elasticsearch 數(shù)據(jù)目錄的用戶和組更改為1000:1000(Elasticsearch 用戶的 UID)。因?yàn)槟J(rèn)情況下,Kubernetes 用 root 用戶掛載數(shù)據(jù)目錄,這會使得 Elasticsearch 無法訪問該數(shù)據(jù)目錄,可以參考 Elasticsearch 生產(chǎn)中的一些默認(rèn)注意事項(xiàng)相關(guān)文檔說明:Install Elasticsearch with Docker | Elasticsearch Guide [8.6] | Elastic。
????????第二個名為 increase-vm-max-map 的容器用來增加操作系統(tǒng)對 mmap 計數(shù)的限制,默認(rèn)情況下該值可能太低,導(dǎo)致內(nèi)存不足的錯誤,要了解更多關(guān)于該設(shè)置的信息,可以查看 Elasticsearch 官方文檔說明:Virtual memory | Elasticsearch Guide [8.6] | Elastic。
最后一個初始化容器是用來執(zhí)行 ulimit 命令增加打開文件描述符的最大數(shù)量的。
此外?Elastisearch Notes for Production Use?文檔還提到了由于性能原因最好禁用 swap,對于 Kubernetes 集群而言,最好也是禁用 swap 分區(qū)的。
????????現(xiàn)在我們已經(jīng)定義了主應(yīng)用容器和它之前運(yùn)行的 Init Containers 來調(diào)整一些必要的系統(tǒng)參數(shù),接下來可以添加數(shù)據(jù)目錄的持久化相關(guān)的配置。
# 在 StatefulSet 中,使用 volumeClaimTemplates 來定義 volume 模板即可
······
volumeClaimTemplates:
- metadata:
name: data
labels:
app: elasticsearch
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: do-block-storage
resources:
requests:
storage: 10Gi
????????我們這里使用 volumeClaimTemplates 來定義持久化模板,Kubernetes 會使用它為 Pod 創(chuàng)建 PersistentVolume,設(shè)置訪問模式為 ReadWriteOnce,這意味著它只能被 mount 到單個節(jié)點(diǎn)上進(jìn)行讀寫,然后最重要的是使用了一個名為 do-block-storage 的 StorageClass 對象,所以我們需要提前創(chuàng)建該對象,我們這里使用的 NFS 作為存儲后端,所以需要安裝一個對應(yīng)的 nfs? provisioner 驅(qū)動。?
注意:上述幾段內(nèi)容代碼的解釋都是同一個 elasticsearch-statefulset.yaml 文件里的內(nèi)容!
# 查看 es 的 pod 是否創(chuàng)建成功
[root@k8s-master1 efk]# kubectl get pods -n kube-logging
NAME READY STATUS RESTARTS AGE
es-cluster-0 1/1 Running 0 22s
es-cluster-1 1/1 Running 0 15s
es-cluster-2 1/1 Running 0 8s
[root@k8s-master1 efk]# kubectl get svc -n kube-logging
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 88m
????????pod 部署完成之后,可以通過 REST API 檢查 elasticsearch 集群是否部署成功,使用下面的命令將本地端口 9200 轉(zhuǎn)發(fā)到 Elasticsearch 節(jié)點(diǎn)(如es-cluster-0)對應(yīng)的端口:?
[root@k8s-master1 efk]# kubectl port-forward es-cluster-0 9200:9200 --namespace=kube-logging
# 新開一個 master1 終端,執(zhí)行如下請求,可以訪問到數(shù)據(jù)
[root@k8s-master1 efk]# curl http://localhost:9200/_cluster/state?pretty
二、安裝 kibana 可視化 UI 界面
把 kibana_7_2_0.tar.gz 文件上傳到 node1、node2 節(jié)點(diǎn),手動解壓
[root@k8s-node1 ~]# docker load -i kibana_7_2_0.tar.gz
[root@k8s-node2 ~]# docker load -i kibana_7_2_0.tar.gz
[root@k8s-master1 efk]# vim kibana.yaml
apiVersion: v1
kind: Service
metadata:
name: kibana
namespace: kube-logging
labels:
app: kibana
spec:
ports:
- port: 5601
selector:
app: kibana
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kibana
namespace: kube-logging
labels:
app: kibana
spec:
replicas: 1
selector:
matchLabels:
app: kibana
template:
metadata:
labels:
app: kibana
spec:
containers:
- name: kibana
image: docker.elastic.co/kibana/kibana:7.2.0
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 1000m
requests:
cpu: 100m
env:
- name: ELASTICSEARCH_URL
value: http://elasticsearch.kube-logging.svc.cluster.local:9200
ports:
- containerPort: 5601
[root@k8s-master1 efk]# kubectl apply -f kibana.yaml
[root@k8s-master1 efk]# kubectl get pods -n kube-logging | grep kibana
kibana-57dd8dfbb6-5g44t 1/1 Running 0 5m9s
[root@k8s-master1 efk]# kubectl get svc -n kube-logging | grep kibana
kibana ClusterIP 10.108.22.154 <none> 5601/TCP 5m39s
????????上面我們定義了兩個資源對象,一個 Service 和 Deployment,為了測試方便,我們將 Service 設(shè)置為了 NodePort 類型,Kibana Pod 中配置都比較簡單,唯一需要注意的是我們使用 ELASTICSEARCH_URL 這個環(huán)境變量來設(shè)置 Elasticsearch 集群的端點(diǎn)和端口,直接使用 Kubernetes DNS 即可,此端點(diǎn)對應(yīng)服務(wù)名稱為 elasticsearch,由于是一個 headless service,所以該域?qū)⒔馕鰹?3 個 Elasticsearch Pod 的 IP 地址列表。
# 修改 service 的 type 類型為 NodePort
[root@k8s-master1 efk]# kubectl edit svc -n kube-logging kibana
······
selector:
app: kibana
sessionAffinity: None
type: NodePort # 把 ClusterIP 修改為 NodePort
status:
loadBalancer: {}
······
# 隨機(jī)生成端口
[root@k8s-master1 efk]# kubectl get svc -n kube-logging | grep kibana
kibana NodePort 10.108.22.154 <none> 5601:30948/TCP 9m51s
????????在瀏覽器中打開 http://<任意節(jié)點(diǎn)IP>:30948 即可,如果看到如下歡迎界面證明 Kibana 已經(jīng)成功部署到了 Kubernetes 集群之中(需要等待一段時間,等容器初始化完成才可訪問):
上一篇文章:【Kubernetes 企業(yè)項(xiàng)目實(shí)戰(zhàn)】04、基于 K8s 構(gòu)建 EFK+logstash+kafka 日志平臺(上)_Stars.Sky的博客-CSDN博客文章來源:http://www.zghlxwxcb.cn/news/detail-400918.html
下一篇文章:【Kubernetes 企業(yè)項(xiàng)目實(shí)戰(zhàn)】04、基于 K8s 構(gòu)建 EFK+logstash+kafka 日志平臺(下)_Stars.Sky的博客-CSDN博客文章來源地址http://www.zghlxwxcb.cn/news/detail-400918.html
到了這里,關(guān)于【Kubernetes 企業(yè)項(xiàng)目實(shí)戰(zhàn)】04、基于 K8s 構(gòu)建 EFK+logstash+kafka 日志平臺(中)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!