Instantly share code, notes, and snippets.

@yefim /Dockerfile
Last active Nov 25, 2018

Embed
What would you like to do?
Build a Docker image, push it to AWS EC2 Container Registry, then deploy it to AWS Elastic Beanstalk
#!/bin/bash
# usage: ./deploy.sh staging f0478bd7c2f584b41a49405c91a439ce9d944657
# license: public domain
BRANCH=$1
SHA1=$2
AWS_ACCOUNT_ID=12345678900
NAME=name-of-service-to-deploy
EB_BUCKET=aws-s3-bucket-to-hold-application-versions
VERSION=$BRANCH-$SHA1
ZIP=$VERSION.zip
aws configure set default.region us-east-1
# Authenticate against our Docker registry
eval $(aws ecr get-login)
# Build and push the image
docker build -t $NAME:$VERSION .
docker tag $NAME:$VERSION $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/$NAME:$VERSION
docker push $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/$NAME:$VERSION
# Replace the <AWS_ACCOUNT_ID> with the real ID
sed -i='' "s/<AWS_ACCOUNT_ID>/$AWS_ACCOUNT_ID/" Dockerrun.aws.json
# Replace the <NAME> with the real name
sed -i='' "s/<NAME>/$NAME/" Dockerrun.aws.json
# Replace the <TAG> with the real version number
sed -i='' "s/<TAG>/$VERSION/" Dockerrun.aws.json
# Zip up the Dockerrun file (feel free to zip up an .ebextensions directory with it)
zip -r $ZIP Dockerrun.aws.json
aws s3 cp $ZIP s3://$EB_BUCKET/$ZIP
# Create a new application version with the zipped up Dockerrun file
aws elasticbeanstalk create-application-version --application-name $NAME-application \
--version-label $VERSION --source-bundle S3Bucket=$EB_BUCKET,S3Key=$ZIP
# Update the environment to use the new application version
aws elasticbeanstalk update-environment --environment-name $NAME \
--version-label $VERSION
# Example Dockerfile
FROM hello-world
{
"AWSEBDockerrunVersion": "1",
"Image": {
"Name": "<AWS_ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com/<NAME>:<TAG>",
"Update": "true"
},
"Ports": [
{
"ContainerPort": "443"
}
]
}
@philipithomas

This comment has been minimized.

philipithomas commented May 12, 2016

Looks like our Staffjoy deploy code. I suggest polling to see if the deploy succeeded. I copied and sanitized some code to do this from our deploys below that should match your variables (I haven't tested the modifications though). It looks for the deployed tag to match the anticipated one, it looks for EB to return to a "Ready" state (where another deploy can be initiated), and it times out if these conditions are not met (returning exit code 1).

deploystart=$(date +%s)
timeout=3000 # Seconds to wait before error. If it's taking awhile - your boxes probably are too small.
threshhold=$((deploystart + timeout))
while true; do
    # Check for timeout
    timenow=$(date +%s)
    if [[ "$timenow" > "$threshhold" ]]; then
        echo "Timeout - $timeout seconds elapsed"
        exit 1
    fi

    # See what's deployed
    current_version=`aws elasticbeanstalk describe-environments --application-name "$NAME-application" --environment-name "$NAME" --query "Environments[*].VersionLabel" --output text`

    status=`aws elasticbeanstalk describe-environments --application-name "$NAME-application" --environment-name "$NAME" --query "Environments[*].Status" --output text`

    if [ "$current_version" != "$VERSION" ]; then
        echo "Tag not updated (currently $version). Waiting."
        sleep 10
        continue
    fi
    if [ "$status" != "Ready" ]; then
        echo "System not Ready -it's $status. Waiting."
        sleep 10
        continue
    fi
    break
done
@theseanstewart

This comment has been minimized.

theseanstewart commented Sep 19, 2016

I'm new to Docker and came across this gist today while researching deployment strategies with Docker and Elastic Beanstalk. How does your application get built into the image? Are you pulling it from the repo as you build it? This is one thing I'm not super clear on.

@yefim

This comment has been minimized.

Owner

yefim commented Oct 4, 2016

@theseanstewart great question! I build the docker image with docker build -t $NAME:$VERSION . then push the built (and tagged) image to the Amazon EC2 Container Registry with docker push $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/$NAME:$VERSION.

The way the Elastic Beanstalk application environment knows how to deploy itself is the Dockerrun.aws.json file. In that file I specify the docker image to use and create a new application version with that points to the newly built, tagged, and pushed docker image URL. Does that make sense?

@revl-ca

This comment has been minimized.

revl-ca commented Oct 18, 2016

Is it possible to accomplish this with the awsebcli?

@mskutin

This comment has been minimized.

mskutin commented Dec 13, 2016

https://gist.github.com/yefim/93fb5aa3291b3843353794127804976f#file-deploy-sh-L28
missing trailing slash
from:
sed -i='' "s/<NAME>/$NAME" Dockerrun.aws.json
to:
sed -i='' "s/<NAME>/$NAME/" Dockerrun.aws.json

@ericbmerritt

This comment has been minimized.

ericbmerritt commented Dec 27, 2016

@yefim any chance you can explicitly specify a license for this? I am assuming its public domain, but its always nice to be explicit.

@marcmarcet

This comment has been minimized.

marcmarcet commented Dec 29, 2016

This is really helpful. Thank you!

@rootux

This comment has been minimized.

rootux commented Feb 17, 2017

Would like to add a comment for new comers that you need to create a EC2 container first here that will be the $NAME param - https://console.aws.amazon.com/ecs

@sibelius

This comment has been minimized.

sibelius commented Mar 21, 2017

instead of this

aws s3 cp $ZIP s3://$EB_BUCKET/$ZIP

# Create a new application version with the zipped up Dockerrun file
aws elasticbeanstalk create-application-version --application-name $NAME-application \
    --version-label $VERSION --source-bundle S3Bucket=$EB_BUCKET,S3Key=$ZIP

# Update the environment to use the new application version
aws elasticbeanstalk update-environment --environment-name $NAME \
      --version-label $VERSION

you can use awsebcli

eb deploy ${EB_ENV_NAME}
@stephen-swensen

This comment has been minimized.

stephen-swensen commented Apr 9, 2017

Super helpful, thanks!

I adapted it so that it can be downloaded and executed with curl / eval as a single self-contained script with project specific env vars pulled out: https://github.com/relayfoods/aws-docker-deploy

@Alexhha

This comment has been minimized.

Alexhha commented Apr 11, 2017

Note: deploy.sh script won't work for the first time. aws elasticbeanstalk update-environment command will work only for existing environment

# Replace the <NAME> with the real name
sed -i='' "s/<NAME>/$NAME" Dockerrun.aws.json

should contain trailing slash at the end

sed -i "s/<NAME>/$NAME/" Dockerrun.aws.json
@wprater

This comment has been minimized.

wprater commented Jun 16, 2017

should probably be user to add node_modules to a .dockerignore file as well

@simonguldstrand

This comment has been minimized.

simonguldstrand commented Jun 30, 2017

@Alexhha, would you just add the aws ecs register-task-definition to be able to use this script without existing env?

@codinronan

This comment has been minimized.

codinronan commented Aug 13, 2017

@stephen-swensen unbelievable lifesaver. I spent 2 hours reading AWS docs and with your scripts completed the same in < 10 minutes.

Seriously, code shouts, documentation whispers.

@javahometech

This comment has been minimized.

javahometech commented Sep 29, 2017

How elastic beanstalk knows the credentials of ECS registry?
Thanks,
Hari

@skunkworker

This comment has been minimized.

skunkworker commented Jan 25, 2018

If you are using docker-compose instead of docker build

In deploy.sh
instead of

docker build -t $NAME:$VERSION .

put this

export IMAGE_NAME=$NAME:$VERSION
docker-compose -f docker-compose.yml build

and add the image: key to your docker-compose.yml file

version: '3.3'
services:
  service_name:
     image: $IMAGE_NAME

Reference:
https://stackoverflow.com/questions/33816456/how-to-tag-docker-image-with-docker-compose

@lmanzieri

This comment has been minimized.

lmanzieri commented Mar 8, 2018

Hello All,

I'm doing different.
I'm using AWSEBCLI to deploy the application with the structure bellow:

  • .
  • .elasticbeanstalk/config.yml
  • Dockerrun.aws.json
  • (Dockerfile and all files of application)

So in config.yml is necessary put the keys bellow:

deploy:
  artifact: Dockerrun.aws.json

The archive will be like this:

branch-defaults:
  master:
    environment: myEnv
deploy:
  artifact: Dockerrun.aws.json
global:
  application_name: myApp
  default_ec2_keyname: myKey
  default_platform: arn:aws:elasticbeanstalk:sa-east-1::platform/Docker running on
    64bit Amazon Linux/2.8.4
  default_region: sa-east-1
  include_git_submodules: true
  instance_profile: null
  platform_name: null
  platform_version: null
  profile: null
  sc: git
  workspace_type: Application

then is just execute the command 'eb deploy' in main directory os your app.

@rich-allen-gov

This comment has been minimized.

rich-allen-gov commented Jun 27, 2018

@javahometech when using elastic beanstalk ,and ecr, you set up an iam role. So then when the following was run:

eval $(aws ecr get-login)

aws ecr get-login prints out a docker login command with a temporary credential. That output then gets executed with the eval statement and that's how auth is handled.

@ivarprudnikov

This comment has been minimized.

ivarprudnikov commented Nov 25, 2018

sed command contains minor "error":
sed -i='' "s/<AWS_ACCOUNT_ID>/$AWS_ACCOUNT_ID/" Dockerrun.aws.json will make a backup file called Dockerrun.aws.json= which is not what would be expected. Assume because -i was used the expectation is that file will be modified in place.

Documentation https://linux.die.net/man/1/sed
-i='' needs to be replaced with either --in-place='' or with -i '' or with a sensible backup extension -i.bak
First 2 options will not work on all systems and I found the last one -i.bak a bit more reliable when running sed on OSX and on Linux

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment