天天看点

Kubernetes 搭建 ES 集群(存储使用 local pv)

推荐阅读

Helm3(K8S 资源对象管理工具)视频教程:https://edu.csdn.net/course/detail/32506
Helm3(K8S 资源对象管理工具)博客专栏:https://blog.csdn.net/xzk9381/category_10895812.html
本文原文链接:https://blog.csdn.net/xzk9381/article/details/109571008,转载请注明出处。如有发现文章中的任何问题,欢迎评论区留言。

一、集群规划

  1. 由于当前环境中没有分布式存储,所以只能使用本地 PV 的方式来实现数据持久化,如果希望了解使用 cephfs 搭建 ES 集群,可以参考我的另外两篇文章:CentOS 7 搭建 Ceph 集群(nautilus 版本) 和 Kubernetes 搭建 ES 集群(存储使用 cephfs)。
  2. ES 集群的 master 节点至少需要三个,防止脑裂。
  3. 由于 master 在配置过程中需要保证主机名固定和唯一,所以搭建 master 使用 StatefulSet 控制器
  4. node 节点需要固定的主机名和固定的物理节点以及物理节点上的本地PV,所以需要使用 StatefulSet,配合 StorageClass 来固定。
  5. kibana为无状态服务,使用deployment。

二、修改 elasticsearch 镜像

在部署 elasticsearch 的时候建议配置 memlock:true,这个要求系统必须配置ulimit。所以需要修改镜像,使其在容器内自动执行。

Dockerfile 内容如下:

FROM docker.elastic.co/elasticsearch/elasticsearch:7.3.0

MAINTAINER [email protected]

COPY run.sh /
RUN chmod 755 /run.sh

CMD ["/run.sh"]
           

run.sh 脚本内容如下:

#!/bin/bash

ulimit -l unlimited
 
exec su elasticsearch /usr/local/bin/docker-entrypoint.sh
           
elasticsearch 用户是官方镜像中已经创建好的用户

在 Dockerfile 目录中执行如下命令构建镜像:

构建完成的镜像可以选择推送到私有镜像仓库中,也可以选择将镜像导出到本地,然后再导入到各个 k8s node 节点中。这里选择首先将镜像导出到本地:

docker save elasticsearch:7.3.0 -o elasticsearch_ulimit_7.3.0.tar
           

再将镜像导入到各个 node 节点中:

docker load --input elasticsearch_ulimit_7.3.0.tar
           

三、创建命名空间

将 ES 集群统一放到一个单独的命名空间中,yaml 文件内容如下:

---
apiVersion: v1
kind: Namespace
metadata:
  name: ns-elasticsearch
  labels:
    name: ns-elasticsearch
           

四、创建 ServiceAccount 并绑定角色

设置 ES 使用单独的 ServiceAccount,所以需要手动创建一个并分配进群角色,yaml 文件内容如下:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    elastic-app: elasticsearch
  name: elasticsearch-admin
  namespace: ns-elasticsearch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: elasticsearch-admin
  labels:
    elastic-app: elasticsearch
rules: 										# 根据需要配置相应的api/资源/权限
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get","watch","list"] 
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: elasticsearch-admin
  labels:
    elastic-app: elasticsearch
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: elasticsearch-admin
    namespace: ns-elasticsearch
           

五、创建本地持久化存储

1. 存储规划

首先在 k8s-node1 至 k8s-node5 节点中创建 /opt/es/es-node-data 目录,用于存储 ES Data 节点的数据。在 k8s-node3 至 k8s-node5 节点中创建 /opt/es/es-master-data 目录用于存储 ES Master 节点的数据。在 k8s-node3 节点中创建 /opt/es/kibana-data 目录用于存储 kibana 数据。需要注意的是,es-node-data、es-master-data、kibana-data 这三个目录都需要设置 777 权限。

2. 设置 label

为了确保 Pod 调度到指定机器中,需要设置以下 label:

  • 为 k8s-node1 至 k8s-node5 节点添加 es-data-node=true 标签;
kubectl label nodes k8s-node1 es-data-node=true
kubectl label nodes k8s-node2 es-data-node=true
kubectl label nodes k8s-node3 es-data-node=true
kubectl label nodes k8s-node4 es-data-node=true
kubectl label nodes k8s-node5 es-data-node=true
           
  • 为 k8s-node3 至 k8s-node5 节点添加 es-data-master=true 标签;
kubectl label nodes k8s-node3 es-data-master=true
kubectl label nodes k8s-node4 es-data-master=true
kubectl label nodes k8s-node5 es-data-master=true
           
  • 为 k8s-node3 节点添加 es-kibana-data=true 标签;
kubectl label nodes k8s-node3 es-kibana-data=true
           

3. 创建 StorageClass

创建 StorageClass 的 yaml 文件内容如下:

---
kind: StorageClass 
apiVersion: storage.k8s.io/v1
metadata:
  name: local-es-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer 	# 绑定模式为等待消费者,即当Pod分配到节点后,进行与PV的绑定
           

4. 创建 PV 和 PVC

由于有三个服务需要进行持久化存储,所以需要创建三个 PV 和 PVC。

4.1 ES Master 存储

创建用于 ES Master 节点数据存储的 PV 和 PVC yaml 文件内容如下:

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-es-master-pv
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 200Gi
  local:
    path: /opt/es/es-master-data                # 需要在指定的节点创建相应的目录
  nodeAffinity:                                 # 指定节点,对节点配置label
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: es-data-master
          operator: In
          values:
          - "true"
  persistentVolumeReclaimPolicy: Retain         # 回收策略为保留,不会删除数据,即当pod重新调度的时候,数据不会发生变化.
  storageClassName: local-es-storage

---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: local-es-master-pvc
  namespace: ns-elasticsearch
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: local-es-storage
  resources:
    requests:
      storage: 200Gi
           
4.2 ES Node 存储

创建用于 ES Node 节点数据存储的 PV 和 PVC yaml 文件内容如下:

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-es-node-pv
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 1024Gi
  local:
    path: /opt/es/es-node-data                   # 需要在指定的节点创建相应的目录
  nodeAffinity:                                  # 指定节点,对节点配置label
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: es-data-node
          operator: In
          values:
          - "true"
  persistentVolumeReclaimPolicy: Retain         # 回收策略为保留,不会删除数据,即当pod重新调度的时候,数据不会发生变化.
  storageClassName: local-es-storage
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: local-es-node-pvc
  namespace: ns-elasticsearch
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: local-es-storage
  resources:
    requests:
      storage: 1024Gi
           
4.3 Kibana 存储

创建用于 Kibana 节点数据存储的 PV 和 PVC yaml 文件内容如下:

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-kibana-pv
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 2Gi
  local:
    path: /opt/es/kibana-data                   # 需要在指定的节点创建相应的目录
  nodeAffinity:                                 # 指定节点,对节点配置label
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: es-kibana-data
          operator: In
          values:
          - "true"
  persistentVolumeReclaimPolicy: Retain         # 回收策略为保留,不会删除数据,即当pod重新调度的时候,数据不会发生变化.
  storageClassName: local-es-storage
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: local-kibana-pvc
  namespace: ns-elasticsearch
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: local-es-storage
  resources:
    requests:
      storage: 2Gi
           

六、创建 ES Master 节点

1. 创建 StatefulSet

Master 主节点采用三个节点的方式,避免出现脑裂的情况,由于Master所占资源较低,可以配置其容忍 k8s 主节点的污点并调度到该节点上,yaml 文件内容如下:

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    elastic-app: elasticsearch
    role: master
  name: elasticsearch-master
  namespace: ns-elasticsearch
spec:
  replicas: 3
  serviceName: elasticsearch-discovery          # 用于给每一个pod提供一个podname.serviceName的域名进行访问.
  selector:
    matchLabels:
      elastic-app: elasticsearch
      role: master
  template:
    metadata:
      labels:
        elastic-app: elasticsearch
        role: master
    spec:
      serviceAccountName: elasticsearch-admin
      restartPolicy: Always
      containers:
        - name: elasticsearch-master
          image: elasticsearch:7.3.0
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              memory: "20480Mi"
              cpu: "1000m"
          securityContext:
            privileged: true                   # 获取root权限,这样才能进行初始化命令执行.
          lifecycle:
            postStart:                         # 初始化命令,配置系统参数
              exec:
                command:
                - /bin/bash
                - -c
                - sysctl -w vm.max_map_count=262144; ulimit -l unlimited;
          ports:                               # 开放端口一个是集群端口,一个是数据端口
            - containerPort: 9200
              protocol: TCP
            - containerPort: 9300
              protocol: TCP
          env:                                 # 环境变量,非容器下在配置文件配置的,这里对应配置为环境变量就可以了
            - name: cluster.name
              value: "es_cluster"
            - name: bootstrap.memory_lock
              value: "true"
            - name: node.master
              value: "true"
            - name: node.data
              value: "false"
            - name: discovery.seed_hosts
              value: "elasticsearch-discovery"
            - name: cluster.initial_master_nodes
              value: "elasticsearch-master-0,elasticsearch-master-1,elasticsearch-master-2"
            - name: node.ingest
              value: "false"
            - name: ES_JAVA_OPTS
              value: "-Xms10g -Xmx10g"
          volumeMounts:
            - name: es-master-data
              mountPath: /usr/share/elasticsearch/data
      volumes:
      - name: es-master-data
        persistentVolumeClaim:
          claimName: local-es-master-pvc
      tolerations:                             # 使其可以运行在k8s主节点上
      - effect: NoSchedule
        key: node-role.kubernetes.io/master
           
本文原文链接:https://blog.csdn.net/xzk9381/article/details/109571008,转载请注明出处。如有发现文章中的任何问题,欢迎评论区留言。

2. 创建 Service

Master 主节点不需要对外暴露端口,所以 yaml 文件内容如下:

---
kind: Service
apiVersion: v1
metadata:
  labels:
    elastic-app: elasticsearch
  name: elasticsearch-discovery
  namespace: ns-elasticsearch
spec:
  ports:
    - port: 9300
      targetPort: 9300
  selector:
    elastic-app: elasticsearch
    role: master
           

七、创建 ES Data 节点

1. 创建 StatefulSet

Data 节点用于存储收集到的日志信息,为了便于部署,此次实施将 Ingest 和 Data 节点部署在一起(在配置文件中同时启动 data 和 ingest),yaml 文件内容如下:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    elastic-app: elasticsearch
    role: node
  name: elasticsearch-node
  namespace: ns-elasticsearch
spec:
  replicas: 5
  serviceName: elasticsearch-service
  selector:
    matchLabels:
      elastic-app: elasticsearch
      role: node
  template:
    metadata:
      labels:
        elastic-app: elasticsearch
        role: node
    spec:
      serviceAccountName: elasticsearch-admin
      restartPolicy: Always
      containers:
        - name: elasticsearch-node
          lifecycle:
            postStart:
              exec:
                command: ["/bin/bash", "-c", "sysctl -w vm.max_map_count=262144; ulimit -l unlimited;"]
          image: elasticsearch:7.3.0
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              memory: "30720Mi"
              cpu: "2000m"
          securityContext:
            privileged: true
          ports:
            - containerPort: 9200
              protocol: TCP
            - containerPort: 9300
              protocol: TCP
          env:
            - name: cluster.name
              value: "es_cluster"
            - name: "bootstrap.memory_lock"
              value: "true"
            - name: node.master
              value: "false"
            - name: node.data
              value: "true"
            - name: discovery.seed_hosts
              value: "elasticsearch-discovery"
            - name: cluster.initial_master_nodes
              value: "elasticsearch-master-0,elasticsearch-master-1,elasticsearch-master-2,elasticsearch-master-3,elasticsearch-master-4"
            - name: node.ingest
              value: "true"
            - name: ES_JAVA_OPTS
              value: "-Xms10g -Xmx10g"
          volumeMounts:
            - name: es-node-data
              mountPath: /usr/share/elasticsearch/data  # 需要localPV绑定到该目录,这个官方指定的容器内数据目录
      volumes:
      - name: es-node-data
        persistentVolumeClaim:
          claimName: local-es-node-pvc
           

2. 创建 Service

需要将 Data 节点的 9200 端口暴露出来,同时也用于 Ingest 接收 Filebeat 传送过来的日志信息,yaml 文件内容如下:

---
kind: Service
apiVersion: v1
metadata:
  labels:
    elastic-app: elasticsearch-service
  name: elasticsearch-service
  namespace: ns-elasticsearch
spec:
  ports:
  - port: 9200
    protocol: TCP
    targetPort: 9200
  selector:
    elastic-app: elasticsearch
  type: NodePort
           

八、创建 Kibana

1. 创建 Deployment

Kibana 作为一个无状态服务,直接使用 Deployment 创建即可,yaml 文件内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kibana
  labels:
    elastic-app: kibana
  namespace: ns-elasticsearch
spec:
  replicas: 1
  selector:
    matchLabels:
      elastic-app: kibana
  template:
    metadata:
      name: kibana
      labels:
        elastic-app: kibana
    spec:
      serviceAccountName: elasticsearch-admin
      restartPolicy: Always
      containers:
      - name: kibana
        image: kibana:7.3.0
        imagePullPolicy: IfNotPresent
        env:
          - name: SERVER_NAME
            value: "kibana"
          - name: SERVER_HOST
            value: "0.0.0.0"
          - name: ELASTICSEARCH_HOSTS
            value: "http://elasticsearch-service.ns-elasticsearch:9200"
          - name: I18N_LOCALE
            value: zh-CN
        volumeMounts:
            - name: kibana-data
              mountPath: /usr/share/kibana/data
      volumes:
      - name: kibana-data
        persistentVolumeClaim:
          claimName: local-kibana-pvc
           

2. 创建 Service

需要将 Kibana 的 5601 端口暴露出来,yaml 文件内容如下:

---
apiVersion: v1
kind: Service
metadata:
  name: kibana-service
  labels:
    elastic-app: kibana-service
  namespace: ns-elasticsearch
spec:
  ports:
  - port: 5601
    targetPort: 5601
  selector:
    elastic-app: kibana
  type: NodePort
           

Kibana 创建完成后查看 Service 信息:

[@k8s-master1 ~]# kubectl get svc -n ns-elasticsearch
NAME                      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
elasticsearch-discovery   ClusterIP   10.102.167.126   <none>        9300/TCP         77m
elasticsearch-service     NodePort    10.101.60.203    <none>        9200:30187/TCP   74m
kibana-service            NodePort    10.98.206.184    <none>        5601:31837/TCP   73m
           

可以看到将 Kibana 的 5601 端口映射到 31837 端口中,直接在浏览器中使用 NodeIP:31837 即可访问 Kibana 页面。

九、启动 Filebeat 收集日志

在此次实施过程中没有在 K8S 的 POD 中安装 filebeat,所以直接使用物理机中已有的 filebeat 服务。

首先在 /opt/filebeat-7.3.0/conf 目录下(提前在 /opt 目录下安装 filebeat)创建一个名为 ES-test.yml 的配置文件,内容如下:

filebeat.idle_timeout: 2s
filebeat.inputs:
- backoff: 1s
  backoff_factor: 2
  close_inactive: 1h
  enabled: true
  encoding: plain
  harvester_buffer_size: 262144
  max_backoff: 10s
  max_bytes: 10485760
  paths:
  - /opt/test.log
  scan_frequency: 10s
  tail_lines: true
  type: log
filebeat.name: filebeat-shiper
filebeat.spool_zie: 50000
output.elasticsearch:
  bulk_max_size: 8192
  hosts:
  - k8s-node1:30187
  index: es-test
  workers: 4
processors:
- drop_fields:
    fields:
    - agent.ephemeral_id
    - agent.hostname
    - agent.id
    - agent.type
    - agent.version
    - ecs.version
    - input.type
    - log.offset
    - version
- decode_json_fields:
    fields:
    - message
    max_depth: 1
    overwrite_keys: true
setup.ilm.enabled: false
setup.template.name: es-test
setup.template.pattern: es-test-*
           

启动 filebeat:

此时在 kibana 中可以看到新建了一个名为 es-test 的索引,根据这个索引创建对应的索引模式,即可查看收集的相关日志。

十、查看 ES 集群状态

通过查看 Service 信息可以看到 ES Data node 节点暴露出来的端口号信息:

[@k8s-master1 ~]# kubectl get svc -n ns-elasticsearch
NAME                      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
elasticsearch-discovery   ClusterIP   10.102.167.126   <none>        9300/TCP         77m
elasticsearch-service     NodePort    10.101.60.203    <none>        9200:30187/TCP   74m
kibana-service            NodePort    10.98.206.184    <none>        5601:31837/TCP   73m
           

9200 对外映射的端口为 30187,在浏览器中输入 NodeIP:30187/_cat/nodes?v 可以查看到各个节点的信息:

[@k8s-master1 ~]# curl http://10.11.16.211:30187/_cat/nodes?v
ip              heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
100.111.156.90            59          29   2    0.25    0.28     0.48 di        -      elasticsearch-node-0
100.102.107.215           11          33   2    0.43    0.51     0.70 di        -      elasticsearch-node-4
100.67.139.19              1          17   1    0.40    0.39     0.59 m         *      elasticsearch-master-0
100.100.52.26              1          17   1    0.31    0.36     0.60 m         -      elasticsearch-master-1
100.67.139.20             39          17   2    0.40    0.39     0.59 di        -      elasticsearch-node-2
100.102.107.214            1          33   2    0.43    0.51     0.70 m         -      elasticsearch-master-2
100.100.52.27             30          17   1    0.31    0.36     0.60 di        -      elasticsearch-node-3
100.64.169.149            53          26   2    0.69    0.74     0.79 di        -      elasticsearch-node-1
           

在浏览器中输入 NodeIP:30187/_cat/health?v 可以查看集群的健康信息:

[@k8s-master1 ~]# curl http://10.11.16.211:30187/_cat/health?v
epoch      timestamp cluster    status node.total node.data shards pri relo init unassign pending_tasks
1594709799 06:56:39  es_cluster green           8         5     34  17    0    0        0             0
           
本文原文链接:https://blog.csdn.net/xzk9381/article/details/109571008,转载请注明出处。如有发现文章中的任何问题,欢迎评论区留言。

继续阅读