NetApp + Ansible
Меня уже несколько раз на различных мероприятиях спрашивали по поводу первоначального конфигурирования массивов NetApp при помощи Ansible, да и статьи по Ansible, судя по статистике посещаемости моего блога, крайне популярны. Поэтому не будем отставать от трендов перехода к infrastructure as a code и поговорим о том, как быстро и просто сконфигурировать с нуля систему на Ontap.
Главная сложность массивов NetApp (но в том же и их прелесть), что вам для конфигурирования доступно практически всё, что вашей душе угодно. Такого количества параметров нет, пожалуй, ни у одного другого вендора СХД. Но в этом же и сложность, особенно учитывая «многослойность» системы и большое количество абстракций.
Настраивать всё это через GUI удовольствия действительно мало, да и порой это крайне неудобно. Можно использовать консоль — она понятна и читабельна, все команды в целом интуитивно понятны, но они длинные, их много и вам всё равно необходимо иметь некий чек-лист того, что вам необходимо настроить на системе, для того чтобы это было во-первых единообразно с остальными вашими системами, а во-вторых чтобы в большом количестве настроек не упустить и не забыть что-либо.
Но если вам всё равно необходимо хотя бы однажды описать всю конфигурацию, то почему бы не сделать это сразу в эталонном конфигурационном файле и далее уже по необходимости туда вносить изменения, необходимые для конкретных систем? Если вы не один занимаетесь поддержкой этих систем, то можно дополнить эту схему при помощи Git репозитория, куда можно складывать конфиги под каждую систему и каждый из администраторов сможет вносить в них изменения, и при этом всем будет понятно когда и по какой причине в конфиг для конкретной системы вносились изменения (при условии, что всё это документируется при коммитах, конечно же).
Да и вспомнить через пару лет как была сконфигурирована система намного быстрее и нагляднее при помощи одного конфигурационного файла, нежели проводить инвентаризацию системы через GUI или консоль.
Но немного о самих модулях NetApp для Ansible. NetApp пожалуй активнее всего развивает их среди остальных стораджовых вендоров. И лишь Pure дышит им в затылок. Поддержка NetApp не ограничивается только системами под управлением ONTAP, также есть модули как для SolidFire, так и для E-series. Есть даже модули для поддержки 7-mode в старых версиях Ansible (были удалены в 2.11).
И так, расскажу, как на мой взгляд лучше построить этот процесс, а вы уже сможете применить его под себя, внеся необходимые правки. Но прежде чем переходить к написанию конфигурационного файла, надо всё-таки подготовить нашу рабочую станцию к работе. Как разворачивается сам Ansible я писал в одной из своих старых статей «Ansible знакомимся с системой на примерах». Дополнительно к этому нам понадобится модуль для работы с системами NetApp. Когда вы работаете с Ansible, крайне важным является использование самой свежей версии модулей. Очень часто проблемы с плейбуками возникают из-за того, что написаны они, например, для версии 2.8, а в версии 2.9 уже многое что изменилось и надо заглянуть в документацию на предмет изменений, которых обычно довольно много, в том числе и новые возможности в модулях. Поэтому ставить будем из Git.
yum install git -y git clone https://github.com/ansible/ansible.git ~/ansible-devel cd ~/ansible-devel git pull cd ~/ansible-devel/lib/ansible sudo yes|cp -aRv module_utils/netapp* /usr/lib/python2.7/site-packages/ansible/module_utils sudo yes|cp -aRv modules/storage/netapp/* /usr/lib/python2.7/site-packages/ansible/modules/storage/netapp/
Условно разделим на 2 этапа наше конфигурирование:
- Настройка параметров массива, которые не привязываются к SVM, а едины для всей системы
- Создание и настройка SVM
Начну с того, что первоначальную настройку я делаю всё-таки на самом массиве — это настройка менеджмента нод и создание кластера, после чего мы уже, собственно, сможем получить удалённый доступ к системе. И ещё одно действие, которое я предпочитаю всё-таки делать руками, привязка дисков в контроллерам и создание агрегатов. Во-первых потому что в модуле NetApp для Ansible нет поддержки работы с дисками, а создание аггрегатов вручную делается мной уже просто на автоматизме при конфигурировании дисков. Хотя никто не запрещает вам использовать для этого и Ansible, ведь это действительно просто. Начинать нужно с того, что мы скажем нашему плейбуку — где именно он будет запускаться и определим некоторые переменные.
--- - hosts: localhost gather_facts: False name: System setup vars: hostname: 192.168.1.130 username: admin password: pass
Если вы уже имели дело с Ansible, то скорее всего заметите, что мы указываем нашему плейбуку, что запускаться он будет на localhost, хотя обычно мы указываем там имена хостов или имена групп хостов. Дело в том, что для работа Ansible с ONTAP (да на самом деле и с ElementOS) идёт не через привычный ssh, а посредствам http/https при помощи модулей, которые мы устанавливали ранее.
А теперь буквально в несколько строк мы создадим 2 агрегата
- name: Create Aggregates na_ontap_aggregate: state: present service_state: online name: "{{ item.aggr }}" disk_count: "{{ item.disk_count }}" hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false loop: - { aggr: 'aggr1', disk_count: '13' } - { aggr: 'aggr2', disk_count: '13' }
Есть ещё одна задача, которую необходимо выполнить на новой системе — создание VLAN’ов на портах. Если мы используем классическую двухконтроллерную систему, то мы должны как минимум на 4 портах массива настроить пару VLAN’ов. Конечно это не всегда так, их может как больше, так и меньше, или, если вы используете ONTAP Select, у вас может быть вообще один контроллер и один порт. Но я покажу общую концепцию, которую можно будет применить потом к любому количеству портов.
- name: Create VLANs na_ontap_net_vlan: state: present vlanid: "{{ item.vlanid }}" node: "{{ item.node }}" parent_interface: "{{ item.parent_interface }}" hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false loop: - { node: 'korphome-01', vlanid: '13', parent_interface: 'e0a' } - { node: 'korphome-01', vlanid: '14', parent_interface: 'e0a' } - { node: 'korphome-01', vlanid: '15', parent_interface: 'e0a' } - { node: 'korphome-01', vlanid: '16', parent_interface: 'e0a' }
Всё в принципе просто. На каждой из нод нашей системы на портах e0a мы создаём интерфейс с 13 VLAN ID, а на e0b с 14. В данном случае я использую loop и метод создания виртуального интерфейса выполнится 4 раза с заданными параметрами. Это не самая сложная схема, чуть более сложный вариант использования циклов я применю при создании вольюмов на агрегатах чуть позже.
Следующий этап — создание IPspaces и Broadcast Domains.
- name: Сreate broadcast domain na_ontap_broadcast_domain: state: present name: ansible_domain mtu: 1000 ipspace: Default ports: ["korphome-01:e0a-13", "korphome-01:e0a-14"] hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false - name: Create ipspace na_ontap_ipspace: state: present name: ansibleIpspace hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false
И последним остаётся задать NTP сервер
- name: Create NTP server na_ontap_ntp: state: present version: auto server_name: "3.ru.pool.ntp.org" hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false
Теперь определив в первом конфигурационном файле все необходимые нам параметры (а вы, подправив их под свои нужды), можем запустить данный плейбук и получить первоначальные настройки на нашей системе.
Не удивляйтесь что у меня настройки немного расходятся с тем, что я предлагаю делать, просто эксперименты я провожу на ONTAP Select у которого всего один “контроллер” и всего один диск. Чтобы не собирать весь конфиг по тексту статьи, для удобства я выложу полный листинг обоих плейбуков в конце статьи. При помощи na_ontap_user вы возможно захотите добавить ещё и пользователей в систему с различными правами доступа.
С первым плейбуком и предварительной настройкой системы мы закончили, переходим ко второму этапу — создание и конфигурирование SVM. Это как раз одна из тех виртуальных сущностей, которая есть в системах ONTAP. Почему я решил их разделить на 2 части? Потому, что по моему опыту — создавать и модифицировать SVM приходится намного чаще, чем остальные настройки. Раз мы создаём отдельный плейбук, то ещё раз определим как он будет запускаться и с какими переменными, добавив туда сразу и имя нашего SVM.
--- - hosts: localhost gather_facts: False name: Create SVM vars: hostname: 192.168.1.130 username: admin password: pass vserver: AnsibleSVM
И первым делом, мы создаём саму сущностью SVM, которую будем уже дальше наполнять различными настройками.
- name: SVM Create na_ontap_svm: state: present name: "{{ vserver }}" root_volume: "{{ vserver }}_root" root_volume_aggregate: aggr1 root_volume_security_style: unix allowed_protocols: nfs,cifs,iscsi hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false
Используется модуль na_ontap_svm, состояние указано в качестве present, т.е. мы его создаём. На самом деле, чтобы удалить какой-то элемент достаточно сменить present на absent, так что стоит быть внимательнее. Но по логике работы самого Ontap вы не сможете просто удалить SVM, предварительно нужно будет удалить всё его содержимое с данными (луны, вольюмы, шары) и некоторые связанные с ним настройки (igrop’ы, например), а уже потом удалять сам SVM. Но вернёмся к заданию создания SVM. Если вы работали с системами ONTAP, то большинство указанных параметров вам понятны. Имя SVM Create мы объявили в переменной в самом начале — AnsibleSVM, т.к. все наши настройки будут связаны именно с SVM, чтобы нам было достаточно только один раз его указать в конфигурационном файле для большей гибкости в далнейшем использовании этого конфига с другими системами. А вот последние 5 строк задачи создания SVM будут преследовать нас до самого конца. Как я уже говорил ранее, работа Ansible с ONTAP осуществляется посредством http/https и каждая задача — это отдельное обращение к массиву, для чего нам требуется каждый раз авторизовываться, говорить какой протокол мы используемся и что делать с сертификатом. Конечно это не совсем удобно и очень сильно раздувает конфигурационный файл.
Зададим настройки DNS
- name: Create DNS na_ontap_dns: state: present vserver: "{{ vserver }}" hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" domains: korphome.local nameservers: 192.168.1.216 skip_validation: true https: true validate_certs: false
С применением loop, который мы использовали при создании VLAN’ов, мы создадим необходимые виртуальные интерфейсы.
- name: Create interface na_ontap_interface: state: absent interface_name: "{{ item.interface_name }}" home_port: "{{ item.home_port }}" home_node: "{{ item.node }}" role: data protocols: "{{ item.protocols }}" admin_status: up firewall_policy: mgmt address: "{{ item.address }}" netmask: 255.255.255.0 vserver: "{{ vserver }}" hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false loop: - { node: 'korphome-01', interface_name: '{{ vserver }}_iscsi_1', protocols: 'iscsi', home_port: 'e0a', address: '192.168.1.165' } - { node: 'korphome-01', interface_name: '{{ vserver }}_iscsi_2', protocols: 'iscsi', home_port: 'e0a', address: '192.168.1.166' } - { node: 'korphome-01', interface_name: '{{ vserver }}_data_1', protocols: 'nfs,cifs', home_port: 'e0a', address: '192.168.1.167' } - { node: 'korphome-01', interface_name: '{{ vserver }}_data_2', protocols: 'nfs,cifs', home_port: 'e0a', address: '192.168.1.168' }
Как я уже упоминал выше — моя конфигурация будет казаться немного странной. В данном случае у меня весь трафик идёт через один единственный порт, но т.к. мы готовим всё-таки универсальный скрипт для физической системы, я хочу показать как он должен выглядеть в идеальном случае.
Одним из протоколов, с которым мы будем работать, который мы указали при создании SVM, будет iSCSI, мы также создали для него 2 интерфейса, через которые будет ходить трафик и теперь нам необходимо создать на SVM сам сервис iSCSI и запустить его.
- name: Start iscsi service na_ontap_iscsi: state: absent service_state: started vserver: "{{ vserver }}" hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false
Следующим этапом станет создание группы инициаторов, которые будут работать с нашим массивом по iSCSI.
- name: Create igroup na_ontap_igroup: state: absent name: ansibleIgroup initiator_group_type: iscsi ostype: vmware initiator: iqn.1998-01.com.vmware:esxi6-68316bc6,iqn.1991-05.com.microsoft:veeamv10 vserver: "{{ vserver }}" hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false
Определяем произвольное имя группы хостов, задаём ostype и через запятую указываем iqn наших серверов. При создании SVM мы указали, что он будет работать ещё и с файловыми протоколами nfs,cifs и для них также необходимо сконфигурировать и запустить сервисы.
- name: Start nfs service na_ontap_nfs: state: absent service_state: started vserver: "{{ vserver }}" nfsv3: disabled nfsv4: disabled nfsv41: enabled tcp: disabled udp: disabled vstorage_state: disabled nfsv4_id_domain: korphome.local hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false - name: Create ans start cifs service na_ontap_cifs_server: state: absent cifs_server_name: ontap workgroup: korphome service_state: started vserver: "{{ vserver }}" hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false
Для NFS нам необходимо указать по какой из версий протокола у нас клиенты будут получать доступ, в описании к na_ontap_nfs есть параметры, связанные с правами доступа, которые вам тоже могут понадобится. А для CIFS достаточно указать только workgroup.
Теперь нам осталось организовать луны и шары, на которых собственно и будут храниться наши данные. Но прежде чем переходить к их созданию, немного поговорим об именовании. Дело в том, что в зависимости от проекта, я именую луны и вольюмы по-разному. Где-то это просто порядковые номер vol1, vol2, vol3. А для некоторых проектов мне необходимо указывать какие-то более человеческие имена, типа sevr1_db_2. От этого варианты генериции конфига для Ansible будут немного отличаться. Я покажу оба варианта, а вы уже сможете взять тот вариант, который больше подходит для вас. И так, первый вариант — числовое именование.
- name: Volume Create na_ontap_volume: state: present name: "vol_{{ item.1.name }}" vserver: "{{ vserver }}" aggregate_name: "{{ item.0.aggr }}" size: 30 size_unit: gb policy: default percent_snapshot_space: 0 efficiency_policy: default hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false loop: "{{ lookup('subelements', aggrs, 'volumes', {'skip_missing': True}) }}" vars: aggrs: - { name: "aggr1", volumes: [11,13,15,17] } - { name: "aggr2", volumes: [12,14,16,18] }
Здесь мы используем итератор внутри loop. Данный конфиг создаст 4 вольюма vol11, vol13, vol15, vol17 на агрегате aggr1 и 4 вольюма с чётными числами на втором агрегате. Не забываем внести изменения в size и size_unit и поправить percent_snapshot_space и efficiency_policy под свои требования.
Создать луны под этот шаблон именования будет также просто
- name: Create LUN na_ontap_lun: state: present name: "lun_{{ item }}" flexvol_name: "vol_{{ item }}" vserver: "{{ vserver }}" size: 5 size_unit: gb ostype: vmware space_reserve: no space_allocation: yes hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false with_sequence: start=11 end=18
with_sequence это такой же итератор, который создаст нам по одному луну на каждом из наших вольюмов. Не забываем внести изменения в size и size_unit и поправить percent_snapshot_space и efficiency_policy под свои требования. Изменяем ostype, если наши хосты не являются VMware и правим space_reserve и space_allocation, если хотите использовать другие параметры. Таким образом мы получим следующую структуру
aggr1/vol11/lun11
aggr2/vol12/lun12
aggr1/vol13/lun13
aggr2/vol14/lun14
aggr1/vol15/lun15
aggr2/vol16/lun16
aggr1/vol17/lun17
aggr2/vol18/lun18
Быстро и удобно, но не все отвечает требования задачи. Если мы хотим указывать какие-то конкретные имена вольюмов/лунов, то можно воспользоваться другим вариантом
- name: Volume Create na_ontap_volume: state: present name: "vol_{{ item.1.name }}" vserver: "{{ vserver }}" aggregate_name: "{{ item.0.aggr }}" size: 30 size_unit: gb policy: default percent_snapshot_space: 0 efficiency_policy: default hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false with_subelements: - "{{ volumes }}" - volume vars: volumes: - aggr: aggr1 volume: - name: server1_db1_vol - name: server2_db1_vol - aggr: aggr2 volume: - name: server1_db2_vol - name: server2_db2_vol
Также не забываем про size, size_unit, percent_snapshot_space и efficiency_policy. И по аналогии создадим луны
- name: Create LUN na_ontap_lun: state: present name: "lun_{{ item }}" flexvol_name: "vol_{{ item }}" vserver: "{{ vserver }}" size: 5 size_unit: mb ostype: vmware space_reserve: no space_allocation: yes hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false with_subelements: - "{{ volumes }}" - lun vars: volumes: - vol: server1_db1_vol lun: - name: server1_db1_lun - vol: server2_db1_vol lun: - name: server2_db1_lun - vol: server1_db2_vol lun: - name: server1_db2_lun - vol: server2_db2_vol lun: - name: server2_db2_lun
Здесь тоже не забудьте про параметры: size и size_unit, percent_snapshot_space, efficiency_policy, ostype, space_reserve и space_allocation. Честно скажу, этот вариант мне не сильно нравится, но иногда приходится использовать и его. Проблема в том, что это сильно увеличивает конфиг и снижает его читабельность. При этом потом такую же конструкцию придётся использовать при мапинге, т.к. нам нужно будет указывать целиком путь /vol/vol_name/lun_name. Потому что с итератором это делать всё-таки намного проще
- name: Create LUN mapping na_ontap_lun_map: state: present initiator_group_name: ansibleIgroup lun_id: "{{ item }}" path: "/vol/vol_{{ item }}/lun_{{ item }}" vserver: "{{ vserver }}" hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false with_sequence: start=11 end=18
Параметр lun_id в принципе можно не указывать, но удобнее, когда порядковый номер луна совпадает с Lun ID, который видно со стороны сервера. И главный параметр в этом конфиге — initiator_group_name, группа, которую мы создавали уже ранее и к которой мы мапим наши луны.
И последнее, что осталось нам сегодня сделать — создать CIFS и создать доступ по NFS.
- name: Create CIFS share na_ontap_cifs: state: present share_name: Share path: / share_properties: browsable,oplocks symlink_properties: read_only,enable vserver: "{{ vserver }}" hostname: "{{ hostname }}" username: "{{ username }}" password: "{{ password }}" https: true validate_certs: false
Все share_properties описаны в документации к ONTAP vserver cifs share properties show, а параметры symlink_properties в Configuring UNIX symbolic link support on SMB shares.
Конечно в этой статья я описал далеко не все модули и даже не все возможности модулей, которые использовал для примеров. Но я и не ставил перед собой такой задачи, я лишь хотел показать, как можно удобно построить процесс настройки массивов под управлением ONTAP (в том числе и ONTAP Select). По сути, при помощи Ansible вы можете настроить практически всё тоже самое, что можете настроить из GUI (в CLI возможности конечно шире). Самое главное — сделать это будет удобнее и быстрее. Предварительно собираете необходимую для настройки информацию: ip-адреса для lif’ов, адреса dns, ntp, имена SVM и томов, быстро заполняете это в конфигурационном файле и за одну минуту производите настройку всей системы. Я считаю это отличным решением и потихоньку стараюсь внедрить этот подход у нас. Но а если у вас остались ещё вопросы, или что то не получается, можно написать мне или в канал Netapp.io в Slack.
Как и обещал, в конце полный листинги:
system_setup.yml
create_svm.yml
Один ответ к «NetApp + Ansible»