Update your AWS Beanstalk platform and code at the same time

At Potloc, we use AWS Beanstalk for our staging and production environments. Like most Rails project, we use a .ruby-version dotfile to specify our current ruby version. We also specify it in our Gemfile.

AWS Beanstalk allows you to upgrade platform and/or image with a single click on their dashboard but unfortunately it comes short if you need to update both the code AND the platform at once, which is the case if both must match.

After digging around we found a way to push an environment update with code while changing the platform at the same time.

Steps

Get your new stack name for the available stacks.

aws elasticbeanstalk list-available-solution-stacks |  jq ".SolutionStacks" | grep 'Ruby'

Create an application version by zipping your code, pushing it your Beanstalk S3 bucket

git archive --format zip --output /tmp/v1.0.0.zip HEAD

aws s3 cp --quiet --acl private /tmp/v1.0.0.zip s3://elasticbeanstalk-us-east-1-1234567890/my-application

Create an application version pointing to your zipped code

aws elasticbeanstalk create-application-version --application-name my-application --version-label v1.0.0 --source-bundle S3Bucket="elasticbeanstalk-us-east-1-1234567890",S3Key="production/v1.0.0.zip" --auto-create-application

Deploy an application version and update stack all at once

aws elasticbeanstalk update-environment --application-name my-application --environment-name production --version-label v1.0.0 --solution-stack-name "64bit Amazon Linux 2018.03 v2.9.1 running Ruby 2.5 (Puma)"

If like us you also use custom AMI you can specify it using the following flag:

 --option-settings Namespace=aws:autoscaling:launchconfiguration,OptionName=ImageId,Value=ami-a1b2c3d4e5f6g7

You can also use option_settings in a .ebextensions file.