The elastic-ip-manager, manages the assignment of a pool of Elastic IP addresses to instances. When the instance is stopped or terminated, the elastic ip address is removed. When a new instance is started, an elastic ip is assigned to it.
The manager will listen to all EC2 instance state change notifications. When an instance with the tag elastic-ip-manager-pool
reaches the state running, it will assign a free elastic ip addresses with the same tag and tag value.
You can start using the elastic IP manager, in two simple steps:
- create a pool of tagged elastic IP addresses
- create an auto scaling group of tagged instances OR adjust autoscaling group of existing ones
To deploy the provider, type: ~
cd ..
git clone https://github.com/binxio/ec2-elastic-ip-manager.git
cd ec2-elastic-ip-manager
LAMBDA_BUCKET_PREFIX=binxio-public
LAMBDA_BUCKET_REGION=eu-central-1
make S3_BUCKET_PREFIX=${LAMBDA_BUCKET_PREFIX:-binxio-public} AWS_REGION=${LAMBDA_BUCKET_REGION:-eu-central-1} deploy
aws cloudformation create-stack \
--capabilities CAPABILITY_IAM \
--stack-name elastic-ip-manager \
--template-body file://./cloudformation/elastic-ip-manager.yaml \
--parameters ParameterKey=LambdaS3Bucket,ParameterValue=${LAMBDA_BUCKET_PREFIX}-${LAMBDA_BUCKET_REGION} \
--parameters ParameterKey=CFNCustomProviderZipFileName,ParameterValue=lambdas/elastic-ip-manager-latest.zip
Create a pool of elastic ip addresses, and tag them with an elastic-ip-manager-pool
value:
EIP1:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
-
Key: "elastic-ip-manager-pool"
Value: bastion
Create an auto scaling group and apply the tag elastic-ip-manager-pool
to all the instances:
AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
...
Tags:
- Key: elastic-ip-manager-pool
Value: bastion
PropagateAtLaunch: true
The manager will automatically associate elastic ip addresses to instance tagged with elastic-ip-manager-pool
. It does
this by subscribing to EC2 state change events. It will not do anything on instances without the
tag elastic-ip-manager-pool
. The elastic IP manager also syncs the state every 5 minutes, to ensure that we are eventually
consistent in the face of errors.
If an auto scaling group with instances already exist,
aws autoscaling create-or-update-tags --tags ResourceId=elastic-ip-manager-demo,ResourceType=auto-scaling-group,Key=elastic-ip-manager-pool,Value=bastion,PropagateAtLaunch=true
instances=$(aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names elastic-ip-manager-demo | jq -r '..|.InstanceId?| select(. != null)' | tr '\n' ' ')
aws ec2 create-tags --resources `echo $instances` --tags Key=elastic-ip-manager-pool,Value=bastion
That is all. If you want to see it all in action, deploy the demo.
Run these commands to deploy the demo using CloudFormation Stack:
export VPC_ID=$(aws ec2 --output text --query 'Vpcs[?IsDefault].VpcId' describe-vpcs)
export SUBNET_IDS=$(aws ec2 describe-subnets --output text \
--filters Name=vpc-id,Values=$VPC_ID Name=default-for-az,Values=true --query 'Subnets[?MapPublicIpOnLaunch].SubnetId' \
| tr '\t', '\,')
aws cloudformation create-stack --stack-name elastic-ip-manager-demo \
--template-body file://./cloudformation/demo-stack.yaml \
--parameters ParameterKey=VPC,ParameterValue=$VPC_ID ParameterKey=Subnets,ParameterValue=\"$SUBNET_IDS\"
Make sure you have terraform 0.12+ installed and run these commands:
export VPC_ID=$(aws ec2 --output text --query 'Vpcs[?IsDefault].VpcId' describe-vpcs)
export SUBNET_LIST=$(aws ec2 describe-subnets --output json \
--filters Name=vpc-id,Values=$VPC_ID Name=default-for-az,Values=true --query 'Subnets[?MapPublicIpOnLaunch].SubnetId' \
| tr -d '\n ')
cd ./terraform/demo
terraform init
terraform apply -var="vpc_id=$VPC_ID" -var="subnets=$SUBNET_LIST"
There are two alternative solutions to achieve the same functionality:
- use a network load balancer
- associate an address on instance startup In my use case, I did not want to spent money on keeping an NLB running nor give the instance all the permissions to associate an EIP to itself.