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的形式连接,同集群内部服务使用
方案2:nacos解耦k8s集群,独立部署nacos集群。统一使用haproxy+port的连接方式。有利于worker节点的扩容、下线等维护操作,避免节点因故障影响到nacos的可用性
建议使用方案2,有效提高nacos集群稳定性、可控性,缩短处理故障问题的时间