we're encountering a strange issue with AWS CloudFormation.
We're using CloudFormation in order to automate the deployment of some our machines; our CloudFormation yml describes the deployment, which contains a persistent EBS volume which was created outside the stack, and we don't want to remove or recreate along such stack (it contains a lot of the state of our application).
The relevant CloudFormation yml snippet is:
DataVolumeAttachment01:
Type: AWS::EC2::VolumeAttachment
Properties:
Device: "/dev/xvdm"
InstanceId: !Ref EC2Instance01
VolumeId: !Ref DataVolumeId
EC2Instance01:
Type: "AWS::EC2::Instance"
Properties:
ImageId: "ami-6f587e1c"
KeyName: !Ref "KeyName"
InstanceType: !Ref "InstanceType"
BlockDeviceMappings:
# Root device
- DeviceName: "/dev/sda1"
Ebs:
VolumeType: "gp2"
DeleteOnTermination: "true"
VolumeSize: 20
So, the root device is "transient" (every time the stack is updated, such volume is deleted and gets reprovisioned with userdata), while /dev/xvdm should contain our persistent data; such device gets mounted at the end of the userdata, and added to fstab.
Following AWS own documentation, I created a script that unmounts such volume from inside the VM, and I even tried deattaching such volume from the EC2 Instance, something like:
${SSH_CMD} "cd /home/application && application stop && sudo umount /data && echo data volume unmounted"
echo "detaching data volume"
VOLID=$(aws ec2 describe-volumes --filters Name=tag-key,Values="Name" Name=tag-value,Values=persistent-volume --query 'Volumes[*].{ID:VolumeId}' --output text)
aws ec2 detach-volume --volume-id "${VOLID}"
I have verified the umount and the detach succeed.
The creation of a new stack with my template and parameters succeeds.
And yet, when I launch
aws cloudformation update-stack --capabilities CAPABILITY_IAM --stack-name $STACK_NAME --template-body file://single_ec2_instance.yml --parameters file://$AWS_PARAMETERS_FILE
The update fails, with this error:
Update to resource type AWS::EC2::VolumeAttachment is not supported.
Even though I'm not changing anything within such resource.
What's up? How can I solve or work around?
It seems that the thing was a non-issue.
Either CloudFormation is influenced by exhausted t2 cpu credits (which we had exhausted, we were trying to change the instance type for that exact reason in order to use m3 or m4) or we got a bad day for EC2/CloudFormation in Ireland. Today, with the same exact setup, every update succeeded.
I just had this problem and found the solution was to Terminate my stack which creates EC2 instances and then redploy.
Related
I have a working cloudFormation yaml template. I know its working because when I go to the aws portal and create a stack by clicking-away the stack gets created.
However, when I try to use the cloudformation on the command line the same yaml errors out.
I'm at loss to what's causing this issue. Does anyone know what may be causing the failure?
Here is the command I am calling
aws cloudformation create-stack --stack-name ${stack_name} --template-body file://template.yaml --region ${region}
where region is the same region I am in the aws portal. And here is the template.yaml
---
AWSTemplateFormatVersion: 2010-09-09
Description: EC2 example instance
Resources:
TestEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-01ec0fa63b2042232
InstanceType: t3.medium
SubnetId: subnet-*********
UserData:
Fn::Base64:
!Sub |
#!/bin/bash -xe
echo "Running apt install -y git nfs-common binutils jq"
apt-get install -y git nfs-common binutils jq
when I run the command I see the stack starting to be created on the portal with the following events
ec2-boilerplate ROLLBACK_COMPLETE -
TestEC2Instance DELETE_COMPLETE -
TestEC2Instance DELETE_IN_PROGRESS -
ec2-boilerplate ROLLBACK_IN_PROGRESS The following resource(s) failed to create: [TestEC2Instance]. Rollback requested by user.
TestEC2Instance CREATE_FAILED Instance i-0bdd3e7ee34edf1ef failed to stabilize. Current state: shutting-down. Reason: Client.InternalError: Client error on launch
TestEC2Instance CREATE_IN_PROGRESS Resource creation Initiated
TestEC2Instance CREATE_IN_PROGRESS -
ec2-boilerplate CREATE_IN_PROGRESS User Initiated
Is it something about my template.yaml? about my command line call? some environment variable?
This may be related to the length of time the instance is taking to create, but your 'userdata' script seems simple enough that it is hard to imagine that being the case. The AWS documentation states that this error relates to the resource creation time exceeding the CloudFormation timeout:
A resource didn't respond because the operation exceeded the AWS
CloudFormation timeout period or an AWS service was interrupted. For
service interruptions, check that the relevant AWS service is running,
and then retry the stack operation.
One quick thing I would check is that the -e option to bash in your userdata script isn't causing it to fail in some way that hinders instance creation.
Another possible solution, per the AWS recommendation, is to ensure that your CloudFormation stack is provided a service role when it is created. This will allow it to create infrastructure beyond the timeout imposed when using the creating user's IAM permissions.
im working on a template in which i deploy an ec2 instance, in the instances user data, the instance pulls a script from a git repo and uses that script create an AMI. I would like to refer to that newly created ami’s ID in another resource in the same cloudformation stack using the either by using !ref or some other way.
so far I have placed this line below in the user data to get the name of the ami
export AMIID=$(aws ec2 describe-images --filters "Name=name,Values=ami-name" | jq -r ".Images[].ImageId")
and this line to create an entry to put the AMI ID in the parameter store
aws ssm put-parameter --name aminame --type String --value "$AMIID"
In the cloudformation stack I have a parameter here
AMI:
Type : 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
Default: aminame
and in the resource block I have this the reference to the ami that looks something like this
EC2Instance:
Type: "AWS::EC2::Instance"
CreationPolicy:
ResourceSignal:
Timeout: PT120M
Properties:
ImageId: !Ref AMI
UserData:
Fn::Base64: |
#!/bin/bash
So far when I run this I get an error stating that the parameter cannot be found.. which makes sense, however is there any other way to do something like this ?
Technically you can do that using lambda:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html
The AWS documentation is so large and confusing, I can't seem to get this working.
I have a docker image that I am deploying onto elasticbeanstalk t2 instance. I want to set the volume to 50 gigs.
It creates the Docker running on 64bit Amazon Linux 2/3.0.1 Platform.
Instance created with:
eb create --single --tier webserver --instance_type t2.nano
I have tried a few solutions suggested and none of them seem to work when i redeploy or create the instance.
Attempt 1:
Inside .ebextensions/options.config
option_settings:
aws:autoscaling:launchconfiguration:
RootVolumeType: gp2
RootVolumeSize: "50"
Attempt 2:
Resources:
AWSEBAutoScalingLaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType:
'gp2'
VolumeSize:
'50'
followed by:
eb deploy
Neither of these change the size of the volume, it's staying put at default.
What am I missing?
I figured out my problem, my .gitignore was setup to ignore the config files.
Both seem to be valid options, not sure which is better.
My requirement is to create an EC2 instance which will have the Keypair created dynamically from the same Cloudformation template.As of now,I am creating the KeyPair from AWS console and assigning it to EC2 instance through Cloudformation by taking the input from the user.
I have checked AWS document and found that the KeyPair can be create from AWS console.
Is there anyway through which Keypair can be created from Cloudformation and copy the .PEM file in the instance.
It's about private key management.
EC2 Keypair has two components. Public and private. The public key is what AWS stores and pushes to the instance on instance creation. The private key is never stored at AWS. The moment you create keypair either with the console or via CLI - you have the one and only chance to store it on your machine.
Cloud formation has no way of storing the private key on your machine as a part of the stack initialization.
You might consider two-step approach here:
1) Either create the key or import one from your machine. In either way you and only you would have access to the Private key part.
aws ec2 import-key-pair
or
aws ec2 create-key-pair
2) Use this newly created key in cloudformation.
SshKeyParameter:
Description: SSH Keypair to login to the instance
Type: AWS::EC2::KeyPair::KeyName
...
KeyName: !Ref SshKeyParameter
followed the Anton's answer and its works fine. written shell script which is launching a cloudformation template and if key is not preset ,script willl create it and will upload it to the s3 bucket.
#!/bin/bash
Region=eu-central-1
key=myapp-engine-$Region
Available_key=`aws ec2 describe-key-pairs --key-name $key | grep KeyName | awk -F\" '{print $4}'`
if [ "$key" = "$Available_key" ]; then
echo "Key is available."
else
echo "Key is not available: Creating new key"
aws ec2 create-key-pair --key-name $key --region $Region > myapp-engine-$Region.pem
aws s3 cp myapp-engine-$Region.pem s3://mybucket/myapp-engine-$Region.pem
fi
##### create stack #########
/usr/local/bin/aws cloudformation deploy --stack-name myapp-engine --template-file ./lc.yml --parameter-overrides file://./config.json --region $Region
Below is an example of a CloudFormation launch configuration stack where you can pass the key.
Resources:
renderEnginelc:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId:
Ref: "AMIID"
SecurityGroups:
- Fn::ImportValue:
!Sub "${SGStackName}-myapp"
InstanceType:
Ref: InstanceType
LaunchConfigurationName : !Join [ "-", [ !Ref Environment, !Ref ApplicationName, lc ] ]
KeyName: !Join [ "-", [ !Ref KeyName, !Ref AWS::Region ] ]
Passing a paramter value of KeyName is "myapp-engine" and it will consider a region according to AWS::Region
Anton's answer is correct.
However, there are alternatives using other tools. Usually they allow to automate the public key import.
Ansible: https://docs.ansible.com/ansible/latest/collections/amazon/aws/ec2_key_module.html#ansible-collections-amazon-aws-ec2-key-module
Terraform: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/key_pair
Or even: https://binx.io/blog/2017/10/25/deploying-private-key-pairs-with-aws-cloudformation/
I'm creating a cloud9 instance in cloudformation as follows:
Resources:
DevEnv:
Type: 'AWS::Cloud9::EnvironmentEC2'
Properties:
SubnetId: !Ref PublicSubnet
Name: MyEnvironment
InstanceType: !Ref Cloud9InstanceType
Subsequently, I want to run a bash script on that EC2 instance (within the cloudformation script) to set it up properly. How do I do that?
Unfortunately you can't. AWS::Cloud9::EnvironmentEC2 doesn't expose UserData or something like that and you cannot run SSM Documents against Cloud9 instances.
The closest you can get is using Repositories to clone a AWS CodeCommit into the instance, and that repository has a script that you run manually first time you connect...