Вот допустим у меня есть файл конфигурации для гуглового Deployment Manager, который создаёт виртуальную машину из убунтового образа, даёт ей временную внешнюю айпишку и отправляет в облако. Ну примерно такой:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
resources: - name: tiny-vm type: compute.v1.instance properties: zone: us-central1-a machineType: zones/us-central1-a/machineTypes/f1-micro disks: - deviceName: boot type: PERSISTENT boot: true autoDelete: true initializeParams: sourceImage: projects/ubuntu-os-cloud/global/images/family/ubuntu-1804-lts networkInterfaces: - network: global/networks/default accessConfigs: - name: External NAT type: ONE_TO_ONE_NAT |
А что делать, если я захотел пять таких? Ну или просто похожих. Это что, теперь копировать эту конфигурацию пять раз, меняя по паре строк вроде имени, образа и, возможно, зоны?
Но нет, Deployment Manager поддерживает Jinja и Python шаблоны, так что копипасты можно избежать. Давайте смотреть как это делается, например, на Питоне.
Как оно работает
Вообще-то, всё просто. Вместо того, чтобы указывать в шаблоне, что нам нужен ресурс типа compute.v1.instance
(строка #3 в примере выше) мы можем создать Python шаблон и использовать его имя в качестве типа. Когда DM его запустит, то передаст внутрь окружающий YAML в качестве параметра, и будет ждать на выходе уже Питоновский dict()
, который, если его сериализовать, сделает обычную YAML конфигурацию. На деле это выглядит намного проще, чем звучит, так что давайте глянем на пример.
Переносим VM в шаблон
Есть такая задача. Я хочу, чтобы исходная конфигурация виртуальной машины стала шаблоном, в который я могу передавать в качестве параметров имя, зону, образ и добавлять ли виртуальной машине внешнюю айпишку. Другими словами, я хочу использовать вот такие упрощённые конфигурации для создания виртуалок:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
imports: - path: vm.py # This is going to be a template resources: - name: first-vm type: vm.py properties: zone: us-central1-a sourceImage: projects/ubuntu-os-cloud/global/images/family/debian-9 assignPublicIP: true - name: second-vm type: vm.py properties: zone: us-central1-c sourceImage: projects/ubuntu-os-cloud/global/images/family/ubuntu-1804-lts |
Эта вот должна создать две виртуальные машины, одна Ubuntu, другая Debian, одна с внешней айпишкой, другая без, и и всё в разных зонах.
Сделать шаблон для этого — очень просто. Можно, например, вот так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
def generate_config(context): """ Process source YAML and produce actual resources config """ name = context.env['name'] zone = context.properties['zone'] source_image = context.properties['sourceImage'] assign_public_ip = context.properties.get('assignPublicIP') vm = { 'type': 'compute.v1.instance', 'name': name, 'properties': { 'zone': zone, 'machineType': 'zones/{}/machineTypes/f1-micro'.format(zone), 'disks': [{ 'deviceName': 'boot', 'type': 'PERSISTENT', 'boot': True, 'autoDelete': True, 'initializeParams': { 'sourceImage': source_image } }], 'networkInterfaces': [{ 'network': 'global/networks/default' }] } } if assign_public_ip: vm['properties']['networkInterfaces'][0]['accessConfig'] = [{ 'name': 'External NAT', 'type': 'ONE_TO_ONE_NAT' }] return { 'resources': [vm] } |
Единственная функция create_config
принимает на вход окружающий шаблон YAML в виде параметра context
. На выходе, как я уже говорил, возвращается dict()
, который выглядит точь в точь как YAML конфигурация из первого примера.
Параметры, которые мы задавали в YAML properties
(вроде zone) теперь доступны из context.properties
. Кроме них некоторые данные можно вытянуть из переменных окружения — context.env
. При запуске шаблона, Deployment Manager добавляет туда что-то от себя, например имена деплоймента и текущего ресурса. Зная это, я решил схитрить и не задавать имя виртуальной машины в parameters
секции, а просто взять имя самого ресурса (- name: first-vm
). Именно поэтому все свойства идут из context.properties
, и только имя — из context.
env['name']
.
Всё остальное тривиально. Если в параметрах шаблона был assign_public_ip
, то мы добавим соответствующую секцию в accessConfig
, если нет, то нет, и т. п.
К сожалению, Deployment Manager не умеет делать превью шаблонов, поэтому узнать, есть ли там какие-нибудь ошибки можно только после запуска. Флаг --preview
, который на самом деле у команды gcloud deployment-manager deployments create
есть, делает абсолютно посторонние вещи и для локального превью бесполезен.
Зато если теперь отправить нашу конфигурацию с шаблонами к облакам через gcloud deployment-manager deployment my-cluster --config templated-deployment.yaml
, то мы реально увидим, что в космосе появились новые две машины. А в свойствах деплоймента можно даже рассмотреть из каких шаблонов он собирался, и на что была похожа финальная конфигурация.
Мораль
Шаблоны для Deployment Manager — реально мощные. Это не просто способ избежать копипасты, а вся гибкость полноценного языка программирования. Можно создавать несколько ресурсов из одного шаблона, можно вызывать один шаблон из другого, можно делать даже переиспользуемые компоненты. Вариантов уйма.
У гугла даже есть репозиторий с примерами для них. Там конечно есть как устаревшие штуки, так и откровенно странные, но так же есть и новая ветка, в которой это хозяйство сейчас чистится и всячески переделывается. В общем, есть где смотреть.