I would like to add lifecycle hooks to my Elastic Beanstalk's autoscaling group. I see how lifecycle hooks can be added to an autoscaling group through cloudformation, but I don't know how this can be done through Elastic Beanstalk.
To create a lifecycle hook on an autoscaling group, you need the autoscaling group's name. This doesn't appear to be possible since the Elastic Beanstalk resource doesn't have an export for the ASG name.
Type: AWS::AutoScaling::LifecycleHook
Properties:
AutoScalingGroupName: String
DefaultResult: String
HeartbeatTimeout: Integer
LifecycleHookName: String
LifecycleTransition: String
NotificationMetadata: String
NotificationTargetARN: String
RoleARN: String
The Elastic Beanstalk doesn't allow defining this configuration either. It does allow defining an sns topic, but adding one doesn't appear to change the configuration in the console, and scaling operations don't appear to be using this topic.
- Namespace: aws:elasticbeanstalk:sns:topics
OptionName: NotificationTopicARN
Value: !ImportValue MyLifecycleHookTopic
How can I add Lifecycle hooks to my Elastic Beanstalk application, so that terminating an environment can go through my graceful shutdown process?
You might be able to use .ebextensions files to further modify settings like these.
Resources:
lifecyclehook:
Type: AWS::AutoScaling::LifecycleHook
Properties:
AutoScalingGroupName: { "Ref" : "AWSEBAutoScalingGroup" }
LifecycleHookName: "autoscaling:EC2_INSTANCE_TERMINATING"
https://github.com/awsdocs/aws-elastic-beanstalk-developer-guide/blob/master/doc_source/environment-resources.md
Related
Is there a way to assign an elastic ip to a ec2 instance that was just made using cloud formation scripts in amazon aws? I'm not able to find any simple examples of how to "get an elastic ip" by it's tag, or any api references about whether or not this is even possible. I need to first get the elastic ip by it's tag, and then assign it to an existing instance in lambda.
In the AWS CLI (I'm using 2.2.4) I can get EIP's by the Name tag:
aws ec2 describe-addresses --filters "Name=tag:Name,Values=some-tag-here"
My tag has the Key "Name" as part of it.
For Python/Boto3 you can run something like:
import boto3
client = boto3.client('ec2')
response=client.describe_addresses(...)
where the parameters to describe_addresses are defined in these docs.
From AWS::EC2::EIP - AWS CloudFormation:
MyEIP:
Type: AWS::EC2::EIP
Properties:
InstanceId: !Ref Logical name of an AWS::EC2::Instance resource
The easiest way is to include this in the same template that launched the EC2 instance. The !Ref can then refer to the instance elsewhere in the template. If you want to assign an Elastic IP address in a separate template, then you would need to provide a reference to the EC2 instance that was previously launched.
I am trying to create an EKS cluster via CloudFormation. I have read all the EKS Security Group guidelines by Amazon and already put in place my security groups as I want clearer more tidy naming and also to be able to define the intricacies between these and some others (BastionHost SG and RDS SG) beforehand.
For the love of God I cannot understand why it keeps creating the Cluster Security Group by itself ignoring the one that I am passing as reference in my template and also the same thing kind of happens in the NodeGroup's remote access security group where I specify my Bastion Host's security group. Instead of accepting it it goes on to create a new security group of its own which has as source the security group of my BastionHost.
Literally confused. Can I overcome this?
Update:
So I am having the 3 security groups that Amazon suggests for my EKS. Let's call them cluster-sg, control-plane-sg, and nodegroup-sg. Also assume that they have been configured as per the guide above adopting the "recommended" inbound/outbound traffic guidelines and not the minimum (although I don't see this playing an important role at this part). Additionally there is the security group of a separate EC2 instance which is my Bastion Host, let's call it bastion-sg.
My CloudFormation template looks like this:
EKSCluster:
Type: 'AWS::EKS::Cluster'
Properties:
Name: 'my-cluster'
Version: '1.17'
ResourcesVpcConfig:
SecurityGroupIds:
- !Ref clusterSG #do I need this cluster-sg here? do I need also nodegroup-sg? do I need both?
SubnetIds:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
- !Ref PrivateSubnet3
RoleArn: !GetAtt ClusterInstanceRole.Arn
NodeGroupCluster:
Type: AWS::EKS::Nodegroup
Properties:
ClusterName: !Ref EKSCluster
DiskSize: !Ref ClusterDiskSize
InstanceTypes: !Ref NodeInstanceTypes
ForceUpdateEnabled: false
NodegroupName: 'cluster-nodegroup'
NodeRole: !GetAtt NodeInstanceRole.Arn #this is a resource that I haven't provided
RemoteAccess:
Ec2SshKey: !Ref EC2KeyPair
SourceSecurityGroups:
- !Ref bastionSG
ScalingConfig:
DesiredSize: !Ref DesiredNodeSize
MaxSize: !Ref MaximumNodeSize
MinSize: !Ref MinimumNodeSize
Subnets:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
- !Ref PrivateSubnet3
All in all the issue is two-fold:
a) I seem to be missing where to put what in terms of configuration and security groups. i.e. I have 3 security groups recommended by Amazon for the whole cluster but only two places where security groups are accepted.
b) Any combination that I have tried (as per my original post) does not take into consideration the cluster-sg but auto-creates one on its own which is not convenient for my IaaC and auto-deploy philosophy.
I was going through the same issue. The EKS Control Plane is on a separate VPC somewhere within AWS. When we create the EKS Cluster,it automatically will create an ENI with which it will attach a security group which will be used in communication between control plane and worker nodes. This SG for the cluster will always get created no matter what. Now, if you are passing other security groups as the argument for SG in your cloudformation script it will simply attach those security groups as well with the ENI which was created. If you launch a Nodegroup NG-1 and attach it with a different security group, then make sure to provide the SG in the cluster cloudformation script so that it can attach that security group with the ENI and open respective ports so worker nodes can communicate with the cluster.
I created launchtemplate with a dedicated SG and used the same launchtemplate to create an NodeGroup. Also I mentioned the SG of my Launchtemplate in the cluster script in CF so as to make sure that my nodes can communicate with the control plane else the nodegroups will fail to launch.
So in short just remember following points:
-There will always be a security group created by cluster
-ClusterSG or any other SG which you are passing in your cf cluster script will be attached to the ENI created by EKS on launch.
Please refer to the following documentation to get a better understanding.
https://docs.aws.amazon.com/eks/latest/userguide/sec-group-reqs.html
Using the eb CLI, one can enable SSH through eb ssh. This recreates all instances, and I'm assuming it updates the security group ingress rules & adds the correct keys to the instances.
How can one programmatically achieve this (terraform, pulumi, CF ... - I am using Pulumi but any will do) ?
In CloudFormation, for example, in your AWS::ElasticBeanstalk::ConfigurationTemplate you can use OptionSettings to provide EC2KeyName.
For instance;
Resources:
MyConfingTemplate:
Type: AWS::ElasticBeanstalk::ConfigurationTemplate
Properties:
ApplicationName: YourApplicationName
OptionSettings:
- Namespace: aws:autoscaling:launchconfiguration
OptionName: EC2KeyName
Value: <key-pair-name>
SolutionStackName: 64bit Amazon Linux 2 v3.1.0 running Python 3.7
You don't have to modify security groups. They will automatically allow ssh.
I am building a cloud formation template(YML format) for my ECS service and stuck in load-balancer target group, it was not able to attach to my ECS instance and trying to add Targets by referring this official AWS docs https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-elasticloadbalancingv2-targetgroup-targetdescription.html
Below is my target group and as I stop start(which terminates) my instance several times, my instance id will be changing all the time and will not be static, like VPC or subnet ids and how can I build the value dynamically in Id field of Targets ?
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Matcher:
HttpCode: "200"
Name: "foo"
Port: "8080"
Protocol: "HTTP"
Targets:
Id: String // This I need to build dynamically
Port: 8080
TargetType: "instance"
UnhealthyThresholdCount: 3
VpcId: "vpc-79251d11"
Note: I tried search for EC2 resources and found this https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/quickref-ec2.html but it didn't help me. Also I am using ASG and LC to create my ECS instance.
Based on the discussion in chat.
Since the instances will be running in an Auto Scaling Group, there is no need to specify their ids directly in the TargetGroup resource of type AWS::ElasticLoadBalancingV2::TargetGroup.
Instead TargetGroup ARN should be provided in the AWS::AutoScaling::AutoScalingGroup resource. Specifically, TargetGroupARNs parameter:
A list of Amazon Resource Names (ARN) of target groups to associate with the Auto Scaling group. Instances are registered as targets in a target group, and traffic is routed to the target group.
For example, since your AWS::ElasticLoadBalancingV2::TargetGroup resource is called TargetGroup, when defining your ASG you would do the following (if same template file):
MyASG:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
# only one parameter shown
TargetGroupARNs:
- !Ref TargetGroup
Naturally, you would skip Targets parameter in your TargetGroup. This will make MyASG automatically register/de-register your instances from the TargetGroup.
I am templating an EB app and several environments. I want to ensure that the ELB is set to be internal, but cant find the reference in the Cloudformation documentation.
You can configure an internal Elastic Load Balancer within an Elastic Beanstalk application by setting the ELBScheme property in the EB's aws:ec2:vpc namespace:
Specify internal if you want to create an internal load balancer in your VPC so that your Elastic Beanstalk application cannot be accessed from outside your VPC.
To configure this within a CloudFormation template, add the option to the OptionSettings property of your AWS::ElasticBeanstalk::Environment resource:
Type: AWS::ElasticBeanstalk::Environment
Properties:
ApplicationName: !Ref AppName
SolutionStackName: !Ref SolutionStackName
OptionSettings:
-
Namespace: "aws:ec2:vpc"
OptionName: ELBScheme
Value: internal
It's the "Scheme" parameter: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-elb.html#cfn-ec2-elb-scheme
Accepts either 'internal' or 'internet-facing' as a string.