Эта тема является предметом моей презентации в пользовательской группе пользователей AWS ManiLa Manila 20 августа 2020 года. Настраиваемость часть моей презентации покрыта в эта почта
Шаблоны облачных детенов — это наименее вероятный из всех ваших кодов, чтобы изменить после того, как он будет развернут до производства. Для большинства маленьких и средних команд среднего человека в группе AWS-Savvy в группе создаст шаблон CF, и он едва изменится на протяжении всего его жизни. Поскольку только один человек работает над шаблоном CF, есть немного стимулов, чтобы сделать шаблон для пользователя. Это укусило команду, когда инженер AWS покидает компанию, а оставшиеся позади должны обновлять шаблон в чрезвычайной ситуации.
Дизайн шаблонов CF для технических людей
Ключ к решению этой проблемы найдет время для улучшения пользовательского опыта. Вероятно, верно, что это другой разработчик, который внесет изменения в шаблон. Нам не нужно упростить шаблон, который будет оценен обычным человеком. Мы просто должны убедиться, что кто-то техничен с небольшим представлением о том, как работает WAWS, могут понять достаточно шаблона, чтобы внести изменения в него изменения.
Из моего опыта создания шаблонов CF для клиентов они обычно несколько разбираются в облачности. Но, конечно, они хотели бы, чтобы шаблон CF быть простым в использовании и обслуживании. Основываясь на их запросах изменения, я определил три вещи, которые они обычно ищут в шаблоне:
- 📚 Читаемый — Может ли пользователю знать, что делает шаблон CF, просто читая его?
- 🎛 Настраиваемый — Сколько может поменять пользователю со стеком без изменения самого шаблона?
- 🕹 Простота использования — Насколько легко использовать ваш шаблон?
В этом посте я представлю шесть трюков, которые я делаю, чтобы сделать шаблон CF более ориентирован на пользователя и сделать мои клиенты счастливыми.
(1) Разделите ваши параметры в разделы
Когда вы хотите, чтобы ваши шаблоны были настраиваемыми, вы неизбежно окажетесь слишком много параметров. Чтобы дать вам представление, для службы ECS CF шаблона, который я создал, у меня было 29 параметров. К сожалению для Cloudbation, мы не можем добавить стили HTML/CSS для разделения 29 параметров в их соответствующие разделы: Он просто представлен как один алфавитно-упорядоченный длинный список параметров. Это может быть подавляющее для большинства пользователей, пытаясь использовать свой шаблон в первый раз.
Решение: я добавляю имя параметра на основе их раздела. Для шаблона службы ECS у меня есть три функции (a a autoScaling, serviciscovery, abcconnection), каждый из которых требует своих собственных параметров. Поэтому я сгруппировал параметры, добавив раздел на имя каждого параметра, чтобы, когда он появляется на облачности, параметры в том же разделе будут сосезны вместе.
(2) Дайте своим пользователям выбор, следует ли включить функцию или нет
Часто пользователь захочет, чтобы использовать функцию в вашем шаблоне или нет. Способ сделать это — создание нескольких шаблонов: «ECS-Service-Screment-Auto-Scaling», «ECS-Service-No-Auto-Scaling». Но это означает, что ваш код повторяется через шаблоны. Эта договоренность будет тяжело поддерживать, поскольку количество объектов объектов увеличивается.
РЕШЕНИЕ
- Вы можете иметь параметры «коммутатора», где вы даете пользователю возможность использовать функцию или нет. Я обычно добавляю «AA» после префикса раздела, чтобы убедиться, что параметры «коммутатора» всегда заканчиваются сверху секции. Для приведенного выше пример ECS это может означать имя параметра коммутатора: «AutoScalingaaswitch»
- Если функция не будет использоваться, остальные настройки больше не должны быть заполнены. Чтобы добавить подписи для этого, я префикс описание параметра с меткой «Требуется для определенной функции для работы».
В сам шаблон я добавляю условия на том, создать ли конкретный сервис или нет. В шаблоне фрагмент ниже
ECSINSTANCEPROFILE
Ресурс создан только в том случае, еслиEC2InstanceProfileaaswitch
Отказ-
IaminstanceProfile
Свойство EC2Instance все еще ссылается на ecsInstanceprofile, даже если он не создан. Чтобы исправить это, мы добавили заявление, если Действительно Если [AddInstanceProfile,! Ref ecsinstanceprofile,! Ref «AWS:: Novalue»]указать на недвижимость
IaminstanceProfileNovalue, если
ECSINSTANCEPROFILEне был создан.
-
AWSTemplateFormatVersion: '2010-09-09' Parameters: Ec2InstanceProfileAASwitch: Description: UNIVERSALLY REQUIRED - Will your Ec2 have an instance profile? Default: No, it will not have an instance profile Type: String AllowedValues: - Yes, add an instance profile - No, it will not have an instance profile Conditions: AddInstanceProfile: !Equals [!Ref Ec2InstanceProfileAASwitch, "Yes, add an instance profile"] NoInstanceProfile: !Equals [!Ref Ec2InstanceProfileAASwitch, "No, it will not have an instance profile"] Resources: ECSInstanceProfile: Type: AWS::IAM::InstanceProfile Condition: AddInstanceProfile DependsOn: - ECSRole Properties: Path: / Roles: - !Ref ECSRole Ec2Instance: Type: AWS::EC2::Instance Properties: ImageId: ami-1234567891011 KeyName: Ref: BastionHostKeyName InstanceType: Ref: BastionHostInstanceType IamInstanceProfile: !If [AddInstanceProfile, !Ref ECSInstanceProfile, !Ref "AWS::NoValue"] ECSRole: ...
(3) Используйте CF Macros для уменьшения количества параметров
Как вы строите более настраиваемые шаблоны, вы будете наткнуться на ограничения CloudFormation. Одним из них является то, что вы должны создать десятки параметров, когда вы хотите, чтобы ваши шаблоны были настраиваемыми. Но что, если есть способ сгруппировать подобные параметры?
Parameters: SecurityGroupIngressRuleString: Description: REQUIRED - Required for the Security Group of the ECS Service. Make sure to allow access to the assigned SSH Port. Type: CommaDelimitedList MinLength: '9' Default: 80:80:0.0.0.0/0,443:443:sg-1234567890 Resources: SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: VpcId: Ref: VpcId GroupDescription: Security Group SecurityGroupIngress: | #!PyPlate output = [] for ip_combo in params['SecurityGroupIngressRuleString']: from_port, to_port, cidr_ip = ip_combo.split(':') if 'sg' in cidr_ip: output.append({'IpProtocol': 'tcp', 'FromPort': from_port, 'ToPort': to_port, 'SourceSecurityGroupId': cidr_ip}) else: output.append({'IpProtocol': 'tcp', 'FromPort': from_port, 'ToPort': to_port, 'CidrIp': cidr_ip})
В кодовом фрагменте выше, у нас есть SecurityGroupingressruleString
параметр. Это запятой, который указывает правила входа для группы безопасности, которую мы создаем. Каждый элемент строки содержит одно входное правило с форматом Fretrange: Torgane: пункт назначения
:
- «От диапазона» и «для диапазона» — это диапазон портов, которые мы хотим открыть до места назначения.
- «Направление» может быть либо IP CIDR (например, 12.33.44.55/32), либо идентификатор группы безопасности.
Следовательно, заявление 1000: 2000: SG-1234567890
означает, что мы позволяем всем ресурсам, связанным с SG-1234567890
Группа безопасности для связи с ресурсами, связанными с этой группой безопасности, через любые порты от 1000 до 2000 года. Пользователь может добавить столько правил входа, так как он любит внутри этого параметра.
Как все это работает?
Сначала мы зарегистрируем макрос Pypaper, загрузив это CF шаблон Отказ Этот шаблон создает функцию лямбда.
Когда мы загружаем шаблон CF, облачность смотрит на раздел преобразований. Поскольку мы добавили Pyapple в нашем фрагменте шаблона выше, он находит макрос деформации Pypaper CloudFation, который мы только что зарегистрированы. Он вызывает функцию лямбда и передает шаблон и наши параметры выполнения для этой функции. Py Paper смотрит на наш шаблон линией по линии и когда она видит «#! Pypaper «String, запускает код Python. Независимо от того, какая бы переменная «вывод» содержит становится вывод Для этого блока шаблона CF.
Взгляд на раздел Python из фрагмента кода, мы петлю через каждое правило входа в Парами ['SecuritygroupingressruleString']
Список, создайте словарь и добавьте, что в выходную переменную.
Возьми его дальше
Вы также можете создать параметр стиля ключей (I.E. »). Затем вы можете создать необходимый код Python, чтобы Mincount и MaxCount свойство ресурса будет использовать соответствующее значение в вашем параметре. При этом вам нужно иметь один параметр вместо 2. (Посмотрите на изображение на # 4 для иллюстрации).
(4) Создание разумных параметров по умолчанию
Даже со всеми вашими лучшими усилиями для уменьшения количества параметров пользователь должен вводить, иногда этого не будет достаточно. Альтернативой состоит в том, чтобы предоставить стандартные значения по умолчанию для этих параметров. Пользователю не нужно менять по умолчанию, если они не особенно чувствительны о том, как работает функция. Может быть, они просто хотят это работать из коробки?
Примером будет функция автоматического масштабирования шаблона службы ECS, я строю. Представьте, что я оставил эту часть заготовки. Пользователь должен будет решить каждый параметр самостоятельно. Имея по умолчанию, пользователь может сделать функцию автоматического масштабирования, работающую вне коробки. Он может вернуться к этому позже, если он хочет FineTune поведение автоматического масштабирования на основе его потребностей.
(5) Используйте ссылки CF Cross-Stack для ссылочных значений из другого стека
Создание разумных по умолчанию все еще оставляет некоторые параметры для заполнения. Такие параметры, такие как ALB_Listener_arn, Имя кластера ECS, ID VPC, идентификаторы подсети должны быть заполнены правильным значением.
Один подход — использовать ссылки на перекрестные стеки. Например, у нас есть шаблон «сетевой стек» ниже. В своем выходе, мы видим, что мы экспортировали некоторые значения. Эти значения будут доступны для других шаблонов для использования после развертывания этого стека. Обратите внимание, о том, как мы добавили имя стека AWS в этом шаблоне, чтобы убедиться, что переменные являются уникальными, если мы решили развернуть несколько стеков из этого шаблона.
AWSTemplateFormatVersion: '2010-09-09' Description: 'AWS CloudFormation Sample Template from AWS' Resources: VPC: Type: AWS::EC2::VPC Properties: EnableDnsSupport: 'true' EnableDnsHostnames: 'true' CidrBlock: 10.0.0.0/16 PublicSubnet: Type: AWS::EC2::Subnet Properties: VpcId: Ref: VPC CidrBlock: 10.0.0.0/24 InternetGateway: Type: AWS::EC2::InternetGateway Outputs: VPCId: Description: VPC ID Value: Ref: VPC Export: Name: Fn::Sub: "${AWS::StackName}-VPCID" PublicSubnet: Description: The subnet ID to use for public web servers Value: Ref: PublicSubnet Export: Name: Fn::Sub: "${AWS::StackName}-SubnetID"
Во втором шаблоне CF мы развертываем экземпляр EC2. Чтобы развернуть экземпляр, нам нужны некоторые значения из сетевого стека (I.E VPC и подсети). Вместо того, чтобы просить общих параметрах как VPC-ID и идентификатор подсети, мы просим имя стека CF, созданного ресурсами VPC и подсети. Затем в разделе экземпляра EC2 мы просто ссылаемся на имя переменной, которую мы экспортировали в стеке «Сеть». Мы добавляем имя стека для формирования переменной: «$ {Neighlestackname} -SubbetId».
AWSTemplateFormatVersion: 2010-09-09 Description: AWS CF Cross-Stack Reference Sample Template Parameters: NetworkStackName: Description: Stack Name of the Network Stack stack. Type: String Default: SampleNetworkCrossStack Resources: WebServerInstance: Type: AWS::EC2::Instance Properties: InstanceType: t2.micro ImageId: ami-05a66c68 NetworkInterfaces: - GroupSet: - Fn::ImportValue: Fn::Sub: "${NetworkStackName}-SecurityGroupID" AssociatePublicIpAddress: 'true' DeviceIndex: '0' DeleteOnTermination: 'true' SubnetId: Fn::ImportValue: Fn::Sub: "${NetworkStackName}-SubnetID"
(6) Используйте локальный препроцессор для создания профилей
Альтернатива ссылками для перекрестных стеков использует локальный препроцессор для префиляции значений по умолчанию. Я сделал это, создав простой сценарий Python в моем локальном и запуском этот скрипт перед загрузкой шаблона.
import cfn_flip.yaml_dumper import yaml from cfn_tools import load_yaml # (1) read the template with open("raw_template.yml") as f: raw = f.read() cf_template = load_yaml(raw) # (2) read the profile definition with open("blogsite-profile.yml") as f: raw = f.read() profile_definition = load_yaml(raw) # (3) merge the values of the profile definition as the default value for its respective parameter in the template for parameter_key in profile_definition: parameter_value = profile_definition[parameter_key] cf_template['Parameters'][parameter_key]['Default'] = parameter_value # (4) write the new template to a new YAML file with open("output_template.yml", 'w') as f: dumper = cfn_flip.yaml_dumper.get_dumper(clean_up=False, long_form=False) raw = yaml.dump( cf_template, Dumper=dumper, default_flow_style=False, allow_unicode=True ) f.write(raw)
Во-первых, у нас есть шаблон CF, который мы используем для создания ресурсов. У нас также есть другой файл YAML, который содержит значения, которые мы хотим вставить в наши параметры шаблона (давайте назовем это профиль_definition). В 4-м блоке кода в нашем скрипте Python мы проходим через каждый параметр в профиле_definition, найдите эквивалентный параметр для него в шаблоне Cloudbation, и установите значение по умолчанию параметра, равное значению параметра в профиле_definition.
Процесс выглядит так:
- Вы можете создать профиль_Доформления для различных сред/приложений Ты можешь иметь
- Наполняем значение по умолчанию параметра для предоставления стандарта для приложения. Но пользователь все еще может изменить эти значения, если ему нужно.
Это все!
А ты? Каковы трюки, которые вы можете поделиться, чтобы сделать свои шаблоны COULLFORTION CLOLLFATION больше пользователей?
Я рад принять ваши комментарии/отзывы на этом посте. Просто комментируйте ниже, или напишите мне!
Особая благодарность Даниэлю МакКалло на фоновое изображение
Оригинал: «https://dev.to/raphael_jambalos/user-centric-cloudformation-templates-3jef»