В предыдущей статье «vRA 8: интеграция с Ansible» тестируется использование Ansible для настройки серверов в vRealize Automation 8. Проверим, как это работает на реальной задаче — развертывание кластера kubernetes. Существует большой выбор готовых плейбуков Ansible, один из самых продвинутых — Kubespray. Разработаем блюпринт vRA для создания кластера K8S с помощью Kubespray.
Kubespray. Настройка и первый запуск

Kubespray — готовый к использованию комплект плейбуков и ролей Ansible для установки и конфигурации кластера kubernetes.
Описание проекта: https://kubespray.io/
Загрузка кода: https://github.com/kubernetes-sigs/kubespray.
Основные преимущества Kubespray (по мнению команды разработчиков):
- Создание высокодоступных кластеров;
- Возможность выбора компонентов и гибкой настройки;
- Поддержка самых популярных Linux-дистрибутивов;
- Развёртывание как на железе, так и в различных облачных платформах.
Прежде чем приступать к запуску Kubespray через vRA, обязательно сделайте тестовое развёртывание кластера K8S: скачайте Kubespray, закажите через vRA несколько VM и запустите установку. Скорее всего, потребуется Ваше вмешательство для устранения непредвиденных ошибок.
- Используем сервер с Ansible, настроенный ранее: vRA 8: интеграция с Ansible;
- локальный пользователь ansible;
- Kubespray загружен в ~/playbooks/kubespray;
- доступ к настраиваемым серверам по ключу, удалённый пользователь на нодах также ansible;
- ОС на виртуальных машинах Ubuntu 18.04 (несмотря на заявленную «поддержку самых популярных дистрибутивов», на CentOS 7/8 у меня так и не завелось).
# Установите зависимости по списку из ``requirements.txt``
sudo pip3 install -r requirements.txt
# В директории ``inventory/sample`` находятся конфигурационные файлы
# Скопируйте ``inventory/sample`` в ``inventory/vra``
cp -rfp inventory/sample inventory/vra
# Создайте файл инвентори с помощью inventory builder
declare -a IPS=(10.10.1.3 10.10.1.4 10.10.1.5)
CONFIG_FILE=inventory/vra/hosts.yaml python3 contrib/inventory_builder/inventory.py ${IPS[@]}
# Изучите получаемый файл inventory/vra/hosts.yaml для разного количества VM
# Две мастер-ноды, 1 или 3 ноды с etcd, все ноды рабочие
# Изучите и откорректируйте параметры в файлах ``inventory/vra/group_vars/``
cat inventory/vra/group_vars/all/all.yml
cat inventory/vra/group_vars/k8s-cluster/k8s-cluster.yml
# Развёртывание Kubespray с Ansible Playbook
ansible-playbook -i inventory/vra/hosts.yaml --become --become-user=root cluster.yml
# Если имя пользователя на нодах отличается от имени локального пользователя,
# то добавьте --user=<имя пользователя>
Плейбук запуска Kubespray
Для развёртывания кластера kubernetes при помощи vRA и Kubespray требуется автоматизировать:
- Клонирование директории с настройками Kubespray, копировать будем из inventory/vra/;
- Генерирование файла инвентори;
- Правку конфигурационных файлов по выбранным пользователем значениям;
- Запуск развёртывания кластера.
Все перечисленные операции будут выполняются локально, поэтому в плейбуке connection == local. Текст плейбука для развёртывания кластера (описанные ниже ansible-плейбуки и код блюпринта доступны на https://github.com/isas2/vra):
# ~/playbooks/kubespray/vra_deploy.yaml
- name: Deploy K8S cluster
hosts: kubespray
connection: local
roles:
- kwoodson.yedit
tasks:
- name: "01. Create new inventory"
copy: src=inventory/vra/ dest=inventory/{{ inventoryName }}/
- name: "02. Create hostlist file"
file:
path: inventory/{{ inventoryName }}/vra_hosts
state: touch
- name: "03. Write to hostlist first master-node IP"
lineinfile:
path: inventory/{{ inventoryName }}/vra_hosts
line: "{{ ipAddressMn }}"
- name: "04. Write to hostlist all node IPs"
lineinfile:
path: inventory/{{ inventoryName }}/vra_hosts
line: "{{ item }}"
loop: "{{ ipAddressWn }}"
- name: "05. Exclude pods subnets"
shell: sed -i '/^10\.233\./d' inventory/{{ inventoryName }}/vra_hosts
- name: "06. Create Inventory File"
shell: CONFIG_FILE=inventory/{{ inventoryName }}/hosts.yaml python3 contrib/inventory_builder/inventory.py $(cat inventory/{{ inventoryName }}/vra_hosts)
- name: "07. Enable external cloud provider"
yedit:
src: inventory/{{ inventoryName }}/group_vars/all/all.yml
key: cloud_provider
value: "external"
when: vcpIstall == true
- name: "08. Set external cloud provider name"
yedit:
src: inventory/{{ inventoryName }}/group_vars/all/all.yml
key: external_cloud_provider
value: "vsphere"
when: vcpIstall == true
- name: "09. Enable vSphere CSI"
yedit:
src: inventory/{{ inventoryName }}/group_vars/all/vsphere.yml
key: vsphere_csi_enabled
value: true
when: vcpIstall == true
- name: "10. Set network plugin"
yedit:
src: inventory/{{ inventoryName }}/group_vars/k8s-cluster/k8s-cluster.yml
key: kube_network_plugin
value: "{{ netPlugin }}"
- name: "11. Wait a nodes"
shell: sleep 1m
- name: "12. Start Kubespray deploy"
shell: /usr/bin/ansible-playbook -i inventory/{{ inventoryName }}/hosts.yaml --become --become-user=root cluster.yml
- Для работы с файлами yaml используется модуль yedit (установка kwoodson.yedit);
- 01: Поскольку кластер может быть не один и настройки у них могут отличаться, то для каждого создаём отдельный инвентори. Необходимо обеспечить генерацию и передачу уникального значения в переменную inventoryName;
- 02 — 05: Создание файла со списком IP-адресов виртуальных машин, мастер-ноды в начале списка;
- 06: Создание файла инвентори, на вход скрипту передан файл vra_hosts со списком IP всех нод;
- 07 — 09: Включение vSphere Cloud Provider, если переменная vcpIstall == true. В файле inventory/vra/group_vars/all/vsphere.yml должны быть заполнены поля для соединения с vCenter, кроме поля vsphere_csi_enabled;
- 10: Установка имени сетевого плагина;
- 11: Небольшая задержка запуска, были случаи старта плейбука до полной готовности хостов (можно предусмотреть перед всеми запусками плейбуков vRA — Ansible).
При удалении кластера нужно удалить и каталог с его инвертори:
# ~/playbooks/kubespray/vra_destroy.yaml
- name: Destroy cluster
hosts: kubespray
connection: local
tasks:
- name: "Delete inventory directory"
file:
path: inventory/{{ inventoryName }}/
state: absent
Блюпринт vRA

Kubespray по умолчанию создаёт две мастер-ноды, но на схеме всего одна. Это связано с особенностью запуска плейбуков: сколько VM, столько и плейбуков, что нам не подходит. В качестве второй мастер-ноды будет использована первая VM из рабочих нод.
formatVersion: 1
name: K8S cluster with Ansible and Kybespray
version: 1
inputs:
workerNodes:
type: integer
default: 2
minimum: 1
maximum: 5
title: Number worker nodes
nodeSize:
type: string
enum:
- small
- medium
- large
default: small
title: Node size
vcpIstall:
type: boolean
default: false
title: Install vSphere cloud provider
netPlugin:
type: string
enum:
- calico
- flannel
- weave
default: calico
title: Select network plugin
resources:
K8S-Install:
type: Cloud.Ansible
dependsOn:
- WorkerVM
properties:
inventoryFile: ~/hosts
username: ansible
privateKeyFile: ~/.ssh/id_rsa
playbooks:
provision:
- ~/playbooks/kubespray/vra_deploy.yaml
de-provision:
- /home/ansible/playbooks/kubespray/vra_destroy.yaml
hostVariables: |
inventoryName: ${to_lower(join([env.projectName, env.requestedBy, env.deploymentId], '-'))}
ipAddressWn: ${resource.WorkerVM.address}
ipAddressMn: ${resource.MasterVM.address}
vcpIstall: ${input.vcpIstall}
netPlugin: ${input.netPlugin}
osType: linux
groups:
- kubespray
maxConnectionRetries: 10
host: '${resource.MasterVM.*}'
account: Ansible (vra-ssh)
MasterVM:
type: Cloud.Machine
properties:
image: Ubuntu_18
flavor: '${input.nodeSize}'
customizationSpec: tmp-linux-vra
networks:
- network: '${resource.NetworkVM.id}'
assignment: static
WorkerVM:
type: Cloud.Machine
dependsOn:
- MasterVM
properties:
count: '${input.workerNodes}'
image: Ubuntu_18
flavor: '${input.nodeSize}'
customizationSpec: tmp-linux-vra
networks:
- network: '${resource.NetworkVM.id}'
assignment: static
NetworkVM:
type: Cloud.vSphere.Network
properties:
networkType: existing
- В playbooks.provision и playbooks.de-provision укажите пути до плейбуков. Обратите внимание, что путь в de-provision указан абсолютный, с относительным он у меня не запускался (возможно просто глюк, проверьте у себя);
- Переменная inventoryName — имя каталога инвентори: передаётся строка из имени проекта, имени пользователя и ID развёртывания. Если у Вас названия проектов длинные, то можете их не добавлять.
Управление кластером
Что дальше? Попробуйте доработать эти примеры для использования возможностей масштабирования и обновления кластеров (scale.yml, upgrade-cluster.yml).
Первое препятствие на данном пути — сам vRA. После установки кластера Kubernetes он начинает видеть на виртуальных машинах дополнительные IP-адреса из подсети K8S (для Kubespray по умолчанию это 10.233.64.0/18). Эти IP-адреса vRA начинает отображать в описании деплоймента и использовать при вызовах плейбуков ansible. Если при установке кластера использовался один IP, а для обновления передаётся другой, то такой хост не будет найден в инвентори.
- Добавьте в файл инвентори все хосты по маске: 10.233.[64:127].0;
- В плейбуке vra_deploy.yaml есть специальный пункт «05. Exclude pods subnets», который исключает эти адреса из файла инвентори Kubespray.
Все использованные в статье плейбуки ansible и код блюпринта vRA доступны на https://github.com/isas2/vra.