Опыт построения Infrastructure-as-Code в VMware. Часть 1: Обозначение проблемы

от автора

Приветствую, дорогой читатель.

Я начинаю цикл статей о том, как мы искали решение для применения подхода Infrastructure-as-Code в нашем виртуальном окружении VMware VSphere.

У нас есть система управления конфигурациями Puppet для Linux, есть (на данный момент) DSC для Windows Server.
Что касается Linux — практически все автоматизированно. Мы заносим конфигурации машин в nodes.yaml, мы заносим роли в Hiera, строим модули (или берем готовые), у нас есть PXE, IP адреса раздаются из DHCP по MAC адресу.
То есть с момента как Linux виртуалка стартует, до момента, когда виртуалка готова к эксплуатации — никаких действий не нужно. Попробуйте угадать, что в этой цепочке делается вручную? Верно, создание самой виртуальной машины в VSphere.

Когда я впервые поднял этот вопрос, мне сказали, что искали решение, пробовали варианты, но ничего не получилось. “К черту!” — подумал я и поспорил на ящик пива, что найду решение, которое будет работать по следующему сценарию: разработчик или инженер делает Pull Request, в котором у нас находится конфигурация виртуальной машины (ядра, память, сеть, шаблон и т.д.) — далее некая магия обращается в VSphere и создает машину, согласно настройкам в файле.

Позволь рассказать немного о нашем окружении, чтобы ты понял с чем мне приходится иметь дело.
У нас в качестве On-Premise виртуализации используется VMware VSphere — парочка датацентров, datastore-кластер и несколько Resource Pool’ов (RP) под каждую команду. Члены команды имеют права на создание виртуальных машин в пределах RP, ребята-инфраструктурщики им в этом не мешают и просто занимаются обслуживанием всей платформы, периодически напоминая разработчикам и инженерам убирать за собой неиспользуемые машины (ресурсы-то не резиновые).
У нас есть Windows виртуалки, Linux виртуалки, масштаб задач огромен — веб серверы, реверс прокси, балансировщики, контроллеры домена, серверы приложений и баз данных и нет им конца и края.

Теперь я поведаю тебе, какие инструменты я пытался применять, и почему они мне не подошли.

Эмпирическим путем…

Ansible vsphere_guest

Как я уже писал в предыдущей статье, я очень люблю Ansible и в вопросах автоматизации я первым делом смотрю, можно ли его для этого использовать.
Согласно документации, есть хороший модуль vsphere_guest который может создавать и удалять виртуалки. То, что нужно. Вот так выглядит мой плейбук createvm.yaml

--- - name: Create a VM in resource pool   hosts: localhost   connection: local   gather_facts: False   vars_prompt:   - name: "user"     prompt: "Enter your username to virtualcenter"     private: no   - name: "password"     prompt: "Enter your password to virtualcenter"     private: yes   - name: "guest"       prompt: "Enter you guest VM name: "     private: no   tasks:   - name: create VM     vsphere_guest:       vcenter_hostname: vcenter.example.com       validate_certs: no       username: '{{ user }}'       password: '{{ password }}'       guest: '{{ guest }}'       state: powered_off       vm_extra_config:         vcpu.hotadd: yes         mem.hotadd: yes         notes: This is a test VM       vm_disk:         disk1:           size_gb: 10           type: thick           datastore: mydatastore       vm_nic:         nic1:           type: vmxnet3           network: mynetwork           network_type: standard       vm_hardware:         memory_mb: 1024         num_cpus: 1         osid: centos64Guest         scsi: paravirtual       resource_pool: "/Resources/MyResourcePool"       esxi:         datacenter: mysite         #hostname: myesxhost01  

Я сознательно комментирую hostname esxi потому, что я создаю виртуалку непосредственно в RP, а не на хосте. DRS сам решит, куда виртуалку положить.
Если я запускаю плейбук, он ругается что необходимый параметр hostname не указан. Если я его раскоментирую, то он поругается на отсутствие прав на создание виртуалки на esx хосте (что очевидно, т.к. права у меня есть только на RP). Я создал соответствующий issue, так что надеюсь, ребята из Ansible это исправят, поскольку инструмент реально хороший.

Terraform

Иная тулза, которая умеет создавать виртуалки в VMware это Terraform, продукт от HashiCorp. Изначально он заточен под взаимодействие с Packer и деплоит в AWS, но наши задачи он тоже решает. Вот собственно файл с конфигурацией:

provider "vsphere" {   user           = “mylogin@example.com"   password       = "${var.vsphere_password}"   vsphere_server = “virtualcenter.example.com"   allow_unverified_ssl = "true" }  resource "vsphere_virtual_machine" "test" {   name   = "${var.machine_name}"   vcpu   = 1   memory = 1024   domain = “test.example.com”   datacenter = "mysite"   resource_pool = "Production Cluster #1/Resources/myresourcepool"      network_interface {       label = "test"       ipv4_address = "192.168.1.2"       ipv4_prefix_length = "24"       ipv4_gateway = "192.168.1.1"   }    disk {    datastore = "${var.datastore}"    size = "10"    name = "${var.datastore}/${var.machine_name}/${var.machine_name}.vmdk"    template = "mytemplate"   } } 

variables.tf

variable "vsphere_password" {} variable "machine_name" {     type = "string"     default = "test" } variable "datastore" {     type = "string"     default = "mysite/mydatastore" } 

terraform plan работает прекрасно.

 $ terraform plan var.vsphere_password   Enter a value:  supersecurepassword  Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage.   The Terraform execution plan has been generated and is shown below. Resources are shown in alphabetical order for quick scanning. Green resources will be created (or destroyed and then created if an existing resource exists), yellow resources are being changed in-place, and red resources will be destroyed. Cyan entries are data sources to be read.  Note: You didn't specify an "-out" parameter to save this plan, so when "apply" is called, Terraform can't guarantee this is what will execute.  + vsphere_virtual_machine.test     datacenter:                             "mysite"     detach_unknown_disks_on_delete:         "false"     disk.#:                                 "1"     disk.1370406802.bootable:               ""     disk.1370406802.controller_type:        "scsi"     disk.1370406802.datastore:              ""     disk.1370406802.iops:                   ""     disk.1370406802.keep_on_remove:         ""     disk.1370406802.key:                    "<computed>"     disk.1370406802.name:                   ""     disk.1370406802.size:                   ""     disk.1370406802.template:               "mytemplate"     disk.1370406802.type:                   "eager_zeroed"     disk.1370406802.uuid:                   "<computed>"     disk.1370406802.vmdk:                   ""     domain:                                 “test.example.com”     enable_disk_uuid:                       "false"     linked_clone:                           "false"     memory:                                 "1024"     memory_reservation:                     "0"     name:                                   "test"     network_interface.#:                    "1"     network_interface.0.ip_address:         "<computed>"     network_interface.0.ipv4_address:       “192.168.1.2"     network_interface.0.ipv4_gateway:       "192.168.1.1"     network_interface.0.ipv4_prefix_length: "24"     network_interface.0.ipv6_address:       "<computed>"     network_interface.0.ipv6_gateway:       "<computed>"     network_interface.0.ipv6_prefix_length: "<computed>"     network_interface.0.label:              "test"     network_interface.0.mac_address:        "<computed>"     network_interface.0.subnet_mask:        "<computed>"     resource_pool:                          "Production Cluster #1/Resources/myresourcepool"     skip_customization:                     "false"     time_zone:                              "Etc/UTC"     uuid:                                   "<computed>"     vcpu:                                   "1"   Plan: 1 to add, 0 to change, 0 to destroy. 

Что так же здорово, можно задать IP адрес, доменное имя — то есть задать полноценную кастомизацию машинки из шаблона.
Пробуем запустить…

Error applying plan:  1 error(s) occurred:  * vsphere_virtual_machine.test: Datastore 'mysite/mydatastore not found.  Terraform does not automatically rollback in the face of errors. Instead, your Terraform state file has been partially updated with any resources that successfully completed. Please address the error above and apply again to incrementally change your infrastructure. 

Хм, не найден datastore. Как я уже говорил, у нас кластер, так что я попробую сделать по-грязному указав одну из нод кластера.

 Error applying plan:  1 error(s) occurred:  * vsphere_virtual_machine.test: Datastore 'mysite/mydatastore/mydatastore-vol01' not found.  Terraform does not automatically rollback in the face of errors. Instead, your Terraform state file has been partially updated with any resources that successfully completed. Please address the error above and apply again to incrementally change your infrastructure.  

Что ж… снова неудача.
Позже выяснилось, что Terraform не умеет работать с datastore-кластерами. Соответственный issue был создан на GitHub моим коллегой, но успехов на этот поприще тоже, увы, нет.

PowerCLI

Претерпев неудачу в поисках рабочих инструментов от третьих лиц, я решил обратиться к вендорскому решению.
Вендор предлагает два решения — PowerCLI (надстройка над Powershell) и vmware-cli (командный интерфейс для *nix).
Заставить работать vmware-cli на CentOS 7 и OS X не удалось (один страдалец даже написал блог об этом), посему я решил сразу начать пользоваться инструментом, который работает.
Внимательный читатель может поинтересоваться, почему я потратил столько времени на Ansible и Terraform, в то время как PowerCLI уже давно используется. Причины просты — я не знаю Powershell на должном уровне, чтобы с наскоку начать пользоваться им, плюс это вынуждает меня использовать windows машину, которая будет заниматься чистым provision’ом. Впрочем, иных вариантов у меня и нет.
Беглое изучение документации дало мне достаточно навыков, чтобы написать простенький скрипт.

Param(     [string]$Name,     [string]$ResourcePool,     [string]$Location,     [int]$NumCPU,     [int]$MemoryGB,     [int]$DiskGB) $ErrorActionPreference = "Stop" Try {  $credential = Get-Credential Add-PSSnapin VMware.VimAutomation.Core [string] $username = $credential.GetNetworkCredential().UserName $username = 'example\' + $username Connect-VIServer -Server virtualcenter.example.com -User $username -Password $credential.GetNetworkCredential().Password -Force   $params = @{     name = $Name     ResourcePool =  $ResourcePool     Location =  $Location      NumCPU = $NumCPU     MemoryGB = $MemoryGB     DiskGB = $DiskGB  }  new-vm @params   }  Catch [VMware.VimAutomation.ViCore.Types.V1.ErrorHandling.DuplicateName] {"VM exists"} 

Этот скрипт рабочий и делает все необходимое.
Запуск скрипта выглядит следующим образом:

 .\createvm.ps1 -Name mytestvm -ResourcePool myresourcepool -Location myteam -NumCPI 1 - MemoryGB 1 -DisckGB 10 

Скрипт попросит меня предоставить логин и пароль, переиграет переменные и создаст машинку с помощью cmdlet’а new-vm.
Читатель может поинтересоваться, почему присутствует вот эта строка:

[string] $username = $credential.GetNetworkCredential().UserName $username = 'example\' + $username 

Пусть меня поправят опытные powershell ребята, если я ошибаюсь.
Get-Credential создает объект состоящий из логина, пароля и домена (если он есть). Пароль находится в состоянии SecureString. К сожалению, PowerCLI не умеет работать ни с объектом Get-Credential, ни с SecureString, потому приходится идти на подобные ухищрения, чтобы передать ему логин и пароль простой строковой переменной.

Выводы

Дорогой читатель, если у тебя однажды встанет задача автоматизировать создание виртуальных машин в VMware, то учти следующее:

  • используешь ли ты Resource Pool’ы
  • используешь ли ты Datastore кластеры

Если у тебя single node ESX, то я рекомендую пользоваться Ansible, у него низкий порог вхождения, и он довольно легкий и шустрый.

Если же у тебя такая же сложная инфраструктура, как и у нас, то лучше не изобретай велосипед, а осваивай PowerCLI.

В следующей части я расскажу, как мы сделали наш скрипт умнее, и научили его делать проверки на кастомизацию, количество ядер и других ресурсов и naming convention.
ссылка на оригинал статьи https://habrahabr.ru/post/317188/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *