Using Elastic Beanstalk to Launch Docker

I am a big fan of AWS, but I have to admit that I have never been overly fond of their documentation. Over the past week, I had the opportunity to start a new project and decided to try using elastic beanstalk to launch my docker containers from an Elastic Container Repository (ECR – another AWS service.) Along the way, I encountered a couple of hurdles and the purpose of this posting to help others with similar goals to navigate the process with a little more ease.

SETUP

If you are interested in following this post, I recommend getting DockerAWS-CLI and the Elastic Beanstalk command line tools installed first.

DOCKER AND ECR

This was the first hurdle. The aws cli gives you a handy function that is supposed to log your Docker session into the AWS registry, but when I run it as described in the AWS documentation, it fails:

bash> $(aws ecr get-login)
unknown shorthand flag: 'e' in -e
See 'docker login --help'.

Apparently, my version of Docker does not support the email option on login.

bash> $(aws ecr get-login –no-include-email)
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
Login Succeeded

The warning looks serious, but the command seems to have logged me in any way.

ELASTIC BEANSTALK FOR CONTAINERS

The next hurdles came here. Elastic Beanstalk (EB) has a handful of different ways for deploying container environments. By far the easiest way I found to deploy something to EB is to use the EB command line tool. You start by running ‘eb init’ which will guide you through the process of setting up a new application or connecting to an existing one. Note that your run ‘eb init’ in a directory that contains files that you want to deploy. The ‘eb init’ command stores the choices you make in the initialization process to a hidden directory (.elasticbeanstalk) and will be used to set preferences for future invocations of the ‘eb’ command.

Once you have set up an application, you need to create an environment. ‘eb create’ will create you an environment, using the files in your local directory.  There are some immediate caveats to this. By default, the eb cli tool is going to zip up your entire current directory and upload it to S3. If you have a Dockerfile, the elastic beanstalk cloud servers will use it to build your container, regardless of whether or not you have a Dockerrun.aws.json file.  If you are wanting to deploy from an AWS ECR image, you must ensure that you create your environment from a directory that has a Dockerrun.aws.json file and NO Dockerfile.

Ready for the next caveat? There are two versions of the Dockerrun.aws.json file. They are not interchangeable. Version 1 is for single container environments and is quite limited. In fact, there is no way to specify environment variables for the container via the version 1 Dockerrun file. If you are like me, you might be tempted to try to use the version 2 Dockerrun file, but it only works for multi-container environments. In my case, the application I was trying to deploy was really quite simple and I did not want to got the path of multiple containers, but I most certainly did not want to bake configuration information into the container. After a lot of searching, I found that there is a way to push environment variables to single-container eb applications – you have to set up a `.ebextensions` directory that contains a ‘.config’ file. The config file format is somewhat less than obvious but is detailed here.

FINAL RESULT

In the end, this is what my final deployment environment looks like for my project that deploys from ECR:

bash> ls -alR
.:
total 17
drwxr-xr-x 1 chris 197609   0 Feb 26 09:32 ./
drwxr-xr-x 1 chris 197609   0 Feb 24 09:46 ../
drwxr-xr-x 1 chris 197609   0 Feb 24 10:44 .ebextensions/
drwxr-xr-x 1 chris 197609   0 Feb 24 10:45 .elasticbeanstalk/
-rw-r--r-- 1 chris 197609 208 Feb 24 10:17 Dockerrun.aws.json

./.ebextensions:
total 9
drwxr-xr-x 1 chris 197609   0 Feb 24 10:44 ./
drwxr-xr-x 1 chris 197609   0 Feb 26 09:32 ../
-rw-r--r-- 1 chris 197609 425 Feb 24 10:44 .config

./.elasticbeanstalk:
total 5
drwxr-xr-x 1 chris 197609   0 Feb 24 10:45 ./
drwxr-xr-x 1 chris 197609   0 Feb 26 09:32 ../
-rw-r--r-- 1 chris 197609 535 Feb 24 10:18 config.yml

bash> cat Dockerrun.aws.json
{
   "AWSEBDockerrunVersion": "1",
   "Image": {
     "Name": "123456789876.dkr.ecr.us-east-2.amazonaws.com/container-name",
     "Update": "true"
   },
   "Ports": [ { "ContainerPort" : 3000 } ]
}

bash> cat .ebextensions/.config
option_settings:
   - option_name: FOO_SETTING
     value: foo
   - option_name: BAR_OPTION
     value: bar

With this directory I can create a new environment that launches a container from the ‘123456789012.dkr.ecr.us-east-2.amazonaws.com/container-name’ image, passing in the FOO_SETTING and BAR_OPTION environment variables. When I need to redeploy, I can just tag a new image with ‘123456789012.dkr.ecr.us-east-2.amazonaws.com/container-name:latest’ and run ‘eb deploy’ in the same directory.