Nacos

alibabamicro-services

一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

# 一、Nacos入门

# 什么是 Nacos

Nacos 官网 (opens new window)

Nacos致力于服务注册与发现、服务健康监测、动态配置服务。

Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。

# 基本架构

# 概念

# 服务 (Service)

服务是指一个或一组软件功能(例如特定信息的检索或一组操作的执行),其目的是不同的客户端可以为不同的目的重用(例如通过跨进程的网络调用)。Nacos 支持主流的服务生态,如 Kubernetes Service、gRPC|Dubbo RPC Service 或者 Spring Cloud RESTful Service.

# 服务注册中心 (Service Registry)

服务注册中心,它是服务,其实例及元数据的数据库。服务实例在启动时注册到服务注册表,并在关闭时注销。服务和路由器的客户端查询服务注册表以查找服务的可用实例。服务注册中心可能会调用服务实例的健康检查 API 来验证它是否能够处理请求。

# 服务元数据 (Service Metadata)

服务元数据是指包括服务端点(endpoints)、服务标签、服务版本号、服务实例权重、路由规则、安全策略等描述服务的数据

# 服务提供方 (Service Provider)

是指提供可复用和可调用服务的应用方

# 服务消费方 (Service Consumer)

是指会发起对某个服务调用的应用方

# 配置 (Configuration)

在系统开发过程中通常会将一些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。目的是让静态的系统工件或者交付物(如 WAR,JAR 包等)更好地和实际的物理运行环境进行适配。配置管理一般包含在系统部署的过程中,由系统管理员或者运维人员完成这个步骤。配置变更是调整系统运行时的行为的有效手段之一。

# 配置管理 (Configuration Management)

在数据中心中,系统中所有配置的编辑、存储、分发、变更管理、历史版本管理、变更审计等所有与配置相关的活动统称为配置管理。

# 名字服务 (Naming Service)

提供分布式系统中所有对象(Object)、实体(Entity)的“名字”到关联的元数据之间的映射管理服务,例如 ServiceName -> Endpoints Info, Distributed Lock Name -> Lock Owner/Status Info, DNS Domain Name -> IP List, 服务发现和 DNS 就是名字服务的2大场景。

# 配置服务 (Configuration Service)

在服务或者应用运行过程中,提供动态配置或者元数据以及配置管理的服务提供者。

# 二、Nacos安装

# Linux安装

# 准备环境

Nacos 依赖 Java 环境来运行。如果您是从代码开始构建并运行 Nacos,还需要为此配置 Maven 环境,请确保是在以下版本环境中安装使用:

  • 64 bit OS,支持 Linux/Unix/Mac/Windows,推荐选用 Linux/Unix/Mac。
  • 64 bit JDK 1.8+
  • Maven 3.2.x+

# 下载并安装

# 下载源码
git clone https://github.com/alibaba/nacos.git

# 安装到本地仓库
cd nacos/
mvn -Prelease-nacos clean install -U
1
2
3
4
5
6

注:下载依赖时间较长,请耐心等待...

# 启动服务

cd distribution/target/nacos-server-0.7.0/nacos/bin

# Linux
./startup.sh -m standalone

# Windows
startup.cmd
1
2
3
4
5
6
7

打开浏览器访问:http://localhost:8848/nacos

# Docker安装Nacos1.x

使用Docker安装Nacos1.x(standalone)步骤如下。

# 创建MySQL库

  • # 建库脚本

    • 创建MySQL用户:nacos/nacos
    • 创建MySQL库:nacos
    -- 创建库
    CREATE DATABASE nacos DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
    
    -- 创建用户
    create user 'nacos'@'%' identified by '1q2w3e';
    grant all on nacos.* to nacos;
    FLUSH PRIVILEGES;
    
    1
    2
    3
    4
    5
    6
    7
  • # 建表脚本

    • 创建11张表
    • 创建Nacos账户:nacos/123456
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for config_info
    -- ----------------------------
    DROP TABLE IF EXISTS `config_info`;
    CREATE TABLE `config_info`  (
      `id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
      `data_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'data_id',
      `group_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
      `content` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'content',
      `md5` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'md5',
      `gmt_create` datetime(0) NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
      `gmt_modified` datetime(0) NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
      `src_user` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'source user',
      `src_ip` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'source ip',
      `app_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
      `tenant_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT '' COMMENT '租户字段',
      `c_desc` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
      `c_use` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
      `effect` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
      `type` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
      `c_schema` text CHARACTER SET utf8 COLLATE utf8_bin,
      PRIMARY KEY (`id`) USING BTREE,
      UNIQUE INDEX `uk_configinfo_datagrouptenant`(`data_id`, `group_id`, `tenant_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 470 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = 'config_info' ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Table structure for config_info_aggr
    -- ----------------------------
    DROP TABLE IF EXISTS `config_info_aggr`;
    CREATE TABLE `config_info_aggr`  (
      `id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
      `data_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'data_id',
      `group_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'group_id',
      `datum_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'datum_id',
      `content` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '内容',
      `gmt_modified` datetime(0) NOT NULL COMMENT '修改时间',
      `app_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
      `tenant_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT '' COMMENT '租户字段',
      PRIMARY KEY (`id`) USING BTREE,
      UNIQUE INDEX `uk_configinfoaggr_datagrouptenantdatum`(`data_id`, `group_id`, `tenant_id`, `datum_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '增加租户字段' ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Table structure for config_info_beta
    -- ----------------------------
    DROP TABLE IF EXISTS `config_info_beta`;
    CREATE TABLE `config_info_beta`  (
      `id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
      `data_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'data_id',
      `group_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'group_id',
      `app_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'app_name',
      `content` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'content',
      `beta_ips` varchar(1024) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'betaIps',
      `md5` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'md5',
      `gmt_create` datetime(0) NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
      `gmt_modified` datetime(0) NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
      `src_user` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'source user',
      `src_ip` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'source ip',
      `tenant_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT '' COMMENT '租户字段',
      PRIMARY KEY (`id`) USING BTREE,
      UNIQUE INDEX `uk_configinfobeta_datagrouptenant`(`data_id`, `group_id`, `tenant_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = 'config_info_beta' ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Table structure for config_info_tag
    -- ----------------------------
    DROP TABLE IF EXISTS `config_info_tag`;
    CREATE TABLE `config_info_tag`  (
      `id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
      `data_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'data_id',
      `group_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'group_id',
      `tenant_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT '' COMMENT 'tenant_id',
      `tag_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'tag_id',
      `app_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'app_name',
      `content` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'content',
      `md5` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'md5',
      `gmt_create` datetime(0) NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
      `gmt_modified` datetime(0) NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
      `src_user` text CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'source user',
      `src_ip` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'source ip',
      PRIMARY KEY (`id`) USING BTREE,
      UNIQUE INDEX `uk_configinfotag_datagrouptenanttag`(`data_id`, `group_id`, `tenant_id`, `tag_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = 'config_info_tag' ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Table structure for config_tags_relation
    -- ----------------------------
    DROP TABLE IF EXISTS `config_tags_relation`;
    CREATE TABLE `config_tags_relation`  (
      `id` bigint(0) NOT NULL COMMENT 'id',
      `tag_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'tag_name',
      `tag_type` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'tag_type',
      `data_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'data_id',
      `group_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'group_id',
      `tenant_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT '' COMMENT 'tenant_id',
      `nid` bigint(0) NOT NULL AUTO_INCREMENT,
      PRIMARY KEY (`nid`) USING BTREE,
      UNIQUE INDEX `uk_configtagrelation_configidtag`(`id`, `tag_name`, `tag_type`) USING BTREE,
      INDEX `idx_tenant_id`(`tenant_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = 'config_tag_relation' ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Table structure for group_capacity
    -- ----------------------------
    DROP TABLE IF EXISTS `group_capacity`;
    CREATE TABLE `group_capacity`  (
      `id` bigint unsigned NOT NULL COMMENT '主键ID',
      `group_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
      `quota` int unsigned NOT NULL COMMENT '配额,0表示使用默认值',
      `usage` int unsigned NOT NULL COMMENT '使用量',
      `max_size` int unsigned NOT NULL COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
      `max_aggr_count` int unsigned NOT NULL COMMENT '聚合子配置最大个数,,0表示使用默认值',
      `max_aggr_size` int unsigned NOT NULL COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
      `max_history_count` int unsigned NOT NULL COMMENT '最大变更历史数量',
      `gmt_create` datetime(0) NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
      `gmt_modified` datetime(0) NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
      PRIMARY KEY (`id`) USING BTREE,
      UNIQUE INDEX `uk_group_id`(`group_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '集群、各Group容量信息表' ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Table structure for his_config_info
    -- ----------------------------
    DROP TABLE IF EXISTS `his_config_info`;
    CREATE TABLE `his_config_info`  (
      `id` bigint unsigned NOT NULL,
      `nid` bigint unsigned NOT NULL,
      `data_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
      `group_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
      `app_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'app_name',
      `content` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
      `md5` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
      `gmt_create` datetime(0) NOT NULL DEFAULT '2010-05-05 00:00:00',
      `gmt_modified` datetime(0) NOT NULL DEFAULT '2010-05-05 00:00:00',
      `src_user` text CHARACTER SET utf8 COLLATE utf8_bin,
      `src_ip` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
      `op_type` char(10) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
      `tenant_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT '' COMMENT '租户字段',
      PRIMARY KEY (`nid`) USING BTREE,
      INDEX `idx_gmt_create`(`gmt_create`) USING BTREE,
      INDEX `idx_gmt_modified`(`gmt_modified`) USING BTREE,
      INDEX `idx_did`(`data_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '多租户改造' ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Table structure for roles
    -- ----------------------------
    DROP TABLE IF EXISTS `roles`;
    CREATE TABLE `roles`  (
      `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
      `role` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
    ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of roles
    -- ----------------------------
    INSERT INTO `roles` VALUES ('nacos', 'ROLE_ADMIN');
    
    -- ----------------------------
    -- Table structure for tenant_capacity
    -- ----------------------------
    DROP TABLE IF EXISTS `tenant_capacity`;
    CREATE TABLE `tenant_capacity`  (
      `id` bigint unsigned NOT NULL COMMENT '主键ID',
      `tenant_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Tenant ID',
      `quota` int unsigned NOT NULL COMMENT '配额,0表示使用默认值',
      `usage` int unsigned NOT NULL COMMENT '使用量',
      `max_size` int unsigned NOT NULL COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
      `max_aggr_count` int unsigned NOT NULL COMMENT '聚合子配置最大个数',
      `max_aggr_size` int unsigned NOT NULL COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
      `max_history_count` int unsigned NOT NULL COMMENT '最大变更历史数量',
      `gmt_create` datetime(0) NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
      `gmt_modified` datetime(0) NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
      PRIMARY KEY (`id`) USING BTREE,
      UNIQUE INDEX `uk_tenant_id`(`tenant_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '租户容量信息表' ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Table structure for tenant_info
    -- ----------------------------
    DROP TABLE IF EXISTS `tenant_info`;
    CREATE TABLE `tenant_info`  (
      `id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
      `kp` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'kp',
      `tenant_id` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT '' COMMENT 'tenant_id',
      `tenant_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT '' COMMENT 'tenant_name',
      `tenant_desc` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'tenant_desc',
      `create_source` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT 'create_source',
      `gmt_create` bigint(0) NOT NULL COMMENT '创建时间',
      `gmt_modified` bigint(0) NOT NULL COMMENT '修改时间',
      PRIMARY KEY (`id`) USING BTREE,
      UNIQUE INDEX `uk_tenant_info_kptenantid`(`kp`, `tenant_id`) USING BTREE,
      INDEX `idx_tenant_id`(`tenant_id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = 'tenant_info' ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Table structure for users
    -- ----------------------------
    DROP TABLE IF EXISTS `users`;
    CREATE TABLE `users`  (
      `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
      `password` varchar(500) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
      `enabled` tinyint(1) NOT NULL,
      PRIMARY KEY (`username`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of users
    -- ----------------------------
    INSERT INTO `users` VALUES ('nacos', '$2a$10$PCBFD0Qp99a2w62owikb1OL5On37RTHyY.dzVlY8FfpQHyIy/QwQO', 1);
    
    SET FOREIGN_KEY_CHECKS = 1;
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216

# 部署Nacos

mkdir -p /usr/local/docker/nacos-mysql-standalone

version: '3.3'
services:
  nacos-standalone:
    restart: unless-stopped
    image: nacos/nacos-server:1.3.2
    container_name: nacos-standalone
    environment:
      - MODE=standalone
      - NACOS_SERVER_IP=192.168.1.101
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=192.168.1.101
      - MYSQL_SERVICE_DB_NAME=nacos
      - MYSQL_SERVICE_PORT=3306
      - MYSQL_SERVICE_USER=nacos
      - MYSQL_SERVICE_PASSWORD=123456
    volumes:
      - ./logs/:/home/nacos/logs
    ports:
      - "8848:8848"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

说明: 使用该单机版Naocos时,数据库必须使用MySQL5.6.x5.7.x

# Docker安装Nacos2.x

使用Docker安装Nacos2.x(standalone)步骤如下。

# 创建MySQL库

  • # 建库脚本
    • 创建MySQL用户:nacos/nacos
    • 创建MySQL库:nacos2
-- ============nacos-开发环境(mysql8)============
-- 创建用户
create user 'nacos'@'%' identified by 'nacos';
GRANT PROCESS ON *.* TO 'nacos'@'%';
FLUSH PRIVILEGES;

-- 创建nacos2.X版本的数据库
CREATE DATABASE nacos2 DEFAULT CHARACTER SET utf8mb3 DEFAULT COLLATE utf8_general_ci;
grant all on nacos2.* to nacos;
FLUSH PRIVILEGES;
1
2
3
4
5
6
7
8
9
10
  • 建表脚本
    • 创建12张表
    • 创建Nacos账户:nacos/123456

最新建表脚本:https://github.com/alibaba/nacos/blob/master/config/src/main/resources/META-INF/nacos-db.sql (opens new window)

/******************************************/
/*   数据库全名 = 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(128) DEFAULT NULL,
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) 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(128) 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 '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) 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 '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) 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 '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' 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(64) 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 '2010-05-05 00:00:00',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00',
  `src_user` text,
  `src_ip` varchar(20) 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 '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' 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,
	constraint uk_username_role UNIQUE (username,role)
);

CREATE TABLE permissions (
    role varchar(50) NOT NULL,
    resource varchar(512) NOT NULL,
    action varchar(8) NOT NULL,
    constraint uk_role_permission UNIQUE (role,resource,action)
);

INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$PCBFD0Qp99a2w62owikb1OL5On37RTHyY.dzVlY8FfpQHyIy/QwQO', TRUE);

INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205

说明:

  1. 新增了NACOS用户:nacos,密码:123456
  2. 密码使用MD5加密;

# 部署Nacos2.x

mkdir -p /usr/local/docker/nacos2-mysql8-standalone

version: "3.0"
services:
  nacos2-standalone:
    image: nacos/nacos-server:v2.0.4
    restart: unless-stopped
    environment:
      MODE: standalone
      SPRING_DATASOURCE_PLATFORM: mysql
      MYSQL_SERVICE_HOST: 192.168.1.101
      MYSQL_SERVICE_DB_NAME: nacos2
      MYSQL_SERVICE_PORT: 3306
      MYSQL_SERVICE_USER: nacos
      MYSQL_SERVICE_PASSWORD: 123456
      MYSQL_SERVICE_DB_PARAM: characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false
    ports:
      - "8848:8848"
      - "9848:9848"
      - "9849:9849"
    volumes:
      - ./logs/:/home/nacos/logs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

启动后进行登录 (opens new window)

nacos/123456

# 三、Nacos高级使用

# Nacos升级2.0

  1. docker部署Nacos v2.0.4

  2. 新增开发端口9848、9849

  3. 升级client依赖包

    <!-- ***  Nacos搭建 Begin  *** -->
    <!-- nacos 动态配置 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        <exclusions>
            <exclusion>
                <groupId>com.alibaba.nacos</groupId>
                <artifactId>nacos-client</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- nacos 注册中心-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <exclusions>
            <exclusion>
                <groupId>com.alibaba.nacos</groupId>
                <artifactId>nacos-client</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- Nacos2.0客户端 -->
    <dependency>
        <groupId>com.alibaba.nacos</groupId>
        <artifactId>nacos-client</artifactId>
        <version>2.0.0-BETA</version>
    </dependency>
    <!-- ***  Nacos搭建 End  *** -->
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30

# Nacos配置加密

官方文档:Nacos插件——配置加密 (opens new window)

为保证用户敏感配置数据的安全,Nacos 提供了配置加密的新特性。降低了用户使用的风险,也不需要再对配置进行单独的加密处理。

加密主要是针对于配置文件当中的配置,存储到数据库的时候,加密成密文。然后Nacos展示出来的是明文。

因为我们有时候会在配置文件存储很多敏感信息,例如数据库连接方式,或者第三方存储系统的相关信息。

出于此考虑,Nacos在2.1版本新发布了配置文件加密功能,根本不需要我们自己来实现,很轻松的就能实现配置内容AES加密功能。

实现的效果如下

  1. 展示的配置:

  1. 存储的配置(配置了AES加密后):

配置文件都是放在config_info表当中的,然后配置内容是放在content字段当中的。

  • 假如不配置加密,content字段里面都是存放的明文;

  • 添加加密后,里面存储的都是密文。

而在Nacos客户端展示配置的时候都是明文。

# 使用前提条件

  1. 版本要求:老版本暂时不兼容,目前只基于2.1版本进行了改造,推荐版本2.1.x +

  2. 数据库表 config_infoconfig_info_betahis_config_info中需要新增字段 encrypted_data_key ,用来存储每一个配置项加密使用的秘钥。

    • 新版本(2.1.x +)默认创建表的sql中已经添加该字段。

    • 对于目前已经搭建好的 Nacos 使用以下 sql 将字段添加到对应的表中:

      ALTER TABLE config_info ADD COLUMN `encrypted_data_key` text NOT NULL COMMENT '秘钥';
      ALTER TABLE config_info_beta ADD COLUMN `encrypted_data_key` text NOT NULL COMMENT '秘钥';
      ALTER TABLE his_config_info ADD COLUMN `encrypted_data_key` text NOT NULL COMMENT '秘钥';
      
      1
      2
      3

# 插件化实现

通过 SPI 的机制抽象出加密和解密的操作,Nacos 默认提供 AES 的实现。用户也可以自定义加解密的实现方式。具体的实现在 nacos-plugin (opens new window) 仓库。

在 Nacos 服务端启动的时候就会加载所有依赖的加解密算法,然后通过发布配置的 dataId 的前缀来进行匹配是否需要加解密和使用的加解密算法。

客户端发布的配置会在客户端通过filter完成加解密,也就是配置在传输过程中都是密文的。而控制台发布的配置会在服务端进行处理。

注意:想要使用加密是需要进行修改源码的,通过在源码上进行引入依赖,然后再重新打包。

重点有两个步骤,如下:

  1. 因为插件那个项目没有上传maven仓库,那也就是我们想要使用它,就需要下载下来,然后打包到本地仓库。
  2. 然后再下载下来nacos源码,将插件依赖添加到nacos源码当中,再将nacos打包。
  3. 然后我们通过自己打包的nacos,启动后会发现他已经存在加密功能了。

# Nacos源码打包

第一步:下载插件源码

下载插件源码:https://github.com/nacos-group/nacos-plugin (opens new window)

下载好之后直接通过IDEA打开项目。

  1. 注意:引入的Nacos版本需与后面下载的Nacos版本保持一致。

  1. 改完之后直接mvn install,或者直接上传到公司的Nexus私服。

第二步:下载Nacos源码并启动

下载源码有两种方式,一种是通过git clone直接克隆仓库到本地,一种是直接下载zip源码包,然后解压。

下载好之后直接通过IDEA打开项目。

注意:Nacos分了好多子模块,我们本次主要使用三个模块。

模块 作用
console 该模块测试nacos源码是否能正常启动使用。
config 该模块就是配置文件读写的源码,在该模块加入AES加密项目的依赖
distribution 该模块进行打包

第三步:console启动,测试Nacos

  1. 打开数据库配置

  2. 单机启动

Nacos默认是集群启动方式,所以需要指定为单机启动(不然会启动报错的): -Dnacos.standalone=true

在启动配置VM options中加入该配置参数。

启动后测试看看是否可以访问。

第四步:Nacos源码中添加插件依赖包

我们需要在nacos源码的config模块,手动添加依赖nacos-aes-encryption-plugin

<properties>
    <nacos-aes-encryption-plugin.version>1.0.0-SNAPSHOT</nacos-aes-encryption-plugin.version>
</properties>

<!-- AES加密插件 -->
<dependency>
	<groupId>com.alibaba.nacos</groupId>
	<artifactId>nacos-aes-encryption-plugin</artifactId>
	<version>${nacos-aes-encryption-plugin.version}</version>
</dependency>
1
2
3
4
5
6
7
8
9
10

第五步:修改distribution配置

在nacos源码的distribution模块修改2个配置文件。

  1. 修改nacos\distribution\conf\application.properties

    • 打开鉴权,nacos.core.auth.enabled=true
    • 打开数据库MySQL连接。

  2. 修改nacos\distribution\bin\startup.cmd

    set MODE="standalone"
    
    1

第六步:打包测试使用

在nacos源码的目录下执行:

mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
1

打好后,包路径:nacos\distribution\target

# Nacos打包后使用

打完包解压即可通过bin目录下的startup.cmd启动。

加密主要是依靠dataId的命名来区分是否要进行加密的

配置前缀使用cipher-[加密算法名称]-dataId来标识这个配置需要加密,系统会自动识别并加密。

例如使用 AES 算法来解密配置:cipher-aes-application-dev.yml

# 项目当中添加依赖

在项目中添加加密插件,需要依靠加密插件进行解密

<properties>
    <nacos-aes-encryption-plugin.version>1.0.0-SNAPSHOT</nacos-aes-encryption-plugin.version>
</properties>

<!-- nacos-config -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <exclusions>
        <!-- 排除低版本nacos客户端 -->
        <exclusion>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!-- 重新引入nacos-client -->
<dependency>
    <groupId>com.alibaba.nacos</groupId>
    <artifactId>nacos-client</artifactId>
    <version>2.2.0</version>
</dependency>
<!-- nacos-discovery -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- AES加密插件 -->
<!-- 切记这个包是本地包,nacos官方并没有上传中央仓库 -->
<dependency>
	<groupId>com.alibaba.nacos</groupId>
	<artifactId>nacos-aes-encryption-plugin</artifactId>
	<version>${nacos-aes-encryption-plugin.version}</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34