First, make sure you installed aws with mamba install awscli
, make sure to not install this in the same environment as isis.
Log into AWS via the cli https://docs.aws.amazon.com/signin/latest/userguide/command-line-sign-in.html
CloudFormation works simply by defining services in YAML templates that imitate the parameters you would input into the command line.
For example, in order to create a new ECR record, that is, a repository to push docker images to, you would do the following using the AWS CLI:
aws ecr create-repository \
--repository-name postgres \
--image-scanning-configuration scanOnPush=true
But on CloudFormation yaml:
# ECRTemplate.yml
AWSTemplateFormatVersion: 2010-09-09
Description: postgres ECR Deploy
Resources:
Astrocloud:
Type: AWS::ECR::Repository
Properties:
RepositoryName: "postgres"
ImageScanningConfiguration:
ScanOnPush: true
and then deploy the stack with:
aws cloudformation deploy --stack-name PostgresTemplate --template-file ECRTemplate.yml --role-arn your-role-arn
NOTE: Might not need role-arn if you're using a free account since your account might not be as locked down as ours
You can see the parallels clearly by looking at the CloudFormation docs for creating the ECR vs the CLI docs for creating an ECR
Infrastructure as Code (IaC), it allows us to create complete stack deployments more consistently, define them more explicitly in CloudFormation templates, and to manage them more purposefully through source control. Almost as important, our AWS services are configured such that we as developers and users have limited permissions to create or modify a service outside a CloudFormation context. This is because of the issues inherit with modifying services manually via AWS CLI or console.
Additionally, real deployments are often more complex and require policies and roles to be attached.
Here is a real example of an ECR deployment for the Astrocloud service with accounts censored:
AWSTemplateFormatVersion: 2010-09-09
Description: Astrocloud ECR Deploy
Resources:
Astrocloud:
Type: AWS::ECR::Repository
Properties:
RepositoryName: "astrocloud"
RepositoryPolicyText:
Version: "2012-10-17"
Statement:
-
Sid: AllowPushPull
Effect: Allow
Principal:
AWS:
- "arn:aws:iam::xxxxxxxxxx:role/xxx-xxxxxxxxxx"
Action:
- "ecr:GetDownloadUrlForLayer"
- "ecr:BatchGetImage"
- "ecr:BatchCheckLayerAvailability"
- "ecr:PutImage"
- "ecr:InitiateLayerUpload"
- "ecr:UploadLayerPart"
- "ecr:CompleteLayerUpload"
And complete deployments require multiple services. Managing them via CLI or Console alone would be time-consuming and error-prone. For example, the complete Astrocloud container deployment running on a Fargate deployment with details removed. Basically, this is a web service running from a docker container.
#prod ssl 443
AWSTemplateFormatVersion: 2010-09-09
Description: Astrocloud SSL Deploy
Resources:
LogGroup:
Type: 'AWS::Logs::LogGroup'
Properties:
Things...
astrocloudProdTaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Stuff...
ContainerDefinitions:
- Stuff...
RequiresCompatibilities:
More Stuff...
ECSastrocloudProdCluster:
Type: 'AWS::ECS::Cluster'
Properties:
- Things...
astrocloudProdFargateAlb:
Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
Properties:
So many properties...
astrocloudProdFargateTargetGroup:
Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
Properties:
More things....
astrocloudListener:
Type: 'AWS::ElasticLoadBalancingV2::Listener'
Properties:
Things...
astrocloudProdFargateAlbSG:
Type: 'AWS::EC2::SecurityGroup'
Properties:
Things...
astrocloudProdSlot1ContainerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
...Things
astrocloudProdSlot1DNS:
Type: "AWS::Route53::RecordSet"
Properties:
DNS Routing Stuff...
astrocloudProdSlot1ECSService:
Type: AWS::ECS::Service
DependsOn:
- astrocloudListener
Properties:
omg even more stuff
Every CF template is basically this:
# Some boilerplate at the top saying this is a AWS CF template
AWSTemplateFormatVersion: 2010-09-09
Description: Astrocloud SSL Deploy
Resources:
LogicalID:
Type: Resource type
Properties:
Set of properties
Resource Type is the AWS service you are trying to create. Some ecamples:
- DNS record:
AWS::Route53::RecordSet
- Docker Repo:
AWS::ECR::Repository
- Security Group:
AWS::EC2::SecurityGroup
- Creating a box on the cloud (i.e., an EC2 instance):
AWS::EC2::Instance
LogicalID is a name you want to give the resource, this is a variable you set and used to reference the resource in within the stack e.g., !REF LogicalID
or !GetAtt LogicalID.Property
in situations where one service needs to reference another one. Like routing a DNS resource to a Load Balancing service:
astrocloudProdSlot1DNS:
Type: "AWS::Route53::RecordSet"
Properties:
HostedZoneName: nau.edu.
Name: myservice.nau.edu
Type: A
AliasTarget:
HostedZoneId: !GetAtt 'astrocloudProdFargateAlb.CanonicalHostedZoneID'
DNSName: !GetAtt 'astrocloudProdFargateAlb.DNSName'
astrocloudProdFargateAlb:
Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
Properties:
Name: astrocloudProdFargateAlb
Scheme: internal
Subnets:
- subnet-xxxxxxxxx
- subnet-xxxxxxxxx
- subnet-xxxxxxxxx
Type: application
SecurityGroups:
- !GetAtt astrocloudProdFargateAlbSG.GroupId
You can usually google "<resource> CloudFormation" and it'll give you the docs for that specific resource type. The docs include the complete list of properties for the resource type.
Look through the properties and intuit what you probably need and what is optional. Properties that are strictly optional are labeled as such in the AWS docs.