STEP BY STEP的指导客户将微服务从Eureka快速迁移到NACOS注册中心上并使用EDAS联动K8S快速上线应用。

背景信息

企业级分布式应用服务EDAS(Enterprise Distributed ApplicationService)是阿里巴巴中间件团队研发的 PaaS 平台,为企业提供高可用和分布式的互联网架构解决方案。

EDAS支持三大主流微服务框架HSF、Apache Dubbo 和 Spring Cloud,此次介绍的是Spring Cloud应用上云,包括:将客户注册中心Eureka微服务迁移至EDAS,云服务器及容器服务的应用部署。

组件介绍

Eureka注册中心

Eureka是Netflix开发的服务发现框架,基于REST的服务,主要用于负载均衡和中间层服务故障转移。Spring Cloud将它集成在其子项目spring-cloud-netflix中,以实现Spring Cloud的服务发现功能。

Eureka包含两个组件:Eureka Server和Eureka Client。

  • Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在页面中直观的看到。
  • Eureka Client是一个Java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。

EDAS注册中心

EDAS产品包含新老两种组件,一种是老版本的ANS组件,一种是功能更为多样的新组件Nacos。

ANS(Application Naming Service) 是隶属于阿里云 EDAS 产品的组件, Spring Cloud AliCloud ANS 提供了 Spring Cloud 规范下商业版的服务注册与发现,可以让用户方便的在本地开发,同时也可以运行在云环境里。

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

组件关系

转移关系

应用环境

  • EDAS基于专有云企业版V3.9.0版本。
  • Spring Cloud框架基于Finchley.SR1版本。

注册中心原理图

图 1. Eureka架构原理图
Eureka架构原理图
图 2. Nacos架构原理图
Nacos架构原理图

Eureka迁移到EDAS Nacos

Eureka是Spring Cloud套件中常用的服务注册中心。

  1. 替换pom.xml文件的导入依赖包。
    Eureka-Server的pom.xml文件配置:
    <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-eureka-server</artifactId>
    </dependency>

    Eureka-Client的pom.xml文件配置:

    <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>

    Nacos服务注册pom.xml的文件配置:

    <dependency>
           <groupId>com.alibaba.cloud</groupId>
           <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
           <version>2.1.0.RELEASE</version>
    </dependency>
  2. 替换注册中心配置文件。
    Eureka-Server的application.yml:
    eureka:
        server: 
            enable-self-preservation: false
        instance:
            hostname: eureka7001.com #eureka服务端的实例名称,单机配置是localhost
        client:
            register-with-eureka: false
            fetch-registry: false     
            service-url:        
            #单机配置 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
            defaultZone: http://eureka7002.com:7002/eureka

    Eureka-Client的application.yml:

    eureka:
        client: #客户端注册进eureka服务列表内
            service-url:
            #单机配置defaultZone: http://localhost:7001/eureka
            defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
         
            register-with-eureka: true
            fetch-registry: true
        instance:
            instance-id: mircoservicecloud-dept8001
            prefer-ip-address: true #访问路径可以显示IP地址
      info:
            app.name: poc-mircoservicecloud
            company.name: www.***.com  
            build.artifactId: $project.artifactId$
            build.version: $project.version$

    Nacos服务注册的application.properties:

    spring.application.name=nacos-service-consumer
    server.port=8082
    spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
  3. 替换应用主程序类注解。
    Eureka启动类注解:
    @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
    @MapperScan(basePackages="com.poc.springcloud.dao")
    @EnableEurekaClient
    //@EnableDiscoveryClient  //服务发现
    //@EnableCircuitBreaker //对Hystrix熔断机制支持
    public class DeptProvider_App {    
      
           public static void main(String[] args) {
                  SpringApplication.run(DeptProvider_App.class, args);
           }
    }

    Nacos启动类注解:

    @SpringBootApplication
    @EnableDiscoveryClient
    public class ProviderApplication {
    
        public static void main(String[] args) {SpringApplication.run(ProviderApplication.class, args);}
    }

EDAS ANS迁移到Nacos

当专有云为企业版V3.8.0或V3.8.1时Spring Cloud应用需要从EDAS ANS向EDAS Nacos注册中心进行迁移。

  1. 替换pom.xml文件的导入依赖包。
    ANS的pom.xml文件的配置:
    <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-alicloud-ans</artifactId>
           <version>0.2.2.RELEASE</version>
    </dependency>

    Nacos的pom.xml文件的配置:

    <dependency>
           <groupId>com.alibaba.cloud</groupId>
           <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
           <version>2.1.0.RELEASE</version>
    </dependency>
  2. 替换注册中心配置文件。
    说明 注解无需替换。

    ANS的application.properties:

    spring.application.name=ans-service-consumer
    server.port=8081
    # ans directory and amc config
    spring.cloud.alicloud.ans.server-list=127.0.0.1
    spring.cloud.alicloud.ans.server-port=8080
    #alibaba.acm.endpoint=127.0.0.1
    logging.path=/home/admin/logs
    #logging.path=c:\
    logging.file=biz.log
    logging.level.root=info

    Nacos的application.properties:

    spring.application.name=nacos-service-consumer
    server.port=8082
    # nacos directory and amc config
    spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
    #alibaba.acm.endpoint=127.0.0.1
    logging.path=/home/admin/logs
    #logging.path=c:\
    logging.file=biz.log
    logging.level.root=info

在 ECS 集群中部署 Web 应用

  1. 创建ECS实例。
    1. 登录 Apsara Stack控制台
    2. 在左侧导航栏中单击云基础产品 > 云服务器
    3. 云服务器页面中,单击创建实例
    4. 创建云服务器ECS页面中,根据提示完成参数配置:
      表 1. 实例参数配置
      类别 配置 说明
      区域 区域 ECS实例所在的地理位置。
      可用区 指在同一区域下,电力、网络隔离的物理区域,可用区之间内网互通,不同可用区之间故障隔离。如果您需要提高应用程序的高可用性,建议您将实例创建在不同的可用区内。
      基本配置 部门 待创建的ECS实例所属的部门。
      项目 待创建的ECS实例所属的项目。
      网络 网络类型 默认为专有网络,必选项。请选择具体的专有网络名称以及交换机名称。
      配置私网IP 可选项,IP地址网段取决于交换机网段。
      说明
      • 如果私网IP为空,系统会自动分配私网IP。
      • 如果此处配置了私网IP,则无法批量创建实例。
      安全组 安全组 必选项,选择实例所属的安全组。
      说明 创建ECS实例前,您需要提前创建好安全组。
      实例 I/O优化 可选项,默认为I/O优化实例。
      实例系列 必选项,支持创建的实例系列:系列二系列三系列四
      实例规格 可选项,根据实际应用需要选择CPU和内存,有些CPU和内存的组合不能选择Windows的镜像。
      镜像 镜像类型 必选项,根据需要选择镜像类型为公共镜像自定义镜像,并选择具体的镜像信息。
      存储 系统盘 必选项,选择SSD磁盘或高效磁盘,用于安装操作系统。
      数据盘 可选项,选择SSD磁盘或高效磁盘。最多可以添加16块数据盘。每个数据盘的最大容量为32 TB,可以勾选随实例释放加密
      说明
      • 勾选随实例释放,则该磁盘随实例一起释放,数据不可恢复;如果不勾选,则该实例释放时,系统会为用户从实例上卸载该云盘,不会被释放。
      • 勾选加密,则所创建的磁盘为加密磁盘;如果不勾选,所创建的磁盘为非加密磁盘。
      • 您也可以在创建实例后再添加数据盘。
      配置密码 设置密码 可选项。默认为立即设置,您也可以选择创建后设置,即在控制台通过重置密码来设置密码。
      登录密码 若选择立即设置,需输入登录密码。密码要求为8-30个字符,且同时包含三项(大写字母、小写字母、数字、特殊字符)。
      确认密码 重新输入已设置的登录密码。
      说明 这里设置的密码为远程连接实例的登录密码,非VNC密码。
      部署集 部署集 选择实例要加入的部署集名称。
      实例名称 实例名称 可选项。建议您为自己的实例设置一个易识别的名称。
      说明 2-114个字符,以大小写字母或中文开头,可包含字母数字、下划线和横杠。
      自定义数据 自定义数据 您可以输入相应的自定义数据编码。如果您要输入的数据已经采用Base64编码,应勾选输入已采用 Base64 编码
      说明 Windows支持bat和powershell两种格式,在Base64编码前,第一行为[bat] 或者[powershell]。Linux支持shell脚本。
      申请数量 申请台数 默认为1台。如果这里申请的数量多于1台,则会按照您当前选择的配置批量创建实例。
      说明 最多可批量创建50台ECS,如果配置了私网IP,则不支持批量创建。
    5. 单击创建
  2. 创建EDAS集群。
    1. 登录 Apsara Stack控制台
    2. 在左侧导航栏中,单击中间件产品 > 分布式应用服务
    3. 分布式应用服务页面选择区域和部门后单击EDAS
    4. 在左侧导航栏中,选择资源管理 > 集群
    5. 集群页面上方选择命名空间,然后在右侧单击创建集群
    6. 创建集群对话框中设置集群参数,然后单击创建
      EDAS资源管理之创建ECS集群
      • 集群名称:输入集群名称。名字仅支持字母、数字、下划线(_)、中划线(-)和英文句号(.),且长度不能超过64个字符。
      • 集群类型:选择 ECS
      • 集群网络类型:包括经典网络和 VPC 网络。根据实际需求在下拉菜单中选择网络类型。
      • VPC 网络:在下拉菜单中选择 VPC。

        说明 如果没有可选 VPC 网络,请单击创建 VPC 跳转到 VPC 控制台创建。
      • 命名空间:显示在集群列表页面选择的命名空间,不可配置。如果未选择,则默认显示地域。

      集群创建成功后当前页面右上角会出现创建成功的提示,同时新创建的集群会在集群列表中显示。

    7. 在左侧导航栏中,选择资源管理 > 集群
    8. 单击集群名称,进入集群详情页面。
    9. 集群详情页面,单击添加已有ECS
      创建实例
    10. 添加ECS实例页面,单击同步ECS,选择需要添加的ECS实例,单击完成
      同步实例
  3. 部署应用。
    1. EDAS控制台页面,单击左侧导航栏应用管理 > 命名空间,单击创建命名空间创建新的命名空间。
      创建命名空间
      说明 命名空间为应用提供互相隔离的运行环境,如开发、测试和生产环境等
    2. 在左侧导航栏选择应用管理 > 应用列表
    3. 应用列表页面右上角单击创建应用
    4. 应用基本信息页面设置应用参数,然后单击下一步
      表 2. 应用基本信息参数说明
      名称 描述
      命名空间 在下拉菜单中选择命名空间。
      集群类型 在第一个下拉菜单中选择 ECS集群,在第二个下拉菜单中选择一个具体集群。
      应用名称 输入应用名称,长度为 1~36 个字符。
      应用部署方式 根据实际应用,选择 WAR包部署JAR包部署
      应用运行环境 选择 标准Java应用运行环境
      Java环境 选择Open JDK 8
      应用描述 输入该应用的备注信息。
    5. 单击下一步,在实例例表页面中按下图所示顺序来选择实例。
      新增实例
    6. 选择立即部署,上传JAR包,输入版本号,然后单击确认创建
      确认创建
    7. 部署完成之后,在应用列表找到部署应用名称,单击进入可以查看部署好应用的实例部署信息,同时该页面可以对部署的应用执行停止、回滚、扩容、删除、重新部署操作。
      查看实例
    8. 单击左侧导航栏日志管理 > 日志目录,日志文件catalina.out可以查看启动日志。
      日志1日志2

在容器服务K8s集群中部署应用

  1. 创建K8s集群。
    1. 登录EDAS控制台。
    2. 单击左侧导航中的集群 > 集群,单击右上角的创建Kubernetes集群
    3. 设置集群的基本信息。
      表 3. 集群参数配置表
      名称 描述
      集群名称 要创建的集群的名称。可以包含1~63个字符,包括数字、中文字符、英文字符和短划线(-)。
      说明 集群名称在同一个用户下必须唯一。
      地域 所创建集群将要部署到的地域。
      可用区 集群的可用区。
      专有网络 您可以在已有 VPC 列表中选择所需的VPC。
      • 如果您使用的 VPC 中当前已有 NAT 网关,容器服务会使用已有的 NAT 网关。
      • 如果 VPC 中没有 NAT 网关,系统会默认自动为您创建一个 NAT 网关。如果您不希望系统自动创建 NAT 网关,可以取消勾选页面下方的为专有网络配置 SNAT
      说明 若选择不自动创建 NAT 网关,您需要自行配置 NAT 网关实现 VPC 安全访问公网环境,或者手动配置 SNAT,否则 VPC 内实例将不能正常访问公网,会导致集群创建失败。
      节点类型 计划支持两种节点类型:按量付费和包年包月,包年包月暂未开放。
      Master配置 选择实例规格和系统盘:
      • 实例规格:参见ECS云服务器 用户指南 中关于实例规格族的文档。
      • 系统盘:支持SSD云盘和高效云盘。
      • Master实例数量:支持添加3个实例。
      Worker实例 您可选择新增实例或添加已有实例。
      Worker配置 Worker实例选择新增实例,可进行如下配置。
      • 实例规格:参见ECS云服务器 用户指南 中关于实例规格族的文档。
      • 数量:选择Worker的数量。
      • 系统盘:支持SSD云盘和高效云盘。
      • 挂载数据盘:支持SSD云盘、高效云盘和普通云盘。
      Docker 版本Kubernetes 版本 显示当前支持的Docker版本和Kubernetes版本,您可查看对应版本,并根据需要进行选择。
      登录密码 设置节点的登录密码。
      确认密码 确认设置的节点登录密码。
      网络插件 支持Flannel和Terway,默认启用Flannel。
      Pod网络CIDRService CIDR(可选项) 选择使用已有专有网络时可配置。
      配置 SNAT 可选,若不选择,需要自行配置NAT网关,或手动配置SNAT。
      公网SLB 会创建一个公网SLB,同时把Master节点的6443端口(对应API Server)暴露出来,用户可以在外网通过kubeconfig连接/操作集群。
      SSH登录
      • 选择开放公网 SSH 登录,您可以 SSH 访问集群。
      • 选择不开放公网 SSH 登录,将无法通过 SSH 访问集群,也无法通过 kubectl 连接 集群。您可手动进行配置 。
      日志服务 您可使用已有Project或新建一个Project。勾选使用日志服务,会在集群中自动配置日志服务插件。
      集群删除保护 防止通过控制台或 API 误删除集群。
      高级选项
      • 节点Pod数量:单节点可运行 Pod 数量的上限。
      • 集群CA:设置是否开启集群CA。
    4. 在集群设置页面的右上角,最后单击创建集群
    5. 当前配置确认页面,所有项目检查通过后,单击确认,启动部署。
  2. 在容器服务 K8s 集群中部署应用(镜像)。
    EDAS 支持通过镜像部署容器服务 Kubernetes 版集群应用,您需准备好镜像,在容器服务 Kubernetes 版控制台中创建容器服务 Kubernetes 版集群,并将该集群导入到 EDAS 控制台,然后创建应用并完成部署。

    容器服务 Kubernetes 版提供高性能可伸缩的容器应用管理能力,支持企业级 Kubernetes 容器化应用的全生命周期管理。容器服务 Kubernetes 版简化集群的搭建和扩容等工作,整合阿里云虚拟化、存储、网络和安全能力,打造云端极佳的 Kubernetes 容器化应用运行环境。

    1. 登录EDAS控制台。
    2. 在左侧导航栏中选择资源管理 > 集群
    3. 集群列表页面单击容器服务 K8S 集群。在集群列表中选择已创建的容器服务 Kubernetes 集群,在操作列单击导入,并在导入 Kubernetes 集群的对话框中单击导入
      创建并导入容器服务 Kubernetes 集群

      当创建的容器服务 Kubernetes 集群的操作列的按钮变为删除,且集群状态为运行中,则表示容器服务的 Kubernetes 版集群已成功导入到 EDAS。

    4. 在 EDAS 控制台左侧导航栏选择应用管理 > 应用列表
    5. 应用列表页面选择地域命名空间,然后在页面右上角单击创建应用
    6. 应用基本信息页面中设置应用的基本信息和参数,然后单击下一步
      • 命名空间:在左侧下拉列表选择地域;在右侧下拉列表选择命名空间,如果不做选择命名空间则设置为默认
      • 集群类型:在左侧下拉列表中选择集群类型为 容器服务 K8s 集群,右侧下拉列表内选择具体的集群。
      • K8s Namespace:K8s Namespace 通过将系统内部的对象分配到不同的 Namespace 中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。
        • default:没有其他命名空间的对象的默认命名空间。
        • kube-system:系统创建的对象的命名空间。
        • kube-public:此命名空间是自动创建的,并且可供所有用户(包括未经过身份验证的用户)读取。
      • 应用名称:输入应用名称。
      • 应用描述:填写应用的基本情况。
    7. 应用配置页面配置镜像。应用部署方式默认选择为镜像。在我的镜像区域选择您创建的镜像。
    8. 设置 Pod。
      1. 设置单 Pod 资源配额

        Pod 在运行失败或出现故障时,可以自动重启或者快速迁移,保证应用的高可用。有状态应用如果使用了持久化存储,能保存实例数据;无状态应用重新部署时不保存实例数据。您最多可以设置 Pod 总数为 50 。

      2. 设置单 Pod 资源配额

        系统默认不做配额限制,即单 Pod 的 CPU 和 Memory 显示为 0。如果需要限制配额,请填设置数字。

    9. 设置启动命令和启动参数。
      • 启动命令:输入启动命令,如命令 CMD ["/usr/sbin/sshd","-D"],则在输入框内填写 /usr/sbin/sshd –D
      • 启动参数:一个参数写一行。如 args:["-c"; "while sleep 2"; "do echo date"; "done"] 中包含 4 个参数,需要分为 4 行来填写。
    10. 设置环境变量。

      在创建应用过程中,将所填环境变量注入到即将生成的容器中,这样可以避免常用环境变量的重复添加。

      假如您使用 MySQL 镜像时,可以参考如下环境变量:

      • MYSQL_ROOT_PASSWORD(必选项):用于设置 MySQL 的 root 密码,必选项。
      • MYSQL_USER 和 MYSQL_PASSWORD(可选项):用于添加除 root 之外的账号并设置密码。
      • MYSQL_DATABASE(可选项):用于设置生成容器时需要新建的数据库。

      如使用其它类型的镜像,请根据实际需求进行配置。

    11. 设置应用生命周期管理。

      容器服务 Kubernetes 集群中的应用有两种状态:

      • 无状态应用:支持多副本部署。重新部署时不保存实例数据。适用于以下使用场景:

        • Web 应用,应用升级或迁移时,实例内数据不保留。
        • 需要灵活水平扩展,以应对业务量骤然变化的应用。
      • 有状态应用:区别于无状态应用,有状态应用会存储需要持久化的数据,在应用升级或迁移时,实例内数据不会丢失。适用于以下使用场景:

        • 需要频繁通过 SSH 到容器进行操作。
        • 数据需要持久化存储(如数据库应用 MySQL 等),或者集群之间有选举特性,服务发现的应用,如 ZooKeeper,etcd等。

      有状态应用可以选择设置应用生命周期管理。

      生命周期管理脚本说明:

      • Poststart 脚本:一种容器钩子。该钩子在容器被创建后立刻触发,通知容器它已经被创建。该钩子不需要向其所对应的 hook handler 传入任何参数。如果该钩子对应的 hook handler 执行失败,则该容器会被杀死,并根据该容器的重启策略决定是否要重启该容器。

      • PreStop 脚本:一种容器钩子。该钩子在容器被删除前触发,其所对应的 hook handler 必须在删除该容器的请求发送给 Docker daemon 之前完成。在该钩子对应的 hook handler 完成后不论执行的结果如何,Docker daemon 会发送一个 SGTERN 信号量给 Docker daemon 来删除该容器。

      • Liveness 脚本:一种探测容器状态的探针,探测应用是否处于健康状态。如果不健康,则删除重建容器。

      • Readiness 脚本:一种探测容器状态的探针,探测应用是否启动完成并且处于正常服务状态。如果不正常,则更新容器的状态。

    12. 设置完成后,单击确认创建
  3. 优化镜像部署。

    使用通用的镜像打包出来的容器镜像体积很大,经常会达到700MB~800MB,不利于应用快速部署。

    • 原因分析:

      选择基础镜像CentOS7的镜像:CentOS7的镜像大小在200MB以上,在CentOS7上安装openjdk8就已经接近600MB,加上应用jar包镜像基本会达到700MB~800MB。

    • 优化方法:

      选择较小的基础镜像:以openjdk:8-jre-alpine作为基础镜像,openjdk:8-jre-alpine的大小不到100MB,加上jar包镜像基本为100MB~200MB。

    下图为demo应用(jar包39M)和openjdk:8-jre-alpine的镜像大小:

    镜像
    将应用包打成镜像,需要执行以下Dockerfile代码:
    FROM openjdk:8-jre-alpine
    
    ENV ADMIN_HOME /home/admin
    ENV LANG="en_US.UTF-8"
    ENV TERM=xterm
    ENV JAVA_OPTS=""
    
    RUN mkdir -p /home/admin/app/
    ADD nacos-service-consumer-0.0.1-SNAPSHOT.jar /home/admin/app/app.jar
    RUN echo 'java -jar $CATALINA_OPTS /home/admin/app/app.jar --server.port=8080' >> /home/admin/start.sh
    RUN chmod +x /home/admin/start.sh
    
    WORKDIR $ADMIN_HOME
    CMD ["/bin/bash", "/home/admin/start.sh"]