This is a bootstrap container for Bottlerocket that associates an elastic IP address to the EC2 instance when it starts up. This is useful if you want to run an EC2 instance that maintains the same IP address even if it is replaced. You can also associate an address from a pool of elastic IP addresses (see below for additional options).
Because Bottlerocket doesn't allow for traditional startup scripts in the user data, you can't just run aws-cli commands like you may be used to. Bottlerocket provides a way to run bootstrap containers instead, which you can use to configure the system when it starts up.
A Rust program compiled using musl was picked to minimize the size of the docker image (the docker image is about 3 MB compressed). It is published on Amazon Public ECR: https://gallery.ecr.aws/stefansundin/bottlerocket-bootstrap-associate-eip
Here's how to configure it in your Bottlerocket user data:
[settings.bootstrap-containers.associate-eip]
source = "public.ecr.aws/stefansundin/bottlerocket-bootstrap-associate-eip:latest"
mode = "once"
essential = false
user-data = "ZWlwYWxsb2MtMDEyMzQ1Njc4OTBhYmNkZWYK"
The user-data
contains the Elastic IP Allocation ID that you want to associate with the instance, encoded using base64. You can generate it like this:
echo eipalloc-01234567890abcdef | base64
There are additional features besides the simple use-case demonstrated above. To use the additional options you need to pass in a JSON string in the user-data
instead of just the eipalloc
identifier.
echo '{"AllocationId":"eipalloc-01234567890abcdef","AllowReassociation":true}' | base64
If you want to dynamically find an EIP to use, e.g. based on tags, then you can use the Filters
option (equivalent to --filters
for aws ec2 describe-addresses
):
echo '{"Filters":[{"Name":"tag:Pool","Values":["ecs"]}]}' | base64
Warning
When Filters
is used, the program will try to pick an unallocated EIP at random. If all the EIPs are in use then one will be chosen at random anyway. Set AllowReassociation
to false
to exit with an error instead.
You can specify an empty array to have the program pick any EIP in the account:
echo '{"Filters":[]}' | base64
Reference:
- Either
AllocationId
orFilters
is required. AllowReassociation
istrue
if omitted.
Tested on Bottlerocket v1.9.2 and v1.10.0.
Make sure your instance has permissions to associate elastic IP addresses.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:AssociateAddress",
"ec2:DescribeAddresses"
],
"Resource": "*"
}
]
}
You only need ec2:DescribeAddresses
if you want to use the Filters
option.
You can get the output from the docker container by running:
enter-admin-container
sheltie
journalctl -u bootstrap-containers@associate-eip.service
If you are unable to connect to the instance then wait 10 minutes and then check the EC2 instance system log.
If you want more logging enabled then use the debug
image:
source = "public.ecr.aws/stefansundin/bottlerocket-bootstrap-associate-eip:debug"
There is an integration test that simulates the required environment.
export RUST_LOG=aws
cargo test -- --nocapture
This is one of my first Rust programs. If you have ideas for improvements, please open an issue or a pull request.
If you have questions then please open an issue or a discussion.