Руководство по облаку CloudStack
Введение
Цель данного раздела — объяснить, как объединить модули Ansible для использования Ansible в контексте CloudStack. Более подробные примеры использования вы найдете в разделе «Подробности» каждого модуля.
Ansible содержит ряд дополнительных модулей для взаимодействия с облаками на базе CloudStack. Все модули поддерживают режим проверки, разработаны для идемпотентности, созданы и протестированы и поддерживаются сообществом.
Примечание
Некоторые модули потребуют прав администратора домена или администратора root.
Предварительные требования
Предварительные требования для использования модулей CloudStack минимальны. Помимо самого Ansible, все модули требуют библиотеку python cs https://pypi.python.org/pypi/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(без точки) в текущей рабочей директории, той же, где расположены ваши playbooks.
Структура файла 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
connection: local
tasks:
- name: ensure VMs are created and running
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 [exmaple_cloud_one] endpoint = https://cloud-one.example.com/client/api key = api key secret = api secret [exmaple_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
local_action: cs_sshkeypair
name: my-ssh-key
public_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
api_region: exoscale
Или, перебирая список регионов, если вы хотите выполнить задачу в каждом регионе:
- 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 }}"
with_items:
- exoscale
- exmaple_cloud_one
- exmaple_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
local_action:
module: cs_sshkeypair
name: my-ssh-key
public_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
- name: ensure my ssh public key
local_action:
module: 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
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
connection: local
tasks:
- 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') }}"
with_items: "{{ 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
В этом play мы определили 3 задачи и использовали группу cloud-vm в качестве цели для обработки всех виртуальных машин в облаке, но вместо SSH-доступа к этим виртуальным машинам мы используем connection=local для выполнения вызовов API локально с нашего рабочего стола.
В первой задаче мы гарантируем, что создана работающая виртуальная машина с шаблоном Debian. Если виртуальная машина уже создана, но остановлена, она просто запустится. Если вы хотите изменить предложение для существующей виртуальной машины, вам нужно добавить force: yes к задаче, которая остановит виртуальную машину, изменит предложение и запустит виртуальную машину снова.
Во второй задаче мы гарантируем, что порты открыты, если мы присвоили виртуальной машине публичный IP-адрес.
В третьей задаче мы добавляем статический NAT для виртуальных машин с заданным публичным IP-адресом.
Примечание
Публичные IP-адреса должны быть получены заранее, также см. cs_ip_address
Примечание
Для некоторых модулей, например cs_sshkeypair, вы обычно хотите, чтобы это выполнялось только один раз, а не для каждой виртуальной машины. Поэтому вы создадите отдельный play для этого, нацеленный на 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
connection: local
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 }}"
with_items:
- default
- web
- name: add inbound SSH to security group default
cs_securitygroup_rule:
security_group: default
start_port: "{{ item }}"
end_port: "{{ item }}"
with_items:
- 22
- name: add inbound TCP rules to security group web
cs_securitygroup_rule:
security_group: web
start_port: "{{ item }}"
end_port: "{{ item }}"
with_items:
- 80
- 443
- name: install VMs in the cloud
hosts: cloud-vm
connection: local
tasks:
- 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
В первом play мы настраиваем группы безопасности, во втором play виртуальные машины будут созданы и назначены этим группам. Кроме того, вы видите, что мы назначаем публичный IP-адрес, возвращаемый модулями, инвентаризации хоста. Это необходимо, так как мы не знаем заранее IP-адреса, которые мы получим. На следующем шаге вы настроите DNS-серверы с этими IP-адресами для доступа к виртуальным машинам по их имени DNS.
В последней задаче мы ждем, пока SSH станет доступен, чтобы любой последующий play мог получить доступ к виртуальной машине по 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.4/guide_cloudstack.html