基于资源编排在专有网络环境下快速部署高可用的Dubbox服务(ZooKeeper版)

本文将介绍在专有网络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.”。
更多Ansible的相关知识可参考Ansible中文权威指南
Ansible的工作机制,可参考基于资源编排和 Ansible 在 VPC 下快速交付应用中“Ansible 及其运行机制”章节。
Dubbox
Dubbox在Dubbo服务的基础上添加了一些新功能,如:REST风格的远程调用、支持基于Jackson的JSON序列化、支持基于Kryo和FST的Java高效序列化实现、支持完全基于Java代码的Dubbo配置、升级Spring、升级Zookeeper等。想了解更多关于Dubbox服务内容可参考Dubbox Github
ZooKeeper
Apache ZooKeeper是Apache软件基金会的一个软件项目,他为大型分布式计算提供开源的分布式配置服务、同步服务和命名注册。ZooKeeper的架构通过冗余服务实现高可用性。本文将介绍采用ZooKeeper集群作为Dubbox服务的注册中心,来保证Dubbox服务的高可用性。更多ZooKeeper相关的知识可参考ZooKeeper Wiki

本文将从以下三个方面展开介绍

  • 准备Ansible主机
  • VPC网络环境下快速部署高可用的Dubbox服务
  • 总结

准备Ansible主机

本章将从以下两个方面展开:

  • 安装Ansible
  • 安装ROS SDK

首先需要新建一个VPC,并在这个VPC下创建一个VSwitch,在这个VPC和VSwitch下申请一台ECS实例,并给这台机器绑定公网IP,方便访问外网。本文所采用的Ansible主机(ECS)系统版本信息如下:

CentOS Linux release 7.0.1406 (Core)

这个版本的ECS已经安装了Python 2.7.5。
说明:专有网络VPC的创建链接。创建好VPC以后直接在该VPC下新建VSwitch即可。新建ECS的链接。

创建好Ansible主机以后,我们需要给这台主机安装Ansible和ROS SDK。Ansible用来实现对远程主机的控制,ROS SDK用来实现对资源栈的操作。

安装Ansible

Dubbox服务的快速部署需要借助Ansible来完成,本文采用了yum来安装Ansible:

yum install ansible

Ansible默认安装目录为/etc/ansible,安装好以后,/etc/ansible/目录结构如下:

[root@iZ94jwkjg0sZ ansible]# ls -l
总用量 24
-rw-r--r-- 1 root root 13819 5月  25 23:49 ansible.cfg
-rw-r--r-- 1 root root   441 8月  17 17:52 hosts
drwxr-xr-x 4 root root  4096 8月  17 17:52 roles

关于Ansible的安装方式可参考Ansible Installation
注意:如果采用的是Ubuntu系统,安装Ansible过程如下:

  apt-get install ansible
  apt-get install sshpass

安装ROS SDK

ROS提供了RESTful API和SDK,本文将介绍用Python的方式来调用ROS API创建资源。
在调用ROS API之前需要安装相关的依赖。

使用pip安装aliyun-python-sdk-core:

pip install aliyun-python-sdk-core

使用pip安装ROS SDK:

pip install aliyun-python-sdk-ros

如果Ansible主机未安装pip,可使用以下命令安装pip:

curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
python get-pip.py

如果不了解pip,可参考维基百科)。
关于ROS SDK详细安装和使用过程可以参考阿里云资源编排服务Python SDK使用入门。

VPC网络环境下快速部署高可用的Dubbox服务

本章将详解讲解Dubbox服务的部署过程。您也可以跳过此章节,直接参考如何快速构建高可用Dubbox服务快速部署Dubbox服务。

本章将从以下五个方面展开:

  • 创建资源栈
  • 编辑Inventory文件
  • 构建PlayBook
  • 执行PlayBook
  • 部署Dubbox服务

创建资源栈

创建资源栈的过程主要分为以下三步:

  • 定义ROS资源模板
  • 调用ROS API,创建资源栈
  • 获取资源栈输出信息

定义ROS资源模板

本文通过调用ROS API的方式来创建资源栈。
ROS资源模板包括以下几种资源类型:

  • "Type": "ALIYUN::ECS::InstanceGroup"

    • 在资源模板中使用两组该类型的资源,一组用来定义Dubbox控制台集群服务器,一组用来定义ZooKeeper集群服务器。
  • "Type": "ALIYUN::SLB::LoadBalancer"
    • 创建一台SLB。
  • "Type": "ALIYUN::SLB::BackendServerAttachment"
    • 给SLB添加后端服务器。
  • "Type": "ALIYUN::SLB::Listener"
    • 配置SLB监听,SLB监听Dubbox控制台集群服务器的8080端口,并配置了健康检查HealthCheck
  • 资源栈的输出为"Outputs",包括:EcsPrivateIps(Dubbox控制台集群服务器的私有IP),ZKPrivateIps(ZooKeeper集群服务器的私有IP),LoadBalanceIp(负载均衡SLB的公网IP)。

在VPC网络环境下,给InstanceGroup指定VPC和VSwtich,并保证和Anisble主机处在同一个VPC和VSwitch下,这样才能保证Ansible主机可通过ECS的私有IP来登录ECS并操控ECS实例。

定义ROS资源模板的Python文件为generate_vpc_ros_template.py,文件内容如下:

from string import Template
# define ros template
create_resources_with_parameters = '''
{
  "ROSTemplateFormatVersion": "2015-09-01",
  "Resources": {
    "InstanceGroupDubboxAdmin": {
      "Type": "ALIYUN::ECS::InstanceGroup",
      "Properties": {
        "ImageId": "centos7u2_64_40G_cloudinit_20160520.raw",
        "Password": "$ecs_password",
        "MinAmount": 2,
        "MaxAmount": 2,
        "InstanceType": "$instance_type",
        "ZoneId": "$zone_id",
        "InternetChargeType": "PayByTraffic",
        "NetworkType": "vpc",
        "InstanceName": "ecs",
        "VpcId": "$vpc_id",
        "VSwitchId": "$vswitch_id"
      }
    },
    "InstanceGroupZK": {
      "Type": "ALIYUN::ECS::InstanceGroup",
      "Properties": {
        "ImageId": "centos7u2_64_40G_cloudinit_20160520.raw",
        "Password": "$ecs_password",
        "MinAmount": 3,
        "MaxAmount": $instance_group_zk_size,
        "InstanceType": "$instance_type",
        "ZoneId": "$zone_id",
        "InternetChargeType": "PayByTraffic",
        "NetworkType": "vpc",
        "InstanceName": "zk",
        "VpcId": "$vpc_id",
        "VSwitchId": "$vswitch_id"
      }
    },
    "LoadBalance": {
      "Properties": {
        "AddressType": "internet",
        "InternetChargeType": "paybytraffic",
        "LoadBalancerName": "balancer"
      },
      "Type": "ALIYUN::SLB::LoadBalancer"
    },
    "Attachment": {
      "Properties": {
        "BackendServers": [
          {
            "ServerId": { "Fn::Select": ["0",{ "Fn::GetAtt": [ "InstanceGroupDubboxAdmin", "InstanceIds" ] }]},
            "Weight": 100
          },
           {
            "ServerId": { "Fn::Select": ["1",{ "Fn::GetAtt": [ "InstanceGroupDubboxAdmin", "InstanceIds" ] }]},
            "Weight": 100
          }
        ],
        "LoadBalancerId": {
          "Ref": "LoadBalance"
        }
      },
      "Type": "ALIYUN::SLB::BackendServerAttachment"
    },
    "Listener": {
      "Type": "ALIYUN::SLB::Listener",
      "Properties": {
          "LoadBalancerId": {
            "Ref": "LoadBalance"
          },
          "ListenerPort": $listen_port,
          "BackendServerPort": $bachend_server_port,
          "Bandwidth": -1,
          "Protocol": "http",
          "HealthCheck": {
              "HealthyThreshold": 3,
              "UnhealthyThreshold": 3,
              "Interval": 2,
              "Timeout": 5,
              "HttpCode": "http_2xx",
              "URI": "$health_check_path"
          },
          "Scheduler": "wrr"
      }
    }
  },
  "Outputs": {
    "EcsPrivateIps": {
      "Value": { "Fn::GetAtt": [ "InstanceGroupDubboxAdmin", "PrivateIps"]}
    },
    "ZKPrivateIps": {
      "Value": { "Fn::GetAtt": [ "InstanceGroupZK", "PrivateIps"]}
    },
    "LoadBalanceIp": {
      "Value": {"Fn::GetAtt": [ "LoadBalance", "IpAddress"]}
    }
   }
}
'''
# define func to generate ros template
def generate_template(**kwargs):
    template = Template(create_resources_with_parameters)
    return template.substitute(kwargs)

调用ROS API,创建资源栈

创建资源栈的Python文件为create_stack.py,文件内容如下:

from aliyunsdkcore.client import AcsClient
from aliyunsdkros.request.v20150901 import CreateStacksRequest
import generate_vpc_ros_template
import json
from config import *
# define func to create stack
def create_stack(stack_name, ak_id, ak_secret, region_id, zk_size):
    print('invoke CreateStackRequest to create instances...')
    client = AcsClient(ak_id, ak_secret, region_id)
    req = CreateStacksRequest.CreateStacksRequest()
    req.set_headers({'x-acs-region-id': region_id})
    #create vpc network resources
    template = generate_vpc_ros_template.generate_template(vpc_id = vpc_id, ecs_password = ecs_password,
        instance_type = instance_type, zone_id = zone_id, vswitch_id = vswitch_id,
        instance_group_zk_size = zk_size, listen_port = 8080,
        bachend_server_port =8080, health_check_path = '/dubbo-admin/favicon.ico')
    create_stack_body = '''
    {
        "Name": "%s",
        "TimeoutMins": %d,
        "Template": %s
    }
    ''' % (stack_name, create_timeout, template)
    req.set_content(create_stack_body)
    # get response
    response = client.get_response(req)
    # deal response
    if 201 == response[0]:
        print('Create stack succeccfully!!!')
        return json.loads(response[-1])
    else:
        print('Unexpected errors: status=%d, error=%s' % (response[0], response[-1]))
        return None
if name == '__main__':
    create_stack(stack_name, ak_id, ak_secret, region_id, zk_size)

下面详细解释该Python文件的执行过程:

  1. 初始化SDK客户端对象:

    client = AcsClient(ak_id, ak_secret, region_id)

  2. 初始化创建资源栈的请求:

    req = CreateStacksRequest.CreateStacksRequest()

  3. 指定请求资源Region:

    req.set_headers({'x-acs-region-id': region_id})

  4. 构造请求体,包括:栈名、过期时间戳、ROS资源模板

    create_stack_body = '''
    {
    "Name": "%s",
    "TimeoutMins": %d,
    "Template": %s
    }
    ''' % (stack_name, create_timeout, template)
    req.set_content(create_stack_body)

  5. 发送请求,创建资源栈:

    response = client.get_response(req)

6. 获取资源栈信息:

 # deal response
 if 201 == response[0]:
      print('Create stack succeccfully!!!')
      return json.loads(response[-1])
 else:
      print('Unexpected errors: status=%d, error=%s' % (response[0], response[-1]))
      return None

请求成功会返回资源栈的IdName信息,请求发出以后,可到ROS 控制台查看资源栈详情。

获取资源栈输出信息

资源栈创建好以后,我们再次调用ROS API获取资源栈的输出信息。方法如下:

def get_stack_outputs(stack, ak_id, ak_secret, region_id):
    print('Start to get stack output...')
    if stack is None:
        return None
    req = DescribeStackDetailRequest.DescribeStackDetailRequest()
    req.set_headers({'x-acs-region-id': region_id})
    req.set_StackName(stack['Name'])
    req.set_StackId(stack['Id'])
    client = AcsClient(ak_id, ak_secret, region_id)
    attempt = attempt_times
    wait = wait_time
    while attempt >= 0 and wait >= 0:
        response = client.get_response(req)
        if 200 == response[0]:
            resources = json.loads(response[-1])
            if (resources is None) or (not resources.has_key('Outputs')):
                    time.sleep(wait)
                    attempt = attempt - 1
                    wait = wait - interval
                    continue
            outputs = resources['Outputs']
            print('Getting stack outputs finished. outputs: ', outputs)
            return outputs
        else:
            print('Unexpected errors: status=%d, error=%s' % (response[0], response[-1]))
            return None
    print('Getting stack outputs timeout.')
    return None

调用时需要传入创建好的资源栈IdName信息。由于创建资源栈需要的时间不确定,所以以上方法定义了超时重试的机制。每次重试以后的等待时间要比上次等待时间少interval秒,在尝试attempt次若仍未获取到资源栈信息视为资源创建失败(一般不会出现这种情况)。

资源栈的输出格式如下:

[{u'OutputKey': u'EcsPrivateIps', u'Description': u'No description given', u'OutputValue': [u'192.168.x.x', u'192.168.x.x']},
{u'OutputKey': u'ZKPrivateIps', u'Description': u'No description given', u'OutputValue': [u'192.168.x.x', u'192.168.x.x', u'192.168.x.x']},
{u'OutputKey': u'LoadBalanceIp', u'Description': u'No description given', u'OutputValue': u'112.74.x.x'}]

我们将以上输出定义为Outputs

编辑Inventory文件

根据上面获取的资源栈输出信息Outputs,获取Dubbox控制台服务器组的私有IP。方法如下:

def get_ecs_ips(outputs):
    for i in range(len(outputs)):
        if outputs[i]['OutputKey'] == ecs_ip_output_key:
            return outputs[i]['OutputValue']
    return None

根据上面获取的资源栈输出信息Outputs,获取ZooKeeper集群服务器组的私有IP。方法如下:

def get_zk_ips(outputs):
    for i in range(len(outputs)):
        if outputs[i]['OutputKey'] == zk_ip_output_key:
            return outputs[i]['OutputValue']
    return None

因为在创建资源栈的时候,已经在配置文件中配置好了ALIYUN::ECS::InstanceGroup的登录密码,所以可以直接使用配置文件中的密码信息,用户名默认为root。编辑/etc/ansible/hosts文件,即通常我们所说的Ansible Inventory文件。编辑该文件的方法如下:

# define func to create inventory
def edit_hosts(host_parameters, zk_parameters):
    print 'Start edit hosts'
    host_str = ' ansible_ssh_port=%s ansible_ssh_user=%s ansible_ssh_pass=%s\n'
    with open(hosts_file, 'wb') as file:
        file.write( '[%s]\n' % host_dubbo_admin )
        for index in range(len(host_parameters)):
            file.write( ('%s'+host_str) % (host_parameters[index][0], host_parameters[index][1], host_parameters[index][2], host_parameters[index][3]) )
        file.write( '[%s]\n' % host_zookeeper )
        for index in range(len(zk_parameters)):
            file.write( ('%s'+host_str) % (zk_parameters[index][0], zk_parameters[index][1], zk_parameters[index][2], zk_parameters[index][3]) )
    print 'Edit hosts end'

执行该方法以后,生成的Inventory文件,即/etc/Ansible/hosts文件,内容如下:

[dubbo_admin]
10.169.. ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=*
10.44.. ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=*
[zookeeper]
10.45.. ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=*
10.170.. ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=*
10.170.. ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=*

Inventory文件中定义了两个远程主机组,dubbo_adminzookeeper,并指定了不同主机的IP、登录协议(默认是 SSH )、登录端口、登录用户名和密码。Ansible在执行PlayBook的时候通过以上信息连接远程主机。

构建PlayBook

本文所描述的高可用Dubbox服务,注册中心采用的是ZooKeeper集群,因此需要构建两个PlayBook。一个用来部署Dubbox控制台集群,一个用来部署ZooKeeper集群。

部署Dubbox控制台集群的PlayBook为vpc_dubbox_admin_playbook,结构如下:

[root@iZ94jwkjg0sZ roles]# ls -l vpc_dubbox_admin_playbook
总用量 12
drwxr-xr-x 2 501 games 4096 8月  17 17:52 files
drwxr-xr-x 2 501 games 4096 8月  17 17:52 tasks
drwxr-xr-x 2 501 games 4096 8月  17 14:20 templates

关于vpc_dubbox_admin_playbook结构的说明如下:

  • files

    • 存放install_Jdk.shinstall_Jetty.shdeploy_Admin.sh三个文件,这三个文件分别用来安装JDK、Jetty以及部署Dubbox控制台服务。
  • tasks
    • 存放要执行的yml文件 install_dubbo_admin.yml,文件内容如下:

      ---
      - name: add config
        template:
          dest: /root/config
          src: config.j2
          mode: 0600
      
      - 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,文件内容如下:

      #第一列 变量名 第二列 变量值 第三列 配置项 不同列之间用tab或者空格分开
      #jetty安装路径,当目录已经存在的时候加上f参数会强制覆盖,否则会退出安装
      JETTY_HOME {{jetty_home}} {{enforce}}
      #设置admin控制台root用户的密码
      DUBBO_ADMIN_ROOT_PASSWD {{dubbo_root}}
      #设置admin控制台guest用户的密码
      DUBBO_ADMIN_GUEST_PASSWD {{dubbo_guest}}
      #注册中心连接地址字符串
      REGISTRY_ADDRESS {{registry_address}}
      #ZooKeeper集群的IP地址
      ZK_IPS_STR {{zk_ips_str}}
      
    • 配置文件config.j2中的参数值从vpc_dubbox_zk.yml文件中获取,通过Ansible执行PlayBook的过程中会在每一台远程主机的/root目录下生成config文件,提供给install_Jdk.shinstall_Jetty.shdeploy_Admin.sh这三个脚本使用。关于vpc_dubbox_zk.yml文件,后面会提到。

部署ZooKeeper集群的PlayBook为vpc_dubbox_zookeeper_playbook,结构如下:

[root@iZ94jwkjg0sZ roles]# ls -l vpc_dubbox_admin_playbook
总用量 12
drwxr-xr-x 2 501 games 4096 8月  17 17:52 files
drwxr-xr-x 2 501 games 4096 8月  17 17:52 tasks
drwxr-xr-x 2 501 games 4096 8月  17 14:20 templates

关于vpc_dubbox_zookeeper_playbook结构的说明如下:

  • files

    • 存放install_Jdk.shinstall_ZK.sh两个文件,这两个文件分别用来安装JDK、部署ZooKeeper集群。
  • tasks
    • 存放要执行的yml文件 install_zk.yml,文件内容如下:

      ---
      - name: add config
        template:
          dest: /root/config
          src: config.j2
          mode: 0600
      
      - name: run install jdk
        script: install_Jdk.sh
      
      - name: run install zookeeper
        script: install_ZK.sh
      
  • templates
    • 存放配置文件模板config.j2,文件内容如下:

      #第一列 变量名 第二列 变量值 第三列 配置项 不同列之间用tab或者空格分开
      #jetty安装路径,当目录已经存在的时候加上f参数会强制覆盖,否则会退出安装
      JETTY_HOME {{jetty_home}} {{enforce}}
      #设置admin控制台root用户的密码
      DUBBO_ADMIN_ROOT_PASSWD {{dubbo_root}}
      #设置admin控制台guest用户的密码
      DUBBO_ADMIN_GUEST_PASSWD {{dubbo_guest}}
      #注册中心连接地址字符串
      REGISTRY_ADDRESS {{registry_address}}
      #ZooKeeper集群的IP地址
      ZK_IPS_STR {{zk_ips_str}}
      
    • 配置文件config.j2中的参数值从vpc_dubbox_zk.yml文件中获取,通过Ansible执行PlayBook的过程中会在每一台远程主机的/root目录下生成config文件,提供给install_Jdk.shinstall_ZK.sh使用。关于vpc_dubbox_zk.yml文件,后面会说明。

这两个PlayBook构建好了以后,可上传到阿里云OSS。在执行脚本的时候需要用到这两个PlayBook,可以通过wget命令从阿里云OSS上下载,然后直接使用。

执行PlayBook

执行PlayBook,需要以下三个步骤:

  • 生成Ansible可执行文件
  • 下载PlayBook
  • 执行PlayBook

生成Ansible可执行文件

我们需要通过Ansible执行vpc_dubbox_zk.yml文件来运行我们构建好的两个PlayBook。
vpc_dubbox_zk.yml文件的生成,需要分两步进行:

  • 定义文件模板
  • 生成文件

定义vpc_dubbox_zk.yml文件模板的Python文件为deploy_vpc_dubbox.py,文件内容如下:

from string import Template
create_hosts_with_parameters = '''
- name: deploy dubbox service
  hosts: $zookeeper
  vars:
    - jetty_home: $jetty_home
    - enforce: $jetty_home_enforce
    - dubbo_root: $dubbo_root_password
    - dubbo_guest: $dubbo_guest_password
    - registry_address: $registry_address
    - zk_ips_str: $zk_ips_str
  roles:
    - $zookeeper_pb_name

- name: deploy dubbox service
  hosts: $dubbo_admin
  vars:
    - jetty_home: $jetty_home
    - enforce: $jetty_home_enforce
    - dubbo_root: $dubbo_root_password
    - dubbo_guest: $dubbo_guest_password
    - registry_address: $registry_address
    - zk_ips_str: $zk_ips_str
  roles:
    - $dubbo_admin_pb_name
'''
#define func to define redis playbook template
def create_playbook(**kwargs):
    template = Template(create_hosts_with_parameters)
    return template.substitute(kwargs)

生成vpc_dubbox_zk.yml文件,方法如下:

# define func to create playbook init config
def create_pb_init(registry_address, zk_ips_str):
    print('Start to edit playbook init config...')
    with open(ansible_dir + pb_file_name, 'wb') as file_pb:
        playbook = generate_playbook_template.create_playbook(dubbo_admin=host_dubbo_admin, zookeeper=host_zookeeper, jetty_home=jetty_home,
            jetty_home_enforce=jetty_home_enforce, dubbo_root_password=dubbo_root_password, dubbo_guest_password=dubbo_guest_password,
            registry_address=registry_address, zk_ips_str=zk_ips_str, dubbo_admin_pb_name=dubbo_admin_pb_name, zookeeper_pb_name=zookeeper_pb_name)
        file_pb.write(playbook)
    print('Editting pb_init is finished.')

生成的vpc_dubbox_zk.yml文件的内容如下:

- name: deploy dubbox service
  hosts: zookeeper
  vars:
    - jetty_home: /opt/jetty
    - enforce: f
    - dubbo_root: *
    - dubbo_guest: *
    - registry_address: 192.168..:2181?backup=192.168..:2181,192.168..:2181
    - zk_ips_str: 192.168..,192.168..,192.168..
  roles:
    - vpc_dubbox_zookeeper_playbook

- name: deploy dubbox service
  hosts: dubbo_admin
  vars:
    - jetty_home: /opt/jetty
    - enforce: f
    - dubbo_root: root
    - dubbo_guest: guest
    - registry_address: 192.168..:2181?backup=192.168..:2181,192.168..:2181
    - zk_ips_str: 192.168..,192.168..,192.168..
  roles:
    - vpc_dubbox_admin_playbook

vpc_dubbox_zk.yml文件中定义了一些参数,下面详细介绍文件中参数的作用:

  • hosts

    • 远程主机组名称,和Inventory文件中的远程主机组相对应。此文件说明要连接的主机组有两个。
  • vars
    • 配置文件config中的参数,提供给install_Jdk.shinstall_Jetty.shdeploy_Admin.shinstall_ZK.sh使用。
  • roles
    • 指定要执行的PlayBook名称。此文件说明要执行的PlayBook有两个。

最终生成的vpc_dubbox_zk.yml文件在目录/etc/ansible/下。

下载PlayBook

前面的章节构建PlayBook中提出,构建好PlayBook后会传到阿里云OSS上,然后通过wget命令下载到/etc/ansible/roles目录下。下载PlayBook的方法如下:

def download_playbook():
    for url in playbook_url:
        file_name = url.split('/')[-1]
        command_wget = 'wget -P ' + playbook_dir + ' ' + url
        subprocess.call(command_wget, shell = True)
        command_tar = 'tar zxf ' + playbook_dir + file_name + ' -C ' + playbook_dir
        subprocess.call(command_tar, shell = True)
        command_rm = 'rm -rf ' + playbook_dir + file_name
        subprocess.call(command_rm, shell = True)

执行playbook

Ansible是通过ssh命令连接远程主机,并执行playbook的。首次执行playbook前,由于当前Ansible主机并没有记录远端主机的RSA Key,会弹出RSA Key的确认对话框,对话框内容如下:

OSX10111-0c4de9cb8aea:dubbox wujin.lhr$ ssh root@112.74.205.137
    The authenticity of host '112.74.205.137 (112.74.205.137)' can't be established.
    ECDSA key fingerprint is SHA256:bbDuVh6dQYDQo/X+Qzh52VGAxBFpGSqVG0jVNCB/9cE.
    Are you sure you want to continue connecting (yes/no)?

因为整个过程不用人为的参与,所以可通过Python脚本自动实现上述确认的过程:

# define func to confirm ssh login before execute ansible
def confirm_ssh_login(all_ips):
    print('Start to confirm ssh login to all nodes...')
    if len(all_ips) == 0:
        print('Host_ips is empty')
        return
    for ip in all_ips:
        child = pexpect.spawn('ssh root@' + ip)
        ret_1 = child.expect(['Are you sure you want ', 'Password', 'root@*', pexpect.EOF])
        if 0 == ret_1:
            child.sendline('yes')
            ret_2 = child.expect(['Password', 'root@', pexpect.EOF])
            if 0 == ret_2 or 1 == ret_2:
                print('Confirm ' + ip + ' ok!')
                child.sendintr()
                continue
            else:
                print('Confirm ' + ip + ' failed!')
        elif 1 == ret_1 or 2 == ret_1:
            print('Confirm ' + ip + ' ok!')
            child.sendintr()
        else:
            print('Confirm ' + ip + ' failed!')
    print('Confirm ssh login finished!')

由于用到了pexpect这个模块,在执行脚本前,需要使用pip安装pexpect模块:

pip install pexpect

VPC网络环境下未给ECS分配公网IP,导致每台ECS无法下载安装包,但是在安装JDK、Jetty以及部署Dubbox Admin和Zookeeper集群的时候需要这些安装包。因为Ansible主机配有公网IP,所以可以将安装包先下载到Ansible主机,又因为Ansible主机和每台ECS在同一个VSwitch下面,可以通过scp命令将安装包从Ansible主机传到每台ECS上。具体操作过程如下:

  1. 首先将JDK、Jetty、Dubbox Admin以及ZooKeeper安装包上传至阿里云OSS,获取安装包的下载地址。
  2. 在Python文件中填入安装包的下载地址,运行Python脚本,下载安装包至Ansible主机。方法如下:
    def wget_files():
        if not os.path.exists(wget_file_path):
            os.makedirs(wget_file_path)
        subprocess.call('wget -P ' + wget_file_path + ' ' + jdk_path, shell = True)
        subprocess.call('wget -P ' + wget_file_path + ' ' + jetty_path, shell = True)
        subprocess.call('wget -P ' + wget_file_path + ' ' + dubbo_admin_path, shell = True)
        subprocess.call('wget -P ' + wget_file_path + ' ' + zookeeper_path, shell = True)
    
  3. 通过scp命令将安装包拷贝到每台ECS。方法如下:
    def scp_files_from_ansible_host_to_ecs_zk(host_ips, zk_ips):
        scp_password_info = 'root@%s\'s password:'
        scp_command_ecs = 'scp ' + wget_file_path + 'dubbo-admin-2.8.4.war ' + wget_file_path + 'jdk-8u101-linux-x64.rpm ' + wget_file_path + 'jetty-distribution-8.1.19.v20160209.tar.gz root@%s:/root'
        scp_command_zk = 'scp ' + wget_file_path + 'jdk-8u101-linux-x64.rpm ' + wget_file_path + 'zookeeper-3.4.6.tar.gz root@%s:/root'
        if host_ips is None or len(host_ips) == 0:
            print 'Host ips is None,exit!'
            return None
        if zk_ips is None or len(zk_ips) == 0:
            print 'ZK ips is None,exit!'
            return None
        for ip in host_ips:
            scp = pexpect.spawn(scp_command_ecs % ip)
            i = scp.expect([scp_password_info % ip, pexpect.EOF])
            if i == 0:
                scp.sendline(ecs_password)
                scp.expect(pexpect.EOF, timeout=None)
            else:
                print 'Scp files to' + ip + 'failed!'
        for ip in zk_ips:
            scp = pexpect.spawn(scp_command_zk % ip)
            i = scp.expect([scp_password_info % ip, pexpect.EOF])
            if i == 0:
                scp.sendline(ecs_password)
                scp.expect(pexpect.EOF, timeout=None)
            else:
                print 'Scp files to' + ip + 'failed!'
    
  4. 通过Ansible,执行PlayBook。方法如下:
    subprocess.call('ansible-playbook ' + pb_file_dir + '/' + pb_file_name, shell=True)
    

运行Ansible以后会进行Dubbox服务的部署过程。

部署Dubbox服务

Dubbox服务的部署,需要以下两个步骤:

  • 搭建ZooKeeper集群
  • 搭建Dubbox控制台集群

搭建ZooKeeper集群

ZooKeeper集群主要用来作为Dubbox服务的注册中心。

搭建ZooKeeper集群,需要以下两个步骤:

  • 安装JDK
  • 搭建ZooKeeper集群
安装JDK

因为ZooKeeper的运行需要Java环境,所以需要先安装JDK。安装JDK的脚本为install_Jdk.sh,文件内容如下:

#!/bin/bash
#日志时间格式
DATE="date +'%Y-%m-%d %H:%M:%S'"
#检查java环境是否存在
if which java 2>/dev/null; then
        echo $(eval $DATE) " java already exits" >> ~/install_dubbox.log
else
        #wget jdk安装包
        #wget http://dubbo.oss-cn-shenzhen.aliyuncs.com/jdk-8u101-linux-x64.rpm
        #echo $(eval $DATE) " wget jdk success" >> ~/install_dubbox.log
        rpm -ivh jdk-8u101-linux-x64.rpm
        rm -rf jdk-8u101-linux-x64.rpm
fi
#检查java环境是否安装成功
if which java 2>/dev/null; then
        echo $(eval $DATE) " install jdk8 success" >> ~/install_dubbox.log
else
        echo $(eval $DATE) " install jdk8 failed" >> ~/install_dubbox.log

安装JDK过程中,首先需要检查当前ECS是否存在Java环境,存在就跳过安装过程,反之则安装。
声明:JDK安装包请从Oracle官网下载,并下载本文指定的JDK版本(jdk-8u101-linux-x64.rpm)。从本文链接中下载JDK带来的任何法律问题,和本文作者无关。

搭建ZooKeeper集群

搭建ZooKeeper集群的脚本为install_ZK.sh,内容如下:

#!/bin/sh
#日志时间格式
DATE="date +'%Y-%m-%d %H:%M:%S'"
#download zk
#wget 'http://dubbo.oss-cn-shenzhen.aliyuncs.com/zookeeper-3.4.6.tar.gz'
#解压zk到/opt目录
tar -zxvf zookeeper-3.4.6.tar.gz -C /opt
#设置软链接
ln -s /opt/zookeeper-3.4.6 /opt/zookeeper
#复制zoo.cfg文件
cp /opt/zookeeper/conf/zoo_sample.cfg /opt/zookeeper/conf/zoo.cfg
#删除压缩包
rm -rf zookeeper-3.4.6.tar.gz
#读取配置文件内容,给变量赋初值
while read line
do
    #过滤掉注释行
    if [ ! "`echo $line|grep '#'`" ]; then
        varname=`echo $line|awk '{print $1}'`
        varvalue=`echo $line|awk '{print $2}'`
        varconfig=`echo $line|awk '{print $3}'`
        eval $varname=$varvalue
        eval $varname"_CONFIG"=$varconfig
    fi
done < ~/config
mkdir -p '/opt/zookeeper/data'
#修改配置文件
sed -i -e 's/^dataDir=.*/dataDir=\/opt\/zookeeper\/data/' /opt/zookeeper/conf/zoo.cfg
ZK_IPS_STR=${ZK_IPS_STR//,/ }
init_id=1
#获取本机ip
SELF_IP=`ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"`
for ip in $ZK_IPS_STR
do
    echo "server.$init_id=$ip:2888:3888" >> /opt/zookeeper/conf/zoo.cfg
    #创建myid文件,标识本机id号
    if [[ $SELF_IP == $ip ]]; then
        echo $init_id >  "/opt/zookeeper/data/myid"
    fi
    init_id=$((init_id+1))
done
#启动zk
nohup /opt/zookeeper/bin/zkServer.sh start &
sleep 10
#centos 7 关闭防火墙
systemctl stop firewalld.service
#查看当前是否存在zookeeper进程
ZK_ID=`ps -ef |grep zookeeper |grep -v grep |awk '{print $2}'`
if [ ! "$ZK_ID" ]; then
    echo $(eval $DATE) " start zookeeper failed" >> ~/install_dubbox.error.log
else
    echo $(eval $DATE) " start zookeeper success" >> ~/install_dubbox.log
fi
#删除配置文件
rm -rf ~/config

这个脚本的主要功能是安装ZooKeeper,并通过修改ZooKeeper配置文件conf/zoo.cfg来配置ZooKeeper集群。修改后的配置文件内容如下:

tickTime=2000
dataDir=/opt/zookeeper/data
clientPort=2181
initLimit=5
syncLimit=2
server.1=slave-01:2888:3888
server.2=slave-02:2888:3888
server.3=slave-03:2888:3888

上述文件,配置了三台机器的ZooKeeper集群。在dataDir目录下,创建一个myid文件,里面内容为一个数字,用来标识当前主机号。
更多关于ZooKeeper集群配置的知识,可参考Running Replicated ZooKeeper

搭建Dubbox控制台集群

由于Dubbox控制台需要运行在Jetty容器上,Jetty容器的运行又需要有Java环境,因此部署Dubbox控制台之前,需要先安装JDK和Jetty。

搭建Dubbox控制台集群,需要以下三个步骤:

  • 安装JDK
  • 安装Jetty
  • 部署Dubbox控制台
安装JDK

安装JDK的文件为install_Jdk.sh,和上述过程安装JDK相同,此处不再重复。

安装Jetty

安装Jetty的文件为install_Jetty.sh,内容如下:

#!/bin/bash
#jetty默认安装目录
JETTY_HOME_DEFAULT="/opt/jetty"
#日志时间格式
DATE="date +'%Y-%m-%d %H:%M:%S'"
#安装jetty
#wget http://dubbo.oss-cn-shenzhen.aliyuncs.com/jetty-distribution-8.1.19.v20160209.tar.gz
#echo $(eval $DATE) " wget jetty success" >> ~/install_dubbox.log
#解压
tar zxf jetty-distribution-8.1.19.v20160209.tar.gz
echo $(eval $DATE) " tar zxf jetty success" >> ~/install_dubbox.log
#删除压缩包
rm -f jetty-distribution-8.1.19.v20160209.tar.gz
echo $(eval $DATE) " rm jetty.tgz success" >> ~/install_dubbox.log
#读取配置文件内容,给变量赋初值
while read line
do
        #过滤掉注释行
        if [ ! "`echo $line|grep '#'`" ]; then
                varname=`echo $line|awk '{print $1}'`
                varvalue=`echo $line|awk '{print $2}'`
                varconfig=`echo $line|awk '{print $3}'`
                eval $varname=$varvalue
                eval $varname"_CONFIG"=$varconfig
        fi
done < ~/config
#JETTY_HOME未配置,选择默认配置JETTY_HOME_DEFAULT
if [ ! -n "$JETTY_HOME" ]; then
        JETTY_HOME=$JETTY_HOME_DEFAULT
        rm -rf $JETTY_HOME
        mkdir -p $JETTY_HOME
        echo $(eval $DATE) " JETTY_HOME采用默认设置 $JETTY_HOME" >> ~/install_dubbox.log
#如果目录不存在,创建目录
elif [ ! -d "$JETTY_HOME" ]; then
        mkdir -p $JETTY_HOME
        echo $(eval $DATE) " 创建JETTY_HOME新目录 $JETTY_HOME" >> ~/install_dubbox.log
#如果目录已经存在,并且配置了强制执行,则覆盖目录
elif [ "$JETTY_HOME_CONFIG" = "f" ]; then
        rm -rf $JETTY_HOME
        mkdir -p $JETTY_HOME
        echo $(eval $DATE) " 强制覆盖已存在的JETTY_HOME $JETTY_HOME" >> ~/install_dubbox.log
#如果目录已经存在,并且没有配置强制执行,退出程序
else
        echo $(eval $DATE) " $JETTY_HOME 已经存在,未选择强制覆盖,请重新设置JETTY_HOME或在配置文件中配
置强制执行选项:f" >> ~/install_dubbox.log
        #退出程序
        exit
        echo $(eval $DATE) " 程序退出" >> ~/install_dubbox.log
fi
#移动jetty到JETTY_HOME
mv jetty-distribution-8.1.19.v20160209/* $JETTY_HOME
rm -rf jetty-distribution-8.1.19.v20160209
echo $(eval $DATE) " mv jetty  success" >> ~/install_dubbox.log
#将jetty配置文件/etc/webdefault.xml中的属性dirAllowed值设置为false
cd $JETTY_HOME/etc
#确认行数
NUMBER=`grep -n "<param-name>dirAllowed</param-name>" webdefault.xml | cut  -d  ":"  -f  1`
sed -i -e "$[++NUMBER]s/.*/<param-value>false<\/param-value>/" webdefault.xml
echo $(eval $DATE) " set dirAllowed to false success" >> ~/install_dubbox.log
#查看jetty服务是否开启,即系统已经安装了jetty并已经开启
JETTY_PROCESS_ID=`ps -fe|grep jetty |grep -v grep |awk '{print $2}'`
#未开启jetty服务
if [ ! "$JETTY_PROCESS_ID" ]; then
        $JETTY_HOME/bin/jetty.sh start
        echo $(eval $DATE) " start jetty" >> ~/install_dubbox.log
else
        kill -9 $JETTY_PROCESS_ID
        echo $(eval $DATE) " stop jetty" >> ~/install_dubbox.log
        $JETTY_HOME/bin/jetty.sh start
        echo $(eval $DATE) " start jetty" >> ~/install_dubbox.log
fi
#查看jetty服务是否开启
JETTY_PROCESS_ID=`ps -fe|grep jetty |grep -v grep |awk '{print $2}'`
if [ ! "$JETTY_PROCESS_ID" ]; then
        echo $(eval $DATE) " install jetty failed" >> ~/install_dubbox.error.log
else
     echo $(eval $DATE) " install jetty success" >> ~/install_dubbox.log
     kill -9 $JETTY_PROCESS_ID
     echo $(eval $DATE) " stop jetty" >> ~/install_dubbox.log
fi

安装Jetty过程,主要包括:读取配置文件,设置Jetty安装目录,修改Jetty的配置文件etc/webdefault.xml。Jetty安装目录的选择包括以下三种情形:

  • 未指定Jetty安装目录,则选择默认目录进行安装
  • 指定了Jetty安装目录但是目录不存在,则创建目录并安装Jetty
  • 指定了Jetty安装目录并且目录已经存在
    • 如果配置了强制执行选项,则覆盖目录并安装Jetty
    • 如果没有配置强制执行选项,程序强制退出
部署Dubbox控制台

部署Dubbox服务的文件为deploy_Admin.sh,内容如下:

#!/bin/sh

#默认jetty安装目录
JETTY_HOME_DEFAULT="/opt/jetty"
#默认root用户密码
DUBBO_ADMIN_ROOT_PASSWD_DEFAULT=root
#默认guest用户密码
DUBBO_ADMIN_GUEST_PASSWD_DEFAULT=guest
#日志时间格式
DATE="date +'%m-%d-%Y %H:%M:%S'"

#读取配置文件内容,给变量赋初值
while read line
do
    #过滤掉注释行
    if [ ! "`echo $line|grep '#'`" ]; then
        varname=`echo $line|awk '{print $1}'`
        varvalue=`echo $line|awk '{print $2}'`
        varconfig=`echo $line|awk '{print $3}'`
        eval $varname=$varvalue
        eval $varname"_CONFIG"=$varconfig
    fi
done < ~/config
#JETTY_HOME未配置,选择默认配置JETTY_HOME_DEFAULT
if [ ! -n "$JETTY_HOME" ]; then
        JETTY_HOME=$JETTY_HOME_DEFAULT
#如果目录已经存在,并且没有要求强制覆盖
elif [ -d "$JETTY_HOME" ]; then
        if [ "$JETTY_HOME_CONFIG" != "f" ]; then
            echo $(eval $DATE) " $JETTY_HOME 已经存在,未选择强制覆盖,请重新设置JETTY_HOME或在配置文件中配置强制执行选项:f" >> ~/install_dubbox.log
            #退出程序
            echo $(eval $DATE) " 程序退出" >> ~/install_dubbox.log
            exit
    fi
fi

#检测admin root用户密码是否设置
if [ ! $DUBBO_ADMIN_ROOT_PASSWD ]; then
        echo $(eval $DATE) " 未设置admin root用户的密码,采用默认密码 $DUBBO_ADMIN_ROOT_PASSWD_DEFAULT" >> ~/install_dubbox.log
        DUBBO_ADMIN_ROOT_PASSWD=$DUBBO_ADMIN_ROOT_PASSWD_DEFAULT
fi

#检测admin guest用户密码是否设置
if [ ! $DUBBO_ADMIN_GUEST_PASSWD ]; then
        echo $(eval $DATE) " 未设置admin guest用户的密码,采用默认密码 $DUBBO_ADMIN_GUEST_PASSWD_DEFAULT" >> ~/install_dubbox.log
        DUBBO_ADMIN_GUEST_PASSWD=$DUBBO_ADMIN_GUEST_PASSWD_DEFAULT
fi

#从oss上下载dubbo-admin的war包
#wget http://dubbo.oss-cn-shenzhen.aliyuncs.com/dubbo-admin-2.8.4.war
#echo $(eval $DATE) " wget dubbo-admin success" >> ~/install_dubbox.log

#将war包部署到jetty上
mv dubbo-admin-2.8.4.war $JETTY_HOME/webapps/dubbo-admin.war
echo $(eval $DATE) " mv dubbo-admin.war to webapps" >> ~/install_dubbox.log

#修改配置文件
mkdir $JETTY_HOME/webapps/dubbo-admin
cd $JETTY_HOME/webapps/dubbo-admin
jar xf ../dubbo-admin.war
cd $JETTY_HOME/webapps/dubbo-admin/WEB-INF

#配置admin注册监听文件
sed -i -e "s/^dubbo.registry.address.*/dubbo.registry.address=zookeeper:\/\/$REGISTRY_ADDRESS/" dubbo.properties
echo $(eval $DATE) " set registry to redis" >> ~/install_dubbox.log

#设置root用户密码
sed -i -e "s/^dubbo.admin.root.password.*/dubbo.admin.root.password=$DUBBO_ADMIN_ROOT_PASSWD/" dubbo.properties
echo $(eval $DATE) " set user root passwd" >> ~/install_dubbox.log
#设置guest用户密码
sed -i -e "s/^dubbo.admin.guest.password.*/dubbo.admin.guest.password=$DUBBO_ADMIN_GUEST_PASSWD/" dubbo.properties
echo $(eval $DATE) " set user guest passwd" >> ~/install_dubbox.log

cd $JETTY_HOME/webapps/dubbo-admin
jar cf dubbo-admin.war *
mv dubbo-admin.war $JETTY_HOME/webapps/
rm -rf $JETTY_HOME/webapps/dubbo-admin

#启动jetty
nohup $JETTY_HOME/bin/jetty.sh start &
echo $(eval $DATE) " start jetty" >> ~/install_dubbox.log

#关闭centos7的防火墙
systemctl stop firewalld.service
sleep 30

CODE=`curl -I -m 10 -o /dev/null -s -w %{http_code}  -u root:$DUBBO_ADMIN_ROOT_PASSWD http://localhost:8080/dubbo-admin/`
echo $(eval $DATE) " return http status code: $CODE" >> ~/install_dubbox.log
if [ $CODE = 200 ]; then
    echo $(eval $DATE) " admin控制台启动成功" >> ~/install_dubbox.log
else
    echo $(eval $DATE) " admin控制台启动失败" >> ~/install_dubbox.error.log
fi
rm -rf ~/config

部署Dubbox服务控制台的过程,主要包括:先将Dubbox服务部署到Jetty上,然后修改dubbo.properties文件的方式来设置Dubbox服务注册中心为ZooKeeper集群的方式,并设置Dubbox服务控制台的登录密码。Dubbox服务注册中心的选择,可参考Dubbo用户指南

在部署Dubbox服务的过程中,有几个需要注意的问题:

  1. 当访问Dubbox服务时,需要访问服务器的8080端口,由于防火墙的原因,外部可能无法访问到服务器的Dubbox服务,因此需要修改防火墙的设置。本文所采用的ECS系统为Centos 7,简单起见,我直接关闭了系统的防火墙。关闭防火墙的方法如下:

    systemctl stop firewalld.service
    

这里不建议采用直接关闭防火墙的方式。
2. 通过Ansible控制远程服务器组启动Jetty服务时,Ansible命令执行结束以后,Jetty服务也自动退出,这是我们不想看到的结果。可通过nohup命令以守护进程的方式启动Jetty服务,可以解决Jetty服务自动退出的问题,启动Jetty命令如下:

    nohup $JETTY_HOME/bin/jetty.sh start &

Dubbox服务部署好了以后,可通过以下地址访问Dubbox服务控制台:

http://ip:8080/dubbo-admin

注意:在VPC网络下,ip指的是SLB的公网IP。

Dubbox服务部署好以后,可通过以下操作登录控制台:

输入用户名密码,点击登录:

登录进去以后的Dubbox控制台界面如下:

现在,我们可以使用Dubbox服务了。

总结

本章将从以下两个方面进行总结:

  • Dubbox服务系统结构图
  • 如何快速构建高可用Dubbox服务

Dubbox服务系统结构图

最终,采用ZooKeeper集群作为注册中心,基于资源编排快速部署出来的高可用Dubbox服务的系统结构图,如下图所示:

Dubbox服务的高可用,主要体现在两个方面:

  • 注册中心的高可用

    • 注册中心采用了ZooKeeper集群的方式,ZooKeeper集群中只要有超过半数的服务可用,Dubbox服务的注册中心就可以正常工作。
  • Dubbox服务控制台的高可用
    • 创建两台ECS实例并分别部署Dubbox控制台服务,这两台ECS挂载到一个SLB上,我们可通过SLB来访问Dubbox控制台服务。

注意:生产环境中应该将SLB放在VPC网络环境内,本文中为了测试方便,把SLB放在VPC网络环境外。若需要修改SLB的网络环境,只需修改ROS资源模板

如何快速构建高可用Dubbox服务

前面章节描述的部署过程看起来可能比较繁琐,本文的核心是快速部署,因此你可以根据下面的指导,快速部署属于你的高可用Dubbox服务。四个步骤快速部署高可用Dubbox服务:

  • 准备Ansible主机
  • 下载源码
  • 修改配置文件
  • 运行main函数
准备Ansible主机

这个过程和前面章节的准备Ansible主机相同,这里不再重复。

下载源码

可从本文的附件中下载源码,然后将vpc_python文件拷贝到Ansible主机。

修改配置文件

修改vpc_python/config.py文件,文件内容如下:

#define stack name
stack_name = 'vpc_dubbox_zookeeper'
# define stack creation timeout(minutes)
create_timeout = 60
#vpc parameter
vpc_id = ''
vswitch_id = ''
#zookeeper cluster size
zk_size = 3
#ecsgroup parameters
ecs_password = ''
instance_type =  'ecs.s2.large'
#ros ak id
ak_id = ''
#ros ak secret
ak_secret = ''
#ros region id
region_id = 'cn-shenzhen'
#zone id
zone_id = 'cn-shenzhen-a'
#set jetty path
jetty_home = '/opt/jetty'
#if jetty_home exists, choose f to overlap
jetty_home_enforce = 'f'
#dubbo admin root password
dubbo_root_password = ''
#dubbo admin guest password
dubbo_guest_password = ''

下面详细讲解配置文件中一些参数所代表的意义:

  • vpc_id

    • Ansible主机所在的VPC ID
  • vswitch_id
    • Ansible主机所在的VSwitch ID
  • zk_size
    • ZooKeeper集群的大小,ZooKeeper集群的大小必须为奇数,且必须大于1
  • ecs_password
    • 申请的ECS服务器的登录密码,用户名默认为root
  • ak_id
    • 用户的ak id
  • ak_secret
    • 用户的ak secret
  • region_id
    • 资源栈创建的区域
  • jetty_home
    • jetty默认安装目录
  • jetty_home_enforce
    • 是否强制安装jetty,f代表强制安装,其它代表非强制
  • dubbo_root_password
    • Dubbox控制台root用户的登录密码
  • dubbo_guest_password
    • Dubbox控制台guest用户的登录密码

用户可根据自己的需求更改配置文件。

运行main函数

运行vpc_python/main.py。函数运行完以后,高可用Dubbox服务就部署好了。

时间: 2024-11-02 05:08:10

基于资源编排在专有网络环境下快速部署高可用的Dubbox服务(ZooKeeper版)的相关文章

基于资源编排在经典网络环境下快速部署高可用的Dubbox服务(Redis版)

本文将介绍在经典网络环境下,基于资源编排快速部署高可用Dubbox服务的过程.做这件事情的意义在于:提供给开发者一套高可用的Dubbox服务框架,节约开发人员部署Dubbox服务的时间,并降低了部署Dubbox过程中出错的风险. ROS阿里云资源编排(Resource Orchestration)是一种简单易用的云计算资源管理和自动化运维服务.用户通过模板描述多个云计算资源的依赖关系.配置等,并自动完成所有资源的创建和配置,以达到自动化部署.运维等目的.编排模板同时也是一种标准化的资源和应用交付

基于资源编排和 Ansible 在 VPC 下快速交付应用

阿里云资源编排服务(ROS)为我们快速搭建和整合云计算资源环境提供一个低成本.标准化的方案.基于ROS提供的能力,我们所要做的就是将所需的资源以资源模板的形式进行定义,进而实现对所定义云资源的快速生产.除此之外,ROS 将应用交付和资源释放的过程也进行了简化. 用户基于 ROS 交付应用可以有两种途径:一种是通过 ROS 搭建资源环境,然后登陆云主机 ECS,手动实现对应用的部署和维护操作:另一种是利用文章基于资源编排一键交付应用中提到的 Cloud-Init 机制,实现对应用的一键交付.但是,

基于资源编排和 Ansible 在经典网络下快速交付应用

本文是基于资源编排和 Ansible 在 VPC 下快速交付应用的姊妹篇,即在经典网络下基于资源编排和 Ansible 实现对应用的快速交付. 在经典网络环境和 VPC 环境下交付应用的最大区别在于经典网络环境不需要 VPC.VSwitch等其他相关资源的支持,只需要 ECS 和 公网 IP 资源即可.除此之外,基于资源编排和 Ansible 在经典网络下快速交付应用的流程和步骤与在 VPC 下完全相同.下面本文仍以搭建 Redis 集群为例,展示在经典网络下快速交付应用. 基于 ROS 和 A

基于资源编排一键交付应用之基于WaitCondition的通知机制

本文是基于资源编排一键交付连接RDS的应用的进阶篇.随着各类应用的不断发展,许多应用开发人员对应用部署的便捷性和应用运行的稳定性都提出了很高的要求,从这个意义上来讲,应用的一键交付以及对应用做负载均衡将会是一个不错的解决方案.对开发人员而言,在交付应用时如何才能保证对应用所做的负载均衡是成功的呢?此时,有效控制应用的部署过程并且感知应用的部署结果,将具有重要的意义.本文将为大家提供一个基于资源编排一键构建负载均衡应用并基于 WaitCondition 的通知机制掌控应用部署过程的解决方案.首先引

基于资源编排一键交付应用

资源编排可通过资源编排模板定义您需要创建的阿里云资源的组合,并依据您的配置来完成对资源的配置和一键销毁,快速方便的构建您的应用.本文将引导您如何基于资源编排服务快速构建一个应用.首先引入三个概念:Meta-Data.Cloud-Init 和 User-Data. Meta-DataMeta-Data 主要包括虚拟机自身的一些常用属性,如 hostname.网络配置信息.资源 InstanceId 等,其主要的形式为键值对.可以通过访问下面的地址查询 Meta-Data 信息 curl http:

基于资源编排一键交付连接RDS的应用

本文是基于资源编排一键交付应用的进阶篇.众所周知,许多 Web 应用都会涉及对数据库的访问,但出于对数据的保护,通常我们在构建应用时会将应用本身和其对应的数据库分别部署在不同的机器上,以实现数据与应用相隔离.同时,为了降低应用构建的复杂度,阿里云提供了稳定可靠.可弹性伸缩的在线数据库服务 RDS,实现了对数据库的快速部署,从而使得对应用的部署工作主要集中在应用本身,所以本文将讲解如何基于资源编排实现应用与 RDS 的连接.基于资源编排一键交付连接 RDS 的应用的工作,主要包括以下两个方面: 熟

linux环境下 weblogic部署应用报错问题

问题描述 linux环境下 weblogic部署应用报错问题 没有部署应用之前weblogic能够正常启动,应用部署完之后,启动weblogic报错: starting weblogic with Java version: java version "1.6.0_29" Java(TM) SE Runtime Environment (build 1.6.0_29-b11) Java HotSpot(TM) Client VM (build 20.4-b02, mixed mode)

link环境下程序部署以后提示/boot/grub/i386-pc.normal.mod

问题描述 link环境下程序部署以后提示/boot/grub/i386-pc.normal.mod link环境下程序部署以后提示/boot/grub/i386-pc.normal.mod not fund是什么意思? 解决方案 http://blog.sina.com.cn/s/blog_7deb436e0101nzkq.html

Jexus~Linux环境下的部署

Jexus 即 Jexus Web Server,简称JWS,是Linux平台上的一款ASP.NET WEB服务器,是 Linux.Unix.FreeBSD 等非Windows系统架设 ASP.NET WEB 服务器的核心程序,是企业级ASP.NET跨平台部署的一种可选方案.与其它WEB服务器相比,Jexus不但具有跨平台ASP.NET服务器这样的标志性特征,同时还拥有内核级的安全监控.入侵检测.URL重写.无文件路由等一系列重要功能和专有特性. 安装与部署 cd /tmp sudo rm je