Prerequisities

  • Python 3
  • AWS account

Step by step

1. Start initial Django project with cookiecutter-django

cd ~/virtualenvs
python3 -m venv cookiecutter
source cookiecutter/bin/activate
pip install "cookiecutter>=1.4"
cd ~/django-projects
cookiecutter https://github.com/pydanny/cookiecutter-django

Cookiecutter will ask a bunch of questions, but for the sake of this tutorial set project_name and project_slug to "mysite". Others can be pretty much left as default values, unless you know what you are doing. After all the questions have been answered, go to your project directory and finalize the installation of the local environment

deactivate # deactivate the current virtualenv, we'd prefer to
           # use fresh virtualenv for the actual Django project
cd mysite
python -m venv venv
source venv/bin/activate
pip install -r requirements/local.txt

Since cookiecutter-django uses django-environ by default, let's create a .env file and configure Django to use SQLite database, and finally tell Django to actually use the .env file.

# .env
DATABASE_URL=sqlite:///my-tmp-sqlite.db
export DJANGO_READ_DOT_ENV_FILE=True

Now we can run database migrations and try running the development server:

python manage.py migrate
python manage.py runserver

All should we well on http://127.0.0.1:8000.

One final thing with this new Django project is to create requirements.txt in your project's root directory, and make it to point to the actual production requirements.txt:

# requirements.txt

-r requirements/production.txt

2. Set up Ansible for deploying the project to AWS

mkdir ansible
cd ansible
git clone git@github.com:Raekkeri/ansible-utils.git
cp ansible-utils/web_app_playbook.yml web_app_playbook.yml
cp ansible-utils/web_base_playbook.yml web_base_playbook.yml

Then create a common_vars.yml file (inside the ansible directory), which will contain the non-secrets about the deployment of your Django project:

# ansible/common_vars.yml

app_name: mysite
app_user: mysite

app_root_dir: "/home/{{app_user}}"
app_base_dir: "/home/{{app_user}}/app/"
app_packages_dir: "/home/{{app_user}}/app/packages"
app_current_location: "/home/{{app_user}}/app/current"

app_version: default

s3_env_file: s3://mysite-configuration/production-env.txt
server_name: mysite
nginx_port: 80

Only thing here to modify is the the s3_env_file, which should point to the environment txt file in S3 which will be downloaded on deployment later on.

3. Preparing AWS resources

Create Policy

  • go to IAM -> Policies -> Create policy
  • choose to type in the JSON and paste the following:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1508047678000",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::mysite-configuration",
                "arn:aws:s3:::mysite-configuration/*"
            ]
        }
    ]
}
  • review and create

Launch an EC2 instance with the newly created role

  • go to EC2 -> Launch instance
  • choose Amazon Linux AMI
  • select appropriate instance type
  • in "Configure instance" step, set the "IAM role" to the role we created in previous steps
  • in "Configure Security Group" step, you might want to open HTTP port for yourself for now
  • launch instance

4. Finalize Ansible configuration

  • in your project's ansible directory, create directory path envs/production with mkdir -p envs/production
  • add the AWS instance IP to production inventory file:
# ansible/envs/prod/inventory

web ansible_host=web ansible_host=53.11.13.143

5. Deploy

We will deploy the current HEAD of the Git repository. For this create a directory dist on your project's root:

mkdir dist

Then archive the Git branch into a tar file:

git archive --format=tar --prefix=/ HEAD > dist/package.tar

First install the generic requirements for a Django deployment on the AWS instance:

cd ansible
ansible-playbook -i envs/prod/inventory web_base_playbook.yml -b --private-key=~/.ssh/your-aws-key.pem
cd ..

Then install the Django application itself:

cd ansible
ansible-playbook -i envs/prod/inventory web_app_playbook.yml -b --private-key=~/.ssh/your-aws-key.pem
cd ..

Misc

Shell script for quick deployments (this should be run from the project's root):

#!/bin/sh
set -e

git archive --format=tar --prefix=/ HEAD > dist/package.tar
cd ansible
ansible-playbook -i envs/prod/inventory web_app_playbook.yml -b
cd ..