[nacos] Nacos <2> 基于Docker安装Nacos
0 序
- Nacos(配置中心、注册中心)是分布式系统的核心子系统之一,是国内分布式系统/微服务领域的事实标准、事实上的唯一选择。
- 环境信息
- centos : 7.9
- docker : 25.0.4
- mysql : 5.7.x
- nacos-server : 2.1.1 (部署模式: nacos standalone / 单机mysql5.7)
注:调研了多个版本后的结论————不同nacos-server版本之间的差异较大,容器内的目录结构、脚本等变化较大。
注:v2.1.1 与 v2.0.3 的区别:1、镜像版本不同;2、mysql数据库脚本不同;(容器内的文件、目录结构,尚未发现差异点)
1 安装步骤(nacos/nacos-server镜像方式)
Step1 拉取镜像
docker pull nacos/nacos-server:v2.1.1
docker images
Step2 创建、并运行 Nacos Server Demo 容器
- 创建、并运行 Nacos Demo 容器
docker run --name demo-nacos-server \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--privileged=true \
--restart=always \
-e JVM_XMS=256m \
-e JVM_XMX=256m \
-e MODE=standalone \
-e PREFER_HOST_MODE=hostname \
-d nacos/nacos-server:v2.1.1
docker ps -a
- 访问 Nacos Server Demo 容器
http://127.0.0.1:8848/nacos/index.html
账号 / 密码 【默认】 : nacos / nacos
Step3 在宿主机中创建持久化文件目录(日志/核心配置)
- 在宿主机中创建日志、配置目录
mkdir -p /data/nacos/logs
mkdir -p /data/nacos/conf
- 从Demo容器中拷贝默认配置到宿主机中
docker exec -it demo-nacos-server sh -c "ls -la /home/nacos/conf"
docker cp demo-nacos-server:/home/nacos/conf/application.properties /data/nacos/conf/
# 拷贝 mysql 8 的 ddl sql : schema.sql (本教程中,实际不会使用)
docker cp demo-nacos-server:/home/nacos/conf/schema.sql /data/nacos/conf/
# nacos-server : 2.1.1 的docker镜像中漏掉了 mysql 5.7 的 ddl sql : nacos-mysql | 详情参加: https://github.com/alibaba/nacos/releases/tag/2.1.1 的 release 包
# 拷贝 ipv6的补丁 ddl sql : 1.4.0-ipv6_support-update.sql
docker cp demo-nacos-server:/home/nacos/conf/1.4.0-ipv6_support-update.sql /data/nacos/conf/
docker cp demo-nacos-server:/home/nacos/conf/nacos-logback.xml /data/nacos/conf/nacos-logback.xml
ls -la /data/nacos/conf/
nacos-server-2.1.1.zip 中存在 mysql 5.7 的 ddl 脚本
Step4 MySQL(5.7)数据库初始化
创建数据库
CREATE DATABASE nacos DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
创建用户
CREATE USER nacos@'%';
ALTER USER nacos@'%' IDENTIFIED BY 'nacosPassword';
GRANT ALL PRIVILEGES ON nacos.* TO nacos@'%';
FLUSH PRIVILEGES;
SHOW GRANTS FOR 'nacos'@'%'; -- localhost
use nacos; -- 使用 nacos 数据库
创建表
- 执行 :
nacos-mysql.sql
脚本内容来源于 : https://github.com/alibaba/nacos/releases/tag/2.1.1 的
nacos-server-2.1.1.zip
包的conf
目录的nacos-mysql.sql
脚本文件
或参见:https://github.com/alibaba/nacos/blob/2.1.1/distribution/conf/nacos-mysql.sql
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = config_info */
/******************************************/
CREATE TABLE `config_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(255) DEFAULT NULL,
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`app_name` varchar(128) DEFAULT NULL,
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`c_desc` varchar(256) DEFAULT NULL,
`c_use` varchar(64) DEFAULT NULL,
`effect` varchar(64) DEFAULT NULL,
`type` varchar(64) DEFAULT NULL,
`c_schema` text,
`encrypted_data_key` text NOT NULL COMMENT '秘钥',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = config_info_aggr */
/******************************************/
CREATE TABLE `config_info_aggr` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(255) NOT NULL COMMENT 'group_id',
`datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
`content` longtext NOT NULL COMMENT '内容',
`gmt_modified` datetime NOT NULL COMMENT '修改时间',
`app_name` varchar(128) DEFAULT NULL,
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = config_info_beta */
/******************************************/
CREATE TABLE `config_info_beta` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`encrypted_data_key` text NOT NULL COMMENT '秘钥',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = config_info_tag */
/******************************************/
CREATE TABLE `config_info_tag` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL COMMENT 'content',
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
`src_user` text COMMENT 'source user',
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = config_tags_relation */
/******************************************/
CREATE TABLE `config_tags_relation` (
`id` bigint(20) NOT NULL COMMENT 'id',
`tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
`tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
`nid` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`nid`),
UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = group_capacity */
/******************************************/
CREATE TABLE `group_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = his_config_info */
/******************************************/
CREATE TABLE `his_config_info` (
`id` bigint(20) unsigned NOT NULL,
`nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`data_id` varchar(255) NOT NULL,
`group_id` varchar(128) NOT NULL,
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
`content` longtext NOT NULL,
`md5` varchar(32) DEFAULT NULL,
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`src_user` text,
`src_ip` varchar(50) DEFAULT NULL,
`op_type` char(10) DEFAULT NULL,
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
`encrypted_data_key` text NOT NULL COMMENT '秘钥',
PRIMARY KEY (`nid`),
KEY `idx_gmt_create` (`gmt_create`),
KEY `idx_gmt_modified` (`gmt_modified`),
KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';
/******************************************/
/* 数据库全名 = nacos_config */
/* 表名称 = tenant_capacity */
/******************************************/
CREATE TABLE `tenant_capacity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';
CREATE TABLE `tenant_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`kp` varchar(128) NOT NULL COMMENT 'kp',
`tenant_id` varchar(128) default '' COMMENT 'tenant_id',
`tenant_name` varchar(128) default '' COMMENT 'tenant_name',
`tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
`create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
`gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
`gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
CREATE TABLE `users` (
`username` varchar(50) NOT NULL PRIMARY KEY,
`password` varchar(500) NOT NULL,
`enabled` boolean NOT NULL
);
CREATE TABLE `roles` (
`username` varchar(50) NOT NULL,
`role` varchar(50) NOT NULL,
UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
);
CREATE TABLE `permissions` (
`role` varchar(50) NOT NULL,
`resource` varchar(255) NOT NULL,
`action` varchar(8) NOT NULL,
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
);
INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);
INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
1.4.0-ipv6_support-update.sql
ALTER TABLE `config_info_tag`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;
ALTER TABLE `his_config_info`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL AFTER `src_user`;
ALTER TABLE `config_info`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;
ALTER TABLE `config_info_beta`
MODIFY COLUMN `src_ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'source ip' AFTER `src_user`;
Step5 修改配置文件(application.properties)
vi /data/nacos/conf/application.properties
修改如下配置项
...
#spring.datasource.platform=${SPRING_DATASOURCE_PLATFORM:""}
spring.datasource.platform=${SPRING_DATASOURCE_PLATFORM:"mysql"}
...
db.num=${MYSQL_DATABASE_NUM:1}
# db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false
db.url.0=jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT:3306}/${MYSQL_SERVICE_DB_NAME:nacos}?${MYSQL_SERVICE_DB_PARAM:characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&auto
Reconnect=true&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true}
# [注释此行] db.url.1=jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT:3306}/${MYSQL_SERVICE_DB_NAME}?${MYSQL_SERVICE_DB_PARAM:characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&aut
oReconnect=true&useSSL=false}
db.user=${MYSQL_SERVICE_USER}
db.password=${MYSQL_SERVICE_PASSWORD}
...
#server.tomcat.basedir=
server.tomcat.basedir=file:.
...
Step6 重建正式的 Nacos Server 容器
- 删除正在运行的 Nacos Demo 容器,重新用命令创建启动
docker stop demo-nacos-server
docker rm demo-nacos-server
- 启动 正式的 Nacos Server 容器
docker run --name nacos-server \
-p 18848:8848 \
-p 19848:9848 \
-p 19849:9849 \
--privileged=true \
--restart=always \
-e SPRING_DATASOURCE_PLATFORM=mysql \
-e NACOS_AUTH_ENABLE=true \
-e MYSQL_SERVICE_HOST="172.17.0.1" \
-e "MYSQL_SERVICE_PORT=33060" \
-e MYSQL_SERVICE_DB_NAME=nacos \
-e MYSQL_SERVICE_USER=nacos \
-e MYSQL_SERVICE_PASSWORD="123456" \
-e JVM_XMS=256m \
-e JVM_XMX=256m \
-e MODE=standalone \
-e PREFER_HOST_MODE=hostname \
-v /data/nacos/logs:/home/nacos/logs \
-v /data/nacos/conf/:/home/nacos/conf/ \
-d nacos/nacos-server:v2.1.1
NACOS_AUTH_ENABLE=true
: 开启身份鉴权(默认:不开启)。若不开启,有安全风险(可直接调用Nacos Web API,这是高危漏洞)172.17.0.1
: 在Linux系统中,可以使用特殊的IP地址172.17.0.1
来代表宿主机
,这个IP地址通常用于Docker默认的网络桥接模式中。注:docker 容器内的
127.0.0.1
≠ 宿主机中的127.0.0.1
- 查看 Nacos Server 容器
docker ps -a
docker logs nacos-server
ls -la /data/nacos/logs
docker exec -it nacos-server sh -c "ls -la /home/nacos/conf/application.properties"
docker exec -it nacos-server sh -c "cat /home/nacos/conf/application.properties"
# ↓ 此命令无效,需进入容器内部才能查看到真实情况
# docker exec -it nacos-server sh -c "echo $MYSQL_SERVICE_HOST"
docker exec -it nacos-server bash
> echo $MYSQL_SERVICE_HOST
> exit
# 宿主机中测验:
curl http://127.0.0.1:18848/nacos
- 测验:调用Nacos Web API
# 通过Nacos Web API 获取登录accessToken (nacos server开启身份鉴权后,web api request中需依赖此accessToken)
curl -X POST 'http://xx.yy.zz.ff:18848/nacos/v1/auth/login' -d 'username=nacos&password=nacos'
# 注:demo response : {"accessToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTcxMTYzNzE3NX0.ul940V4eB3aQwsQLeGQqgbnkrL0n45bkeSYBfGvYM2w","tokenTtl":18000,"globalAdmin":true,"username":"nacos"}
# 注:demo 关键内容翻译 : accessToken : '{"alg":"HS256"}.{"sub":"nacos","exp":1711637175}.ul940V4eB3aQwsQLeGQqgbnkrL0n45bkeSYBfGvYM2w'
# 服务注册
# curl -X POST 'http://xx.yy.zz.ff:18848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'
curl -X POST 'http://xx.yy.zz.ff:18848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080&accessToken=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTcxMTYzNzE3NX0.ul940V4eB3aQwsQLeGQqgbnkrL0n45bkeSYBfGvYM2w'
# 服务发现
# curl -X GET 'http://xx.yy.zz.ff:18848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName'
curl -X GET 'http://xx.yy.zz.ff:18848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName&accessToken=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTcxMTYzNzE3NX0.ul940V4eB3aQwsQLeGQqgbnkrL0n45bkeSYBfGvYM2w'
# 发布配置
# curl -X POST "http://xx.yy.zz.ff:18848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"
curl -X POST "http://xx.yy.zz.ff:18848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld&accessToken=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTcxMTYzNzE3NX0.ul940V4eB3aQwsQLeGQqgbnkrL0n45bkeSYBfGvYM2w"
# 获取配置
# curl -X GET "http://xx.yy.zz.ff:18848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"
curl -X GET "http://xx.yy.zz.ff:18848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&accessToken=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTcxMTYzNzE3NX0.ul940V4eB3aQwsQLeGQqgbnkrL0n45bkeSYBfGvYM2w"
nacos ui
Y 扩展:nacos身份认证与鉴权
Y.1 Nacos启用身份认证/鉴权
- 注意
- Nacos是一个内部微服务组件,需要在可信的内部网络中运行,不可暴露在公网环境,防止带来安全风险。
- Nacos提供简单的鉴权实现,为防止业务错用的弱鉴权体系,不是防止恶意攻击的强鉴权体系。
- 如果运行在不可信的网络环境或者有强鉴权诉求,请参考官方简单实现做替换增强。
Y.1.1 非Docker环境
- 按照官方文档配置启动,默认是不需要登录的,这样会导致配置中心对外直接暴露。而启用鉴权之后,需要在使用用户名和密码登录之后,才能正常使用nacos。
- 开启鉴权之前,application.properties中的配置信息为:
### If turn on auth system:
nacos.core.auth.enabled=false
- 开启鉴权之后,application.properties中的配置信息为:
### If turn on auth system:
nacos.core.auth.system.type=nacos
nacos.core.auth.enabled=true
- 【自定义密钥】
开启鉴权之后,你可以自定义用于生成JWT令牌的密钥,application.properties中的配置信息为:
注意:
文档中提供的密钥为公开密钥,在实际部署时请更换为其他密钥内容,防止密钥泄漏导致安全风险。
在2.2.1版本后,社区发布版本将移除以文档如下值作为默认值,需要自行填充,否则无法启动节点。
密钥需要保持节点间一致,长时间不一致可能导致403 invalid token错误。
### The default token(Base64 String):
nacos.core.auth.default.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
自定义密钥时,推荐将配置项设置为Base64编码的字符串,且原始密钥长度不得低于32字符。例如下面的的例子:
### The default token(Base64 String):
nacos.core.auth.default.token.secret.key=VGhpc0lzTXlDdXN0b21TZWNyZXRLZXkwMTIzNDU2Nzg=
注意:鉴权开关是修改之后立马生效的,不需要重启服务端。
Y.1.2 Docker环境
- 官方镜像
如果使用官方镜像,请在启动docker容器时,添加如下环境变量
NACOS_AUTH_ENABLE=true
例如,可以通过如下命令运行开启了鉴权的容器:
docker run --env PREFER_HOST_MODE=hostname --env MODE=standalone --env NACOS_AUTH_ENABLE=true -p 8848:8848 nacos/nacos-server
除此之外,还可以添加其他鉴权相关的环境变量信息:
name | description | option |
---|---|---|
NACOS_AUTH_ENABLE | 是否开启权限系统 | 默认:false |
NACOS_AUTH_TOKEN_EXPIRE_SECONDS | token 失效时间 | 默认:18000 |
NACOS_AUTH_TOKEN | token | 默认:SecretKey012345678901234567890123456789012345678901234567890123456789 |
NACOS_AUTH_CACHE_ENABLE | 权限缓存开关 ,开启后权限缓存的更新默认有15秒的延迟 | 默认 : false |
然后运行docker-compose
构建命令,例如
docker-compose -f example/standalone-derby.yaml up
- 自定义镜像
如果选择自定义镜像,请在构建镜像之前,修改nacos工程中的application.properties文件,
将下面这一行配置信息
nacos.core.auth.enabled=false
修改为
nacos.core.auth.system.type=nacos
nacos.core.auth.enabled=true
然后再配置nacos启动命令。
Y.2 客户端如何进行鉴权
Y.2.1 Java SDK鉴权
在构建“Properties”类时,需传入用户名和密码。
properties.put("username","${username}");
properties.put("password","${password}");
- 示例代码
try {
// Initialize the configuration service, and the console automatically obtains the following parameters through the sample code.
String serverAddr = "{serverAddr}";
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
// if need username and password to login
properties.put("username","nacos");
properties.put("password","nacos");
ConfigService configService = NacosFactory.createConfigService(properties);
} catch (NacosException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Y.2.2 其他语言的SDK鉴权
- Open-API鉴权
首先需要使用用户名和密码登陆nacos。
curl -X POST '127.0.0.1:8848/nacos/v1/auth/login' -d 'username=nacos&password=nacos'
若用户名和密码正确,返回信息如下:
{"accessToken":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTYwNTYyOTE2Nn0.2TogGhhr11_vLEjqKko1HJHUJEmsPuCxkur-CfNojDo","tokenTtl":18000,"globalAdmin":true}
接下来进行配置信息或服务信息时,应当使用该accessToken鉴权,在url后添加参数accessToken={accessToken},其中{accessToken}为登录时返回的token信息,例如
curl -X GET '127.0.0.1:8848/nacos/v1/cs/configs?accessToken=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTYwNTYyMzkyM30.O-s2yWfDSUZ7Svd3Vs7jy9tsfDNHs1SuebJB4KlNY8Q&dataId=nacos.example.1&group=nacos_group'
curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?accessToken=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTYwNTYyMzkyM30.O-s2yWfDSUZ7Svd3Vs7jy9tsfDNHs1SuebJB4KlNY8Q&port=8848&healthy=true&ip=11.11.11.11&weight=1.0&serviceName=nacos.test.3&encoding=GBK&namespaceId=n1'
Y.2.x 身份鉴权测试类 NacosConfigTest
- 引入Maven依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- <L3> test & code quality [start] -->
<!-- junit : unit test -->
<junit.version>4.13.1</junit.version>
<!-- <L3> test & code quality [end] -->
<!-- 1.4.3 / 2.1.1 -->
<nacos-client.version>1.4.4</nacos-client.version>
<slf4j.version>1.7.25</slf4j.version>
<log4j.version>2.13.3</log4j.version>
<guava.version>28.0-jre</guava.version>
<jackson.version>2.13.4</jackson.version>
<httpclient.version>4.5.13</httpclient.version>
<prometheus.client.version>0.9.0</prometheus.client.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- nacos-client [start] -->
<!-- https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-api -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-api</artifactId>
<version>${nacos-client.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-common</artifactId>
<version>${nacos-client.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-client -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${nacos-client.version}</version>
</dependency>
<!-- nacos-client [end] -->
<!-- log [start] -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jul</artifactId>
<!--<version>2.13.3</version>-->
<version>${log4j.version}</version>
<scope>compile</scope>
</dependency>
<!-- log [end] -->
<!-- cache [start] -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- cache [end] -->
<!-- jackson | start -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- jackson | end -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version> <!-- 使用最新的稳定版本 -->
</dependency>
<!-- prometheus | start -->
<!-- java 读取Prometheus api/v1/query - 51cto - https://blog.51cto.com/u_16175470/6860623 -->
<!-- prometheus使用三(自定义监控指标实现) - 博客园 - https://www.cnblogs.com/lpcyj/p/13408930.html -->
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<version>${prometheus.client.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_httpserver</artifactId>
<version>${prometheus.client.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_pushgateway</artifactId>
<version>${prometheus.client.version}</version>
</dependency>
<!-- prometheus | end -->
</dependencies>
- NacosConfigTest
package org.example;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import org.junit.Test;
import java.util.Properties;
/**
* nacos 配置中心测试
* @description NACOS Server 端 : 2.0.3 / NACOS 客户端 : 1.4.3
* @reference-doc
* [1] NACOS 用户指南(JAVA SDK) - nacos - https://nacos.io/zh-cn/docs/sdk.html
* [2] https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-client
*/
public class NacosConfigTest {
/** NACOS 服务器地址 **/
private final static String SERVER_ADDR = "https://config-uat.xxxx.com.cn"; // 形如 : 127.0.0.1:8848 或 http://127.0.0.1:8848
private final static String USERNAME = "nacos";//nacos
private final static String PASSWORD = "nacos";//nacos
private final static String NAMESPACE = "xxx_team";//public
private final static String GROUP = "DEFAULT_GROUP";//DEFAULT_GROUP
private final static String DATA_ID = "cn.com.xxxx.business.parse";
/**
* NACOS 服务器端启用强制客户端输入密码,但客户端不提供密码
* @sample [shell] curl -X GET 'http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.example&group=com.alibaba.nacos'
* @descrption
* [1] nacos server 2.0.3 : 执行成功
* [2] nacos server 2.3.1 : 执行失败,ErrCode:403, ErrMsg:<html><body><h1>Whitelabel Error Page</h1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback
*/
@Test
public void nacosServerEnablePasswordButClientNotUsePasswordTest(){
try {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, SERVER_ADDR);
properties.put(PropertyKeyConst.NAMESPACE, NAMESPACE);
//properties.put(PropertyKeyConst.USERNAME, USERNAME);
//properties.put(PropertyKeyConst.PASSWORD, PASSWORD);
ConfigService configService = NacosFactory.createConfigService(properties);
String content = configService.getConfig(DATA_ID, GROUP, 5000);
System.out.println(content);
} catch (NacosException e) {//读取配置超时或网络异常,抛出 NacosException 异常
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* NACOS 服务器端不启用强制客户端输入密码,且客户端也提供密码
* @description
* [1] nacos server 2.0.3 : 密码正确时,执行成功 ; 密码错误时, 报 403
* [1] nacos server 2.3.1 : 密码正确时,执行成功 ; 密码错误时, 报 403
*/
@Test
public void nacosServerDisablePasswordAndClientUsePasswordTest(){
try {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, SERVER_ADDR);
properties.put(PropertyKeyConst.NAMESPACE, NAMESPACE);
properties.put(PropertyKeyConst.USERNAME, USERNAME);
properties.put(PropertyKeyConst.PASSWORD, PASSWORD);
ConfigService configService = NacosFactory.createConfigService(properties);
String content = configService.getConfig(DATA_ID, GROUP, 5000);
System.out.println(content);
} catch (NacosException e) {//读取配置超时或网络异常,抛出 NacosException 异常
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* NACOS 服务器端不启用强制客户端输入密码,但客户端不提供密码
* @sample [shell] curl -X GET 'http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.example&group=com.alibaba.nacos'
* @description
* [1] nacos server 2.0.3 : 请求成功
* [2] nacos server 2.3.1 : 请求成功
*/
@Test
public void nacosServerDisablePasswordButClientNotUsePasswordTest(){
try {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, SERVER_ADDR);
properties.put(PropertyKeyConst.NAMESPACE, NAMESPACE);
//properties.put(PropertyKeyConst.USERNAME, USERNAME);
//properties.put(PropertyKeyConst.PASSWORD, PASSWORD);
ConfigService configService = NacosFactory.createConfigService(properties);
String content = configService.getConfig(DATA_ID, GROUP, 5000);
System.out.println(content);
} catch (NacosException e) {//读取配置超时或网络异常,抛出 NacosException 异常
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* NACOS 服务器端启用强制客户端输入密码,且客户端也提供密码
* @description 执行成功
*/
@Test
public void nacosServerEnablePasswordAndClientUsePasswordTest(){
try {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, SERVER_ADDR);
properties.put(PropertyKeyConst.NAMESPACE, NAMESPACE);
properties.put(PropertyKeyConst.USERNAME, USERNAME);
properties.put(PropertyKeyConst.PASSWORD, PASSWORD);
ConfigService configService = NacosFactory.createConfigService(properties);
String content = configService.getConfig(DATA_ID, GROUP, 5000);
System.out.println(content);
} catch (NacosException e) {//读取配置超时或网络异常,抛出 NacosException 异常
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
Y.3 开启服务身份识别功能
-
开启鉴权功能后,服务端之间的请求也会通过鉴权系统的影响。考虑到服务端之间的通信应该是可信的,因此在1.2~1.4.0版本期间,通过User-Agent中是否包含Nacos-Server来进行判断请求是否来自其他服务端。
-
但这种实现由于过于简单且固定,导致可能存在安全问题。因此从1.4.1版本开始,Nacos添加服务身份识别功能,用户可以自行配置服务端的Identity,不再使用User-Agent作为服务端请求的判断标准。
开启方式:
### 开启鉴权
nacos.core.auth.enabled=true
### 关闭使用user-agent判断服务端请求并放行鉴权的功能
nacos.core.auth.enable.userAgentAuthWhite=false
### 配置自定义身份识别的key(不可为空)和value(不可为空)
nacos.core.auth.server.identity.key=example
nacos.core.auth.server.identity.value=example
注意 : 所有集群均需要配置相同的server.identity
信息,否则可能导致服务端之间数据不一致或无法删除实例等问题。
Y.4 旧版本升级
- 考虑到旧版本用户需要升级,可以在升级期间,开启
nacos.core.auth.enable.userAgentAuthWhite=true
功能,待集群整体升级到1.4.1并稳定运行后,再关闭此功能。
K 扩展:Nacos 2.x 新特性
K.1 新增端口
Nacos 使用的若干端口
webui端口
:8080
address.server.port
- 2.x最大的变化就是端口。
- 在默认主端口:
8848
之外又新增了三个端口,新增端口是在配置的主端口(server.port
)基础上,进行一定偏移量自动生成:
server.port
9848
(主端口+1000)客户端gRPC请求服务端端口,用于客户端向服务端发起连接和请求
9849
(主端口+1001)服务端gRPC请求服务端端口,用于服务间同步等
7848
(主端口-1000)Jraft请求服务端端口,用于处理服务端间的Raft相关请求
K.2 Nginx 代理 Nacos
- 注意事项
所以,需要注意的是,若需要对主端口做修改,
8848
在修改后一定要大于1000
。
如果需要使用Nginx做转发或映射端口,还需要额外转发主端口 +1000
端口。
使用Nginx请求时,需要配置成TCP转发,不能配置http2转发,否则连接会被Nginx断开。9849
和7848
端口为服务端之间的通信端口,请勿暴露到外部网络环境和客户端测。
- nginx
- 检查你的Nginx是否支持TCP转发:
sudo nginx -V | grep with-stream
- 配置:
http{
upstream nacos {
server xxx.xxx.xxx.xxx:8848;
}
server{
listen 8000;
location / {
proxy_pass http://nacos;
}
}
}
- TCP转发:
stream{
upstream nacos-server-grpc {
server xxx.xxx.xxx.xxx:9848;
}
server {
listen 9000;
proxy_pass nacos-server-grpc;
}
}
X 参考文献
- nacos
- https://nacos.io/en-us/docs/quick-start-docker.html
- 权限认证 - Nacos 【参考/推荐】
- https://nacos.io/zh-cn/docs/open-api.html 【参考/推荐】
- https://github.com/nacos-group/nacos-docker/blob/v2.1.1
- https://github.com/nacos-group/nacos-docker/tree/v2.1.1
- https://github.com/nacos-group/nacos-docker/blob/v2.1.1/example/standalone-mysql-5.7.yaml
- https://github.com/nacos-group/nacos-docker/blob/v2.1.1/env/mysql.env
- https://github.com/alibaba/nacos/blob/2.1.1
- https://github.com/alibaba/nacos/blob/2.1.1/distribution/conf/nacos-mysql.sql 【推荐】
- https://github.com/alibaba/nacos/blob/master/config/src/main/resources/META-INF/nacos-db.sql
- docker
- (十四)docker安装nacos - CSDN 【参考】
- Docker安装Nacos详细步骤 - CSDN
- Docker设置获取环境变量 - CSDN
- Caused by: java.lang.IllegalStateException: No DataSource set - CSDN
- 在docker中安装Nacos--详细教程 - CSDN
- 【初识 Docker | 中级篇】 Docker 中使用 docker-compose 安装 Nacos - CSDN
docker compose + standalone 方式
docker compose + standalone + mysql8 方式
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!