Detailed Explanation of Spring Cloud Integration with Nacos

overview

Nacos official documentation: https://nacos.io/zh-cn/docs/what-is-nacos.html

Nacos is dedicated to discovering, configuring and managing microservices. Nacos provides a set of easy-to-use features to quickly realize dynamic service discovery, service configuration, service metadata and traffic management.

Nacos builds, delivers and manages microservice platforms more agilely and easily. Nacos is a service infrastructure for building a "service"-centric modern application architecture (such as microservice paradigm, cloud native paradigm).


Services are first-class citizens in the Nacos world. Nacos supports the discovery, configuration and management of almost all mainstream types of "services":

  • Kubernetes Service

  • gRPC & Dubbo RPC Service

  • Spring Cloud RESTful Service


Key features of Nacos include:

  • Service discovery and service health monitoring

    Nacos supports DNS-based and RPC-based service discovery. After the service provider uses the native SDK, OpenAPI, or an independent Agent TODO to register the Service, the service consumer can use DNS TODO or HTTP&API to find and discover the service.

    Nacos provides real-time health checks on services, preventing requests from being sent to unhealthy hosts or service instances. Nacos supports transport layer (PING or TCP) and application layer (such as HTTP, MySQL, user-defined) health checks. For the health check of services in a complex cloud environment and network topology environment (such as VPC, edge network, etc.), Nacos provides two health check modes: agent reporting mode and server active detection mode. Nacos also provides a unified health check dashboard to help manage service availability and traffic based on health status.

  • Dynamic configuration service

    The dynamic configuration service manages the application configuration and service configuration of all environments in a centralized, externalized and dynamic way.

    Dynamic configuration eliminates the need to redeploy applications and services when configuration changes, making configuration management more efficient and agile.

    Configuration centralized management makes it easier to implement stateless services and make it easier for services to expand elastically on demand.

    Nacos provides a simple and easy-to-use UI to manage all service and application configurations. Nacos also provides a series of out-of-the-box configuration management features including configuration version tracking, canary release, one-click rollback configuration, and client configuration update status tracking, which can more safely manage configuration changes in the production environment and reduce the risks caused by configuration changes.

  • Dynamic DNS service

    The dynamic DNS service supports weighted routing, which makes it easier to implement middle-tier load balancing, more flexible routing policies, flow control, and simple DNS resolution services for the intranet of the data center. The dynamic DNS service can also more easily implement service discovery based on the DNS protocol to eliminate the risk of coupling to the vendor's private service discovery API.

    Nacos provides some simple DNS APIs TODO management service associated domain name and available IP:PORT list.

  • Services and their metadata management

    Nacos can manage all services and metadata in the data center from the perspective of microservice platform construction, including management service description, life cycle, service static dependency analysis, service health status, service traffic management, routing and security policies, service SLA and the most important metrics statistics.


nacos integration

Reference: https://blog.csdn.net/ZHANGLIZENG/article/details/119065077

Dependency import

	<!-- nacos -->
	<dependency>
		<groupId>com.alibaba.cloud</groupId>
    	<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    	<version>2.2.1.RELEASE</version>
	</dependency>
    <dependency>
    	<groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2.2.1.RELEASE</version>
    </dependency>

Notice:

  • If you use the dependency version number of the example, the Spring Boot version must be lower than 2.4, otherwise an error will be reported when starting the application.

  • Comparison of SpringBoot, SpringCloud and nacos integration version correspondence (if the version does not match, the application may start an error):

    https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E


Configure Nacos

The default configuration file in the project is application.properties. If Nacos configuration is added to this configuration file, the application startup will report failure to connect to Nacos. You need to create a bootstrap.properties or bootstrap.yml configuration file (add any one). The following uses bootstrap.yml as an example:

spring:
  application:
    # 项目(微服务)名称
    name: apm-mobile-android
  cloud:
    nacos:
      # nacos用户名
      username: nacos
      # nacos用户密码
      password: nacos
      # nacos服务器地址
      server-addr: 10.0.7.115:18117
      # nacos配置中心相关
      config:
        # 开启nacos作为配置中心,默认值:true
        enabled: true
        # 作为配置中心的nacos服务器地址,默认值:${spring.cloud.nacos:server-addr}
        #server-addr: 10.0.7.115:18117
        # 配置文件读取的nacos命名空间ID,默认值:public
        namespace: PROD
        # 配置文件在nacos命名空间中的分组,默认值:DEFAULT_GROUP
        group: apm
        # 配置文件的文件前缀(配置文件名称),默认值:${spring.application.name}
        prefix: ${
    
    spring.application.name}
        # 配置文件的文件后缀(文件类型),默认值:properties
        file-extension: properties
        # 配置内容的编码方式,默认值:UTF-8
        encode: UTF-8
        # 获取配置的超时时间,单位:ms,默认值:3000
        timeout: 3000
        # 开启监听和自动刷新,动态感知配置变化,默认值:true
        refresh-enabled: true
        # AccessKey
        #access-key: 123
        # SecretKey
        #secret-key: 123
        # 引入共享配置(同一分组)
        shared-configs:
            # 配置支持共享的 Data Id
          - data-id: comm.properties
        # 配置 Data Id 所在分组,缺省默认 DEFAULT_GROUP
            group: DEFAULT_GROUP
        # 配置Data Id 在配置变更时,是否动态刷新,缺省默认 false
            refresh: true
        # 引入扩展配置(同一分组或不同分组)
        extension-configs:
            # 配置支持共享的 Data Id
          - data-id: comm.properties
            # 配置 Data Id 所在分组,缺省默认 DEFAULT_GROUP
            group: DEFAULT_GROUP
            # 配置Data Id 在配置变更时,是否动态刷新,缺省默认 false
            refresh: true
      # nacos注册中心相关
      discovery:
        # 开启nacos作为服务注册中心,默认值:true
        enabled: true
        # 作为注册中心的nacos服务器地址,默认值:${spring.cloud.nacos:server-addr}
        #server-addr: 10.0.7.115:18117
        # 服务注册在nacso上的命名空间ID,默认值:public
        namespace: PROD

Load Nacos configuration center configuration items

Just add annotations to the initialization class @EnableDiscoveryClient:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient		// 开启服务发现客户端,加载Nacos配置中心配置项
@SpringBootApplication
public class SpringbootdemoApplication {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(SpringbootdemoApplication.class, args);
        new BootstrapManager();
    }
}

Nacos configuration center configuration items take effect dynamically

Preconditions:

  • The nacos configuration item in the bootstrap configuration file refresh-enabled: true (enabled by default)

    # 开启监听和自动刷新,动态感知配置变化,默认值:true
    spring.cloud.nacos.config.refresh-enabled=true
    

Method 1: @Value + @RefreshScope to get the latest value

@RestController
@RefreshScope	// 配置项动态生效
public class TestController {
    
    
    @NacosValue(value = "${test.data}", autoRefreshed = true)
    private String data;
    @Value(value = "${test.data}")
    private String datas;
    @GetMapping("test")
    public String test() {
    
    
        return "data :" + data + ",datas="+datas;
    }
}

Method 2: Obtain the latest value through applicationContext.getEnvironment.getProperty

@SpringBootApplication
public class NacosConfigSimpleApplication {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        ConfigurableApplicationContext applicationContext =
                  SpringApplication.run(NacosConfigSimpleApplication.class, args);
        //取到Spring的配置环境
        while(true){
    
    
            ConfigurableEnvironment environment = applicationContext.getEnvironment();
            String username = environment.getProperty("user.name");
            String age = environment.getProperty("user.age");
            System.out.println("username:"+username+" | age:"+age);
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

Method 3: Obtain the latest value through @NacosValue

Standalone uses @NacosValue to get the latest value of nacos, and the configuration information needs to be written on the configuration class

@Configuration
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848"))
@NacosPropertySource(dataId = "example", group="test",autoRefreshed = true)
public class NacosConfiguration {
    
     }
@Controller
public class ConfigController {
    
    
    @NacosValue(value = "${test.data}", autoRefreshed = true)
    private boolean data;                                     
    @RequestMapping(value = "/test", method = GET)
    @ResponseBody
    public boolean get() {
    
     return data; }
}

Import public configuration files

The configuration file read by default is the configuration of the configuration file with the same service name; if there are other public configurations that need to be read in, it involves the reading of multiple configuration files.

The way to introduce public configuration files in the bootstrap configuration file:

  • Method 1: Expand the configuration method

    It is possible to import public profiles in the same group as the default profile or in a different group

    • Use extension-configs to import configurations as arrays, and set data_id, group, and refresh values

      # 配置支持共享的 Data Id
      spring.cloud.nacos.config.extension-configs[0].data-id=comm.properties
      # 配置 Data Id 所在分组,缺省默认 DEFAULT_GROUP
      spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP
      # 配置Data Id 在配置变更时,是否动态刷新,缺省默认 false
      spring.cloud.nacos.config.extension-configs[0].refresh=true
      
    • Use ext-configs to import configurations as arrays, and set data_id, group, and refresh values

      (ext-config official flag obsolete; replaced by extension-configs)

  • Method 2: Shared configuration method

    Only public profiles in the same group as the default profile can be imported

    • Use shared-configs to import configurations as arrays, and set data_id, group, and refresh values

      # 配置支持共享的 Data Id
      spring.cloud.nacos.config.shared-configs[0].data-id=comm.properties
      # 配置 Data Id 所在分组,缺省默认 DEFAULT_GROUP
      spring.cloud.nacos.config.shared-configs[0].group=DEFAULT_GROUP
      # 配置Data Id 在配置变更时,是否动态刷新,缺省默认 false
      spring.cloud.nacos.config.shared-configs[0].refresh=true
      
    • Use shared-dataids to specify the DataID to read the shared configuration file, multiple files are ,separated by using refreshable-dataids to specify the shared configuration file, which supports automatic refresh

      (the shared-dataids official flag is deprecated; replaced by shared-configs)

      spring.cloud.nacos.config.shared-dataids=shareconfig1.yml,shareconfig2.yml
      spring.cloud.nacos.config.refreshable-dataids=shareconfig1.yml,shareconfig2.yml
      

Configuration file read priority:

  • profile > default > extension-configs (the larger the array subscript, the greater the priority) > shared-configs (the larger the array subscript, the greater the priority)
  • The larger the array subscript, the greater the priority, that is, the items introduced later in the array will overwrite the same items introduced earlier

Support profile granular configuration

When spring-cloud-starter-alibaba-nacos-config loads the configuration, it not only loads ${spring.application.name}.${file-extension:properties}the file prefixed with dataid, but also loads ${spring.application.name}-${profile}.${file-extension:properties}the basic configuration with dataid. In the daily development environment, if you encounter multiple sets of configurations, you can use ${spring.profiles.active}this to configure which configuration to choose

#选择加载的文件为application-dev.properties
spring.profiles.active=dev

Notice:

  • Only the default configuration file can be used in conjunction with profile; except the default configuration file, other configuration files (for example: dev) need to be written with a suffix. And the suffix must be consistent with the extension configured in the configured boostrap.properties (spring.cloud.nacos.config.file-extension=?)

  • Default configuration file: the configuration file with the same DataId as the service name spring.application.name (no file extension), called the default configuration file


Deploy nacos

docker stack deploy nacos cluster

Docker stack deploys the deployment template of the nacos cluster: docker-compose-swarm-nacos.yml

Note:

  • Replace @nacos_image, @mysql_image with the actual image
  • Replace @nacos_logs_path and @nacos_data_path with the actual storage path
version: "3.5"
services:
  nacos1:
    hostname: nacos1
    container_name: nacos1
    image: @nacos_image
    volumes:
      - @nacos_logs_path/nacos1:/home/nacos/logs
    ports:
      # 8848端口是Nacos对客户端提供服务的端口
      - "32101:8848"
    expose:
      # 7848是Nacos集群通信端口,用于Nacos集群间进行选举,检测等
      - "7848"
    environment:
      NACOS_REPLICAS: 3
      MYSQL_SERVICE_HOST: nacos-mysql
      MYSQL_SERVICE_DB_NAME: nacos_devtest
      MYSQL_SERVICE_PORT: 3306
      MYSQL_SERVICE_USER: nacos
      MYSQL_SERVICE_PASSWORD: nacos
      MODE: cluster
      NACOS_SERVER_PORT: 8848
      PREFER_HOST_MODE: hostname
      NACOS_SERVERS: nacos1:8848 nacos2:8848 nacos3:8848
    restart: always
    networks:
      - apps_net
    depends_on:
      - nacos-mysql
    deploy:
      labels: 
        name: nacos1
      placement:
        constraints:
          - node.role == manager
  
  nacos2:
    hostname: nacos2
    image: @nacos_image
    container_name: nacos2
    volumes:
      - @nacos_logs_path/nacos2:/home/nacos/logs
    expose:
      - "8848"
      - "7848"
    environment:
      NACOS_REPLICAS: 3
      MYSQL_SERVICE_HOST: nacos-mysql
      MYSQL_SERVICE_DB_NAME: nacos_devtest
      MYSQL_SERVICE_PORT: 3306
      MYSQL_SERVICE_USER: nacos
      MYSQL_SERVICE_PASSWORD: nacos
      MODE: cluster
      NACOS_SERVER_PORT: 8848
      PREFER_HOST_MODE: hostname
      NACOS_SERVERS: nacos1:8848 nacos2:8848 nacos3:8848
    restart: always
    networks:
      - apps_net
    depends_on:
      - nacos-mysql
    deploy:
      labels: 
        name: nacos2
      placement:
        constraints:
          - node.role == worker
  nacos3:
    hostname: nacos3
    image: @nacos_image
    container_name: nacos3
    volumes:
      - @nacos_logs_path/nacos3:/home/nacos/logs
    expose:
      - "8848"
      - "7848"
    environment:
      NACOS_REPLICAS: 3
      MYSQL_SERVICE_HOST: nacos-mysql
      MYSQL_SERVICE_DB_NAME: nacos_devtest
      MYSQL_SERVICE_PORT: 3306
      MYSQL_SERVICE_USER: nacos
      MYSQL_SERVICE_PASSWORD: nacos
      MODE: cluster
      NACOS_SERVER_PORT: 8848
      PREFER_HOST_MODE: hostname
      NACOS_SERVERS: nacos1:8848 nacos2:8848 nacos3:8848
    restart: always
    networks:
      - apps_net
    depends_on:
      - nacos-mysql
    deploy:
      labels: 
        name: nacos3
      placement:
        constraints:
          - node.role == worker
  
  nacos-mysql:
    hostname: nacos-mysql
    container_name: nacos-mysql
    image: @mysql_image
    volumes:
      - @nacos_data_path:/var/lib/mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: nacos_devtest
      MYSQL_USER: nacos
      MYSQL_PASSWORD: nacos
    restart: always
    networks:
      - apps_net
    deploy:
      labels: 
        name: mysql
      placement:
        constraints:
          - node.role == manager

networks:
  apps_net:
    # 引用已创建的网络。手动创建命令:docker network create -d overlay --attachable apps_net
    external: true

k8s deploy nacos cluster

Use the k8s helm tool to deploy the deployment template of the nacos cluster:

values.yaml

mysqlImage: "harbor.paic.com.cn/library/nacos-mysql:latest"
nacosImage: "harbor.paic.com.cn/library/nacos-service:1.4.1"
busyboxImage: "harbor.paic.com.cn/library/busybox:1.30.0"
mysqlHost: "mysql"
mysqlPort: "3306"
mysqlDatabase: "nacos_devtest"
mysqlRootPassword: password
mysqlUser: nacos
mysqlPassword: nacos
nfsPath: /home/nacos/
nacosDataPath: /home/nacos/data
service_name: nacos
namespace: public

Chart.yaml

apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: nacos
version: 0.1.0
maintainers:
- name: name

configmap.yaml under the templates folder

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: nacos-cm
  namespace: {
    
    {
    
     .Values.namespace }}
data:
  mysql.host: mysql
  mysql.port: "3306"
  mysql.db.name: {
    
    {
    
     .Values.mysqlDatabase }}
  mysql.user: {
    
    {
    
     .Values.mysqlUser }}
  mysql.password: {
    
    {
    
     .Values.mysqlPassword }}

mysql.yaml under the templates folder

apiVersion: v1
kind: ReplicationController
metadata:
  name: mysql
  namespace: {
    
    {
    
     .Values.namespace }}
  labels:
    name: mysql
spec:
  replicas: 1
  selector:
    name: mysql
  template:
    metadata:
      labels:
        name: mysql
    spec:
      containers:
      - name: mysql
        image: {
    
    {
    
     .Values.mysqlImage }}
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: {
    
    {
    
     .Values.mysqlRootPassword }}
        - name: MYSQL_DATABASE
          value: {
    
    {
    
     .Values.mysqlDatabase }}
        - name: MYSQL_USER
          value: {
    
    {
    
     .Values.mysqlUser }}
        - name: MYSQL_PASSWORD
          value: {
    
    {
    
     .Values.mysqlPassword }}
      volumes:
      - name: mysql-data
        hostPath:
          path: {
    
    {
    
     .Values.nacosDataPath }}
      nodeSelector:
        nacos: nacos-mysql
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: {
    
    {
    
     .Values.namespace }}
  labels:
    name: mysql
spec:
  ports:
  - port: 3306
    targetPort: 3306
  selector:
    name: mysql

nacos.yaml under the templates folder

###使用自建数据库;使用Ingress发布配置后台###
---
apiVersion: v1
kind: Service
metadata:
  name: nacos-headless
  namespace: {
    
    {
    
     .Values.namespace }}
  labels:
    caas_service: nacos-headless
spec:
  ports:
    - port: 8848
      name: server
      protocol: TCP
      targetPort: 8848
    - port: 7848
      name: rpc
      targetPort: 7848
  clusterIP: None
  sessionAffinity: None
  type: ClusterIP
  publishNotReadyAddresses: true
  selector:
    caas_service: {
    
    {
    
     .Values.service_name }}
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {
    
    {
    
     .Values.service_name }}
  namespace: {
    
    {
    
     .Values.namespace }}
spec:
  serviceName: nacos-headless
  replicas: 3
  template:
    metadata:
      labels:
        caas_service: {
    
    {
    
     .Values.service_name }}
      annotations:
        pod.alpha.kubernetes.io/initialized: "true"
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                    - key: "caas_service"
                      operator: In
                      values:
                         - nacos-headless
              topologyKey: "kubernetes.io/hostname"
      containers:
        - name: k8snacos
          imagePullPolicy: Always
          image: {
    
    {
    
     .Values.nacosImage }}
          resources:
            requests:
              memory: "2Gi"
              cpu: "500m"
          ports:
            - containerPort: 8848
              name: client
            - containerPort: 7848
              name: rpc
          livenessProbe:
            httpGet:
              path: /nacos
              port: 8848
            initialDelaySeconds: 10
            periodSeconds: 3
            timeoutSeconds: 1
            failureThreshold: 5
          readinessProbe:
            httpGet:
              path: /nacos
              port: 8848
            initialDelaySeconds: 10
            periodSeconds: 3
            timeoutSeconds: 1
            failureThreshold: 5
          env:
            - name: NACOS_REPLICAS
              value: "3"
            - name: MYSQL_SERVICE_HOST
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.host
            - 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_PASSWORD
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.password
            - name: MODE
              value: "cluster"
            - name: NACOS_SERVER_PORT
              value: "8848"
            - name: PREFER_HOST_MODE
              value: "hostname"
            - name: NACOS_SERVERS
              value: {
    
    {
    
     .Values.service_name }}-0.nacos-headless.{
    
    {
    
     .Values.namespace }}.svc.cluster.local:8848 {
    
    {
    
     .Values.service_name }}-1.nacos-headless.{
    
    {
    
     .Values.namespace }}.svc.cluster.local:8848 {
    
    {
    
     .Values.service_name }}-2.nacos-headless.{
    
    {
    
     .Values.namespace }}.svc.cluster.local:8848
      initContainers:
      - command:
        - sh
        - -c
        - sleep 10; mkdir /wls/logs/nacos-0 /wls/logs/nacos-1 /wls/logs/nacos-2 -p;chown -R 798:5682 /wls/logs/nacos-0 /wls/logs/nacos-1 /wls/logs/nacos-2 ; echo init finished
        env:
        image: {
    
    {
    
     .Values.busyboxImage }}
        imagePullPolicy: IfNotPresent
        name: init
        volumeMounts:
        - mountPath: /wls/logs/
          name: logs
      volumes:
      - name: logs
        hostPath:
          path: {
    
    {
    
     .Values.nfsPath }}/logs
  selector:
    matchLabels:
      caas_service: {
    
    {
    
     .Values.service_name }}

---
# ------------------- App Service ------------------- #
apiVersion: v1
kind: Service
metadata:
  name: {
    
    {
    
     .Values.service_name }}-nodeport
  annotations:
    {
    
    {
    
    - range $key, $value := .Values.annotations }}
      {
    
    {
    
     $key }}: {
    
    {
    
     $value | quote }}
    {
    
    {
    
    - end }}
  labels:
    caas_service: {
    
    {
    
     .Values.service_name }}
spec:
  ports:
  - name: "nodeport"
    port: 8848
    protocol: TCP
    targetPort: 8848
    nodePort: 32101
  publishNotReadyAddresses: true
  selector:
    caas_service: {
    
    {
    
     .Values.service_name }}
  type: NodePort

Check whether the nacos cluster is healthy and started

After the nacos cluster is started, it may appear that the container status is health/running, but it is not actually started in a healthy manner, which will cause problems with the registration of microservices, which need to be manually checked

  1. After entering the container of the nacos instance, execute the following command to view the response information
curl -X PUT '127.0.0.1:8848/nacos/v1/ns/instance/beat?serviceName=nacos'
  1. If the nacos instance does not start healthily, restart the instance container of nacos and check again (generally, it can start healthily after restarting once)

    # nacos实例健康启动的响应信息
    {"clientBeatInterval":5000,"code":20404}
    

Guess you like

Origin blog.csdn.net/footless_bird/article/details/125362050