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
- 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'
-
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}