Deploying a Django Application to Elastic Beanstalk

Setting up a staging/development instance

It is recommended to have a instance on which activities like pulling the code from git and pushing it to Elastic Beanstalk (EB) can be done. This instance can also be used for development or testing purposes of your Django app.

Install the following packages on your instance:

Pip: apt-get install python-pip

Virtualenv: apt-get install python-virtualenv

Awsebcli: pip install awsebcli


Setting up the tools and environment for running Django by using a virtual environment

  1. Create a virtual env: virtualenv eb-virt
  2. Activate the env: source ~/eb-virt/bin/activate
  3. Install Django using pip: pip install django==1.9.2
  4. Verify Django is installed by running: pip freeze
  5. Deactivate the environment: deactivate

Creating a sample Django project

  1. Activate the env: source ~/eb-virt/bin/activate
  2. Create a sample project: django-admin startproject skywide
  3. Enter the project directory: cd skywide
  4. Run the Django server: python manage.py runserver 0.0.0.0:8000
  5. Deactivate the environment before moving to the next step: deactivate

You can now see the following page by hitting the public IP of your instance in your browser. Example: 54.255.233.22:8000

django

Now that Django is up and running on your EC2 instance, we can proceed to prepare it to be deployed on Elastic Beanstalk.


Configuring your application to work with Elastic Beanstalk

  1. Activate the virtual environment: source ~/eb-virt/bin/activate
  2. Create a requirements.txt file. This file is used by EB to install the dependencies on the instances it will launch: pip freeze > requirements.txt (Do verify that requirements.txt contains “django==1.9.2”)
  3. Create a new directory called .ebextensions inside ~/skywide. We will create a configuration file inside this directory later: mkdir .ebextensions
  4. Create a file django.config inside .ebextensions containing the following code: This setting, WSGIPath specifies the location of the WSGI script that Elastic Beanstalk uses to start your application.
  5. Finally, deactivate the virtual environment: deactivate

Next step is to deploy your Django app to EB.


Deploying your applicaiton to Elastic Beanstalk

Make sure you have a directory structure is correct.

  1. Go inside your project directory (~/skywide) and create a new EB application (initiate the repository) with the following command: eb init -p python3.4 skywide
  2. Run eb init again configure a default keypair that will be used to login to the instances launched by EB.
  3. Next, create an environment inside the application we just created: eb create skywide-env

To see the app live, go to the Elastic Beanstalk console, click on the Application we created and then on the Environment created (skywide-env). Click on the URL listed at the top of the page and you willll see your app in action in your browser!

IAM: Restrict Access to Folders Inside Bucket

The following policy restricts access of a user to the folder inside the bucket that is named after the user’s username. It is suited to be applied to IAM groups.

This helps create a bucket, inside which you can create several user directories and each directory can be accessed only by it’s owner.

Replace the following policy with your S3 bucket name. The policy assumes that the parent directory is a directory named “home”. If you have a differently named directory, replace all occurrences of “home” with the name of your directory.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": ["s3:ListAllMyBuckets", "s3:GetBucketLocation"],
      "Effect": "Allow",
      "Resource": ["arn:aws:s3:::*"]
    },
    {
      "Action": ["s3:ListBucket"],
      "Effect": "Allow",
      "Resource": ["arn:aws:s3:::bucket-name"],
      "Condition":{"StringEquals":{
      "s3:prefix":["","home/"],"s3:delimiter":["/"]}}
    },
    {
      "Action": ["s3:ListBucket"],
      "Effect": "Allow",
      "Resource": ["arn:aws:s3:::bucket-name"],
      "Condition":{"StringLike":{"s3:prefix":["home/${aws:username}/*"]}}
    },
    {
      "Action":["s3:*"],
      "Effect":"Allow",
      "Resource": ["arn:aws:s3:::bucket-name;/home/${aws:username}"
      "arn:aws:s3:::bucket-name/home/${aws:username}/*"]
    }
  ]
}

Moving your DNS to Route 53

About Route 53

Amazon Route 53 is a Domain Name System (DNS) owned and provided by AWS. Being part of the AWS ecosystem, it works well with other services like EC2 instances, Elastic Load Balancing, S3 storage etc compared to other Domain Registrars. So if your infrastructure is completely built on AWS, you should consider moving your DNS to Route 53 since it would help create a homogeneous environment.


Here are a few common use-cases along with a broad overview of the process steps:

Migrating an existing domain’s DNS to Route 53

  1. Create a Hosted Zone and enter the existing domain name (www.example.com)
  2. Add a Record Set to the Hosted Zone and add the IP of the server as a A record (also create MX, CNAME and other records depending on your requirement)
  3. Copy the four name servers provided by the Hosted Zone
  4. Log in to your domain registrar’s control panel/admin console. If your registrar supports TTL modification, It is recommended to set it to 900 seconds for a quicker propagation. Replace your domain registrar’s NS records with the four name servers you copied from Route 53.
  5. The DNS propagation from your domain registrar to Route 53 will take 48 hours or more.

Migrating the sub-domain DNS to Route 53 without migrating the parent domain

  1. Create a Hosted Zone and enter the sub domain name (www.aws.example.com)
  2. Add a Record Set to the hosted zone and add the IP of the server as a A record (similarly add MX, CNAME records if required)
  3. Copy the four name servers provided by the Hosted Zone. Replace the NS Records of the registrar with these name servers

Important: Do not add a start of authority (SOA) record to the zone file for the parent domain. Reason for this being since the sub-domain will use Amazon Route 53, the DNS service for the parent domain is not the authority for the sub-domain.


Private Hosted Zone

  1. Private Hosted Zone is a Hosted Zone for managing domains within an AWS VPC
  2. First step is to set the following Amazon VPC settings to true:
    • enableDnsHostnames
    • enableDnsSupport
  3. On the Route 53 page, click on Create Hosted Zone.
  4. Next, in the Create Private Hosted Zone pane, enter your domain name. Select Private Hosted Zone for Amazon VPC in the Type list.
  5. Finally, in the VPC ID list, select the VPC you want to associate with Route 53.
  6. Click on Create. Your VPC should get linked with Route 53 within a few minutes.

Integration with other AWS Services

Once a Hosted Zone is created, incorporating other AWS Services into Route 53 is just a matter of creating a few record sets. Here’s a list of the record sets needed for the corresponding AWS services.

  1. EC2: Create an A record with the Elastic IP of the instance
  2. ELB: Add public DNS of the load balancer to a CNAME record
  3. CloudFront: Add Distribution URL to a CNAME record
  4. S3: Add the Bucket URL to a CNAME record
  5. RDS: Add the RDS endpoint to a CNAME record

EC2 Instances Automated Deployment using Vagrant

Why use Vagrant to launch EC2 instance?

EC2 instances can be deployed seamlessly using Vagrant. Once you setup Vagrant and configure it, launching an EC2 instance becomes as easy as running the command vagrant up. Such automation is especially useful when you have to launch a large fleet of EC2 instances quickly.

Setting up Vagrant on your machine

  1. Install vagrant:
`sudo apt-get install vagrant`   2. Initialize vagrant:
  
`vagrant init hashicorp/precise32`
  
`vagrant up`
  
(This will download the example virtualbox image from vagrant servers. It might take a few minutes)   3. Install vagrant aws plugin:
  
`sudo vagrant plugin install vagrant-aws`   4. Get the AWS Box image:
  
`vagrant box add dummy https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box`

Launching the instance

  1. Create a directory in your home folder and from inside the directory, run
`vagrant init hashicorp/precise32`
  
(This will create a “Vagrantfile” in your directory)   2. Open your Vagrantfile, clear all contents and add the following. Please modify the values wherever necessary.
  1. Save the file and run:

    vagrant up --provider=aws

  2. Your instance should be up and running in a few minutes.


The above configuration only contains the bare essential configurations. Here are some more configuration parameters.

availability_zone Specify the desired availability zone. (ap-southeast-1a)
instance_type The default value of this if not specified is “m3.medium”
private_ip_address The private IP address to assign to an instance within a VPC
instance_ready_timeout The number of seconds to wait for the instance to become “ready” in AWS. Defaults to 120 seconds
instance_package_timeout The number of seconds to wait for the instance to be burnt into an AMI during packaging. Defaults to 600 seconds
elastic_ip Can be set to ‘true’, or to an existing Elastic IP address
security_groups An array of security groups for the instance. If this instance will be launched in VPC, this must be a list of security group Name. For a non-default VPC, you must use security group IDs instead
subnet_id The subnet to launch the instance inside
associate_public_ip true/false. If true, will associate a public IP address to an instance in a VPC

The full list of options can be found here: https://github.com/mitchellh/vagrant-aws#configuration


Note: This guide is written for a *nix environment. The steps are similar for Windows based environments.

IAM: Restrict User to Specific Instance

This policy restricts an IAM user to perform start and stop actions only on instances having their IDs specified in the Resource attribute of the policy.

In order to further restrict the actions that can be performed, additional actions like “ec2:TerminateInstances” can be added.