基於資源編排和 Ansible 在 VPC 下快速交付套用

來源:互聯網
上載者:User

摘要: 阿裡雲資源編排服務(ROS)為我們快速搭建和整合雲端運算資源環境提供一個低成本、標準化的方案。基於ROS提供的能力,我們所要做的就是將所需的資源以資源範本的形式進行定義,進而實現對所定義雲資源的快速生產。除此之外,ROS將套用交付和資源釋放的程序也進行了簡化。用戶基於ROS 交付套用可以有兩種

阿裡雲資源編排服務(ROS)為我們快速搭建和整合雲端運算資源環境提供一個低成本、標準化的方案。基於ROS提供的能力,我們所要做的就是將所需的資源以資源範本的形式進行定義,進而實現對所定義雲資源的快速生產。除此之外,ROS將套用交付和資源釋放的程序也進行了簡化。

用戶基於ROS 交付套用可以有兩種途徑:一種是通過ROS 搭建資源環境,然後登陸雲主機ECS,手動實現對套用的部署和維修動作;另一種是利用本文基於資源編排一鍵交付套用中提到的Cloud-Init 機制,實現對套用的一鍵交付。但是,不管利用哪種方式,它們都將面臨同一個問題:隨著ECS 數量的增多和套用部署複雜度的增大,套用部署和維修的成本會相應的增大。那麼如何在降低構建套用動作成本的同時,實現對套用的快速交付呢?這裡就要使用自動化運維管理工具Ansible

可以說,ROS說明我們快速搭建了資源環境,Ansible可說明我們在已搭建好的資源環境中實現了套用的快速交付。

本文將介紹利用ROS和Ansible實現對套用的快速交付。為了更好的理解套用交付的整個實現程序,本文首先對Ansible 及其執行機制進行簡單的介紹,然後講述基於ROS和Ansible快速交付套用的程序,最後以搭建Redis 集群作為樣本,閱聽整個套用交付程序,本文大致流程如下:

  • Ansible 及其執行機制
  • 基於 ROS 和 Ansible 快速交付套用
  • 基於 ROS 和 Ansible 快速搭建 Redis 集群

Ansible 及其執行機制

Ansible 是一個基於 Python paramiko 開發的、分散式的、需用戶端的、羽量級的自動化運維管理工具,它可以實現自動化部署套用、設定、執行 task 等工作。面對多台伺服器的運維工作時,它大大簡化了運維人員的投入量,降低了套用的部署和交付成本。

Ansible 使用YMAL 文法及Jinja2 範本語言,採用paramiko 合約庫,通過SSH 或者ZeroMQ 等方式串連工作主機,進而實現對遠端主機的控制和維修。Ansible一般每兩個月出一個發行版本本。

Ansible的執行機制:管理節點Master 利用存放節點知識Inventory 檔案將Ansible 模組通過SSH 合約(或者Kerberos、LDAP)發送到被管理節點,然後執行Playbooks,執行結束後自動移除,如下圖所示:
ansible_work

  • Master:Ansible 的控制節點核心
  • Inventory:定義 Ansible 管理主機的清單
  • Playbooks:定義 Ansible 執行任務檔案及其設定檔
  • Modules:包括 Ansible 自帶的核心模組及自訂模組
  • Plugins:完成模組功能的匯集

基於ROS 和Ansible 快速交付套用

在瞭解了Ansible 的執行機制後,接下來將介紹利用ROS 快速生產套用執行環境,並結合Ansible 實現對套用的快速交付,大致流程如下:
ros_and_ansible

  • 安裝 ROS SDK 和 Ansible
  • 基於 ROS 建立資源棧,搭建資源環境
  • 追蹤主機資訊,並建立 Inventory 檔案,追蹤 Playbook
  • 執行 Playbook,完成套用的快速交付基於 Ansible 快速部署套用

值得注意的是,本文介紹的快速交付套用是在VPC 環境下進行的,並且過是以python 的形式執行的,所以在開始之前,需要有一台可以存取公網的ECS 作為Master,以執行所有的python 程式。下面詳細介紹基於ROS 和Ansible 快速交付套用的流程。

安裝ROS SDK 和Ansible

本文中介紹的建立資源棧是以python 叫用ROS 開放API 實現的,所以首先需要在Master 上安裝ROS SDK,具體的安裝程序可參考阿裡雲資源編排服務Python SDK使用入門

對套用的部署是通過Ansible 完成的,所以在Master 上要安裝Ansible。為了避免不必要的麻煩,建議安裝Ansible 的最新組建,具體安裝程序可參考Ansible 安裝文件

基於ROS 建立資源棧,搭建資源環境

在安裝完開發環境後,將開始基於ROS 搭建資源環境。首先根據需求,定義所要建立資源的範本,並將範本新增到python 檔案中,然後python 以該範本作為參數叫用ROS API,進而實現對資源的建立,具體的呼叫者式可參考阿裡雲資源編排服務Python SDK使用入門或者本文第三部份的樣本套用。

建立Inventory,追蹤Playbook

根據Ansible 的執行機制,在搭建好資源環境後,首先需要根據資源棧的建立結果,再次叫用ROS API 以追蹤雲主機資源的登入資訊,如:主機IP、主機登入密碼等。然後利用主機資訊生成Inventory 檔案,以作為Ansible 管理主機的清單。在Inventory 檔案中,你可以定義登入雲主機的方式,如下是一個樣本Inventory 檔案:

[webservers]
192.168.xx.xx ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=abc123
192.168.xx.xx ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=abc123

檔案中定義了遠程主機webservers,並指明了該主機群組下有兩台雲主機的登入位址、登入合約(預設是SSH )、登入埠、登入使用者名稱和密碼。

最後,根據所要部署的套用,可在Ansible 社群中查詢並追蹤套用相關的playbook。當然,除了這種追蹤方式,您還可以根據套用部署的程序,依據YMAL 文法和Jinja2 範本語言編寫自己的playbook。

執行Playbook,快速部署套用

Ansible 在執行Playbook 時需要指定執行檔案,執行檔案可根據Inventory 檔案和Playbook 進行編寫。執行檔案中需要指定所要啟動並執行Playbook 名稱和遠端主機或者遠端主機群組名,如下是一個執行檔案example.yml,檔案中顯示了對遠程組webservers執行名稱為example 的Playbook:

---
- hosts: webservers
roles:
- Example

執行檔案編寫成功後,執行以下指令即可完成對Playbook 的執行:

ansible-playbook example.yml

基於ROS 和Ansible 快速搭建Redis 集群

為了更好的說明基於ROS 和Ansible 快速交付套用的程序,本文將以搭建Redis 集群作為閱聽樣本。

目前我已經構建好了我的VPC 環境,我的Master 上已經安裝了ROS SDK 和Ansible,下面我將閱聽基於ROS SDK 和Ansible 快速搭建一主(Master)兩備(Slave) Redis 集群的詳細程序。

為了提高Redis 集群的高可用工時,在搭建Redis 集群時為其部署了高可用工時解決方案Sentinel,以說明Redis 集群實現自動化的主備切換。

構建資源環境

首先定義資源棧範本。由於我已經構建好了我的VPC 環境和控制節點Master,所以範本中只需要定義構建三台雲主機ECS 資源並與已有的VPC 環境相關聯即可。為了方便起見,我在範本中使用資源"Type":"ALIYUN::ECS::InstanceGroup"定義 ECS 資源。定義資源棧的範本可詳見周邊中的python 檔案create_instancegroup_template.py。

範本定義成功後,編輯python 代碼,以範本作為參數,叫用ROS API 即可實現對資源環境的搭建,如下是叫用ROS API 的python 檔案create_stack_instancegroup.py:

# invoke CreateStackRequest to create InstanceGroup stack

from aliyunsdkcore.client import AcsClient
from aliyunsdkros.request.v20150901 import CreateStacksRequest
import create_instancegroup_template
import json

# define stack creation timeout(minutes)
create_timeout = 60

# define func to create stack
def create_stack(stack_name, ak_id, ak_secret, region_id):
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})

template = create_instancegroup_template.generate_template(io_optimized='optimized', network_type='vpc', image_id='centos6u5_64_40G_cloudinit_20160427.raw', security_group_id='sg-94qyqvpvj', instance_password='********', instance_min_amount=3, system_disk_category='cloud_ssd', instance_max_amount=3, vswitch_id='vsw-sm9i9vhin', vpc_id='vpc-a6al8acn4', instance_type='ecs.n1.small')

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]:
parameters = json.loads(response[-1])
print('Create stack succeccfully!!!')
return parameters
else:
print('Unexpected errors: status=%d, error=%s' % (response[0], response[-1]))
return None

叫用成功後,登入ROS 主控台即可看到正在建立的資源棧。

建立Inventory,追蹤Playbook

接下來建立Inventory 檔案。為了省去手動編寫Inventory 檔案的麻煩,本文使用python 程式自動生成。首先在棧資源建立成功後,再次叫用ROS API 追蹤資源ECS 的登入資訊,由於資源棧的建立時間一般需要2~5分鐘(視具體情況而定),所以在程式中需設定一定的等待時間,如下所示:

# define func to get host ip
def get_host_ips(stack, ak_id, ak_secret, region_id):
# get host ip
print('Start to get host ips...')

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
private_ips = resources['Outputs'][0]['OutputValue']
print('Getting host ips finished. ips: ', private_ips)
return private_ips
else:
print('Unexpected errors: status=%d, error=%s' % (response[0], response[-1]))
return None
print('Getting host ips timeout.')
return None

追蹤雲主機IP 後,即可開始生成Inventory 檔案,由於遠端主機的登入密碼在建立資源棧時指定的,所以此處可直接參考,如下所示:

# define func to create inventory
def edit_hosts(remote_ips, remote_ports, remote_users, remote_pass, is_sentinel):
if remote_ips is None or 0>=len(remote_ips):
print('Error! Remote ips is empty!')
return
else:
if remote_ports is None or len(remote_ips)!=len(remote_ports):
print('Error! Remote ports is empty!')

if remote_users is None or len(remote_ips)!=len(remote_users):
print('Error! Remote users is empty!')

if remote_pass is None or len(remote_ips)!=len(remote_pass):
print('Error! Remote pass is empty!')

host_str = ' ansible_ssh_port=%s ansible_ssh_user=%s ansible_ssh_pass=%s\n'
file = open(hosts_dir + '/' + hosts_file, 'wb')
file.write( '[%s]\n' % host_master )
file.write( ('%s'+host_str) % (remote_ips[0], remote_ports[0], remote_users[0], remote_pass[0]) )
if len(remote_ips)>1:
file.write( '\n[%s]\n' % host_slave )
for index in range(1,len(remote_ips)):
file.write( ('%s'+host_str) % (remote_ips[index], remote_ports[index], remote_users[index], remote_pass[index]) )
if is_sentinel:
file.write( '\n[%s]\n' % host_sentinel )
for index2 in range(0,len(remote_ips)):
file.write( ('%s redis_sentinel=True'+host_str) % (remote_ips[index2], remote_ports[index2], remote_users[index2], remote_pass[index2]) )
file.close()
print 'End'

檔案生成後,開始追蹤搭建Redis 集群的playbook,本文使用的是DavidWittman 編寫的playbook:DavidWittman.redis,直接叫用ansible 的命令列工具ansible-galaxy即可將playbook 直接下載到Ansible 的roles 目錄下(當然也可以使用其他下載方式,但下載後要將其放在roles 目錄下)。由於指令ansible-galaxy使用的是https 通訊協定,所以在叫用該指令前應該確認本期主機以安裝openssl,如下所示:

# Install openssl before execute ansible-galaxy
print('Install openssl ...')
subprocess.call('yum install openssl -y', shell=True)

# install playbook
print('Download playbook %s...' % pb_name)
subprocess.call('ansible-galaxy install ' + pb_name + ' -vvv', shell=True)

搭建Redis 集群的playbook DavidWittman.redis 追蹤成功後,由於DavidWittman.redis 編寫完成時預設只部署了Sentinel,沒有實現Redis 集群的主備設定,所以在執行DavidWittman.redis 前,需要對DavidWittman.redis 的/tasks/main.yml 進行修改,使其完成分散式Redis 集群的搭建,如下所示:

# define func to mod playbook
def mod_playbook():
file = open(ansible_dir + '/roles/' + pb_name + '/tasks/main.yml', 'rb+')
lines=file.readlines()
for row in range(0, len(lines)):
if lines[row].find('when: not redis_sentinel')>=0:
lines[row] = '#' + lines[row]
break
file = open(ansible_dir + '/roles/' + pb_name + '/tasks/main.yml', 'wb+')
file.writelines(lines)

執行Playbook,快速部署套用

在執行playbook 前需要編寫playbook 的執行檔案。和Inventory 檔案一樣,執行檔案可根據下載的playbook 利用程式自動生成,如下所示:

# define func to create playbook init config
def create_pb_init(host_ip, has_slaves, is_sentinel):
# config master
file_pb = open(pb_file_dir + '/' + pb_file_name, 'wb')
file_pb.write(redis_playbook_template.create_playbook(template='master', host_master_name=host_master, host_slave_name=host_slave, host_sentinel_name=host_sentinel, playbook_name=pb_name, master_ip=host_ip, master_port='6379', master_name='master01'))
file_pb.close()

# config slaves
if has_slaves:
file_pb = open(pb_file_dir + '/' + pb_file_name, 'ab')
file_pb.write(redis_playbook_template.create_playbook(template='slaves', host_master_name=host_master, host_slave_name=host_slave, host_sentinel_name=host_sentinel, playbook_name=pb_name, master_ip=host_ip, master_port='6379', master_name='master01'))
file_pb.close()

# config sentinel
if is_sentinel:
file_pb = open(pb_file_dir + '/' + pb_file_name, 'ab')
file_pb.write(redis_playbook_template.create_playbook(template='sentinel', host_master_name=host_master, host_slave_name=host_slave, host_sentinel_name=host_sentinel, playbook_name=pb_name, master_ip=host_ip, master_port='6379', master_name='master01'))
file_pb.close()

程式中使用到的生成執行檔案的範本檔案redis_playbook_template.py可詳見周邊。

接下來即可通過執行ansible 的指令ansible-playbook執行 playbook ,從而完成Redis 集群的搭建,如下所示:

# execute playbook
subprocess.call('ansible-playbook ' + pb_file_dir + '/' + pb_file_name, shell=True)

建立Inventory、追蹤Playbook、生成執行檔案以及執行Playbook 的代碼可詳見周邊中的execute_redis_playbook.py 檔案。

python 代碼執行的main.py 如下所示:

import execute_redis_playbook
import time
# invoke ros api params
ak_id=''
ak_secret=''
instance_password=''
region_id='cn-shenzhen'
is_sentinel = True

# define func main
def main():
start_time = time.time()
execute_redis_playbook.execute(ak_id, ak_secret, region_id, instance_password, is_sentinel)
end_time = time.time()
print end_time-start_time
if __name__=='__main__':
main()

在執行main.py 前,需要指定帳戶的AccessKeys 資訊、雲主機密碼以及可用區。

以上便是基於ROS 和Ansible 搭建Redis 集群的全部程序,樣本中Redis 集群中節點數量是三個,當然也可以通過修改雲主機ECS 的數量,實現對單個節點或其他節點的Redis 集群的搭建。本樣本Redis 集群搭建成功後的資源拓撲圖如下所示:
redis

相關產品:

  1. 資源編排ROS
  2. 智能語音互動
  3. 容器服務(Docker)
  4. 雲端服務器ECS
相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.