k8s-安装elasticsearch组件/解决nfs动态生成pv报错

root
233
文章
0
评论
2021年8月30日13:38:28 评论 10209字阅读34分1秒

k8s-安装elasticsearch组件/解决nfs动态生成pv报错

k8s集群:

k8s的控制节点

  • ip:192.168.1.180/181/182
  • 主机名:master01/02/03
  • 配置:6vCPU/6Gi内存

 

k8s的工作节点:

  • ip:192.168.1.183
  • 主机名:node01
  • 配置:6vCPU/8Gi内存

安装elasticsearch组件

1.创建名称空间

在安装Elasticsearch集群之前,我们先创建一个名称空间,在这个名称空间下安装日志收工具elasticsearch、fluentd、kibana。我们创建一个kube-logging名称空间,将EFK组件安装到该名称空间中。

[root@master01 EFK]# cat kube-logging.yaml
kind: Namespace
apiVersion: v1
metadata:
  name: kube-logging
[root@master01 EFK]# kubectl apply -f kube-logging.yaml 
namespace/kube-logging created

查看kube-logging名称空间是否创建成功

[root@master01 EFK]# kubectl get namespaces | grep kube-logging
kube-logging           Active   29s

 安装elasticsearch组件

通过上面步骤已经创建了一个名称空间kube-logging,在这个名称空间下去安装日志收集组件efk,首先,我们需要部署一个有3个节点的Elasticsearch集群。我们使用3个Elasticsearch Pods可以避免高可用中的多节点群集中发生的“裂脑”的问题。 Elasticsearch脑裂可参考如下:

https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html#split-brain

2.创建headless service服务

创建一个headless service的Kubernetes服务,服务名称是elasticsearch,这个服务将为3个Pod定义一个DNS域。headless service不具备负载均衡也没有IP。要了解有关headless service的更多信息,

可参考https://kubernetes.io/docs/concepts/services-networking/service/#headless-services

[root@master01 elasticsearch]# kubectl apply -f elasticsearch_svc.yaml 
service/elasticsearch created

查看elasticsearch的service是否创建成功

[root@master01 elasticsearch]# kubectl get svc -n kube-logging 
NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)             AGE
elasticsearch   ClusterIP   None         <none>        9200/TCP,9300/TCP   2m5s

elasticsearch_svc.yaml文件如下:

[root@master01 elasticsearch]# cat 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服务,带有app=elasticsearch标签,当我们将 Elasticsearch StatefulSet 与此服务关联时,服务将返回带有标签app=elasticsearch的 Elasticsearch Pods的DNS A记录,然后设置clusterIP=None,将该服务设置成无头服务。最后,我们分别定义端口9200、9300,分别用于与 REST API 交互,以及用于节点间通信。

3.创建Storageclass,实现存储类动态供给

#安装nfs服务,选择k8s集群的master1节点,k8s集群的master1节点的ip是192.168.1.180

3.1安装nfs【master/node都要安装】

yum install nfs-utils -y

3.2创建一个nfs共享目录

[root@master01 nfs]# mkdir /data/v1

3.3#编辑/etc/exports文件

[root@master01 nfs]# echo "/data/v1 192.168.1.0/24(rw,no_root_squash)" >/etc/exports

加载配置

exportfs -arv

3.4#启动nfs服务

systemctl enable nfs.service
systemctl start nfs

3.5#创建nfs作为存储的供应商

1、创建sa

[root@master01 nfs-provisioner]# kubectl apply -f nfs-sa.yaml 
serviceaccount/nfs-provisioner created
[root@master01 nfs-provisioner]# cat nfs-sa.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-provisioner

2、对sa做rbac授权

[root@master01 nfs-provisioner]# kubectl apply -f rbac.yaml 
clusterrole.rbac.authorization.k8s.io/nfs-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-provisioner created

rbac.yaml文件如下:

[root@master01 nfs-provisioner]# cat 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

不想写了,参考前面写的这篇

k8s-持久化存储[PVC]

 

4.通过statefulset创建elasticsearch集群

4.1下载安装镜像

[root@node01 ~]# docker pull elasticsearch:7.14.0

4.2#更新资源清单文件

[root@master01 elasticsearch]# kubectl apply -f elasticsearch-statefulset.yaml 
statefulset.apps/es-cluster created

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

上面内容的解释:在kube-logging的名称空间中定义了一个es-cluster的StatefulSet。然后,我们使用serviceName 字段与我们之前创建的headless ElasticSearch服务相关联。这样可以确保可以使用以下DNS地址访问StatefulSet中的每个Pod:,es-cluster-[0,1,2].elasticsearch.kube-logging.svc.cluster.local,其中[0,1,2]与Pod分配的序号数相对应。我们指定3个replicas(3个Pod副本),将selector matchLabels 设置为app: elasticseach。该.spec.selector.matchLabels和.spec.template.metadata.labels字段必须匹配。

    spec:
      containers:
      - name: elasticsearch
        image: elasticsearch:7.14.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,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"

上面内容解释:在statefulset中定义了pod,容器的名字是elasticsearch,镜像是docker.elastic.co/elasticsearch/elasticsearch:7.2.0。使用resources字段来指定容器至少需要0.1个vCPU,并且容器最多可以使用1个vC​​PU了解有关资源请求和限制,可参考

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。
  • ES_JAVA_OPTS:这里我们设置为-Xms512m -Xmx512m,告诉JVM使用512 MB的最小和最大堆。这个值应该根据群集的资源可用性和需求调整这些参数。
      initContainers:
      - name: fix-permissions
        image: busybox
        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
        command: ["sysctl", "-w", "vm.max_map_count=262144"]
        securityContext:
          privileged: true
      - name: increase-fd-ulimit
        image: busybox
        command: ["sh", "-c", "ulimit -n 65536"]
        securityContext:
          privileged: true

这里我们定义了几个在主应用程序之前运行的 Init 容器,这些初始容器按照定义的顺序依次执行,执行完成后才会启动主应用容器。

注意事项:

此外 Elastisearch Notes for Production Use 文档还提到了由于性能原因最好禁用 swap,对于 Kubernetes 集群而言,最好也是禁用 swap 分区的。

  volumeClaimTemplates:
  - metadata:
      name: data
      labels:
        app: elasticsearch
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: do-block-storage
      resources:
        requests:
          storage: 10Gi

我们这里使用 volumeClaimTemplates 来定义持久化模板,Kubernetes 会使用它为 Pod 创建 PersistentVolume,设置访问模式为ReadWriteOnce,这意味着它只能被 mount 到单个节点上进行读写,然后最重要的是使用了一个名为do-block-storage的 StorageClass 对象,所以我们需要提前创建该对象,我们这里使用的 NFS 作为存储后端,所以需要安装一个对应的nfs  provisioner 驱动。

#查看es的pod是否创建成功

[root@master01 elasticsearch]# kubectl get pod -n kube-logging 
NAME           READY   STATUS    RESTARTS   AGE
es-cluster-0   1/1     Running   0          39s
es-cluster-1   1/1     Running   0          21s
es-cluster-2   1/1     Running   0          13s
[root@master01 elasticsearch]# kubectl get svc -n kube-logging
NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)             AGE
elasticsearch   ClusterIP   None         <none>        9200/TCP,9300/TCP   15h

pod部署完成之后,可以通过REST API检查elasticsearch集群是否部署成功,使用下面的命令将本地端口9200转发到 Elasticsearch 节点(如es-cluster-0)对应的端口:

[root@master01 elasticsearch]# kubectl port-forward es-cluster-0 9200:9200 --namespace=kube-logging

然后,在另外的终端窗口中,执行如下请求,新开一个master1终端:

[root@master01 nfs-provisioner]# curl http://localhost:9200/_cluster/state?pretty|less

输出如下:

 

注意:k8s1.20+包括1.21+版本通过nfs provisioner动态生成pv会报错

Unexpected error getting claim reference to claim "default/test-claim1": selfLink was empty, can't make reference,报错原因是1.20版本启用了selfLink,解决方法如下;

编辑/etc/kubernetes/manifests/kube-apiserver.yaml

在这里:

spec:
  containers:
  - command:
    - kube-apiserver

添加这一行:

- --feature-gates=RemoveSelfLink=false

[root@master01 nfs-provisioner]# vim /etc/kubernetes/manifests/kube-apiserver.yaml
[root@master02 ~]# vi /etc/kubernetes/manifests/kube-apiserver.yaml
[root@master03 ~]# vi /etc/kubernetes/manifests/kube-apiserver.yaml

然后更新资源清单yaml文件即可:

[root@master01 nfs-provisioner]#  kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
pod/kube-apiserver created
[root@master02 ~]# kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
pod/kube-apiserver created
[root@master03 ~]# kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
pod/kube-apiserver created

 

[root@master01 nfs-provisioner]# kubectl get pods -n kube-system | grep apiserver
kube-apiserver                            0/1     CrashLoopBackOff   2          66s
kube-apiserver-master01                   1/1     Running            0          32s
kube-apiserver-master02                   1/1     Running            24         6d20h
kube-apiserver-master03                   1/1     Running            1          6d20h

重新更新apiserver.yaml会有生成一个新的pod:kube-apiserver,这个pod状态是CrashLoopBackOff,需要删除,高可用集群,需要一台一台的改

[root@master01 nfs-provisioner]# kubectl delete pods kube-apiserver -n kube-system
pod "kube-apiserver" deleted

[root@master02 ~]# kubectl delete pods kube-apiserver -n kube-system
pod "kube-apiserver" deleted

[root@master03 ~]# kubectl delete pods kube-apiserver -n kube-system
pod "kube-apiserver" deleted

 

继续阅读
weinxin
我的微信
这是我的微信扫一扫
  • 文本由 发表于 2021年8月30日13:38:28
  • 除非特殊声明,本站文章均为原创,转载请务必保留本文链接
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: