本文将介绍在专有网络vpc(virtual private cloud)下,基于资源编排服务,快速部署高可用的dubbox服务的过程。dubbox服务采用的注册中心是zookeeper集群。做这件事情的意义在于:节约部署dubbox的时间,降低部署dubbox过程中出错的风险。
ros 阿里云资源编排(resource orchestration)是一种简单易用的云计算资源管理和自动化运维服务。用户通过模板描述多个云计算资源的依赖关系、配置等,并自动完成所有资源的创建和配置,以达到自动化部署、运维等目的。编排模板同时也是一种标准化的资源和应用交付方式,并且可以随时编辑修改,使基础设施即代码(infrastructure as code)成为可能。 ansible ansible是一个简单的自动化it工具。引用ansible官网的介绍就是:“deploy apps.manage systems.crush complexity.ansible helps you build a strong foundation for devops.”。 dubbox zookeeper
本文将从以下三个方面展开介绍:
准备ansible主机
vpc网络环境下快速部署高可用的dubbox服务
总结
本章将从以下两个方面展开:
安装ansible
安装ros sdk
首先需要新建一个vpc,并在这个vpc下创建一个vswitch,在这个vpc和vswitch下申请一台ecs实例,并给这台机器绑定公网ip,方便访问外网。本文所采用的ansible主机(ecs)系统版本信息如下:
这个版本的ecs已经安装了python 2.7.5。
创建好ansible主机以后,我们需要给这台主机安装ansible和ros sdk。ansible用来实现对远程主机的控制,ros sdk用来实现对资源栈的操作。
dubbox服务的快速部署需要借助ansible来完成,本文采用了yum来安装ansible:
ansible默认安装目录为<code>/etc/ansible</code>,安装好以后,<code>/etc/ansible/</code>目录结构如下:
注意:如果采用的是ubuntu系统,安装ansible过程如下:
ros提供了restful api和sdk,本文将介绍用python的方式来调用ros api创建资源。
在调用ros api之前需要安装相关的依赖。
使用pip安装aliyun-python-sdk-core:
使用pip安装ros sdk:
如果ansible主机未安装pip,可使用以下命令安装pip:
本章将从以下五个方面展开:
创建资源栈
编辑inventory文件
构建playbook
执行playbook
部署dubbox服务
创建资源栈的过程主要分为以下三步:
定义ros资源模板
调用ros api,创建资源栈
获取资源栈输出信息
本文通过调用ros api的方式来创建资源栈。
ros资源模板包括以下几种资源类型:
<a href="https://ros.console.aliyun.com/#/resourcetype/detail/aliyun::ecs::instancegroup/metadata">"type": "aliyun::ecs::instancegroup"</a>
在资源模板中使用两组该类型的资源,一组用来定义dubbox控制台集群服务器,一组用来定义zookeeper集群服务器。
<a href="https://ros.console.aliyun.com/#/resourcetype/detail/aliyun::slb::loadbalancer/metadata">"type": "aliyun::slb::loadbalancer"</a>
创建一台slb。
<a href="https://ros.console.aliyun.com/#/resourcetype/detail/aliyun::slb::backendserverattachment/metadata">"type": "aliyun::slb::backendserverattachment"</a>
给slb添加后端服务器。
<a href="https://ros.console.aliyun.com/#/resourcetype/detail/aliyun::slb::listener/metadata">"type": "aliyun::slb::listener"</a>
配置slb监听,slb监听dubbox控制台集群服务器的8080端口,并配置了健康检查<code>healthcheck</code>。
资源栈的输出为<code>"outputs"</code>,包括:ecsprivateips(dubbox控制台集群服务器的私有ip),zkprivateips(zookeeper集群服务器的私有ip),loadbalanceip(负载均衡slb的公网ip)。
在vpc网络环境下,给instancegroup指定vpc和vswtich,并保证和anisble主机处在同一个vpc和vswitch下,这样才能保证ansible主机可通过ecs的私有ip来登录ecs并操控ecs实例。
定义ros资源模板的python文件为<code>generate_vpc_ros_template.py</code>,文件内容如下:
创建资源栈的python文件为<code>create_stack.py</code>,文件内容如下:
下面详细解释该python文件的执行过程:
初始化sdk客户端对象:
client = acsclient(ak_id, ak_secret, region_id)
初始化创建资源栈的请求:
req = createstacksrequest.createstacksrequest()
指定请求资源region:
req.set_headers({'x-acs-region-id': region_id})
构造请求体,包括:栈名、过期时间戳、ros资源模板
create_stack_body = '''
req.set_content(create_stack_body)
发送请求,创建资源栈:
response = client.get_response(req)
6. 获取资源栈信息:
资源栈创建好以后,我们再次调用ros api获取资源栈的输出信息。方法如下:
调用时需要传入创建好的资源栈<code>id</code>和<code>name</code>信息。由于创建资源栈需要的时间不确定,所以以上方法定义了超时重试的机制。每次重试以后的等待时间要比上次等待时间少<code>interval</code>秒,在尝试<code>attempt</code>次若仍未获取到资源栈信息视为资源创建失败(一般不会出现这种情况)。
资源栈的输出格式如下:
我们将以上输出定义为<code>outputs</code>。
根据上面获取的资源栈输出信息<code>outputs</code>,获取dubbox控制台服务器组的私有ip。方法如下:
根据上面获取的资源栈输出信息<code>outputs</code>,获取zookeeper集群服务器组的私有ip。方法如下:
因为在创建资源栈的时候,已经在配置文件中配置好了<code>aliyun::ecs::instancegroup</code>的登录密码,所以可以直接使用配置文件中的密码信息,用户名默认为root。编辑<code>/etc/ansible/hosts</code>文件,即通常我们所说的<code>ansible inventory</code>文件。编辑该文件的方法如下:
执行该方法以后,生成的<code>inventory</code>文件,即<code>/etc/ansible/hosts</code>文件,内容如下:
<code>inventory</code>文件中定义了两个远程主机组,<code>dubbo_admin</code>和<code>zookeeper</code>,并指定了不同主机的ip、登录协议(默认是 ssh )、登录端口、登录用户名和密码。ansible在执行playbook的时候通过以上信息连接远程主机。
本文所描述的高可用dubbox服务,注册中心采用的是zookeeper集群,因此需要构建两个playbook。一个用来部署dubbox控制台集群,一个用来部署zookeeper集群。
部署dubbox控制台集群的playbook为<code>vpc_dubbox_admin_playbook</code>,结构如下:
关于<code>vpc_dubbox_admin_playbook</code>结构的说明如下:
files
存放<code>install_jdk.sh</code>、<code>install_jetty.sh</code>、<code>deploy_admin.sh</code>三个文件,这三个文件分别用来安装jdk、jetty以及部署dubbox控制台服务。
tasks
存放要执行的yml文件 <code>install_dubbo_admin.yml</code>,文件内容如下:
name: add config
template:
name: run install jdk
script: install_jdk.sh
name: run install jetty
script: install_jetty.sh
name: run deploy admin
script: deploy_admin.sh
templates
存放配置文件模板config.j2,文件内容如下:
配置文件config.j2中的参数值从<code>vpc_dubbox_zk.yml</code>文件中获取,通过ansible执行playbook的过程中会在每一台远程主机的<code>/root</code>目录下生成<code>config</code>文件,提供给<code>install_jdk.sh</code>、<code>install_jetty.sh</code>、<code>deploy_admin.sh</code>这三个脚本使用。关于<code>vpc_dubbox_zk.yml</code>文件,后面会提到。
部署zookeeper集群的playbook为<code>vpc_dubbox_zookeeper_playbook</code>,结构如下:
关于<code>vpc_dubbox_zookeeper_playbook</code>结构的说明如下:
存放<code>install_jdk.sh</code>、<code>install_zk.sh</code>两个文件,这两个文件分别用来安装jdk、部署zookeeper集群。
存放要执行的yml文件 <code>install_zk.yml</code>,文件内容如下:
name: run install zookeeper
script: install_zk.sh
配置文件config.j2中的参数值从<code>vpc_dubbox_zk.yml</code>文件中获取,通过ansible执行playbook的过程中会在每一台远程主机的<code>/root</code>目录下生成<code>config</code>文件,提供给<code>install_jdk.sh</code>、<code>install_zk.sh</code>使用。关于<code>vpc_dubbox_zk.yml</code>文件,后面会说明。
执行playbook,需要以下三个步骤:
生成ansible可执行文件
下载playbook
我们需要通过ansible执行<code>vpc_dubbox_zk.yml</code>文件来运行我们构建好的两个playbook。
<code>vpc_dubbox_zk.yml</code>文件的生成,需要分两步进行:
定义文件模板
生成文件
定义<code>vpc_dubbox_zk.yml</code>文件模板的python文件为<code>deploy_vpc_dubbox.py</code>,文件内容如下:
生成<code>vpc_dubbox_zk.yml</code>文件,方法如下:
生成的<code>vpc_dubbox_zk.yml</code>文件的内容如下:
<code>vpc_dubbox_zk.yml</code>文件中定义了一些参数,下面详细介绍文件中参数的作用:
hosts
远程主机组名称,和<code>inventory</code>文件中的远程主机组相对应。此文件说明要连接的主机组有两个。
vars
配置文件<code>config</code>中的参数,提供给<code>install_jdk.sh</code>、<code>install_jetty.sh</code>、 <code>deploy_admin.sh</code>、<code>install_zk.sh</code>使用。
roles
指定要执行的playbook名称。此文件说明要执行的playbook有两个。
最终生成的<code>vpc_dubbox_zk.yml</code>文件在目录<code>/etc/ansible/</code>下。
ansible是通过ssh命令连接远程主机,并执行playbook的。首次执行playbook前,由于当前ansible主机并没有记录远端主机的rsa key,会弹出rsa key的确认对话框,对话框内容如下:
因为整个过程不用人为的参与,所以可通过python脚本自动实现上述确认的过程:
由于用到了pexpect这个模块,在执行脚本前,需要使用pip安装pexpect模块:
vpc网络环境下未给ecs分配公网ip,导致每台ecs无法下载安装包,但是在安装jdk、jetty以及部署dubbox admin和zookeeper集群的时候需要这些安装包。因为ansible主机配有公网ip,所以可以将安装包先下载到ansible主机,又因为ansible主机和每台ecs在同一个vswitch下面,可以通过scp命令将安装包从ansible主机传到每台ecs上。具体操作过程如下:
在python文件中填入安装包的下载地址,运行python脚本,下载安装包至ansible主机。方法如下:
def wget_files():
通过scp命令将安装包拷贝到每台ecs。方法如下:
def scp_files_from_ansible_host_to_ecs_zk(host_ips, zk_ips):
通过ansible,执行playbook。方法如下:
subprocess.call('ansible-playbook ' + pb_file_dir + '/' + pb_file_name, shell=true)
运行ansible以后会进行dubbox服务的部署过程。
dubbox服务的部署,需要以下两个步骤:
搭建zookeeper集群
搭建dubbox控制台集群
zookeeper集群主要用来作为dubbox服务的注册中心。
搭建zookeeper集群,需要以下两个步骤:
安装jdk
因为zookeeper的运行需要java环境,所以需要先安装jdk。安装jdk的脚本为<code>install_jdk.sh</code>,文件内容如下:
安装jdk过程中,首先需要检查当前ecs是否存在java环境,存在就跳过安装过程,反之则安装。
声明:jdk安装包请从oracle官网下载,并下载本文指定的jdk版本(jdk-8u101-linux-x64.rpm)。从本文链接中下载jdk带来的任何法律问题,和本文作者无关。
搭建zookeeper集群的脚本为<code>install_zk.sh</code>,内容如下:
这个脚本的主要功能是安装zookeeper,并通过修改zookeeper配置文件<code>conf/zoo.cfg</code>来配置zookeeper集群。修改后的配置文件内容如下:
上述文件,配置了三台机器的zookeeper集群。在datadir目录下,创建一个myid文件,里面内容为一个数字,用来标识当前主机号。
由于dubbox控制台需要运行在jetty容器上,jetty容器的运行又需要有java环境,因此部署dubbox控制台之前,需要先安装jdk和jetty。
搭建dubbox控制台集群,需要以下三个步骤:
安装jetty
部署dubbox控制台
安装jetty的文件为<code>install_jetty.sh</code>,内容如下:
安装jetty过程,主要包括:读取配置文件,设置jetty安装目录,修改jetty的配置文件<code>etc/webdefault.xml</code>。jetty安装目录的选择包括以下三种情形:
未指定jetty安装目录,则选择默认目录进行安装
指定了jetty安装目录但是目录不存在,则创建目录并安装jetty
指定了jetty安装目录并且目录已经存在
如果配置了强制执行选项,则覆盖目录并安装jetty
如果没有配置强制执行选项,程序强制退出
部署dubbox服务的文件为<code>deploy_admin.sh</code>,内容如下:
在部署dubbox服务的过程中,有几个需要注意的问题:
当访问dubbox服务时,需要访问服务器的8080端口,由于防火墙的原因,外部可能无法访问到服务器的dubbox服务,因此需要修改防火墙的设置。本文所采用的ecs系统为centos 7,简单起见,我直接关闭了系统的防火墙。关闭防火墙的方法如下:
systemctl stop firewalld.service
这里不建议采用直接关闭防火墙的方式。
通过ansible控制远程服务器组启动jetty服务时,ansible命令执行结束以后,jetty服务也自动退出,这是我们不想看到的结果。可通过nohup命令以守护进程的方式启动jetty服务,可以解决jetty服务自动退出的问题,启动jetty命令如下:
nohup $jetty_home/bin/jetty.sh start &
dubbox服务部署好了以后,可通过以下地址访问dubbox服务控制台:
注意:在vpc网络下,ip指的是slb的公网ip。
dubbox服务部署好以后,可通过以下操作登录控制台:
输入用户名密码,点击登录:

登录进去以后的dubbox控制台界面如下:
现在,我们可以使用dubbox服务了。
本章将从以下两个方面进行总结:
dubbox服务系统结构图
如何快速构建高可用dubbox服务
最终,采用zookeeper集群作为注册中心,基于资源编排快速部署出来的高可用dubbox服务的系统结构图,如下图所示:
dubbox服务的高可用,主要体现在两个方面:
注册中心的高可用
注册中心采用了zookeeper集群的方式,zookeeper集群中只要有超过半数的服务可用,dubbox服务的注册中心就可以正常工作。
dubbox服务控制台的高可用
创建两台ecs实例并分别部署dubbox控制台服务,这两台ecs挂载到一个slb上,我们可通过slb来访问dubbox控制台服务。
前面章节描述的部署过程看起来可能比较繁琐,本文的核心是快速部署,因此你可以根据下面的指导,快速部署属于你的高可用dubbox服务。四个步骤快速部署高可用dubbox服务:
下载源码
修改配置文件
运行main函数
可从本文的附件中下载源码,然后将vpc_python文件拷贝到ansible主机。
修改<code>vpc_python/config.py</code>文件,文件内容如下:
下面详细讲解配置文件中一些参数所代表的意义:
<code>vpc_id</code>
ansible主机所在的vpc id
<code>vswitch_id</code>
ansible主机所在的vswitch id
<code>zk_size</code>
zookeeper集群的大小,zookeeper集群的大小必须为奇数,且必须大于1
<code>ecs_password</code>
申请的ecs服务器的登录密码,用户名默认为root
<code>ak_id</code>
用户的ak id
<code>ak_secret</code>
用户的ak secret
<code>region_id</code>
资源栈创建的区域
<code>jetty_home</code>
jetty默认安装目录
<code>jetty_home_enforce</code>
是否强制安装jetty,f代表强制安装,其它代表非强制
<code>dubbo_root_password</code>
dubbox控制台root用户的登录密码
<code>dubbo_guest_password</code>
dubbox控制台guest用户的登录密码
用户可根据自己的需求更改配置文件。
运行<code>vpc_python/main.py</code>。函数运行完以后,高可用dubbox服务就部署好了。