cloud:aws:cloudformation
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| cloud:aws:cloudformation [2018/08/09 15:12] – [Code Style] skipidar | cloud:aws:cloudformation [2023/12/05 15:02] (current) – skipidar | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ===== CloudFormation ===== | ===== CloudFormation ===== | ||
| + | |||
| + | ==== Why is Terraform better? ==== | ||
| + | |||
| + | * " | ||
| + | * " | ||
| + | * " | ||
| + | * CloudFormation has a very NOT user friendly lifecycle. Forcing to "is in ROLLBACK_COMPLETE state and can not be updated" | ||
| + | * Minor. Cloudformation " | ||
| + | * Cloudformation support of moving resources between stacks is very chatty | ||
| + | |||
| + | |||
| + | ==== Deploying with cloudformation ==== | ||
| + | |||
| + | If using nested-stacks first you need a bucket, | ||
| + | into which you will package nested stacks. | ||
| + | |||
| + | <sxh yaml> | ||
| + | AWSTemplateFormatVersion: | ||
| + | Description: | ||
| + | Resources: | ||
| + | |||
| + | MyS3SubstackBucket: | ||
| + | Type: AWS:: | ||
| + | Properties: | ||
| + | BucketName: my-alf-s3-package-bucket-2023-12-05 | ||
| + | AccessControl: | ||
| + | Tags: | ||
| + | - Key: Purpose | ||
| + | Value: CF stacks bucket | ||
| + | |||
| + | |||
| + | MyBucketPolicy: | ||
| + | Type: AWS:: | ||
| + | Properties: | ||
| + | Bucket: !Ref MyS3SubstackBucket | ||
| + | PolicyDocument: | ||
| + | Statement: | ||
| + | - Sid: AllowCloudFormationAccess | ||
| + | Effect: Allow | ||
| + | Principal: | ||
| + | Service: cloudformation.amazonaws.com | ||
| + | Action: s3:* | ||
| + | Resource: !Join | ||
| + | - '' | ||
| + | - - ' | ||
| + | - !Ref MyS3SubstackBucket | ||
| + | - /* | ||
| + | </ | ||
| + | |||
| + | now deploy the bucket | ||
| + | <sxh shell> | ||
| + | |||
| + | FILENAME=" | ||
| + | STACKNAME=" | ||
| + | REGION=" | ||
| + | |||
| + | # validate | ||
| + | aws cloudformation validate-template --template-body file:// | ||
| + | |||
| + | |||
| + | # check the change set | ||
| + | aws cloudformation deploy --stack-name $STACKNAME --template-file $FILENAME --region $REGION --no-execute-changeset | ||
| + | |||
| + | |||
| + | # execute via " | ||
| + | aws cloudformation deploy --stack-name $STACKNAME --template-file $FILENAME --region $REGION | ||
| + | |||
| + | |||
| + | # delete stack | ||
| + | # aws cloudformation delete-stack --stack-name $STACKNAME | ||
| + | </ | ||
| + | |||
| + | |||
| + | parent1.cloudformation.yaml | ||
| + | <sxh yaml> | ||
| + | AWSTemplateFormatVersion: | ||
| + | Description: | ||
| + | |||
| + | Parameters: | ||
| + | |||
| + | VpcIdParameter: | ||
| + | Type: String | ||
| + | Default: " | ||
| + | | ||
| + | packageBucket: | ||
| + | Type: String | ||
| + | Default: " | ||
| + | |||
| + | Resources: | ||
| + | |||
| + | SubStack1: | ||
| + | Type: AWS:: | ||
| + | Properties: | ||
| + | TemplateURL: | ||
| + | Parameters: | ||
| + | VpcId: !Ref VpcIdParameter | ||
| + | |||
| + | </ | ||
| + | |||
| + | substack.helloworld.cloudformation.yaml | ||
| + | <sxh yaml> | ||
| + | AWSTemplateFormatVersion: | ||
| + | Description: | ||
| + | |||
| + | Parameters: | ||
| + | VpcId: | ||
| + | Type: String | ||
| + | |||
| + | |||
| + | Resources: | ||
| + | |||
| + | MySecurityGroup: | ||
| + | Type: AWS:: | ||
| + | Properties: | ||
| + | GroupDescription: | ||
| + | VpcId: !Ref VpcId | ||
| + | SecurityGroupIngress: | ||
| + | - IpProtocol: tcp | ||
| + | FromPort: 80 | ||
| + | ToPort: 80 | ||
| + | CidrIp: 0.0.0.0/0 # Example: Allowing HTTP traffic from anywhere (Please adjust for your use case) | ||
| + | Tags: | ||
| + | - Key: Name | ||
| + | Value: MySecurityGroup | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | now you can package the stack | ||
| + | |||
| + | * the sub-stacks will end up in the package-bucket. | ||
| + | * a new file `packaged-root-template.yaml` is generated, where the `TemplateURL` field is replaced by s3 references. | ||
| + | * you can deploy the parent stack and see nested stacks being deployed too. | ||
| + | |||
| + | |||
| + | |||
| + | <sxh shell> | ||
| + | set -e | ||
| + | |||
| + | FILENAME=" | ||
| + | STACKNAME=" | ||
| + | REGION=" | ||
| + | PACKAGEBUCKET=" | ||
| + | |||
| + | |||
| + | # validate | ||
| + | # aws cloudformation validate-template --template-body file:// | ||
| + | |||
| + | |||
| + | # package uploading substacks | ||
| + | rm packaged-root-template.yaml | ||
| + | aws cloudformation package --template-file $FILENAME --s3-bucket $PACKAGEBUCKET | ||
| + | |||
| + | |||
| + | |||
| + | # check the change set, dont execute : " | ||
| + | # aws cloudformation deploy --stack-name $STACKNAME --template-file $FILENAME --region $REGION --no-execute-changeset | ||
| + | |||
| + | # arn of change set is printed, here arn: | ||
| + | |||
| + | # can see change-set | ||
| + | # aws cloudformation describe-change-set --change-set-name arn: | ||
| + | |||
| + | # can continue via | ||
| + | # aws cloudformation execute-change-set --change-set-name arn: | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | # execute via " | ||
| + | aws cloudformation deploy --stack-name $STACKNAME --template-file packaged-root-template.yaml --region $REGION | ||
| + | |||
| + | |||
| + | # delete stack | ||
| + | # aws cloudformation delete-stack --stack-name $STACKNAME | ||
| + | </ | ||
| + | |||
| ==== Structure ==== | ==== Structure ==== | ||
| Line 22: | Line 201: | ||
| Instead a special script must be executed within the UserData block. | Instead a special script must be executed within the UserData block. | ||
| - | <code> | + | <sxh js> |
| " | " | ||
| " | " | ||
| Line 40: | Line 219: | ||
| "/ | "/ | ||
| ]]} | ]]} | ||
| - | </code> | + | </sxh> |
| For details see: https:// | For details see: https:// | ||
| Line 48: | Line 227: | ||
| https:// | https:// | ||
| - | <code> | + | <sxh js> |
| "/ | "/ | ||
| - | </code> | + | </sxh> |
| Line 180: | Line 359: | ||
| } | } | ||
| + | </ | ||
| + | |||
| + | ==== Use !Sub in commands ==== | ||
| + | |||
| + | To reference cloudformation arguments in commands - use the " | ||
| + | < | ||
| + | Resources: | ||
| + | Parameters: | ||
| + | S3Prefix: | ||
| + | AllowedPattern: | ||
| + | ^s3:// | ||
| + | Description: | ||
| + | Type: String | ||
| + | |||
| + | ... | ||
| + | 04_execute: | ||
| + | command: !Sub | | ||
| + | ansible-playbook / | ||
| </ | </ | ||
| Line 558: | Line 755: | ||
| | Human readable logs of the whole instance initiation | / | | Human readable logs of the whole instance initiation | / | ||
| | Human readable logs of the cfn-init call | / | | Human readable logs of the cfn-init call | / | ||
| + | | Code from AWS:: | ||
| + | |||
| + | |||
| + | |||
| === Debug the initiation of the instance === | === Debug the initiation of the instance === | ||
| Line 599: | Line 800: | ||
| Exporting Stack Output Values vs. Using Nested Stacks: | Exporting Stack Output Values vs. Using Nested Stacks: | ||
| - | * https:// | + | * https:// |
| * https:// | * https:// | ||
| * https:// | * https:// | ||
| Line 607: | Line 808: | ||
| Stack A Export: | Stack A Export: | ||
| - | <code> | + | <sxh js> |
| " | " | ||
| " | " | ||
| Line 620: | Line 821: | ||
| } | } | ||
| } | } | ||
| - | </code> | + | </sxh> |
| Stack B Import | Stack B Import | ||
| - | <code> | + | <sxh js> |
| " | " | ||
| " | " | ||
| Line 640: | Line 841: | ||
| } | } | ||
| } | } | ||
| - | </code> | + | </sxh> |
| AWS specific parameters: | AWS specific parameters: | ||
| * https:// | * https:// | ||
| + | |||
| + | |||
| + | |||
| + | ==== Structure ==== | ||
| + | |||
| + | |||
| + | Example of a custom definition in CLoudFormation. EFS with Fargate in this example | ||
| + | < | ||
| + | |||
| + | CustomTaskDefinition: | ||
| + | Type: ' | ||
| + | Version: ' | ||
| + | Properties: | ||
| + | ServiceToken: | ||
| + | TaskDefinition: | ||
| + | executionRoleArn: | ||
| + | containerDefinitions: | ||
| + | { | ||
| + | name: " | ||
| + | image: !Ref NavvisDockerImage, | ||
| + | memoryReservation: | ||
| + | logConfiguration: | ||
| + | logDriver: " | ||
| + | options: { | ||
| + | awslogs-group: | ||
| + | awslogs-datetime-format: | ||
| + | awslogs-region: | ||
| + | awslogs-stream-prefix: | ||
| + | } | ||
| + | }, | ||
| + | portMappings: | ||
| + | { | ||
| + | hostPort: 8080, | ||
| + | protocol: " | ||
| + | containerPort: | ||
| + | } | ||
| + | ], | ||
| + | command: [], | ||
| + | " | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | , | ||
| + | | ||
| + | | ||
| + | ] | ||
| + | } | ||
| + | ], | ||
| + | family: " | ||
| + | taskRoleArn: | ||
| + | requiresCompatibilities: | ||
| + | cpu: " | ||
| + | memory: " | ||
| + | networkMode: | ||
| + | volumes: [ | ||
| + | { | ||
| + | name: " | ||
| + | efsVolumeConfiguration: | ||
| + | fileSystemId: | ||
| + | } | ||
| + | }, | ||
| + | ] | ||
| + | } | ||
| + | CustomResourceFunction: | ||
| + | Type: ' | ||
| + | Properties: | ||
| + | Code: | ||
| + | ZipFile: | | ||
| + | const aws = require(' | ||
| + | const response = require(' | ||
| + | const ecs = new aws.ECS({apiVersion: | ||
| + | exports.handler = function(event, | ||
| + | console.log(" | ||
| + | if (event.RequestType === ' | ||
| + | ecs.registerTaskDefinition(event.ResourceProperties.TaskDefinition, | ||
| + | if (err) { | ||
| + | console.error(err); | ||
| + | response.send(event, | ||
| + | } else { | ||
| + | console.log(`Created/ | ||
| + | response.send(event, | ||
| + | } | ||
| + | }) | ||
| + | } else if (event.RequestType === ' | ||
| + | ecs.deregisterTaskDefinition({taskDefinition: | ||
| + | if (err) { | ||
| + | if (err.code === ' | ||
| + | console.log(`Task definition: ${event.PhysicalResourceId} does not exist. Skipping deletion.`) | ||
| + | response.send(event, | ||
| + | } else { | ||
| + | console.error(err) | ||
| + | response.send(event, | ||
| + | } | ||
| + | } else { | ||
| + | console.log(`Removed task definition ${event.PhysicalResourceId}`) | ||
| + | response.send(event, | ||
| + | } | ||
| + | }) | ||
| + | } else { | ||
| + | console.error(`Unsupported request type: ${event.RequestType}`) | ||
| + | response.send(event, | ||
| + | } | ||
| + | } | ||
| + | Handler: ' | ||
| + | MemorySize: 128 | ||
| + | Role: !GetAtt ' | ||
| + | Runtime: ' | ||
| + | Timeout: 30 | ||
| + | CustomResourceRole: | ||
| + | Type: ' | ||
| + | Properties: | ||
| + | AssumeRolePolicyDocument: | ||
| + | Version: ' | ||
| + | Statement: | ||
| + | - Effect: Allow | ||
| + | Principal: | ||
| + | Service: ' | ||
| + | Action: ' | ||
| + | Policies: | ||
| + | - PolicyName: ' | ||
| + | PolicyDocument: | ||
| + | Statement: | ||
| + | - Effect: Allow | ||
| + | Action: | ||
| + | - ' | ||
| + | - ' | ||
| + | Resource: ' | ||
| + | - Effect: Allow | ||
| + | Action: | ||
| + | - ' | ||
| + | - ' | ||
| + | - ' | ||
| + | Resource: ' | ||
| + | - Effect: Allow | ||
| + | Action: | ||
| + | - ' | ||
| + | Resource: ' | ||
| + | CustomLogsGroup: | ||
| + | Type: ' | ||
| + | Properties: | ||
| + | LogGroupName: | ||
| + | RetentionInDays: | ||
| + | |||
| + | |||
| + | NavvisServiceFargate: | ||
| + | Type: ' | ||
| + | Properties: | ||
| + | Cluster: {' | ||
| + | LaunchType: FARGATE | ||
| + | DesiredCount: | ||
| + | PlatformVersion: | ||
| + | DeploymentConfiguration: | ||
| + | MinimumHealthyPercent: | ||
| + | MaximumPercent: | ||
| + | TaskDefinition: | ||
| + | NetworkConfiguration: | ||
| + | AwsvpcConfiguration: | ||
| + | AssignPublicIp: | ||
| + | SecurityGroups: | ||
| + | - {' | ||
| + | Subnets: | ||
| + | - {' | ||
| + | - {' | ||
| + | - {' | ||
| + | LoadBalancers: | ||
| + | - ContainerName: | ||
| + | ContainerPort: | ||
| + | TargetGroupArn: | ||
| + | SchedulingStrategy: | ||
| + | |||
| + | |||
| + | </ | ||
| + | |||
cloud/aws/cloudformation.1533827577.txt.gz · Last modified: (external edit)
