Как мы уже писали, сервис Virtual Private Cloud компании Selectel построен на базе платформы OpenStack, об этом подробнее можно прочитать в нашей предыдущей статье.

Многие наши клиенты привыкли использовать в своих проектах систему управления конфигурациями Ansible, которая позволяет автоматизировать рутинные задачи и облегчить жизнь системного администратора. Также к преимуществам Ansible относится множество готовых модулей, в том числе и для автоматизации работы с компонентами OpenStack-платформы (список готовых модулей).

Работа с виртуальным приватным облаком начинается с создания проекта и резервирования для него ресурсов. Эти операции можно выполнить через панель управления или с помощью нашего API.

Часто при работе с VPC-сервисом может возникнуть необходимость создать несколько одинаковых виртуальных машин, добавить, выделить определенное количество ресурсов, создать новых пользователей и так далее.

Чтобы привести начальную конфигурацию проекта и работу с OpenStack API к общему знаменателю, мы разработали пакет ansible-selvpc-modules, который включает в себя несколько ansible-модулей, предназначенных специально для нашего сервиса. Он будет полезен в работе для любого рода специалистов, которые взаимодействуют с нашим API.

Модули покрывают весь набор функций, который предоставляет наш сервис. Теперь нет необходимости вручную, либо через сторонние утилиты устанавливать ресурсы для проекта: все это можно сделать сразу в одном плейбуке с помощью ansible-selvpc-modules.

Пакет ansible-selvpc-modules включает в себя:

  • selvpc_projects — для управления VPC проектами;
  • selvpc_quotas — для управления ресурсами проекта;
  • selvpc_limits — для получения информации о доступных ресурсах;
  • selvpc_users — для работы с пользователями;
  • selvpc_floatingips — для работы с плавающими ip адресами;
  • selvpc_subnets — для работы с подсетями;
  • selvpc_roles — для работы с ролями в проекте;
  • selvpc_tokens — для создания ключей;
  • selvpc_licenses — для работы с лицензиями.

Ниже я опишу процесс установки пакета, а также приведу пример использования, в котором мы по шагам пройдём путь от создания проекта до запуска виртуальных машин.

Установка


Создадим изолированное виртуальное окружение, активируем и установим ansible-selvpc-modules:

$ virtualenv --no-site-packages env
$ source env/bin/activate
$ pip install ansible-selvpc-modules

Также нам понадобятся дополнительные пакеты для работы: shade как зависимость для os_* ansible-модулей и jmespath для удобного парсинга json-а (подробнее). Ставим из PyPi:

$ pip install shade jmespath

Для работы с Resell API нужны ключи. Зарегистрированные пользователи Selectel могут получить их здесь.

Теперь добавим переменные окружения SEL_URL и SEL_TOKEN:

$ export SEL_URL=https://api.selectel.ru/vpc/resell/
// На момент написания статьи актуальной версией API является 2
$ export SEL_TOKEN=<ваш API-ключ полученный выше в панели>

Так как в примере я буду использовать OpenStack модули для Ansible, дополнительно мне понадобятся следующие переменные:

$ export OS_PROJECT_DOMAIN_NAME=<ваш логин на my.selectel.ru>
$ export OS_USER_DOMAIN_NAME=<аналогично предыдущему>

Для облегчения жизни и хождений на хосты через Ansible выставим переменную окружения ANSIBLE_HOST_KEY_CHECKING в значение False:

$ export ANSIBLE_HOST_KEY_CHECKING=False

Все необходимые пакеты установлены, переменные добавлены, приступим к написанию плейбука.

Пример


  1. Создадим файл example_vars.yaml, где определим переменные image, username, password и project_name, а также два списка с именами наших дисков и виртуальных машин. (image — образ OS, под управлением которой будет работать наши виртуальные машины, flavor — конфигурация машины, в нашем случае это 512 RAM и 1 VCPU, подробнее):

    ---
    username: TestUser
    password: 123456
    project_name: TestProject
    image: Ubuntu 16.04 LTS 32-bit
    volumes:
      - display_name: volume1
      - display_name: volume2
      - display_name: volume3
    servers:
      - name: vm1
      - name: vm2
      - name: vm3
    

  2. Создадим файл example.yaml, в котором мы будем описывать наши таски. Добавим необходимые параметры hosts и vars_files.

    Переменная hosts определяет машину/машины, с которым мы будем осуществлять выполнение тасков, а vars_files указывает, откуда подгружать необходимые переменные (тут это файл example_vars.yaml):

    ---
    - hosts: localhost
      vars_files:
        - example_vars.yaml
    

  3. Приступим к написанию тасков. Первым делом добавим создание проекта с помощью selvpc_projects и выделение квот для проекта, используя selvpc_quotas-модуль. Для 3 машин нам будет достаточно 3 процессорных ядер, 1536 RAM и 15 GB SSD-диска:

    ...
    tasks:
       - name: Create project
         selvpc_projects:
             project_name: "{{ project_name }}"
         register: project_out
     
       - name: Set quotas on created project
         selvpc_quotas:
             project_id: "{{ project_out.project.id }}"
             quotas:
                 compute_cores:
                 - region: ru-1
                   zone: ru-1a
                   value: 3
                 compute_ram:
                 - region: ru-1
                   zone: ru-1a
                   value: 1536
                 volume_gigabytes_fast:
                 - region: ru-1
                   zone: ru-1a
                   value: 15
         register: quotas_out
    

  4. Создадим и добавим пользователя в проект:

    tasks:
       ...
         - name: Create user
           selvpc_users:
               username: "{{ username }}"
               password: "{{ password }}"
           register: user_out
      
         - name: Add created user to project
           selvpc_roles:
               project_id: "{{ project_out.project.id }}"
               user_id: "{{ user_out.user.id }}"
    

  5. Создадим сеть:

    tasks:
        ...
         - name: Create public net
           selvpc_subnets:
                project_id: "{{ project_out.project.id }}"
                subnets:
                  - region: ru-1
                    type: ipv4
                    quantity: 1
                    prefix_length: 29
           register: public_net
      
         - name: Get info about network
           selvpc_subnets:
                subnet_id: "{{ public_net|json_query(subnets[0].id') }}"
           register: network_out
    

  6. После создания сети для создания виртуальных машин нам потребуются диски, которые можно создать с помощью готового Ansible модуля os_volume:

    tasks:
       ...
         - name: Create volumes
           os_volume:
              state: present
              auth:
                auth_url: https://api.selvpc.ru/identity/v3
                username: "{{ username }}"
                password: "{{ password }}"
                project_name: "{{ project_name }}"
              display_name: "{{ item.display_name }}"
              image: "{{ image }}"
              size: 5
             region_name: ru-1
           with_items: "{{ volumes }}"
           register: volume
    

  7. Для доступа к нашим машинам нам будут нужны SSH-ключи. Мы создадим один ключ для всех машин. В этом нам поможет os_keypair:

    tasks:
       ...
         - name: Create key
           os_keypair:
              state: present
              auth:
                auth_url: https://api.selvpc.ru/identity/v3
                username: "{{ username }}"
                password: "{{ password }}"
                project_name: "{{ project_name }}"
              name: ansible_key
             region_name: ru-1
              public_key_file: "{{ '~' | expanduser }}/.ssh/id_rsa.pub"
           register: key
    

  8. С помощью os_nova_flavor создадим конфигурацию(flavor) для наших машин, в нашем случае это 512 RAM и 1 VCPU и назовем ее “selectel_test_flavor”(можно дать любое другое):

    tasks:
       ...
         - name: Create flavor
           os_nova_flavor:
              state: present
              auth:
                auth_url: https://api.selvpc.ru/identity/v3
                username: "{{ username }}"
                password: "{{ password }}"
                project_name: "{{ project_name }}"
              name: selectel_test_flavor
              ram: 512
              vcpus: 1
              disk: 0
              region_name: ru-1
              is_public: False
           register: flavor
    

  9. Опишем таск для их создания и дополнительно таск для добавления их в in-memory inventory для последующей работы с уже созданными хостами, в конце небольшую паузу для того, чтобы виртуальные машины успели включиться перед использованием:

    tasks:
       ...
         - name: Create servers
           os_server:
              state: present
              auth:
                auth_url: https://api.selvpc.ru/identity/v3
                username: "{{ username }}"
                password: "{{ password }}"
                project_name: "{{ project_name }}"
              name: "{{ item.1.name }}"
              flavor: "{{ flavor }}"
              boot_volume: "{{ item.0 }}"
              nics: "net-id={{ network_out.subnet.network_id }}"
              key_name: ansible_key
             region_name: ru-1
           with_together:
              - "{{ volume|json_query('results[*].id') }}"
              - "{{ servers }}"
           register: created_servers
      
      
         - name: Add hosts to inventory
           add_host:
              name: "{{ item }}"
              ansible_host: "{{ item }}"
              ansible_ssh_user: root
              groups: just_created
           with_items: "{{ created_servers|json_query('results[*].openstack.accessIPv4') }}"
      
    - pause:
         seconds: 60
    

  10. В конце добавим таск для проверки наших хостов на доступность:

    tasks:
       ...
    - hosts: just_created
      tasks:
        - name: Ping all instances
          ping:
          register: results
     debug: msg={{ results }}
    

    Я также добавил debug и ignore_errors в данном таске для наглядности, это не является обязательным (debug позволит нам выводить более подробный результат выполнения тасков, а ignore_errors не прекратит выполнение плейбука, в случае возникновения каких-либо ошибок).

    Дополнительно в конце плейбука я добавил удаление конфигурации (flavor), пользователя и проекта, чтобы почистить все, что было создано ранее:

    - hosts: localhost
      gather_facts: False
      vars_files:
        - example_vars.yaml
      tasks:
        - name: Delete flavor
          os_nova_flavor:
              state: absent
              auth:
                auth_url: https://api.selvpc.ru/identity/v3
                username: "{{ username }}"
                password: "{{ password }}"
                project_name: "{{ project_name }}"
              name: "{{ flavor.flavor.name }}"
              region_name: ru-1
          register: out
      
         - name: Delete user
           selvpc_users:
               user_id: "{{ user_out.user.id }}"
               state: absent
           register: out
      
         - name: Delete project
           selvpc_projects:
               project_id: "{{ project_out.project.id }}"
               state: absent
           register: out
    

    Полный файл плейбука можно найти здесь.

  11. Запускаем наш плейбук:

    $ ansible-playbook example.yaml
    

    Во время паузы, которую мы добавили ранее в конце пункта 9, можно сходить в панель управления проекта и посмотреть на созданные серверы:



    Результаты выполнения плейбука в консоли:

    TASK [Ping all instances] 
    *************************************************************************
    ok: [95.213.234.211]
    ok: [95.213.234.212]
    ok: [95.213.234.210]
      
    TASK [debug] 
    *************************************************************************
    ok: [95.213.234.210] => {
        "msg": {
            "changed": false, 
            "ping": "pong"
        }
    }
    ok: [95.213.234.211] => {
        "msg": {
            "changed": false, 
            "ping": "pong"
        }
    }
    ok: [95.213.234.212] => {
        "msg": {
            "changed": false, 
            "ping": "pong"
        }
    }
      
    PLAY [localhost] 
    *************************************************************************
    TASK [Delete flavor]
    *************************************************************************
    changed: [localhost]
      
    TASK [Delete user] 
    *************************************************************************
    changed: [localhost]
      
    TASK [Delete project] 
    *************************************************************************
    changed: [localhost]
      
    PLAY RECAP 
    *************************************************************************
    95.213.234.210          : ok=3    changed=0    unreachable=0    failed=0   
    95.213.234.211          : ok=3    changed=0    unreachable=0    failed=0   
    95.213.234.212          : ok=3    changed=0    unreachable=0    failed=0   
    localhost               : ok=25   changed=13   unreachable=0    failed=0 
    

    В выводе мы видим, что все таски выполнились успешно и наши хосты доступны. Также мы видим, что созданный пользователь и проект, а с ним и виртуальные машины были успешно удалены.

Ansible-модули покрывают весь набор функций, которые предоставляет наш сервис, и полезны в работе специалистов, взаимодействующих с нашим API.

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

> Документация и исходники
Поделиться с друзьями
-->

Комментарии (6)


  1. hamnsk
    04.07.2017 11:08
    +1

    красавцы! хороший пример остальным хостинг провайдерам!


  1. ayurtaykin
    04.07.2017 15:22
    +1

    Подскажите вы доступ к openstack api предоставляете?
    У вас инет роскомнадзором обрезается или можно у вас сервачек с ВПНом завести?


    1. fortyseven
      05.07.2017 09:49

      Да, конечно, в БЗ даже есть статья про работу с консольными клиентами https://kb.selectel.ru/22060427.html


  1. silverjoe
    06.07.2017 10:35

    Для vscale.io тоже подойдет?


    1. rutskiy
      06.07.2017 11:23

      Для Vscale есть отдельные модули. Подробнее в этой статье.


      1. silverjoe
        06.07.2017 11:57

        Спасибо!