用ansible自动供应vmware虚拟机

用ansible自动供应vmware虚拟机

1.1 简述

一直以来,打开邮箱被ticket糊一脸的事情时有发生。我一直在想,能不能以一种简单的方案(不花老板的钱)来供应(provisioning)虚拟机呢? 我不喜欢openstack,因为太重,太复杂,除了自服务其它那些编排功能暂时也用不上。我也不喜欢vmware的云套件,因为不想和vmware有太深的羁绊,毕竟不是所有企业都是vmware用户。 所以我一直在寻找一种简单粗暴的办法。

我尝试过用虚机模版,把各种东西都装好打一个大包,以后每次手动改一下配置。用了一阵时间就会发现,模版版本多到自己都晕了。 而且还要祈祷这些模版不用变(可能吗?),因为如果有一个配置要修改,虽然模版改好了, 但是你之前创建的那一堆虚机实例就只能加班慢慢手工操作了。

后来, 我听说了IAC的思路, 我很喜欢这个想法。用管理代码的方式来管理基础架构,一切代码化。利用IAC工具的特性(比如非常重要的幂等性)将虚机模版和配置解耦合。 所有配置都从模版中拿出来,放在代码中。如果有修改只需要修改相应的代码然后重新刷一遍已经生成的实例就行了。

puppet、 ansible 都是不错的工具, 但是我喜欢简单,因此在用了一年多puppet后还是倒向了ansible
现在我们所有的供应,配置,发布都在用ansible

此笔记说的是如何通过ansible 简单的通过虚拟机模版创建虚机实例。

1.2 版本和环境

版本需求

  • python 2.6以上
  • pyvmomi
  • ansible 2.3 以上
  • vsphere 6.0 (据说5.5以上都行)

pyvmomi 是vmware公司维护的, 将vmware api 直接做了python 绑定。

安装pyvmomi模块
pip install pyvmomi

ansible的版本要求较高,主要是我们需要让启动后的虚机实例自动配置上ip,主机名等。这些功能只在2.3以上版本提供。

1.3 VM 模版

模版名:
rhel7.1-mini-vs6-ansible-normal_v2.1

我用的模版就是rhel7.1(centos 7.1) 的mini安装,最小安装什么都没有,然后安装开源vmware tools
open-vm-tools 包信息如下

rpm -qi open-vm-tools
Name : open-vm-tools
Version : 10.0.5
Release : 4.el7_3
Architecture: x86_64
Install Date: Fri 02 Jun 2017 05:33:32 PM CST
Group : Applications/System
Size : 1623590
License : GPLv2
Signature : RSA/SHA256, Thu 09 Feb 2017 02:49:53 PM CST, Key ID 199e2f91fd431d51
Source RPM : open-vm-tools-10.0.5-4.el7_3.src.rpm
Build Date : Sat 04 Feb 2017 12:26:30 AM CST
Build Host : x86-030.build.eng.bos.redhat.com
Relocations : (not relocatable)
Packager : Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>
Vendor : Red Hat, Inc.
URL : http://open-vm-tools.sourceforge.net/
Summary : Open Virtual Machine Tools for virtual machines hosted on VMware
Description :
The open-vm-tools project is an open source implementation of VMware Tools. It
is a suite of open source virtualization utilities and drivers to improve the
functionality, user experience and administration of VMware virtual machines.
This package contains only the core user-space programs and libraries of
open-vm-tools.

无需配置ip主机名等,这些配置都是随后自动改的,
注意要删掉sshd的所有key,按照金模版的标准做虚拟机模版(推荐,不是必须)
具体步骤随后转一片文章说明。

安装好后,就可以在vmware里面制作成模版了。

1.4 playbook

ansible模块说明:
vmware_guest – Manages virtual machines in vcenter
http://docs.ansible.com/ansible/vmware_guest_module.html

代码例子:
vm_provisioning.yml

---
- hosts: localhost ## 在本机执行,因为其实是在调用vcenter的api,因此不是以前登陆再配置的模式
gather_facts: No
connection: local ## 本地连接

tasks:
- name: create the VM
vmware_guest:
hostname: vcenter的ip地址
username: vcenter的用户名 #如果是用的windows域 那就写 xxx@xxxdomain.com
password: vcenter的用户的密码
validate_certs: no #这里注意,跳过证书检验,但是这里我遇到坑,后面说。
datacenter: DataCenter1
esxi_hostname: 某个esxi主机 # esxi_hostname和cluster只能选一个
#cluster: DataCenter-HA-V6.0 # 指定esxi机器或者不指定写集群名
name: ansiblemade_3 # 虚拟机名,在Vcenter中看到的名字
annotation: ansible auto created # 注释
state: poweredon # 开机状态 有:
# present
# absent 删除,小心使用
# poweredon
# poweredoff
# restarted
# suspended
# shutdownguest
# rebootguest

guest_id: rhel7_64Guest # 从以下地址选一个对应的,必须一致。
# https://www.vmware.com/support/developer/converter-sdk/conv55_apireference/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html
disk: # 磁盘列表,这里是一个列表,模版里面做了几块盘都要把配置写上
- size_gb: 16
type: thin
datastore: store1
- size_gb: 8
type: thin
datastore: store1
#hardware: # 虚拟机配置,因为是基于模版创建,这里都pass了
# memory_mb: 512
# num_cpus: 1
# scsi: paravirtual
networks: # 对应的网络信息
- name: VM Network 1
ip: vm——guest的ip
netmask: 255.255.255.0
gateway: x.x.x.x
customization:
hostname: ansiblemade
domain: xxx.com
dns_servers:
- 8.8.8.8
- 8.8.4.4
template: rhel7.1-mini-vs6-ansible-normal_v2.1 # 这个是上一步创建的虚机模版
wait_for_ip_address: yes # 等待创建的机器ip出来后再继续
delegate_to: localhost
register: deploy

执行playbook:

ansible-playbook vm_provisioning.yml

如果顺利就会创建出一个虚拟机,然后就可以用ansible继续做配置。

但是。。。

1.5 坑

还是遇到一个坑。vcenter连接都是https的,使用的是自签发的证书。
然而这里validate_certs: no的配置并未生效

网上找了很多说法,有的说是python的,有的说是ansible的。

从一个叫Jonathan Frappier 的哥那里找到了最直接办法。
:P
直接修改pyvmomi的connect.py
不管要不要验证ssl证书, 都改成不验证。

简单,粗暴, 有效!

如下:

/usr/lib/python2.7/site-packages/pyVim/connect.py

try:
if sslContext is not None and sslContext.verify_mode == ssl.CERT_NONE:
sock = requests.get(url, verify=False)
else:
sock = requests.get(url, verify=False) ## 修改这里,然后删掉connect.pyc就行了

记得备份哦。
修改以后,以上过程就都能跑通了。

记录到此。