K8S部署StatefulSet有状态Nacos集群

K8S部署StatefulSet有状态Nacos集群

Deng YongJie's blog 567 2022-09-25

K8S部署StatefulSet有状态Nacos集群

自行部署csi-nfs插件

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nacos
  namespace: pub-service
  labels:
    app: nacos
spec:
  serviceName: nacos-headless
  replicas: 3
  template:
    metadata:
      labels:
        app: nacos
      annotations:
        pod.alpha.kubernetes.io/initialized: "true"
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                      - nacos
              topologyKey: "kubernetes.io/hostname"
      serviceAccountName: nfs-client-provisioner
      initContainers:
        - name: peer-finder-plugin-install
          image: nacos/nacos-peer-finder-plugin:latest
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - mountPath: /home/nacos/plugins/peer-finder
              name: data   #名字需要和下面动态nfs的挂载名一致
              subPath: peer-finder
      containers:
        - name: nacos
          imagePullPolicy: IfNotPresent
          #image: nacos/nacos-server:v1.4.3
          image: reg.songmao.tech/ops-test/nacos-server:v2.0.4
          resources:
            requests:
              memory: "2Gi"
              cpu: "500m"
          ports:
            - containerPort: 8848
              name: client-port
            - containerPort: 9848
              name: client-rpc
            - containerPort: 9849
              name: raft-rpc
            - containerPort: 7848
              name: old-raft-rpc
          env:
            - name: NACOS_REPLICAS
              value: "3"
            - name: SERVICE_NAME
              value: "nacos-headless"
            - name: DOMAIN_NAME
              value: "cluster.local"
            - name: MODE
              value: "cluster"
            - name: SPRING_DATASOURCE_PLATFORM
              value: "mysql"
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.namespace
            - name: MYSQL_SERVICE_DB_NAME
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.db.name
            - name: MYSQL_SERVICE_PORT
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.port
            - name: MYSQL_SERVICE_USER
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.user
            - name: MYSQL_SERVICE_HOST
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.host
            - name: MYSQL_SERVICE_PASSWORD
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.password
            - name: NACOS_SERVER_PORT
              value: "8848"
            - name: NACOS_APPLICATION_PORT
              value: "8848"
            - name: PREFER_HOST_MODE
              value: "hostname"
            - name: MYSQL_SERVICE_DB_PARAM
              #value: "characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true"
              value: "characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC"  #2.0版本的jdbc,后面要加上UTC,否则出现时区问题
            - name: MYSQL_DATABASE_NUM
              value: "1"
          volumeMounts:
            - name: data
              mountPath: /home/nacos/plugins/peer-finder
              subPath: peer-finder
            - name: data
              mountPath: /home/nacos/data
              subPath: data
            - name: data
              mountPath: /home/nacos/logs
              subPath: logs
  volumeClaimTemplates:
    - metadata:
        name: data
        annotations:
          volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"  #动态nfs-client
      spec:
        accessModes: [ "ReadWriteMany" ]
        resources:
          requests:
            storage: 20Gi     #分别创建3个pod为20G的pvc,并自动关联PV
  selector:
    matchLabels:
      app: nacos

问题:
Headless Service是Kubernetes Service的一种类型,其特点是没有Cluster IP,没有负载均衡能力,且不会为Service中的Pod分配稳定的IP地址。Headless Service的作用是为StatefulSet中的Pod提供固定的DNS名称,使得这些Pod可以被其他服务或者客户端通过这个固定的DNS名称访问到。(这就是nacos集群为什么使用无头service,三节点要互相解析地址并注册建立集群)
Headless Service的原理是通过kube-proxy在每个Node上创建对应的Endpints对象来实现的。每个Endpoints对象都包含了Headless Service对应的所有Pod的IP地址及其端口信息,而这些Pod的IP地址是由Kubernetes集群中的DNS服务器CoreDNS动态分配的。当客户端通过Headless Service的DNS名称访问该Service时,DNS服务器会返回Endpoints中的所有IP地址,而客户端会根据这些IP地址直接访问对应的Pod。(那么其中1个nacos故障,也会请求到故障的nacos节点。)
Headless Service不提供负载均衡能力的原因是因为其目的是为了提供固定的DNS名称,而不是为了实现负载均衡。如果需要实现负载均衡,可以使用其他类型的Service,如ClusterIP类型的Service或NodePort类型的Service。(可以另外创建一个cluster类型的SVC,提供给微服务使用)

方案1:nacos创建NodePort类型SVC并暴露固定端口,开发PC电脑改成haproxy+port的形式连接,同集群内部服务使用..svc.cluster.local:8848连接

方案2:nacos解耦k8s集群,独立部署nacos集群。统一使用haproxy+port的连接方式。有利于worker节点的扩容、下线等维护操作,避免节点因故障影响到nacos的可用性

建议使用方案2,有效提高nacos集群稳定性、可控性,缩短处理故障问题的时间