How to clone an AWS EB environment across platform branches

Viewed 695

Background

Our AWS Elastic Beanstalk environment, running the latest version of the pre-configured "Python 3.7 on 64-bit Amazon Linux 2" platform branch, has a lot of custom configuration and environment properties.

Now we would like to switch this environment to the "Python 3.8 on 64-bit Amazon Linux 2" platform branch.

Basically, the goal is to clone the environment, keeping the current configuration (other than platform branch and version) and environment properties.

Problem

Unfortunately, when cloning, it is not possible to switch between different platform branches (we can only switch between platform versions within the same platform branch).

The documentation suggests that a blue/green deployment is required here. However, a blue/green deployment involves creating a new environment from scratch, so we would still need some other way to copy our configuration settings and environment properties.

Question

What would be the recommended way to copy the configuration settings and/or environment properties from the original environment into a newly created environment?

I suppose we could use eb config to download the original configuration, modify the environment name, platform branch and version, and so on, and then use eb config --update on the new environment. However, that feels like a hack.

1 Answers

Summary

  1. save current config: eb config save <env name>
  2. use a text editor to modify the platform branch in the saved config file
  3. create new environment based on modified config file: eb create --cfg <config name> (add --sample to use the sample application)
  4. if necessary, delete local config files
  5. if necessary, use eb printenv and eb setenv to copy environment properties

EDIT: For some reason the saved config does not include all security group settings, so it may be necessary to check those manually, using the EB console (configuration->instances).

Background

AWS support have confirmed that using eb config is the way to go, and they referred to the online documentation for details. Unfortunately, the documentation for the eb cli does not provide all the answers.

The following is based on my own adventures using the latest version of the eb cli (3.20.2) with botocore 1.21.50, and documentation at the time of writing (Sep 30, 2021). Note there's a documentation repo on github but it was last updated six months ago and does not match the latest online docs...

eb config

Here's a screenshot from the eb config docs:

eb config doesn't show environment properties

Indeed, if you call eb config my-env or eb config my-env --display, environment properties are not shown.

However, this does not hold for eb config save: YAML files created using eb config save actually do include environment properties*.

*Beware, if your environment properties include secrets (e.g. passwords), these also end up in your saved configs, so make sure you don't commit those to version control.

Moreover, it is currently also possible to set environment properties using eb config --update.

This implies we should be able to "copy" both configuration settings and environment properties in one go.

EDIT: After some testing it turns out eb config save does not always get the complete set of environment properties: some properties may be skipped. Not yet sure why... Step 5 below might help in those cases.

Walk-through

Not sure if this is the best way to do it, but here's what seems to work for me:

Suppose we have an existing EB environment called py37-env with lots of custom configuration and properties, running the Python 3.7 platform branch.

The simplest way to "clone" this would be as follows:

Step 1: download the existing configuration

Download the configuration for the existing environment:

eb config save py37-env

By default, the config file will end up in our project directory as .elasticbeanstalk/saved_configs/py37-env-sc.cfg.yml.

The saved config file could look like this (just an example, also see environment manifest):

EnvironmentConfigurationMetadata:
  Description: Configuration created from the EB CLI using "eb config save".
  DateCreated: '1632989892000'
  DateModified: '1632989892000'
Platform:
  PlatformArn: arn:aws:elasticbeanstalk:eu-west-1::platform/Python 3.7 running on 64bit Amazon Linux 2/3.3.5
OptionSettings:
  aws:elasticbeanstalk:application:environment:
    MY_ENVIRONMENT_PROPERTY: myvalue
  aws:elasticbeanstalk:command:
    BatchSize: '30'
    BatchSizeType: Percentage
  aws:elb:policies:
    ConnectionDrainingEnabled: true
  aws:elb:loadbalancer:
    CrossZone: true
  aws:elasticbeanstalk:environment:
    ServiceRole: aws-elasticbeanstalk-service-role
  aws:elasticbeanstalk:healthreporting:system:
    SystemType: enhanced
  aws:autoscaling:launchconfiguration:
    IamInstanceProfile: aws-elasticbeanstalk-ec2-role
    EC2KeyName: my-key
  aws:autoscaling:updatepolicy:rollingupdate:
    RollingUpdateType: Health
    RollingUpdateEnabled: true
EnvironmentTier:
  Type: Standard
  Name: WebServer
AWSConfigurationTemplateVersion: 1.1.0.0

Also see the list of available configuration options in the documentation.

Step 2: modify the saved configuration

We are only interested in the Platform, so it is sufficient here to replace 3.7 by 3.8 in the PlatformArn value.

If necessary, you can use e.g. eb platform list to get an overview of valid platform names.

Step 3: create a new environment based on the modified config file

eb create --cfg py37-env-sc

This will deploy the most recent application version. Use --version <my version> to deploy a specific version, or use --sample to deploy the sample application, as described in the docs.

This will automatically look for files in the default saved config folder, .elasticbeanstalk/saved_configs/.

If you get a ServiceError or InvalidParameterValueError at this point, make sure only to pass in the name of the file, i.e. without the file extension .cfg.yml and without the folders.

Step 4: clean up local saved configuration file

Just in case you have any secrets stored in the environment properties.

Step 5: alternative method for copying environment properties

If environment properties are not included in the saved config files, or if some of them are missing, here's an alternative way to copy them (using bash). This might not be the most efficient implementation, but I think it serves to illustrate the approach. Error handling was omitted, for clarity.

source_env="py37-env"  # or "$1"
target_env="py38-env"  # or "$2"
# get the properties from the source environment
source_env_properties="$(eb printenv "$source_env")"
# format the output so it can be used with `eb setenv`
mapfile -t arg_array < <(echo "$source_env_properties" | grep "=" | sed -e 's/ =/=/g' -e 's/= /=/g' -e 's/^ *//g')
# copy the properties to the target environment
eb setenv -e "$target_env" "${arg_array[@]}"

This has the advantage that it does not store any secrets in local files.

Related