likes
comments
collection
share

k8s使用headless部署nacos集群

作者站长头像
站长
· 阅读数 16

我正在参加「掘金·启航计划」

一、写在前面

nacos是目前比较流行的一个框架,是阿里开源的一个框架。可用于配置中心注册中心

配置中心:就是说nacos,可以帮我们管理项目中,需要用到的配置文件,这些配置都可以交给nacos进行管理。配置中心可以实现多个环境的配置管理,多个环境之间配置的动态切换...

注册中心:就是说,我们的一些微服务可以注册到nacos上,然后其他的微服务就能发现,也就能调用到我们的服务。这就是我们常说的服务发现服务注册。当然,如果我们的微服务宕掉了,nacos也可以帮我们检测到,阻止向不健康的微服务发送请求。这就是我们常说的健康检查

基本上大部分得微服务框架,都会选择nacos,毕竟省事省心呀!!!

万事开头难,那今天我们就来先跑起nacos。本地跑nacos,那当然是很简单啦。

我们来学点高级得:k8s环境下,部署nacos集群

k8s使用headless部署nacos集群

二、nacos集群搭建

RC、Deployment、DaemonSet都是面向无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的,而StatefulSet是什么?顾名思义,有状态的集合,管理所有有状态的服务,比如MySQL、MongoDB集群等。

StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。

在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless service,headless service,即无头服务,与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。

除此之外,StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名,这个域名的格式为:

$(pod.name).$(headless server.name).${namespace}.svc.cluster.local

也即是说,对于有状态服务,我们最好使用固定的网络标识(如域名信息)来标记节点,当然这也需要应用程序的支持(如Zookeeper就支持在配置文件中写入主机域名)。

StatefulSet基于Headless Service(即没有Cluster IP的Service)为Pod实现了稳定的网络标志(包括Pod的hostname和DNS Records),在Pod重新调度后也保持不变。

以下为使用StatefulSet部署Nacos的架构,每一个pod节点,都作为StatefulSet的一个副本,对外暴露为一个Service,接受客户端请求。

2.1创建headless服务

Headless service是StatefulSet实现稳定网络标识的基础。

vi nacos-hs.yaml

---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s.kuboard.cn/layer: cloud
    k8s.kuboard.cn/name: nacos
  name: nacos-hs
  namespace: jxbp
spec:
  clusterIP: None
  ports:
    - name: rjybik
      port: 8848
      protocol: TCP
      targetPort: 8848
  selector:
    k8s.kuboard.cn/layer: cloud
    k8s.kuboard.cn/name: nacos
  type: ClusterIP  

命名空间为:jxbp,名称为:nacos-hs

执行:

kubectl apply -f nacos-hs.yaml

> service/nacos-hs created

网络访问:pod名称.headless名称.namespace名称.svc.cluster.local

即:pod名称.nacos-hs.jxbp.svc.cluster.local

2.2创建nacos的pod集群

创建好Headless service后,就可以利用StatefulSet创建Nacos集群节点,这也是本文的核心内容。

vi nacos.yaml

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    k8s.kuboard.cn/layer: cloud
    k8s.kuboard.cn/name: nacos
  name: nacos
  namespace: jxbp
spec:
  replicas: 3
  selector:
    matchLabels:
      k8s.kuboard.cn/layer: cloud
      k8s.kuboard.cn/name: nacos
  serviceName: nacos-hs
  template:
    metadata:
      labels:
        k8s.kuboard.cn/layer: cloud
        k8s.kuboard.cn/name: nacos
    spec:
      containers:
        - env:
            - name: JAVA_OPT
              value: '-Duser.timezone=GMT+08'
            - name: MODE
              value: cluster
            - name: PREFER_HOST_MODE
              value: hostname
            - name: NACOS_SERVERS
              value: >-
                nacos-0.nacos-hs.jxbp.svc.cluster.local:8848
                nacos-1.nacos-hs.jxbp.svc.cluster.local:8848
                nacos-2.nacos-hs.jxbp.svc.cluster.local:8848
          image: '192.168.4.xx/jxbp/nacos:1.4.2'
          imagePullPolicy: IfNotPresent
          name: nacos
          ports:
            - containerPort: 8848
              protocol: TCP
          volumeMounts:
            - mountPath: /opt/jxbp/nacos/conf/application.properties
              name: volume-efrre
            - mountPath: /etc/localtime
              name: volume-2heaz
      volumes:
        - hostPath:
            path: /opt/jxbp/nacos/conf/application.properties
            type: FileOrCreate
          name: volume-efrre
        - hostPath:
            path: /etc/localtime
            type: FileOrCreate
          name: volume-2heaz

名称为:nacos,对应的镜像为:nacos:1.4.2

挂载的文件:宿主机的/opt/jxbp/nacos/conf/application.properties到nacos容器的/opt/jxbp/nacos/conf/application.properties(application.properties配置文件如下所示)

可能上面的yaml文件,大多数小伙看不太懂,那这里,我们可以使用kuboard客户端来进行部署。

k8s使用kuboard可视化客户端,可以参考我之前的文章k8s部署(juejin.cn/post/706770…)

  • kuboard界面

k8s使用headless部署nacos集群

k8s使用headless部署nacos集群

k8s使用headless部署nacos集群

k8s使用headless部署nacos集群

  • application.properties
# mysql
spring.datasource.platform=mysql
db.jdbcDriverName=com.mysql.cj.jdbc.Driver
db.num=1
db.url.0=jdbc:mysql://localhost:3306/jxbp_nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=root

这里要注意几个参数

MODE: cluster,表示以集群模式启动

PREFER_HOST_MODE: hostname,表示支持域名(支持IP还是域名模式,hostname/ip 默认 ip

NACOS_SERVERS: p1:port1空格ip2:port2 空格ip3:port3 , 表示集群地址

这里,上面提到StatefulSet能提供稳定网络标识,所以这里我们使用域名的方式部署nacos集群,因为每次重启nacos,pod的ip是不断变化的,所以这里不能用固定的ip,所以之类改成域名方式,那这里得配置PREFER_HOST_MODEhostname

这里要说明一下,因为我是修改过nacos源码,为了支持dm,kingbase等国产数据库得,所以我是需要用自己打包好的nacos服务,进行docker镜像的打包。

那就不会存在PREFER_HOST_MODENACOS_SERVERS这些参数,至于这些参数怎么来的,我是参考nacos docker文档

k8s使用headless部署nacos集群

k8s使用headless部署nacos集群

由上可见,我们就可以参考官方的docker打包方式,增加相应的配置:

k8s使用headless部署nacos集群

然后重新打包nacos的docker镜像即可。

2.3nacos集群验证

k8s使用headless部署nacos集群

由上可见,这些节点都是稳定的。

一开始,我没有设置PREFER_HOST_MODE: hostname,这里的节点,总会多几个pod的ip+port,而且总是不稳定。

nacos集群的cluster.conf文件,总会时不时的写入一些pod的ip:

k8s使用headless部署nacos集群

这里找了一些说明,感觉还是挺清晰的:说明

k8s使用headless部署nacos集群

k8s使用headless部署nacos集群

这里的问题,虽然不能解决我的问题,但是,却给我提供了一些思路。

最终通过对比官方k8s的部署,官方的部署是正常的,然后通过对比,验证,最终定位到PREFER_HOST_MODE: hostname,要改成支持域名的方式。

cluster.conf文件也正常了,不再写入一些pod的ip。

2.4创建Service服务

前面我们创建了用于实现StatefulSet的Headless Service,但该Service没有Cluster Ip,因此不能用于外界访问。所以,我们还需要创建一个Service,专用于为Nacos集群提供访问和负载均衡。

这里可以使用ClusterIPNodePort。这里,我使用的是ClusterIP

vi nacos-ss.yaml

---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s.kuboard.cn/layer: cloud
    k8s.kuboard.cn/name: nacos
  name: nacos-ss
  namespace: jxbp
spec:
  clusterIP: 10.96.211.199
  clusterIPs:
    - 10.96.211.199
  ports:
    - name: imdgss
      port: 8848
      protocol: TCP
      targetPort: 8848
  selector:
    k8s.kuboard.cn/layer: cloud
    k8s.kuboard.cn/name: nacos
  type: ClusterIP

创建名称为:nacos-ss的服务。

在K8S集群中暴露8848端口,并且会对labels namek8s.kuboard.cn/name: nacos的pod进行负载均衡。

然后在K8S集群中,就可以通过nacos-ss:8848,对nacos集群进行访问。

kubectl get service -n jxbp
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                                                         AGE
nacos-hs        ClusterIP   None            <none>        8848/TCP                                                        35m
nacos-ss        ClusterIP   10.96.211.199   <none>        8848/TCP                                                        75m

大家可以看到我的yaml文件,我这里是指定了ClusterIP的ip为10.96.211.199,作为nacos集群service的一个固定的ip。

为什么我要这么干呢?因为这里我发现,如果我不指定这个ip,那每次执行kubectl apply -f nacos-ss.yaml,都会重新分配一个ip。然后就会导致其他的pod,例如nginx,还是通过nacos-ss:8848访问nacos集群,还是会用了以前nacos的pod的ip地址(估计是dns没有及时更新)。

遇到这个情况,在重启这个nginx的pod,然后就能正常访问了,所以这里我怀疑的K8S的dns域名存在缓存问题导致。(这问题困惑比较久)

不知道其他人有无遇到过这样的问题,如有,可以指点我一下,十分感谢!!!


好了,以上就是我个人的实操了。可能有些不对,大家伙,轻点喷!!!

个人理解,可能也不够全面,班门弄斧了。

好了,今天就先到这里了!!!^_^

如果觉得有收获的,帮忙点赞、评论、收藏一下呗!!!

k8s使用headless部署nacos集群