AWS CloudFormation – это “бесплатный” сервис, который помогает нам предоставлять и управлять ресурсами AWS только с помощью шаблона. Одно из преимуществ, которое мне нравится – нам не нужно искать, какие модули еще можно использовать, а какие уже устарели, потому что AWS предоставляет полную информацию в документации, нажмите здесь. Все, что нам нужно определить в шаблоне, предоставлено там. Одна из самых важных вещей об этой услуге, которую вы должны помнить: мы можем бесплатно использовать сервис CloudFormation, но вам будет выставлен счет за все услуги, созданные с помощью стека (те, которые вы определите в шаблоне).
Итак, мы будем делать все с CloudFormation через AWS CLI. Итак, убедитесь, что вы установили AWS CLI и настроили учетные данные. Если у вас все готово, давайте начнем!
1. Создайте шаблон
В первой версии шаблона я хочу создать S3 bucket с включенной версионностью. Я подготовил это для следующего шага, потому что когда мы создаем стек, загружая шаблон (хранящийся локально) через CLI, он не показывает нам, где он будет храниться (я расскажу вам об этом через секунду ниже).
Итак, я назвал шаблон cfn-demo.yaml, и он будет выглядеть следующим образом:
Resources:
S3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: cfn-bucket-template
VersioningConfiguration:
Status: Enabled
2. Создание стека
Как я уже говорил выше, когда мы создаем стек, загружая шаблон (хранящийся локально) через CLI, он не показывает нам, где он будет храниться. Совсем другое дело, когда мы создаем стек путем загрузки файла через консоль, который будет храниться в S3 bucket, сгенерированном самим CloudFormation, но этот bucket не будет удален, даже если стек был удален.
Тогда, чтобы предотвратить удаление не удаленного ведра из стека. Мы сначала создадим ведро, загрузим шаблон в ведро и будем использовать объект в качестве источника шаблона. Я просто хочу дать вам понять, что мы можем это сделать.
Давайте создадим стек!
$ aws cloudformation create-stack --stack-name cfn-demo --template-body file://cfn-demo.yaml
{
"StackId": "arn:aws:cloudformation:ap-southeast-3:01234567890:stack/cfn-demo/2953bb10-ced2-11ec-a796-06bb617a2d70"
}
Пожалуйста, подождите, пока статус не будет завершен.
$ aws cloudformation describe-stacks --stack-name cfn-demo
{
"Stacks": [
{
"StackId": "arn:aws:cloudformation:ap-southeast-3:01234567890:stack/cfn-demo/2953bb10-ced2-11ec-a796-06bb617a2d70",
"StackName": "cfn-demo",
"CreationTime": "2022-05-08T13:24:17.386Z",
"RollbackConfiguration": {},
"StackStatus": "CREATE_COMPLETE",
"DisableRollback": false,
"NotificationARNs": [],
"Tags": [],
"EnableTerminationProtection": false,
"DriftInformation": {
"StackDriftStatus": "NOT_CHECKED"
}
}
]
}
Давайте проверим ведро S3! Оно было создано или нет?
$ aws s3 ls
2022-05-08 20:24:45 cfn-bucket-template
3. Обновление стека
Чтобы обновить стек, нам нужно выполнить несколько шагов по сценарию. К ним относятся:
- Внесите любые изменения в шаблон. В данном случае я создам дополнительные ресурсы (VPC, подсеть, интернет-шлюз, таблицу маршрутов, 2 группы безопасности и экземпляр EC2).
- Загрузите вторую версию шаблона в ведро S3.
- Обновите стек, используя объект S3 в качестве источника шаблона.
cfn-demo.yaml (вторая версия)
AWSTemplateFormatVersion: 2010-09-09
Parameters:
EC2Type:
Description: Type of instance
Type: String
Default: t3.micro
AllowedValues:
- t3.micro
- t3.small
- t3.medium
- t3.large
Resources:
S3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: cfn-bucket-template
VersioningConfiguration:
Status: Enabled
VirtualPrivateCloud:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 172.16.0.0/16
Tags:
- Key: "Name"
Value: "CFN VPC"
Subnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VirtualPrivateCloud
CidrBlock: 172.16.1.0/28
AvailabilityZone: ap-southeast-3a
Tags:
- Key: "Name"
Value: "CFN Subnet"
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: "Name"
Value: "CFN IGW"
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VirtualPrivateCloud
InternetGatewayId: !Ref InternetGateway
RouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VirtualPrivateCloud
Tags:
- Key: "Name"
Value: "CFN Route"
Route:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref RouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
SubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref Subnet
RouteTableId: !Ref RouteTable
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow SSH HTTP
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
IpProtocol: tcp
FromPort: 22
ToPort: 22
- CidrIp: 0.0.0.0/0
IpProtocol: tcp
FromPort: 80
ToPort: 80
VpcId: !Ref VirtualPrivateCloud
Tags:
- Key: "Name"
Value: "CFN SG"
SecurityGroup2:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Only Allow SSH
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
IpProtocol: tcp
FromPort: 22
ToPort: 22
VpcId: !Ref VirtualPrivateCloud
Tags:
- Key: "Name"
Value: "CFN SG2"
KeyPair:
Type: AWS::EC2::KeyPair
Properties:
KeyName: ec2-user
PublicKeyMaterial: ssh-rsa VWXYZ.....(your pubkey goes here)
EC2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref EC2Type
AvailabilityZone: ap-southeast-3a
ImageId: "ami-021fb2b73ff1efc96"
KeyName: "ec2-user"
BlockDeviceMappings:
- DeviceName: "/dev/xvda"
Ebs:
DeleteOnTermination: "true"
VolumeSize: "8"
VolumeType: "gp2"
NetworkInterfaces:
- AssociatePublicIpAddress: "true"
DeleteOnTermination: "true"
DeviceIndex: 0
SubnetId: !Ref Subnet
GroupSet:
- Ref: SecurityGroup2
UserData:
Fn::Base64:
!Sub |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl enable httpd
systemctl start httpd
Tags:
- Key: "Name"
Value: "CFN Instance"
Outputs:
EC2IpAddress:
Description: "EC2 Public IP Address"
Value: !GetAtt EC2Instance.PublicIp
Загрузите файл в ведро S3 с помощью функции копирования:
$ aws s3 cp cfn-demo.yaml s3://cfn-bucket-template
upload: ./cfn-demo.yaml to s3://cfn-bucket-template/cfn-demo.yaml
$ aws s3 ls s3://cfn-bucket-template
2022-05-08 20:31:46 4256 cfn-demo.yaml
Затем обновим стек, используя URL объекта S3 в качестве источника шаблона.
$ aws cloudformation update-stack --stack-name cfn-demo --template-url https://cfn-bucket-template.s3.ap-southeast-3.amazonaws.com/cfn-demo.yaml
{
"StackId": "arn:aws:cloudformation:ap-southeast-3:01234567890:stack/cfn-demo/2953bb10-ced2-11ec-a796-06bb617a2d70"
}
Пожалуйста, подождите, пока статус не будет завершен, и мы получим результат.
$ aws cloudformation describe-stacks --stack-name cfn-demo
{
"Stacks": [
{
"StackId": "arn:aws:cloudformation:ap-southeast-3:0123456789:stack/cfn-demo/2953bb10-ced2-11ec-a796-06bb617a2d70",
"StackName": "cfn-demo",
"Parameters": [
{
"ParameterKey": "EC2Type",
"ParameterValue": "t3.micro"
}
],
"CreationTime": "2022-05-08T13:24:17.386Z",
"LastUpdatedTime": "2022-05-08T13:33:13.916Z",
"RollbackConfiguration": {},
"StackStatus": "UPDATE_COMPLETE",
"DisableRollback": false,
"NotificationARNs": [],
"Outputs": [
{
"OutputKey": "EC2IpAddress",
"OutputValue": "108.136.169.98",
"Description": "EC2 Public IP Address"
}
],
"Tags": [],
"EnableTerminationProtection": false,
"DriftInformation": {
"StackDriftStatus": "NOT_CHECKED"
}
}
]
}
Проверим порт экземпляра EC2, зайдя на него через SSH и веб-браузер.
$ ssh ec2-user@108.136.169.98
__| __|_ )
_| ( / Amazon Linux 2 AMI
___|___|___|
https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-172-16-1-8 ~]$ exit
logout
Connection to 108.136.169.98 closed.
Почему мы проверяем порты? Потому что мы создали 2 группы безопасности и уже использовали первую для нашего экземпляра EC2. Теперь давайте внесем изменения в шаблон и снова загрузим его в ведро S3. В результате этого действия у нас будет две версии объекта (шаблона, который хранится в ведре S3).
До (чтобы разрешить SSH и HTTP):
GroupSet:
- Ref: SecurityGroup
После (чтобы разрешить только SSH):
GroupSet:
- Ref: SecurityGroup2
Затем, загрузите этот файл!
$ aws s3 cp cfn-demo.yaml s3://cfn-bucket-template
upload: ./cfn-demo.yaml to s3://cfn-bucket-template/cfn-demo.yaml
Теперь давайте снова обновим стек, используя URL объекта S3 в качестве источника шаблона!
(Будет использоваться самая новая версия шаблона)
$ aws cloudformation update-stack --stack-name cfn-demo --template-url https://cfn-bucket-template.s3.ap-southeast-3.amazonaws.com/cfn-demo.yaml
{
"StackId": "arn:aws:cloudformation:ap-southeast-3:0123456789:stack/cfn-demo/2953bb10-ced2-11ec-a796-06bb617a2d70"
}
Выход:
$ aws cloudformation describe-stacks --stack-name cfn-demo
{
"Stacks": [
{
"StackId": "arn:aws:cloudformation:ap-southeast-3:0123456789:stack/cfn-demo/2953bb10-ced2-11ec-a796-06bb617a2d70",
"StackName": "cfn-demo",
"Parameters": [
{
"ParameterKey": "EC2Type",
"ParameterValue": "t3.micro"
}
],
"CreationTime": "2022-05-08T13:24:17.386Z",
"LastUpdatedTime": "2022-05-08T13:40:42.678Z",
"RollbackConfiguration": {},
"StackStatus": "UPDATE_COMPLETE",
"DisableRollback": false,
"NotificationARNs": [],
"Outputs": [
{
"OutputKey": "EC2IpAddress",
"OutputValue": "108.136.160.193",
"Description": "EC2 Public IP Address"
}
],
"Tags": [],
"EnableTerminationProtection": false,
"DriftInformation": {
"StackDriftStatus": "NOT_CHECKED"
}
}
]
}
Хотя мы меняем только группу безопасности, но через стек он заменит экземпляр EC2 на новый. Поэтому, возможно, это может быть обзор для нас, чтобы выбрать, что будет выполняться через CloudFormation или другими способами, скажем, вручную, может быть, через консоль, CLI, или что-то еще. Здесь я просто покажу вам основные моменты, когда мы используем CloudFormation через CLI и используем S3 для хранения шаблона.
Хорошо, давайте продолжим проверку! Текущий экземпляр должен быть доступен только через SSH.
$ telnet 108.136.160.193 80
Trying 108.136.160.193...
^C
$ ssh ec2-user@108.136.160.193
__| __|_ )
_| ( / Amazon Linux 2 AMI
___|___|___|
https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-172-16-1-12 ~]$ exit
logout
Connection to 108.136.160.193 closed.
Все работает! Теперь я хочу сделать еще одно изменение, но я буду использовать только первую (самую старую) версию объекта, не внося никаких изменений в шаблон. Я просто хочу вернуться назад, создав новый экземпляр, используя первую группу безопасности, которая разрешает SSH и HTTP. Это одно из преимуществ использования версионности S3 для хранения шаблона.
Получите идентификатор версии, а я возьму нижнюю!
$ aws s3api list-object-versions --bucket cfn-bucket-template --query 'Versions[].[Key, VersionId]'
[
[
"cfn-demo.yaml",
"vtPszUgfpn8S9VZj5r6uHWKYL9HSlDRV"
],
[
"cfn-demo.yaml",
"0DY8PO_LdRI_1WcppeMBSFc_ey5Djuxf"
]
]
Теперь давайте сделаем последнее обновление стека, используя URL объекта S3 в качестве источника шаблона! Пожалуйста, не забудьте указать ID версии, добавив ?versionId=xxx
сразу после URL объекта.
$ aws cloudformation update-stack --stack-name cfn-demo --template-url https://cfn-bucket-template.s3.ap-southeast-3.amazonaws.com/cfn-demo.yaml?versionId=0DY8PO_LdRI_1WcppeMBSFc_ey5Djuxf
{
"StackId": "arn:aws:cloudformation:ap-southeast-3:01234567890:stack/cfn-demo/2953bb10-ced2-11ec-a796-06bb617a2d70"
}
Выход:
$ aws cloudformation describe-stacks --stack-name cfn-demo
{
"Stacks": [
{
"StackId": "arn:aws:cloudformation:ap-southeast-3:0123456789:stack/cfn-demo/2953bb10-ced2-11ec-a796-06bb617a2d70",
"StackName": "cfn-demo",
"Parameters": [
{
"ParameterKey": "EC2Type",
"ParameterValue": "t3.micro"
}
],
"CreationTime": "2022-05-08T13:24:17.386Z",
"LastUpdatedTime": "2022-05-08T13:49:09.816Z",
"RollbackConfiguration": {},
"StackStatus": "UPDATE_COMPLETE",
"DisableRollback": false,
"NotificationARNs": [],
"Outputs": [
{
"OutputKey": "EC2IpAddress",
"OutputValue": "108.136.160.169",
"Description": "EC2 Public IP Address"
}
],
"Tags": [],
"EnableTerminationProtection": false,
"DriftInformation": {
"StackDriftStatus": "NOT_CHECKED"
}
}
]
}
Затем HTTP-порт нашего нового экземпляра EC2 должен быть открыт обратно.
4. Удаление шаблона
Мы загрузили 2 версии шаблона в ведро S3. Поэтому нам нужно удалить версии объектов перед удалением стека, так как мы загружаем файлы вручную (они не включены в стек).
$ aws s3api delete-object --bucket cfn-bucket-template --key cfn-demo.yaml --version-id vtPszUgfpn8S9VZj5r6uHWKYL9HSlDRV
{
"VersionId": "vtPszUgfpn8S9VZj5r6uHWKYL9HSlDRV"
}
$ aws s3api delete-object --bucket cfn-bucket-template --key cfn-demo.yaml --version-id 0DY8PO_LdRI_1WcppeMBSFc_ey5Djuxf
{
"VersionId": "0DY8PO_LdRI_1WcppeMBSFc_ey5Djuxf"
}
5. Удалить стек
Теперь ведро пусто, и мы готовы удалить стек.
$ aws cloudformation delete-stack --stack-name cfn-demo
$ aws cloudformation describe-stacks --stack-name cfn-demo
An error occurred (ValidationError) when calling the DescribeStacks operation: Stack with id cfn-demo does not exist
Вот и все. Мы уже дошли до конца этой статьи.
Что мы сделали?
- Создали шаблон CloudFormation со следующими задачами:
- Создать S3 Bucket
- Создать EC2 (VPC, подсеть, интернет-шлюз, таблицу маршрутизации, группу безопасности и экземпляр EC2).
- Создание, обновление и удаление стека CloudFormation через AWS CLI
- Загрузить объект в ведро S3 через AWS CLI
- Удаление версии объекта S3 через AWS CLI
- Используйте 2 разных источника шаблонов CloudFormation – локальный файл и S3 URL.
Вот и все! Спасибо, что пришли, и я с нетерпением жду ваших отзывов. Следите за мной, чтобы получать уведомления о публикации новых статей!