Руководство по облаку CloudStack
Введение
Цель этого раздела — объяснить, как объединить модули Ansible для использования Ansible в контексте CloudStack. Более подробные примеры использования вы найдете в разделе описания каждого модуля.
Ansible содержит ряд дополнительных модулей для взаимодействия с облаками на основе CloudStack. Все модули поддерживают режим проверки, разработаны для идемпотентности, созданы и протестированы, а также поддерживаются сообществом.
Примечание
Некоторые модули потребуют привилегий администратора домена или root-администратора.
Предварительные требования
Предварительные требования для использования модулей CloudStack минимальны. Помимо самого Ansible, все модули требуют библиотеки Python cs https://pypi.org/project/cs/
Этот модуль Python должен быть установлен на хосте выполнения, обычно на вашей рабочей станции.
$ pip install cs
Или, как альтернатива, начиная с Debian 9 и Ubuntu 16.04:
$ sudo apt install python-cs
Примечание
cs также включает командную строку для ад-хок взаимодействия с API CloudStack, например $ cs listVirtualMachines state=Running.
Ограничения и известные проблемы
Поддержка VPC была улучшена с Ansible 2.3, но все еще не полностью реализована. Сообщество работает над интеграцией VPC.
Файл учетных данных
Вы можете передавать учетные данные и конечную точку вашего облака в качестве аргументов модуля, однако в большинстве случаев намного проще хранить ваши учетные данные в файле cloudstack.ini.
Библиотека Python cs ищет файл учетных данных в следующем порядке (последний имеет приоритет):
- Файл
.cloudstack.ini(обратите внимание на точку) в домашнем каталоге. - Переменная среды
CLOUDSTACK_CONFIG, указывающая на файл .ini. - Файл
cloudstack.ini(без точки) в текущей рабочей директории, той же директории, что и ваши playbook'ы.
Структура файла ini должна быть следующей:
$ cat $HOME/.cloudstack.ini [cloudstack] endpoint = https://cloud.example.com/client/api key = api key secret = api secret timeout = 30
Примечание
Раздел [cloudstack] — это раздел по умолчанию. Переменная среды CLOUDSTACK_REGION может использоваться для определения раздела по умолчанию.
Новое в версии 2.4.
Переменные среды поддерживают CLOUDSTACK_* так, как написано в документации библиотеки cs, например, CLOUDSTACK_TIMEOUT, CLOUDSTACK_METHOD, и т.д. Это было реализовано в Ansible. Даже возможно иметь неполную конфигурацию в cloudstack.ini:
$ cat $HOME/.cloudstack.ini [cloudstack] endpoint = https://cloud.example.com/client/api timeout = 30
и восполнить недостающие данные, установив переменные среды или параметры задач:
---
- name: provision our VMs
hosts: cloud-vm
tasks:
- name: ensure VMs are created and running
delegate_to: localhost
cs_instance:
api_key: your api key
api_secret: your api secret
...
Регионы
Если вы используете более одного региона CloudStack, вы можете определить столько разделов, сколько хотите, и назвать их как вам удобно, например:
$ cat $HOME/.cloudstack.ini [exoscale] endpoint = https://api.exoscale.ch/compute key = api key secret = api secret [example_cloud_one] endpoint = https://cloud-one.example.com/client/api key = api key secret = api secret [example_cloud_two] endpoint = https://cloud-two.example.com/client/api key = api key secret = api secret
Подсказка
Разделы также могут использоваться для входа в один и тот же регион с использованием разных учетных записей.
Передав аргумент api_region с модулями CloudStack, будет выбран нужный регион.
- name: ensure my ssh public key exists on Exoscale
cs_sshkeypair:
name: my-ssh-key
public_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
api_region: exoscale
delegate_to: localhost
Или, перебирая список регионов, если вы хотите выполнить задачу в каждом из них:
- name: ensure my ssh public key exists in all CloudStack regions
local_action: cs_sshkeypair
name: my-ssh-key
public_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
api_region: "{{ item }}"
loop:
- exoscale
- example_cloud_one
- example_cloud_two
Переменные окружения
Новое в версии 2.3.
Начиная с Ansible 2.3, можно использовать переменные среды для домена (CLOUDSTACK_DOMAIN), учетной записи (CLOUDSTACK_ACCOUNT), проекта (CLOUDSTACK_PROJECT), VPC (CLOUDSTACK_VPC) и зоны (CLOUDSTACK_ZONE). Это упрощает задачи, так как не нужно повторять аргументы для каждой задачи.
Ниже приведен пример того, как это можно использовать в сочетании с функцией блоков Ansible:
- hosts: cloud-vm
tasks:
- block:
- name: ensure my ssh public key
cs_sshkeypair:
name: my-ssh-key
public_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
- name: ensure my ssh public key
cs_instance:
display_name: "{{ inventory_hostname_short }}"
template: Linux Debian 7 64-bit 20GB Disk
service_offering: "{{ cs_offering }}"
ssh_key: my-ssh-key
state: running
delegate_to: localhost
environment:
CLOUDSTACK_DOMAIN: root/customers
CLOUDSTACK_PROJECT: web-app
CLOUDSTACK_ZONE: sf-1
Примечание
Вы по-прежнему можете перезаписать переменные среды, используя аргументы модуля, например, zone: sf-2
Примечание
В отличие от CLOUDSTACK_REGION, эти дополнительные переменные среды игнорируются в командной строке cs.
Примеры использования
Следующее должно дать вам несколько идей о том, как использовать модули для развертывания виртуальных машин в облаке. Как всегда, существует не только один способ сделать это. Но, как всегда: простота на начальном этапе — хороший старт.
Пример использования: Развертывание в облаке CloudStack с расширенной сетью
Наше облако CloudStack имеет расширенную настройку сети. Мы хотели бы развернуть веб-серверы, которые получают статический NAT и открытые порты 80 и 443 для брандмауэра. Кроме того, мы развертываем серверы базы данных, к которым не предоставляется доступ. Для доступа к виртуальным машинам по SSH мы используем SSH-шлюз.
Вот как выглядит наш инвентарь:
[cloud-vm:children] webserver db-server jumphost [webserver] web-01.example.com public_ip=198.51.100.20 web-02.example.com public_ip=198.51.100.21 [db-server] db-01.example.com db-02.example.com [jumphost] jump.example.com public_ip=198.51.100.22
Как вы видите, общедоступные IP-адреса для наших веб-серверов и шлюза присвоены в качестве переменной public_ip непосредственно в инвентаре.
Для настройки шлюза, веб-серверов и серверов базы данных мы используем group_vars. Директория group_vars содержит 4 файла для конфигурации групп: cloud-vm, jumphost, webserver и db-server. cloud-vm предназначен для определения параметров нашей облачной инфраструктуры.
# file: group_vars/cloud-vm --- cs_offering: Small cs_firewall: []
Наши серверы базы данных должны получить больше ЦП и оперативной памяти, поэтому мы определили использовать предложение Large для них.
# file: group_vars/db-server --- cs_offering: Large
Веб-серверы должны получить предложение Small, так как мы будем масштабировать их горизонтально, что также является нашим предложением по умолчанию. Мы также гарантируем, что известные порты веб-серверов открыты для мира.
# file: group_vars/webserver
---
cs_firewall:
- { port: 80 }
- { port: 443 }
Кроме того, мы развертываем шлюз, который имеет открыт только порт 22 для доступа к виртуальным машинам из нашей офисной IPv4-сети.
# file: group_vars/jumphost
---
cs_firewall:
- { port: 22, cidr: "17.17.17.0/24" }
Теперь к интересному. Мы создаем playbook для создания нашей инфраструктуры, который мы называем infra.yml:
# file: infra.yaml
---
- name: provision our VMs
hosts: cloud-vm
tasks:
- name: run all enclosed tasks from localhost
delegate_to: localhost
block:
- name: ensure VMs are created and running
cs_instance:
name: "{{ inventory_hostname_short }}"
template: Linux Debian 7 64-bit 20GB Disk
service_offering: "{{ cs_offering }}"
state: running
- name: ensure firewall ports opened
cs_firewall:
ip_address: "{{ public_ip }}"
port: "{{ item.port }}"
cidr: "{{ item.cidr | default('0.0.0.0/0') }}"
loop: "{{ cs_firewall }}"
when: public_ip is defined
- name: ensure static NATs
cs_staticnat: vm="{{ inventory_hostname_short }}" ip_address="{{ public_ip }}"
when: public_ip is defined
В этом playbook'е мы определили 3 задачи и используем группу cloud-vm в качестве цели для обработки всех виртуальных машин в облаке, но вместо SSH к этим виртуальным машинам мы используем delegate_to: localhost для выполнения вызовов API локально со своей рабочей станции.
В первой задаче мы убеждаемся, что создана запущенная виртуальная машина с шаблоном Debian. Если виртуальная машина уже создана, но остановлена, она просто запустится. Если вы хотите изменить предложение на существующей виртуальной машине, вы должны добавить force: yes в задачу, которая остановит виртуальную машину, изменит предложение и запустит её снова.
Во второй задаче мы убеждаемся, что порты открыты, если виртуальной машине присвоен общедоступный IP-адрес.
В третьей задаче мы добавляем статический NAT для виртуальных машин, имеющих назначенный общедоступный IP-адрес.
Примечание
Общедоступные IP-адреса должны быть получены заранее, см. также cs_ip_address
Примечание
Для некоторых модулей, например cs_sshkeypair, вы обычно хотите, чтобы это выполнялось только один раз, а не для каждой виртуальной машины. Поэтому вы создадите отдельный playbook для него, нацеленный на localhost. Вы найдете пример в следующих примерах использования.
Пример использования: Развертывание в облаке CloudStack с базовой сетью
Настройка базовой сети CloudStack немного отличается: каждой виртуальной машине непосредственно назначается общедоступный IP-адрес, и для ограничения доступа используются группы безопасности.
Вот как выглядит наш инвентарь:
[cloud-vm:children] webserver [webserver] web-01.example.com web-02.example.com
Настройки по умолчанию для ваших виртуальных машин выглядят так:
# file: group_vars/cloud-vm --- cs_offering: Small cs_securitygroups: [ 'default']
Наш веб-сервер также будет в группе безопасности web:
# file: group_vars/webserver --- cs_securitygroups: [ 'default', 'web' ]
Playbook выглядит следующим образом:
# file: infra.yaml
---
- name: cloud base setup
hosts: localhost
tasks:
- name: upload ssh public key
cs_sshkeypair:
name: defaultkey
public_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
- name: ensure security groups exist
cs_securitygroup:
name: "{{ item }}"
loop:
- default
- web
- name: add inbound SSH to security group default
cs_securitygroup_rule:
security_group: default
start_port: "{{ item }}"
end_port: "{{ item }}"
loop:
- 22
- name: add inbound TCP rules to security group web
cs_securitygroup_rule:
security_group: web
start_port: "{{ item }}"
end_port: "{{ item }}"
loop:
- 80
- 443
- name: install VMs in the cloud
hosts: cloud-vm
tasks:
- delegate_to: localhost
block:
- name: create and run VMs on CloudStack
cs_instance:
name: "{{ inventory_hostname_short }}"
template: Linux Debian 7 64-bit 20GB Disk
service_offering: "{{ cs_offering }}"
security_groups: "{{ cs_securitygroups }}"
ssh_key: defaultkey
state: Running
register: vm
- name: show VM IP
debug: msg="VM {{ inventory_hostname }} {{ vm.default_ip }}"
- name: assign IP to the inventory
set_fact: ansible_ssh_host={{ vm.default_ip }}
- name: waiting for SSH to come up
wait_for: port=22 host={{ vm.default_ip }} delay=5
В первом playbook'е мы настраиваем группы безопасности, во втором playbook'е виртуальные машины будут назначены этим группам. Кроме того, вы видите, что мы назначаем общедоступный IP-адрес, возвращаемый модулями, в инвентарь хостов. Это необходимо, так как мы не знаем заранее полученные IP-адреса. На следующем шаге вы настроите DNS-серверы с этими IP-адресами для доступа к виртуальным машинам по их имени DNS.
В последней задаче мы ждем, пока SSH станет доступным, чтобы любой последующий playbook мог получить доступ к виртуальной машине по SSH без ошибок.
© 2012–2018 Michael DeHaan
© 2018–2019 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.9/scenario_guides/guide_cloudstack.html