Search code examples
amazon-ec2dockeramazon-elastic-beanstalkcloud-initamazon-ecs

HOWTO deploy a docker container on aws without using elastic beanstalk or ec2 container service


I'd like to use docker containers without having to use elastic beanstalk or ec2 container service. I'd like to upload a .zip file describing the container (like you do with elastic beanstalk) and have a generic ec2 instance run it using docker.

When looking into the user data section of a beanstalk-created ec2 instance running a docker container, I see a cloud-init script that downloads a big shell script that does all the setup (Example). I assume that everything that elastic beanstalk does can also be achieved manually by using ec2 instances and a user data script.

My question is: Could someone provide a minimal example for a user data script that

  1. installs/configures docker
  2. downloads the .zip file
  3. runs my docker image

I'm familiar with auto scaling groups etc. and I'd like to get this setup running without using the beanstalk- or ec2 container service magic.


Solution

  • Basically, you need to install Docker and nginx (as web proxy) in your EC2 instance. And then, download the web-app archive and deploy it. This is what Elastic Beanstalk does.

    For the basic/minimal user-data in order to deploy a single docker container web application:

    #!/bin/bash
    
    IMG_LABEL=myapp
    APP_INIT_URL=https://s3.amazonaws.com/your-bucket-app/myapp-init.tar.gz
    
    function prepare_instance {
      apt-get -y update
      apt-get -y install nginx
      curl -sSL https://get.docker.com/ | sh
      mkdir /opt
      curl -o /opt/deployer.sh http://169.254.169.254/latest/user-data
      chmod 775 /opt/deployer.sh
    }
    
    function download_app {
      curl -o /tmp/current.tar.gz $1
      rm -rf /opt/app
      mkdir -p /opt/app
      tar zxvf /tmp/current.tar.gz -C /opt/app
      rm /tmp/current.tar.gz
    }
    
    function build_image {
      docker tag ${IMG_LABEL}:latest ${IMG_LABEL}:prev || echo "No built app"
      docker build -t ${IMG_LABEL}:latest /opt/app
    }
    
    function run_container {
      APP_CID=$(docker run -d ${IMG_LABEL}:latest)
      APP_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' ${APP_CID})
    }
    
    function setup_proxy {
      rm /etc/nginx/sites-enabled/*
      cat <<EOT > /etc/nginx/sites-enabled/app.conf
    map \$http_upgrade \$connection_upgrade {
      default upgrade;
      ''      close;
    }
    upstream app.local {
      server ${APP_IP};
    }
    server {
      listen 80;
      location / {
        proxy_pass http://app.local;
        include /etc/nginx/proxy_params;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection \$connection_upgrade;
      }
    }
    EOT
      service nginx reload
    }
    
    function destroy_previous {
      (docker ps -a --before="${APP_CID}" | awk '{ print $1,$2 }' | grep "${IMG_LABEL}" | awk '{print $1 }' | xargs -I {} docker stop {} | xargs -I {} docker rm {}) || echo "No previous container"
      docker rmi ${IMG_LABEL}:prev || echo "No previous image"
    }
    
    if [ ! -f /opt/deployer.sh ];
    then
      prepare_instance
      download_app ${APP_INIT_URL}
    else
      download_app $1
    fi
    
    build_image
    run_container
    setup_proxy
    destroy_previous
    

    In Elastic Beanstalk, there is an agent that listen to update request. But, to make it simple, we can call the above script to deploy a new web-app version via SSH:

    ssh [email protected] 'sudo /opt/deployer.sh https://s3.amazonaws.com/your-bucket-app/myapp-201510122341.tar.gz'
    

    Note: I use EC2 instance with Ubuntu 14.04.