Nacos命名的前四个字母分别取自Naming(服务注册,即服务命名管理)和Configuration(服务配置)的前两个字母,s取自Service,也就是服务的意思。它是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
简单一句话:Nacos=注册中心+配置中心=Eureka+Config+Bus。
Nacos官网地址:https://nacos.io/zh-cn/,可以在这里下载和查阅官方文档。
服务注册与服务发现框架 | CAP模型 | 控制台管理 | 社区活跃度 |
Eureka | AP | 支持 | 低(2.x版本闭源) |
Zookeeper | CP | 不支持 | 中 |
Consul | CP | 支持 | 高 |
Nacos | AP | 支持 | 高 |
通过Nacos下载地址选择合适的版本(最好选稳定版本)下载zip包,需要本地配置好了Java8和Maven环境,解压缩后,运行startup.cmd启动Nacos,浏览器访问http://localhost:8848/nacos查看管理后台,输入用户名密码(都是nacos)进入。
这里还是采用Docker的安装和启动方式,命令如下。
[root@bogon ~]# docker search nacos # 搜索Nacos镜像,这里只列出了第一个,我们等下也要用这个
INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
docker.io docker.io/nacos/nacos-server This project contains a Docker image meant... 73 [OK]
[root@bogon ~]# docker pull docker.io/nacos/nacos-server:1.3.0 # 拉取1.3.0版本镜像,稍等片刻,如果不带tag时候,默认下载的最新版本
[root@bogon ~]# docker run --env MODE=standalone -d -p 8848:8848 nacos/nacos-server:1.3.0 # 后台运行Nacos,以单机模式运行
[root@bogon ~]# docker ps # 查看当前运行中的docker容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
563aac734e9e nacos/nacos-server:1.3.0 "bin/docker-startu..." 26 seconds ago Up 24 seconds 0.0.0.0:8848->8848/tcp practical_mcnulty
[root@bogon ~]# docker ps -a # 查看所有容器(不管是运行的还是没运行的)
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
563aac734e9e nacos/nacos-server:1.3.0 "bin/docker-startu..." About a minute ago Up About a minute 0.0.0.0:8848->8848/tcp practical_mcnulty
4d6cb9734993 nacos/nacos-server:1.3.0 "bin/docker-startu..." 3 minutes ago Exited (1) 2 minutes ago amazing_liskov
e4622b9228e7 rabbitmq:management "docker-entrypoint..." 7 days ago Exited (255) 23 hours ago 4369/tcp, 5671/tcp, 0.0.0.0:5672->5672/tcp, 15671/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp dreamy_cray
262532b32087 consul:1.6.1 "docker-entrypoint..." 2 weeks ago Exited (255) 7 days ago 8300-8302/tcp, 8301-8302/udp, 8600/tcp, 8600/udp, 0.0.0.0:8500->8500/tcp condescending_bartik
12121ee7ccdf zookeeper:3.4.9 "/docker-entrypoin..." 3 weeks ago Exited (143) 4 hours ago focused_mclean
3a4738e5d496 elasticsearch:6.8.7 "/usr/local/bin/do..." 7 weeks ago Exited (255) 7 weeks ago 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp xenodochial_banach
5eb892279b83 docker.io/rabbitmq:3.7.26-management "docker-entrypoint..." 7 weeks ago Exited (255) 7 weeks ago 4369/tcp, 5671/tcp, 0.0.0.0:5672->5672/tcp, 15671/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp nifty_visvesvaraya
9478537d54f6 redis "docker-entrypoint..." 7 weeks ago Exited (255) 7 weeks ago 0.0.0.0:6379->6379/tcp frosty_easley
0c492ce51767 mysql "docker-entrypoint..." 2 months ago Up 51 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp jolly_sammet
73f3714f4798 tomcat:8.5.34 "catalina.sh run" 2 months ago Exited (143) 2 months ago myTomcat
[root@bogon ~]# docker start 563aac734e9e # 如果已经有了容器,但是容器是关闭状态的,只需要使用docker start 容器id启动即可
安装完成,启动成功后,访问http://192.168.0.123:8848/nacos,输入用户名密码(都是nacos)查看管理后台。
这里,我们需要创建一个服务提供者和一个服务消费者,把他们都注册进Nacos里。
官方文档:https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_start_a_provider_application。
新建cloudalibaba-provider-payment9001模块,在父pom.xml的dependencyManagement坐标的dependencies中加入spring-cloud-alibaba-dependencies坐标。
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.2.0.RELEASE
pom
import
修改子模块的pom.xml,加入spring-cloud-starter-alibaba-nacos-discovery坐标。
cloud2020
com.atguigu.springcloud
1.0-SNAPSHOT
4.0.0
cloudalibaba-provider-payment9001
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-devtools
runtime
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
添加application.yml配置文件。
server:
port: 9001
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: 192.168.0.123:8848 # 指明Nacos的地址
management:
endpoints:
web:
exposure:
include: '*'
添加主启动类,带上@EnableDiscoveryClient用于开启服务发现功能。
package com.atguigu.springcloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class PaymentMain9001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain9001.class, args);
}
}
添加业务类便于测试。
package com.atguigu.springcloud.alibaba.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@GetMapping(value = "/payment/nacos/{id}")
public String getPayment(@PathVariable("id") Integer id) {
return "Hello Nacos Discovery: " + serverPort + "\t id: " + id;
}
}
启动Nacos,启动Provider9001模块访问http://192.168.0.123:8848/nacos,点击左侧“服务管理”-“服务列表”即可看到Provider9001服务已经注册进来了。
Nacos自带负载均衡,为了演示负载均衡,仿照cloudalibaba-provider-payment9001模块创建cloudalibaba-provider-payment9002模块,端口号做相应的修改即可,其他大致相同。
创建完成后,启动Provider9002,查看Nacos管理后台,nacos-payment-provider服务名对应的实例数由1变成了2。
官方文档:https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_start_a_consumer_application
新建cloudalibaba-consumer-nacos-order83模块,pom.xml和cloudalibaba-provider-payment9001一样。添加application.yml。
server:
port: 83
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: 192.168.0.123:8848 # 配置Nacos地址
# 消费者将去访问的微服务地址,这里采用服务名称查找服务(成功注册进nacos的微服务提供者)
service-url:
nacos-user-service: http://nacos-payment-provider
主启动类和cloudalibaba-provider-payment9001一样,需要带上@EnableDiscoveryClient注解。添加业务类。
package com.atuguigu.springcloud.alibaba.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderNacosController {
@Resource
private RestTemplate restTemplate;
@Value("${service-url.nacos-user-service}")// 读取application.yml里的值
private String serverURL;
@GetMapping(value = "/consumer/payment/nacos/{id}")
public String paymentInfo(@PathVariable("id") Integer id) {
return restTemplate.getForObject(serverURL + "/payment/nacos/" + id, String.class);
}
}
添加配置类,注意,这里一定要带上@LoadBalance注解,因为我们是通过服务名访问生产者的,即使只有一个生产者,通过服务名访问,也要带上@LoadBalance注解,否则会报错。
package com.atuguigu.springcloud.alibaba.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
启动两个生产者和一个消费者,通过浏览器访问http://localhost:83/consumer/payment/nacos/1,根据请求返回值,可以看到负载均衡生效了,实际上,Nacos有负载均衡能力,是因为它包含了Ribbon的jar包。
Nacos | Eureka | Consul | CoreDNS | Zookeeper | |
一致性检查 | CP+AP | AP | CP | / | CP |
健康检查 | TCP/HTTP/MySQL/Client Beat | Client Beat | TCP/HTTP/gRPC/Cmd | / | Client Beat |
负载均衡 | 权重/DSL/metadata/CMDB | Ribbon | Fabio | RR | / |
雪崩保护 | 支持 | 支持 | 不支持 | 不支持 | 不支持 |
自动注销实例 | 支持 | 支持 | 不支持 | 不支持 | 支持 |
访问协议 | HTTP/DNS/UDP | HTTP | HTTP/DNS | DNS | TCP |
监听支持 | 支持 | 支持 | 支持 | 不支持 | 支持 |
多数据中心 | 支持 | 支持 | 支持 | 不支持 | 不支持 |
跨注册中心 | 支持 | 不支持 | 支持 | 不支持 | 不支持 |
Spring Cloud集成 | 支持 | 支持 | 支持 | 不支持 | 不支持 |
Dubbo集成 | 支持 | 不支持 | 不支持 | 不支持 | 支持 |
Kubernetes集成 | 支持 | 不支持 | 支持 | 支持 | 不支持 |
Nacos支持AP和CP的切换,命令如下。
curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'
如果不需要存储服务界别的信息且服务实例是通过nacos-client注册的,并且能够保持心跳上报,那么就可以选择AP模式,当前主流服务如Spring Cloud和Dubbo服务,都适用于AP模式,AP模式为了服务的可用性减弱了一致性,因此AP模式下只支持注册临时实例。
如果需要在服务级别编辑或存储配置信息,必须使用CP,Kubernetes服务和DNS服务都适用于CP模式,CP模式下支持注册持久化实例,此时以Raft协议为集群运行,该模式下注册实例前必须先注册服务,如果服务不存在,会报错。
新建cloudalibaba-config-nacos-client3377模块,修改pom.xml,加入spring-cloud-starter-alibaba-nacos-config和spring-cloud-starter-alibaba-nacos-discovery坐标。
cloud2020
com.atguigu.springcloud
1.0-SNAPSHOT
4.0.0
cloudalibaba-config-nacos-client3377
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-devtools
runtime
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
添加bootstrap.yml和application.yml配置文件。这里的bootstrap.yml和application.yml和之前的Spring Cloud Config里的意思是一样的,在项目初始化的时候,会先读取bootstrap.yml,后读取application.yml,其中bootstrap.yml属于系统层面,application.yml属于应用层面。
bootstrap.yml
server:
port: 3377
spring:
application:
name: nacos-config-client
cloud:
nacos:
discovery:
server-addr: 192.168.0.123:8848 # Nacos服务注册中心地址
config:
server-addr: 192.168.0.123:8848 # Nacos作为配置中心地址
file-extension: yml #指定yml格式配置
application.yml
spring:
profiles:
active: dev # 表示开发环境
添加主启动类,带上@EnableDiscoveryClient注解。
package com.atguigu.springcloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class NacosConfigClientMain3377 {
public static void main(String[] args) {
SpringApplication.run(NacosConfigClientMain3377.class, args);
}
}
添加业务类,用于测试
package com.atguigu.springcloud.alibaba.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope // 通过Spring Cloud原生注解@RefreshScope实现配置自动刷新
public class ConfigClientController {
@Value("${config.info}")
private String configInfo;
@GetMapping("/config/info")
public String getConfigInfo() {
return configInfo;
}
}
我们配置bootstrap.yml的目的,就是让模块启动的时候,读取bootstrap.yml的内容,去Nacos上查找配置文件的,那么查找配置文件的规则是怎样的呢?
从官方文档可以看到一个公式:${prefix}-${spring.profile.active}.${file-extension}。下面也对这里的参数做了解释:
根据bootstrap.yml和application.yml可知,这个公式对应的值是:nacos-config-client-dev.yml,有了这个值,就可以在Nacos管理后台做配置了,这个值对应管理后台的Data Id。
进入Nacos管理后台,点击“配置管理”-“配置列表”,点击右侧的“+”,将刚才的值输入到Data Id里。Group保持DEFAULT_GROUP默认即可,配置格式选择YAML,在配置内容里输入如下内容,也就是要对应测试类Controller中的@Value("${config.info}"),最后点击“发布”即可。
config:
info: "this is nacos-config-client-dev.yml version=1"
启动nacos-client3377模块,访问http://localhost:3377/config/info,可以读取到刚才的配置文件,接下来,我们在Nacos上修改配置文件,再次发布,访问http://localhost:3377/config/info,发现读取到的配置信息立刻就变化了。
在前面,我们往Nacos里添加配置文件的时候,可以发现有Data Id,Group,命名空间(NameSpace)这些参数,通过这些参数,我们可以把配置文件做分组,便于查找和归类。
其中NameSpace用于区分部署环境,Group和Data Id在逻辑上区分两个目标对象。
根据官方文档的说明,我们可以知道:
Data Id配置方案:使用默认的NameSpace和默认的Group,在Nacos管理后台创建两个不同Data Id的配置文件,通过修改application.yml里的spring.profile.active的值,即可实现读取不同配置文件。
Group配置方案:在Nacos管理后台创建一个Group,创建几个配置文件,在Group里输入刚才创建的Group的名称。要想读取指定Group下的配置文件,需要在spring.cloud.nacos.config下添加一个group属性,指定要访问哪个Group取配置文件。
NameSpace配置方案:在Nacos管理后台创建一个NameSpace,在它下面创建几个配置文件,要想读取自定义NameSpace下的配置文件,需要在spring.cloud.nacos.config下添加一个namespace属性,值为命名空间的ID。
如果把Data Id、Group、NameSpace类比成一个Java项目的话,那么NameSpace可以类比为一个模块,Group可以类比为某个模块里的一个包,Data Id可以类比为一个类。目的就是为了不同粒度的配置隔离。
Nacos单机部署手册官方文档地址:https://nacos.io/zh-cn/docs/deployment.html
Nacos集群搭建手册官方文档地址:https://nacos.io/zh-cn/docs/cluster-mode-quick-start.html
在重启Nacos后,我们可以看到,之前的配置还是存在的,这是因为Nacos里内置了Derby数据库,但是,因为我们不方便操作Derby数据库,所以,改用MySQL和Nacos进行整合。
另外,正式环境,不可能只有一台Nacos服务,需要Nacos服务集群模式。如果启动了多个Nacos结点,数据存储存在一致性问题,为了解决这个问题,Nacos采用集中式存储来支持集群化部署,目前只支持MySQL存储。
我们先对单机支持MySQL数据库,具体操作步骤:
docker下载安装MySQL镜像,这里我的Nacos使用的是1.3.0版本,MySQL使用的是8.0.19版本(踩坑了,后面说)。
首先创建nacos_config数据库,然后在这个数据库下,使用数据库初始化文件初始化MySQL数据库,这个用Navicat连接上MySQL执行即可。
使用如下命令,进入Docker容器中Nacos目录,并修改application.properties。
[root@bogon ~]# docker ps # 查看当前运行的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
563aac734e9e nacos/nacos-server:1.3.0 "bin/docker-startu..." 9 minutes ago Up 9 minutes 0.0.0.0:8848->8848/tcp practical_mcnulty
0c492ce51767 mysql "docker-entrypoint..." 2 months ago Up 58 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp jolly_sammet
[root@bogon ~]# docker exec -it practical_mcnulty bash # 进入Nacos里,这里的practical_mcnulty是docker ps命令中,Nacos的NAMES字段值,因为我没有取别名
[root@563aac734e9e nacos]# cd conf/ # 进入conf目录下,就能找到application.properties了
[root@563aac734e9e conf]# ll
total 40
-rw-r--r--. 1 root root 2180 Jun 5 18:47 application.properties
-rw-r--r--. 1 501 games 25080 Jun 5 16:33 nacos-logback.xml
-rw-r--r--. 1 501 games 7456 May 15 18:35 schema.sql
[root@563aac734e9e conf]# exit # 使用exit命令退出Docker容器
exit
可以看到如下内容:
# spring
server.servlet.contextPath=${SERVER_SERVLET_CONTEXTPATH:/nacos}
server.contextPath=/nacos
server.port=${NACOS_APPLICATION_PORT:8848}
spring.datasource.platform=${SPRING_DATASOURCE_PLATFORM:""}
nacos.cmdb.dumpTaskInterval=3600
nacos.cmdb.eventTaskInterval=10
nacos.cmdb.labelTaskInterval=300
nacos.cmdb.loadDataAtStart=false
db.num=${MYSQL_DATABASE_NUM:1}
db.url.0=jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT:3306}/${MYSQL_SERVICE_DB_NAME}?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.url.1=jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT:3306}/${MYSQL_SERVICE_DB_NAME}?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=${MYSQL_SERVICE_USER}
db.password=${MYSQL_SERVICE_PASSWORD}
### The auth system to use, currently only 'nacos' is supported:
nacos.core.auth.system.type=${NACOS_AUTH_SYSTEM_TYPE:nacos}
### The token expiration in seconds:
nacos.core.auth.default.token.expire.seconds=${NACOS_AUTH_TOKEN_EXPIRE_SECONDS:18000}
### The default token:
nacos.core.auth.default.token.secret.key=${NACOS_AUTH_TOKEN:SecretKey012345678901234567890123456789012345678901234567890123456789}
### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
nacos.core.auth.caching.enabled=${NACOS_AUTH_CACHE_ENABLE:false}
server.tomcat.accesslog.enabled=${TOMCAT_ACCESSLOG_ENABLED:false}
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D
# default current work dir
server.tomcat.basedir=
## spring security config
### turn off security
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
# metrics for elastic search
management.metrics.export.elastic.enabled=false
management.metrics.export.influx.enabled=false
nacos.naming.distro.taskDispatchThreadCount=10
nacos.naming.distro.taskDispatchPeriod=200
nacos.naming.distro.batchSyncKeyCount=1000
nacos.naming.distro.initDataRatio=0.9
nacos.naming.distro.syncRetryDelay=5000
nacos.naming.data.warmup=true
这个里面有许多${key:value}形式的东西,代表的意思是在Nacos启动的时候,读取启动参数里的key,如果读取不到就使用冒号后面的值,我们的启动参数里并没有带这些值,所以,我们就直接修改配置文件好了。修改后的内容:
# spring
server.servlet.contextPath=${SERVER_SERVLET_CONTEXTPATH:/nacos}
server.contextPath=/nacos
server.port=${NACOS_APPLICATION_PORT:8848}
spring.datasource.platform=mysql
nacos.cmdb.dumpTaskInterval=3600
nacos.cmdb.eventTaskInterval=10
nacos.cmdb.labelTaskInterval=300
nacos.cmdb.loadDataAtStart=false
db.num=1
db.url.0=jdbc:mysql://192.168.0.123:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
db.url.1=jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT:3306}/${MYSQL_SERVICE_DB_NAME}?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=root
### The auth system to use, currently only 'nacos' is supported:
nacos.core.auth.system.type=${NACOS_AUTH_SYSTEM_TYPE:nacos}
### The token expiration in seconds:
nacos.core.auth.default.token.expire.seconds=${NACOS_AUTH_TOKEN_EXPIRE_SECONDS:18000}
### The default token:
nacos.core.auth.default.token.secret.key=${NACOS_AUTH_TOKEN:SecretKey012345678901234567890123456789012345678901234567890123456789}
### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
nacos.core.auth.caching.enabled=${NACOS_AUTH_CACHE_ENABLE:false}
server.tomcat.accesslog.enabled=${TOMCAT_ACCESSLOG_ENABLED:false}
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D
# default current work dir
server.tomcat.basedir=
## spring security config
### turn off security
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
# metrics for elastic search
management.metrics.export.elastic.enabled=false
management.metrics.export.influx.enabled=false
nacos.naming.distro.taskDispatchThreadCount=10
nacos.naming.distro.taskDispatchPeriod=200
nacos.naming.distro.batchSyncKeyCount=1000
nacos.naming.distro.initDataRatio=0.9
nacos.naming.distro.syncRetryDelay=5000
nacos.naming.data.warmup=true
重启Nacos查看效果。然后崩了,访问http://192.168.0.123:8848/nacos/进不去了,可是查找原因:Nacos还不支持MySQL8。
于是,我到Nacos的GitHub上查看,找到了这个:https://github.com/alibaba/nacos/pull/3060,里面说已经支持MySQL8数据库驱动了,再看一眼更新日期:12天前,也就是2020-06-15,回看Docker Hub上的Nacos:1.3.0信息的更新时间:19天前,也就是2020-06-08。好吧,1.3.0版本的还没有更新MySQL8驱动,白高兴了,或许使用latest(更新时间8天前,也就是2020-06-19)就支持了(这个我没有测试,只是猜测),后续正式版本应该就支持了吧。
好吧,这里把MySQL版本换成5.7的,继续走上面的步骤,重启Nacos查看效果,又崩了,查看日志,大致意思是没有找到数据源,仔细对比了一些MySQL连接,找到错了,创建的数据库是nacos_config,可是数据库连接写成了nacos-config,修改后,重启,一切正常了。
Linux的下载安装启动,和Windows上类似,去官网下载即可,Linux需要下在*.tar.gz文件,下载后解压,在bin文件夹下可以看到startup.sh,启动即可。这里,我继续使用Docker进行操作,也是复习一下Docker。
为了演示集群搭建,我们需要一个Nginx,三个Nacos,一个MySQL。使用Docker安装Nginx并启动。
[root@bogon ~]# docker pull nginx:stable
Trying to pull repository docker.io/library/nginx ...
stable: Pulling from docker.io/library/nginx
8559a31e96f4: Already exists
9a38be3aab21: Pull complete
522e5edd83fa: Pull complete
2ccf5a90baa6: Pull complete
Digest: sha256:159aedcc6acb8147c524ec2d11f02112bc21f9e8eb33e328fb7c04b05fc44e1c
Status: Downloaded newer image for docker.io/nginx:stable
[root@bogon ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/rabbitmq management 95bc78c8d15d 10 days ago 187 MB
docker.io/nginx stable 9fc56f7e4c11 2 weeks ago 132 MB
docker.io/mysql 5.7 9cfcce23593a 2 weeks ago 448 MB
docker.io/nacos/nacos-server 1.3.0 d1f1facebfbc 3 weeks ago 756 MB
docker.io/rabbitmq 3.7.26-management d2d45254c99b 7 weeks ago 180 MB
docker.io/redis latest f9b990972689 8 weeks ago 104 MB
docker.io/mysql latest 0c27e8e5fcfa 2 months ago 546 MB
docker.io/elasticsearch 6.8.7 9cdc9986c313 4 months ago 880 MB
docker.io/consul 1.6.1 48b314e920d6 9 months ago 116 MB
docker.io/tomcat 8.5.34 ca9e2fccef98 20 months ago 463 MB
docker.io/zookeeper 3.4.9 3b83d9104a4c 3 years ago 129 MB
[root@bogon ~]# docker run -d -p 80:80 nginx:stable
e950da524e2aa17716f435fe5e745978b4ea36e7fd53a6506efcbed2f7946c7a
[root@bogon ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e950da524e2a nginx:stable "nginx -g 'daemon ..." 3 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp festive_booth
fe0f363d0c89 mysql:5.7 "docker-entrypoint..." About an hour ago Up About an hour 0.0.0.0:3306->3306/tcp, 33060/tcp hungry_colden
563aac734e9e nacos/nacos-server:1.3.0 "bin/docker-startu..." 2 hours ago Up 52 minutes 0.0.0.0:8848->8848/tcp practical_mcnulty
[root@bogon ~]#
通过浏览器访问http://192.168.0.123:80,如果能看到Welcome to nginx!说明Nginx启动成功。Nginx先放到一边过会再做配置,先搭建Nacos集群。
经历了2天的折腾,终于把Nacos集群搞好了,差点放弃,因为官方文档更新不及时,我踩坑了……后文会说。
先说一下我的集群环境,我这里使用的是nacos/nacos-server:1.3.0的镜像,在一台机器上通过Docker镜像的方式,部署了3台Nacos,通过端口号作为区分,虚拟机分配了4G内存(勉强够用,小了恐怕启动不起来),下面开始吧。
docker pull nacos/nacos-server:1.3.0 # 拉取nacos/nacos-server:1.3.0镜像,静静等待即可
# 输入以下命令,搭建集群
docker run -d \
-e MODE=cluster \
-e NACOS_APPLICATION_PORT=3333 \
-e NACOS_SERVERS=192.168.0.123:3333,192.168.0.123:4444,192.168.0.123:5555 \
-e SPRING_DATASOURCE_PLATFORM=mysql \
-e MYSQL_SERVICE_HOST=192.168.0.123 \
-e MYSQL_SERVICE_PORT=3306 \
-e MYSQL_SERVICE_USER=root \
-e MYSQL_SERVICE_PASSWORD=root \
-e MYSQL_SERVICE_DB_NAME=nacos_config \
-e NACOS_SERVER_IP=192.168.0.123 \
-p 3333:3333 \
--name nacos3333 \
nacos/nacos-server:1.3.0
docker run -d \
-e MODE=cluster \
-e NACOS_APPLICATION_PORT=4444 \
-e NACOS_SERVERS=192.168.0.123:3333,192.168.0.123:4444,192.168.0.123:5555 \
-e SPRING_DATASOURCE_PLATFORM=mysql \
-e MYSQL_SERVICE_HOST=192.168.0.123 \
-e MYSQL_SERVICE_PORT=3306 \
-e MYSQL_SERVICE_USER=root \
-e MYSQL_SERVICE_PASSWORD=root \
-e MYSQL_SERVICE_DB_NAME=nacos_config \
-e NACOS_SERVER_IP=192.168.0.123 \
-p 4444:4444 \
--name nacos4444 \
nacos/nacos-server:1.3.0
docker run -d \
-e MODE=cluster \
-e NACOS_APPLICATION_PORT=5555 \
-e NACOS_SERVERS=192.168.0.123:3333,192.168.0.123:4444,192.168.0.123:5555 \
-e SPRING_DATASOURCE_PLATFORM=mysql \
-e MYSQL_SERVICE_HOST=192.168.0.123 \
-e MYSQL_SERVICE_PORT=3306 \
-e MYSQL_SERVICE_USER=root \
-e MYSQL_SERVICE_PASSWORD=root \
-e MYSQL_SERVICE_DB_NAME=nacos_config \
-e NACOS_SERVER_IP=192.168.0.123 \
-p 5555:5555 \
--name nacos5555 \
nacos/nacos-server:1.3.0
拿一个出来简单说说配置吧。
docker run -d \ # -d表示是后台运行
-e MODE=cluster \ # 以集群模式运行
-e NACOS_APPLICATION_PORT=3333 \ # 这台Nacos服务的port是3333
-e NACOS_SERVERS=192.168.0.123:3333,192.168.0.123:4444,192.168.0.123:5555 \ # Nacos集群的所有机器的信息
-e SPRING_DATASOURCE_PLATFORM=mysql \ # 使用外置MySQL存储配置信息
-e MYSQL_SERVICE_HOST=192.168.0.123 \ # 外置MySQL的IP
-e MYSQL_SERVICE_PORT=3306 \ # 外置MySQL的port
-e MYSQL_SERVICE_USER=root \ # 外置MySQL的用户名
-e MYSQL_SERVICE_PASSWORD=root \ # 外置MySQL的密码
-e MYSQL_SERVICE_DB_NAME=nacos_config \ # 外置MySQL的数据库,也就是Nacos的配置文件要存储得到哪个数据库,这个在单机版Nacos使用外置数据库时候介绍过
-e NACOS_SERVER_IP=192.168.0.123 \ # 这台Nacos服务的IP
-p 3333:3333 \ # 容器外部端口映射
--name nacos3333 \ # 给容器起个名字吧
nacos/nacos-server:1.3.0 # 运行哪个镜像
先说下我碰到的坑,从官方文档找参数,Nacos的port对应的是NACOS_SERVER_PORT,那就照着写呗,写上之后,3台启动呗,启动后,使用命令docker logs -f 容器id查看启动日志,3台Nacos看到的都是Nacos started successfully in cluster mode. use external storage,表示启动成功了,那就访问访问呗,结果,提示“无法访问此网站,拒绝了我们的连接请求”,这就很尴尬,肯定是哪里还有问题。进入其中某一台机器,查看conf/naming-raft.log日志,提示的是no leader is available now!,也就是这个集群没有leader,奇了怪了,3台机器都正常启动,正常情况下,要选出一个leader呀。
反反复复检查了几遍参数,并对照着文档看了下,没写错呀,删掉容器重建,折腾了5,6次,还是不行,关于报错,也是没有查到什么有帮助的解释。
这时候,我突然发现了文档上的一个问题,MYSQL_DATABASE_NUM给的默认值是2,和之前conf/application.properties里的${MYSQL_DATABASE_NUM:1}默认值是1不符呀?哪里错了?翻了翻GitHub,找到了答案:移除数据库主从镜像配置。再看官方文档,里面还有MYSQL_MASTER_SERVICE_HOST、MYSQL_SLAVE_SERVICE_HOST等字眼。突然意识到了一个问题:文档很可能没有更新。
查看bin/docker-startup.sh和conf/application.properties这两个文件,因为我们通过-e指定的参数,大多数都用在这里了,很快我发现了conf/application.properties里的{NACOS_APPLICATION_PORT:8848},似曾相识啊!和NACOS_SERVER_PORT确实有点像,坑点就在这里:对于nacos/nacos-server:1.3.0镜像,自定义Nacos端口号的时候,不要使用NACOS_SERVER_PORT,要使用NACOS_APPLICATION_PORT!因为conf/application.properties里写了。
在看bin/docker-startup.sh的时候,我发现了这么一段,不懂Bash,但是大致能看懂一些,就是遍历${NACOS_SERVERS}的值,把它们输出到$CLUSTER_CONF文件里。
function print_servers(){
if [[ ! -d "${PLUGINS_DIR}" ]]; then
echo "" > "$CLUSTER_CONF"
for server in ${NACOS_SERVERS}; do
echo "$server" >> "$CLUSTER_CONF"
done
else
bash $PLUGINS_DIR/plugin.sh
sleep 30
fi
}
看看这个配置文件里写了什么,这就有意思了,打开配置文件cluster.conf一看,里面竟然有4行ip:port值,除了我定义的3333,4444,5555端口之外,还有一个8848端口,这是怎么冒出来的?又一次验证了我对端口配置的怀疑,自定义端口可能没生效,有的服务可能走了默认端口。
抱着试一试的想法,把-e参数里的NACOS_SERVER_PORT改成了NACOS_APPLICATION_PORT,启动3台机器容器,访问http://192.168.0.123:3333/nacos/、http://192.168.0.123:4444/nacos/、http://192.168.0.123:5555/nacos/都可以正常访问了,和刚才相比,向成功迈进了一步。再点击“集群管理”-“结点列表”查看结点,集群搭建成功了!
现在是2020-06-29,文档还没有更新,贴一下吧,踩过的坑……
这种方式搭建Nacos集群有点麻烦,另外介绍一种简单点的方式:使用docker-compose运行Nacos集群,下面开始操作。
使用命令“docker-compose -v”查看本机是否安装过docker-compose,如果没有安装,可以参考这里进行安装。
[root@localhost ~]# sudo curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # 下载docker-compose
……
[root@localhost ~]# sudo chmod +x /usr/local/bin/docker-compose # 给docker-compose加运行权限
[root@localhost ~]# docker-compose -v # 验证docker-compose是否安装成功
docker-compose version 1.26.0, build d4451659
这里还要用到git,如果没有git的还要安装下git才行。
[root@localhost ~]# git --version # 验证是否安装git
git version 1.8.3.1
[root@localhost ~]# yum install -y git # 如果没有安装git,使用这个命令安装git
……
[root@localhost ~]# git clone https://github.com/nacos-group/nacos-docker.git # 下载nacos-docker
很快,nacos-docker下载完成了,主要关注env和example文件夹。env里是一些环境变量,example是运行实例的例子,先把相关的命令列出来,在运行(在nacos-docker文件夹下执行命令)之前,需要查看下*.yaml里到底写的什么,是否需要根据自己的情况做修改呢?
[root@localhost ~]# docker-compose -f example/standalone-derby.yaml up # 使用Derby作为数据源,单机模式启动
[root@localhost ~]# docker-compose -f example/standalone-mysql-5.7.yaml up # 使用mysql-5.7作为数据源,单机模式启动
[root@localhost ~]# docker-compose -f example/standalone-mysql-8.yaml up # 使用mysql-8作为数据源,单机模式启动
[root@localhost ~]# docker-compose -f example/cluster-hostname.yaml up # 使用mysql5.7作为数据源,集群模式启动
这里只说集群模式了(cluster-hostname.yaml),集群模式看懂了,单机就不在话下了。
version: "3"
services:
nacos1:
hostname: nacos1
container_name: nacos1 # 容器名称
image: nacos/nacos-server:latest # 容器使用的镜像
volumes:
- ./cluster-logs/nacos1:/home/nacos/logs
- ./init.d/custom.properties:/home/nacos/init.d/custom.properties
ports: # 端口映射
- "8848:8848"
- "9555:9555"
env_file: # nacos环境变量
- ../env/nacos-hostname.env
restart: always # 开机自启
depends_on: # 数据源使用的是mysql
- mysql
nacos2:
hostname: nacos2
image: nacos/nacos-server:latest
container_name: nacos2
volumes:
- ./cluster-logs/nacos2:/home/nacos/logs
- ./init.d/custom.properties:/home/nacos/init.d/custom.properties
ports:
- "8849:8848"
env_file:
- ../env/nacos-hostname.env
restart: always
depends_on:
- mysql
nacos3:
hostname: nacos3
image: nacos/nacos-server:latest
container_name: nacos3
volumes:
- ./cluster-logs/nacos3:/home/nacos/logs
- ./init.d/custom.properties:/home/nacos/init.d/custom.properties
ports:
- "8850:8848"
env_file:
- ../env/nacos-hostname.env
restart: always
depends_on:
- mysql
mysql:
container_name: mysql
image: nacos/nacos-mysql:5.7 # 使用的mysql版本号
env_file:
- ../env/mysql.env # mysql环境变量
volumes:
- ./mysql:/var/lib/mysql
ports: # 端口映射
- "3306:3306"
如果虚拟机内存足够大(大于等于4G),那么可以直接运行上面的命令,否则,需要在nacos-hostname.env里添加jvm参数后,再使用上面的命令启动(配置完参数后实测,3台Nacos+1台mysql刚刚跑起来已经2.25G内存了,如果不配参数,4G内存接近吃满)。
#jvm
JVM_XMS=256m
JVM_XMX=256m
JVM_XMN=256m
启动的时候,报了一个错:chown: cannot read directory '/var/lib/mysql/': Permission denied,这是因为CentOS7默认开启了selinux安全模块,使用命令:su -c "setenforce 0"临时关闭selinux模块再启动,等待拉取镜像以及初始化之后,通过浏览器就可以访问了,放一个效果图。
既然Nacos集群搭建好了,下面看一下Nginx的配置。
[root@bogon ~]# docker exec -it festive_booth bash # 进入Nginx容器,festive_booth是docker ps命令中nginx的NAMES字段值
root@e950da524e2a:/# cd /etc/nginx/ # 进入/etc/nginx目录
root@e950da524e2a:/etc/nginx# ls -l # 查看目录下的文件
total 36
drwxr-xr-x. 1 root root 26 Jun 9 16:58 conf.d
-rw-r--r--. 1 root root 1007 Apr 21 12:43 fastcgi_params
-rw-r--r--. 1 root root 2837 Apr 21 12:43 koi-utf
-rw-r--r--. 1 root root 2223 Apr 21 12:43 koi-win
-rw-r--r--. 1 root root 5231 Apr 21 12:43 mime.types
lrwxrwxrwx. 1 root root 22 Apr 21 12:43 modules -> /usr/lib/nginx/modules
-rw-r--r--. 1 root root 643 Apr 21 12:43 nginx.conf
-rw-r--r--. 1 root root 636 Apr 21 12:43 scgi_params
-rw-r--r--. 1 root root 664 Apr 21 12:43 uwsgi_params
-rw-r--r--. 1 root root 3610 Apr 21 12:43 win-utf
root@e950da524e2a:/etc/nginx# cat nginx.conf # 查看nginx.conf的内容
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
nginx.conf就是nginx的主配置文件,注意最后一行有一个include /etc/nginx/conf.d/*.conf;的语句,它的意思是:加载配置文件的时候,把/etc/nginx/conf.d下的*.conf文件包括进来,我们看看/etc/nginx/conf.d下有什么文件,发现另一个default.conf。
root@e950da524e2a:/etc/nginx# cd /etc/nginx/conf.d/
root@e950da524e2a:/etc/nginx/conf.d# ls -l
total 4
-rw-r--r--. 1 root root 1114 Jun 9 16:58 default.conf
root@e950da524e2a:/etc/nginx/conf.d# cat default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
当我尝试修改这个配置文件的时候,发现vi和vim命令无法使用,只能采用别的方法:挂载外部配置文件以替代docker容器内的配置文件。
在/usr/下创建一个docker-nginx的文件夹,在里面添加一个nginx.conf配置文件,主要关注点在upstream结点上,内容如下:
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
upstream cluster {
server 192.168.0.123:3333;
server 192.168.0.123:4444;
server 192.168.0.123:5555;
}
server {
listen 80;
listen [::]:80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
#root /usr/share/nginx/html;
#index index.html index.htm;
proxy_pass http://cluster;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
使用docker stop 容器id命令,把之前的容器停掉,docker rm 容器id把之前的容器删除,以挂载外置配置文件方式重新运行一个容器,启动命令:docker run -d -p 80:80 -v /usr/docker-nginx/nginx.conf:/etc/nginx/nginx.conf nginx:stable。
浏览器访问:http://192.168.0.123/nacos,根据Nginx的负载均衡规则, 可以正常访问到某台Nacos,登陆进去即可,一切顺利!
最后一步,我们将cloud-alibaba-provider-payment9002服务注册进Nacos集群。修改application.yml配置文件的server-addr的值,让其指向Nginx。
server:
port: 9002
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: 192.168.0.123:80 # 指向Nginx,由Nginx进行转发(nginx下部署了3台Nacos集群)
# server-addr: 192.168.0.123:8848 # 指明Nacos的地址
management:
endpoints:
web:
exposure:
include: '*'
Nginx下有3台Nacos部署的集群环境,由Nginx进行转发,启动Payment9002,访问http://192.168.0.123/nacos,查看“服务管理”-“服务列表”,可以看到服务成功注册进来了。