在k8s 1.3安装EFK组件
前置条件
查看k8s版本
kubectl get node -owide
相关安装包
链接:https://pan.baidu.com/s/12S5lKEyzzwFwkCwzsPemHw?pwd=ycqx
提取码:ycqx
上传压缩包
把elasticsearch-7-12-1.tar.gz、fluentd-containerd.tar.gz、 kibana-7-12-1.tar.gz上传到k8snode1机器上,手动解压
ctr -n=k8s.io images import elasticsearch-7-12-1.tar.gz
ctr -n=k8s.io images import kibana-7-12-1.tar.gz
ctr -n=k8s.io images import fluentd-containerd.tar.gz
把nfs-subdir-external-provisioner.tar.gz上传到k8snode1上,手动解压。
ctr -n=k8s.io images import nfs-subdir-external-provisioner.tar.gz
把busybox-1-28.tar.gz上传到k8snode1节点,手动解压
ctr -n k8s.io images import busybox-1-28.tar.gz
把fluentd-containerd.tar.gz上传到k8smaster1机器上,手动解压
ctr -n=k8s.io images import fluentd-containerd.tar.gz
安装nfs供应商
两台服务器都执行
yum install nfs-utils -y
systemctl start nfs
systemctl enable nfs.service
在k8smaster1上创建一个nfs共享目录
mkdir /data/v1 -p
vim /etc/exports
/data/v1 *(rw,no_root_squash)
加载配置,使配置生效
exportfs -arv
systemctl restart nfs
创建nfs作为存储的供应商
创建运行nfs-provisioner需要的sa账号
cat serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-provisioner
kubectl apply -f serviceaccount.yaml
对sa授权
kubectl create clusterrolebinding nfs-provisioner-clusterrolebinding --clusterrole=cluster-admin --serviceaccount=default:nfs-provisioner
通过deployment创建pod用来运行nfs-provisioner
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-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: example.com/nfs
- name: NFS_SERVER
value: 192.168.40.120 #这个需要写nfs服务端所在的ip地址,需要写自己安装了nfs服务的机器ip
- name: NFS_PATH
value: /data/v1 #这个是nfs服务端共享的目录
volumes:
- name: nfs-client-root
nfs:
server: 192.168.40.120 #这个需要写nfs服务端所在的ip地址,需要写自己安装了nfs服务的机器ip
path: /data/v1
kubectl apply -f deployment.yaml
验证nfs是否创建成功
kubectl get pods | grep nfs
创建storageclass
vim class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: do-block-storage
provisioner: example.com/nfs
kubectl apply -f class.yaml
注:provisioner: example.com/nfs
#该值需要和nfs provisioner配置的PROVISIONER_NAME处的value值保持一致
安装elasticsearch组件
下面安装步骤均在k8s控制节点操作:
创建kube-logging名称空间
在安装Elasticsearch集群之前,我们先创建一个名称空间,在这个名称空间下安装日志收工具elasticsearch、fluentd、kibana。
我们创建一个kube-logging名称空间,将EFK组件安装到该名称空间中。
vim kube-logging.yaml
kind: Namespace
apiVersion: v1
metadata:
name: kube-logging
kubectl apply -f kube-logging.yaml
查看kube-logging名称空间是否创建成功
kubectl get namespaces | grep kube-logging
创建headless service
- 首先,我们需要部署一个有3个节点的Elasticsearch集群。我们使用3个Elasticsearch Pods可以避免高可用中的多节点群集中发生的“裂脑”的问题。 Elasticsearch脑裂可参考如下:https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#split-brain
- 在kube-logging名称空间定义了一个名为 elasticsearch 的 Service服务,带有app=elasticsearch标签,当我们将 Elasticsearch StatefulSet 与此服务关联时,服务将返回带有标签app=elasticsearch的 Elasticsearch Pods的DNS A记录,然后设置clusterIP=None,将该服务设置成无头服务。
- 最后,我们分别定义端口9200、9300,分别用于与 REST API 交互,以及用于节点间通信。
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
kubectl apply -f elasticsearch_svc.yaml
查看elasticsearch的service是否创建成功
kubectl get services --namespace=kube-logging
创建elasticsearch
现在我们已经为 Pod 设置了无头服务和一个稳定的域名.elasticsearch.kube-logging.svc.cluster.local
接下来我们通过 StatefulSet来创建具体的 Elasticsearch的Pod 应用
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
spec:
containers:
- name: elasticsearch
image: elasticsearch:7.12.1
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,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch"
- name: cluster.initial_master_nodes
value: "es-cluster-0,es-cluster-1,es-cluster-2"
- name: ES_JAVA_OPTS
value: "-Xms512m -Xmx512m"
initContainers:
- name: fix-permissions
image: busybox:1.28
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:1.28
imagePullPolicy: IfNotPresent
command: ["sysctl", "-w", "vm.max_map_count=262144"]
securityContext:
privileged: true
- name: increase-fd-ulimit
image: busybox:1.28
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "ulimit -n 65536"]
securityContext:
privileged: true
volumeClaimTemplates:
- metadata:
name: data
labels:
app: elasticsearch
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: do-block-storage
resources:
requests:
storage: 10Gi
-
在statefulset中定义了pod,容器的名字是elasticsearch,镜像是docker.elastic.co/elasticsearch/elasticsearch:7.12.1
-
使用resources字段来指定容器至少需要0.1个vCPU,并且容器最多可以使用1个vCPU了解有关资源请求和限制,可参考https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/。
-
容器暴露了9200和9300两个端口,名称要和上面定义的 Service 保持一致,通过volumeMount声明了数据持久化目录,定义了一个data数据卷,通过volumeMount把它挂载到容器里的/usr/share/elasticsearch/data目录。
-
容器中设置了一些环境变量:
-
cluster.name:Elasticsearch 集群的名称,我们这里是 k8s-logs。
-
node.name:节点的名称,通过metadata.name来获取。这将解析为 es-cluster-[0,1,2],取决于节点的指定顺序。
-
discovery.seed_hosts:此字段用于设置在Elasticsearch集群中节点相互连接的发现方法,它为我们的集群指定了一个静态主机列表。
-
由于我们之前配置的是无头服务,我们的 Pod 具有唯一的 DNS 地址es-cluster-[0,1,2].elasticsearch.kube-logging.svc.cluster.local,因此我们相应地设置此地址变量即可。由于都在同一个 namespace 下面,所以我们可以将其缩短为es-cluster-[0,1,2].elasticsearch。
第一个名为 fix-permissions 的容器用来运行 chown 命令,将 Elasticsearch 数据目录的用户和组更改为1000:1000(Elasticsearch 用户的 UID)。因为默认情况下,Kubernetes 用 root 用户挂载数据目录,这会使得 Elasticsearch 无法访问该数据目录
第二个名为 increase-vm-max-map 的容器用来增加操作系统对mmap计数的限制,默认情况下该值可能太低,导致内存不足的错误
最后一个初始化容器是用来执行ulimit命令增加打开文件描述符的最大数量的。
我们这里使用 volumeClaimTemplates 来定义持久化模板,Kubernetes 会使用它为 Pod 创建 PersistentVolume,设置访问模式为ReadWriteOnce,这意味着它只能被 mount 到单个节点上进行读写,然后最重要的是使用了一个名为do-block-storage的 StorageClass 对象,所以我们需要提前创建该对象,我们这里使用的 NFS 作为存储后端,所以需要安装一个对应的nfs provisioner 驱动。
kubectl apply -f elasticsearch-statefulset.yaml
kubectl get pods -n kube-logging
kubectl get svc -n kube-logging
安装kibana组件
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: kibana:7.12.1
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 1000m
requests:
cpu: 100m
env:
- name: ELASTICSEARCH_URL
value: http://elasticsearch:9200
ports:
- containerPort: 5601
kubectl apply -f kibana.yaml
kubectl get pods -n kube-logging
kubectl get svc -n kube-logging
修改service的type类型为NodePort:
kubectl edit svc kibana -n kube-logging
把type: ClusterIP变成type: NodePort
kubectl get svc -n kube-logging
kubectl get node -owide
通过上面获取到的节点IP,和服务端口
在浏览器中打开http://192.168.40.121:31692即可,如果看到如下欢迎界面证明 Kibana 已经成功部署到了Kubernetes集群之中。
安装fluentd组件
我们使用daemonset控制器部署fluentd组件,这样可以保证集群中的每个节点都可以运行同样fluentd的pod副本,这样就可以收集k8s集群中每个节点的日志
在k8s集群中,容器应用程序的输入输出日志会重定向到node节点里的json文件中,fluentd可以tail和过滤以及把日志转换成指定的格式发送到elasticsearch集群中。
除了容器日志,fluentd也可以采集kubelet、kube-proxy、docker的日志。
vim fluentd.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: fluentd
namespace: kube-logging
labels:
app: fluentd
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: fluentd
labels:
app: fluentd
rules:
- apiGroups:
- ""
resources:
- pods
- namespaces
verbs:
- get
- list
- watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: fluentd
roleRef:
kind: ClusterRole
name: fluentd
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: fluentd
namespace: kube-logging
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: kube-logging
labels:
app: fluentd
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
spec:
serviceAccount: fluentd
serviceAccountName: fluentd
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
containers:
- name: fluentd
image: docker.io/fluent/fluentd-kubernetes-daemonset:v1.16-debian-elasticsearch7-1
imagePullPolicy: IfNotPresent
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: "elasticsearch.kube-logging.svc.cluster.local"
- name: FLUENT_ELASTICSEARCH_PORT
value: "9200"
- name: FLUENT_ELASTICSEARCH_SCHEME
value: "http"
- name: FLUENTD_SYSTEMD_CONF
value: disable
- name: FLUENT_CONTAINER_TAIL_PARSER_TYPE
value: "cri"
- name: FLUENT_CONTAINER_TAIL_PARSER_TIME_FORMAT
value: "%Y-%m-%dT%H:%M:%S.%L%z"
resources:
limits:
memory: 512Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: containers
mountPath: /var/log/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: containers
hostPath:
path: /var/log/containers
kubectl apply -f fluentd.yaml
kubectl get pods -n kube-logging -owide
Fluentd 启动成功后,我们可以前往 Kibana 的 Dashboard 页面中,点击左侧的Discover,可以看到如下配置页面:
在这里可以配置我们需要的 Elasticsearch 索引,前面 Fluentd 配置文件中我们采集的日志使用的是 logstash 格式
这里只需要在文本框中输入logstash-*即可匹配到 Elasticsearch 集群中的所有日志数据,然后点击下一步,进入以下页面:
logstash-*
点击next step,出现如下
选择@timestamp,创建索引
点击左侧的discover,可看到如下:
测试收集pod容器日志
vim pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox:1.28
imagePullPolicy: IfNotPresent
args: [/bin/sh, -c,'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
kubectl apply -f pod.yaml
登录到kibana的控制面板,在discover处的搜索栏中输入kubernetes.pod_name:counter,这将过滤名为的Pod的日志数据counter,如下所示:
kubernetes.pod_name:counter