AWS Notes
5.6K subscribers
444 photos
42 videos
10 files
2.8K links
AWS Notes — Amazon Web Services Educational and Information Channel

Chat: https://xn--r1a.website/aws_notes_chat

Contacts: @apple_rom, https://www.linkedin.com/in/roman-siewko/
Download Telegram
Реализовать в #CloudFormation #templates зависимость значений от environment не очень сложно. Однако когда требуется переменное количество параметров (т.е. для одного окружения один набор переменных, а для другого - отличный), то для этого Амазон сделал в своё время Fn::Transform.

Однако из-за того, что это (Transform) суть костыльный костыль, реализуемый как надстройка в виде лямбды, которая запускается перед скармливанием CloudFormation конечного вида шаблона, то реальный опыт работы с Transform оказался весьма болезненный.

Потому совет: если можно не использовать Transform - лучше не использовать.

Альтернативой может быть использование #Conditions.

Например, вот реальный кейс. Потребовалось для multi environment шаблона реализовать логику различного набора переменных для #ECS #task_definition - на тестовом окружении требовалось задать другие переменные, при этом обычные не должны быть определены совсем, т.к. чувствительное приложение, написанное в давние времена, спотыкалось о них и падало.

В результате дефолтная таска была скопирована и создана ещё одна такая же, только с нужными переменными. И добавлен волшебный condition, который из двух этих тасок в сервисе подключал нужную:

https://github.com/applerom/cloudformation-examples/blob/master/ecs/task-definition-with-different-set-of-variables.yaml

По умолчанию логика ни для какого (уже ранее имеющегося) окружения не поменяется (т.к. по умолчанию UseTestVariables = 'no'), а для тестового сработает TaskDefinition: !If [ UseTest, !Ref ecsTaskTest, !Ref ecsTask ].

Итого - всё работает стандартно и без трансформатора.
S3 Transfer Acceleration

Для случаев, когда нужно загружать в бакет быстро-много-часто и со всего мира, то на загрузку можно включить ускорение (кушает некоторые деньги):

bucketUploads:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketUploads
AccelerateConfiguration:
AccelerationStatus: Enabled

https://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html

#s3 #acceleration #CloudFormation #templates
CloudFormation development tool - Rain

Для тех, кто работает со стэками в командной строке - очередная попытка хоть как-то обустроить работу с #CloudFormation #templates:

https://github.com/aws-cloudformation/rain

Принцип работы можно понять по гифке в описании репозитория. Для простых вещей кому-то может оказаться полезно.
Шаблон для VPC в N.Virginia с шестью AZ-подзонами

Многие примеры #CloudFormation #templates имеют в большинстве случаев две подзоны (Availability Zones). Это удобно тем, что все регионы имеют как раз минимум эти две подзоны (см. наверняка знакомую картинку из документации).

В большинстве случаев этого хватает - даёт минимальную надёжность и при этом не усложняет конфигурации огородом подсетей и прочих аттрибутов, сопутствующих каждой подзоне.

Но сетевую архитектуру плохо менять по ходу, а чаще просто невозможно. И потому какое-нибудь compliance с требованием трёх подзон, может оказаться неприятным сюрпризом, когда всё давно работает и не понятно, как переделывать. Или когда вы сами решите внедрить spot-инстансы, где принципиально иметь максимум подзон.

Особенно это актуально для N.Virginia, где целых 6 подзон. Использовать в таком регионе лишь 2-3 штуки из имеющихся шести - особо неприятно.

Для создания #VPC можно использовать кучи способов - от вручную в консоли до Terrafrorm и прочих инструментов. У каждого адепта #CloudFormation есть свои "проверенные" шаблоны, в частности, вот мой для региона us-east-1 с зонами от A до F (6 шт.):

https://github.com/applerom/cloudformation-examples/blob/master/vpc/vpc4af.yml

В результате создаётся VPC с диапазоном адресов /16 и с подсетями на /24, в том числе приватными (для которых по умолчанию создаётся NAT) - стандартный набор, короче. Просто с помощью данного шаблона всё это делается просто заданием CIDR prefix типа 10.25, а все остальные подсетки создадутся автоматом, что удобно и можно использовать единый стиль архитектуры со всеми своими проектами (подредактировав шаблон под свой вкус и прочие требования).
Конвертилка существующих AWS ресурсов в CloudFormation шаблон

Стандартная ситуация условного стартапа в начальной стадии:

1. Накликали в AWS Console свой проект
2. Проект не загнулся и даже немножко поехал.
3. Запаривались эмулировать CI вручную.
4. Задумались о том, что нужно бы перести "вот это всё" в #CloudFormation #templates.

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

Таких утилит не так много, они отличаются различной степенью бесполезности. Наименее бесполезная или, наоборот, наиболее полезная и самая красивая из них:

https://former2.com

Официальная же амазоновская называется CloudFormer:

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-using-cloudformer.html

О бесполезности конвертошаблонизаторов

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

Если проект очень простой - посмотрев примерчики (в том числе мои), можно достаточно быстро накрапать нужное.

Если же проект сложный, то результатом работы "формеров" будет туча несвязанных элементов, в которых невозможно разобраться, т.к. ведь год генирируется автоматически.

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

Ещё более единственным вариантом написание шаблона самостоятельно станет, когда будет осознан тот факт, что нужно также добавить в процесс создания переменные, которые могут что-то менять и отличаются для различных окружений, аккаунтов, регионов, назначений. Т.е. заложить в шаблон не только возможность автоматического разворачивания, но и организацию CI/CD-процесса с его помощью. А всё такое можно сделать лишь понимая зачем, для кого и самому.

Короче, всё печально, однако отговаривать не буду и обязательно попробуйте конвертилку в действии. Не стоит верить на слово — убедитесь лично.

#удачи
Последовательность блоков в #CloudFormation #templates можно менять (сначала ресурсы или даже вывод, остальное ниже):

Outputs:
 ecrRepository:
  Value: !Ref ecrRepository
Resources:
 ecrRepository: 
  Type: AWS::ECR::Repository
  Properties: 
   RepositoryName: !Ref RepositoryName
Parameters:
 RepositoryName:
  Type: String
  Description: Name of ECR repository
  Default: some-repo
Description: ECR repository
Соединение элементов строки в CloudFormation

Собрать в кучу строчку в CloudFormation шаблоне можно разными способами.

Стандартный с помощью !Join, например,

ContainerName: !Join ['-', ['service', !Ref MsName]]

Однако то же самое можно сделать с помощью !Sub:

ContainerName: !Sub 'service-${MsName}'

То есть с !Sub олучается короче, иногда существенно короче. Потому такой подход весьма популярен.

Однако длина не единственный показатель удобности и потому, когда вы после дебажите шаблон, все эти важные параметры сливаются на мониторе в строку (ведь это строка) и их не видно на фоне других. В то время как в случае !Join чётко видны логические составляющие - все переменные, из которых будет собрана строка.

Так что я использую !Join - длиннее, но разборчивей.

Кстати, многие забывают, что у !Sub кроме "обычной" возможности просто вставлять параметры из шаблона, есть возможность подставлять их через свои переменные, организуя сложные выборки с !ImportValue и т.п. Например, вот здесь встречается такая конструкция:

ResourceId: !Sub
- 'service/${Cluster}/${Service}'
- Cluster: {'Fn::ImportValue': !Sub '${ParentClusterStack}-Cluster'}
Service: !GetAtt 'Service.Name

Чтобы собрать строчку, мы внутри её делаем две свои "локальные" переменные Cluster и Service (которые указывают после строки как массив) и уже в них делаем ещё какие-то действия.

В "солидной" версии это (не точный аналог - просто очень похожее из реального кода) будет длинным, но очевидным:

ResourceId: !Join ['', ['service/', !ImportValue ecsClusterMs, '/', !GetAtt [ecsService, 'Name']]]

Всё видно и понятно. Как минимум мне.

#CloudFormation #templates
Отличный источник примеров работы с #CloudFormation #templates (а также #Terraform и #aws_cli) плюс прямые ссылки на документацию, официальные блоги, всяческие безопасности и различные #best_practices:

https://asecure.cloud/

Однозначно в закладки.

#security #info
Beanstalk + ALB + CloudFormation

По умолчанию в Elastic Beanstalk создаётся ALB, если делать это через консоль:

By default, Elastic Beanstalk creates an Application Load Balancer for your environment when you enable load balancing with the Elastic Beanstalk console or the EB CLI.

А через CloudFormation - с классическим ELB! (Здравствуй, логика.) Из-за этого в документации не найти примеров кода для создания Beanstalk в CloudFormation.

Cервис старый и все примеры в интернете обычно лишь для классического (старого) ELB. И документация из-за старости и сложности (под капотом) сервиса, весьма неочевидна.

Вот главная ссылка, что всегда требуется при создании шаблона для Beanstalk:

https://docs.amazonaws.cn/en_us/elasticbeanstalk/latest/dg/command-options-general.html

А вот пример кода, как заставить создать Beanstalk + ALB через CloudFormation:

- Namespace:  aws:elasticbeanstalk:environment
OptionName: LoadBalancerType
Value: application
- Namespace: aws:elbv2:listener:443
OptionName: Protocol
Value: HTTPS
- Namespace: aws:elbv2:listener:443
OptionName: SSLCertificateArns
Value: !Ref AcmCertificateArn
- Namespace: aws:elbv2:listener:443
OptionName: DefaultProcess
Value: default
- Namespace: aws:elbv2:loadbalancer
OptionName: SecurityGroups
Value: !ImportValue sgVpc4Web
- Namespace: aws:elasticbeanstalk:environment:process:default
OptionName: Port
Value: !Ref InstancePort
- Namespace: aws:elasticbeanstalk:environment:process:default
OptionName: Protocol
Value: HTTP
- Namespace: aws:elasticbeanstalk:environment:process:default
OptionName: StickinessEnabled
Value: true
- Namespace: aws:elasticbeanstalk:environment:process:default
OptionName: HealthCheckPath
Value: !Ref HealthCheckPath

Переменные нужно поменять на свои, главная оставить LoadBalancerType - application.

#Beanstalk #CloudFormation #templates
ECS task + init container

Часто нужно, чтобы ECS task-а сначала была проиниацилизирована, а уже потом стартовал сервис. Пример, как такое можно сделать с помощью CloudFormation:

https://github.com/applerom/cloudformation-examples/blob/master/ecs/task-with-init-container.yaml

Код из рабочего конфига, но отредактирован (длинный, выброшено не относящееся к делу), чисто к тому, как такое можно сделать. В нём будут интересны следующие строчки.

ecsTaskWithInit:
Type: AWS::ECS::TaskDefinition
Properties:

...
   ContainerDefinitions:
- Name: !Ref StdNameInit
Image: !Ref DockerImage
Essential: false

...
     Command:
- sh
- '-c'
- !Sub |
cd /home/my/app \
&& ./setup.py migrate --noinput \
&& ./setup.py rebuild_index --noinput

...
   - Name:      !Ref StdName
Image: !Ref DockerImage
Essential: true
Links:
- !Ref StdNameInit
Environment:

...

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

Контейнер для инициализации отрабатывает первым и умирает, потому ставим ему:

Essential: false

Он должен выполнить какую-то команду(-ы), запускаем следующим способом:

Command:
- sh
- '-c'
- !Sub |
cd /home/my/app \
&& ./setup.py migrate --noinput \
&& ./setup.py rebuild_index --noinput


После него должен стартовать основной контейнер, чтобы реализовать такую последовательность (сначала - init, а уже потому главный), добавляем зависимость от первого:

Links:
- !Ref StdNameInit


И ставим главному контейнеру:

Essential: true

Так можно регулировать последовательность запуска и инициализировать что-то перед работой основного сервиса.

#CloudFormation #templates #examples