Deploy a Django application to AWS with support for zero downtime rolling updates.
- Python >= 3.5
- VirtualBox >= 6.0.0
- Vagrant >= 2.2.0
- Packer >= 1.4.0
Create and provision the virtual machine.
vagrant up
vagrant reload
The virtual machine copies your ~/.aws/config
and ~/.aws/credentials
files
to the vagrant
user's home folder. However you need to manually start an SSH
agent and forward it to the VM if you want to be able to use your SSH key.
ssh-add
vagrant ssh -- -A
Create a python virtualenv.
virtualenv -p $(which python3) env
source env/bin/activate
Navigate to the /vagrant
folder which is synchronized with the top-level
project folder. Install python dependencies.
cd /vagrant
pip install -r requirements.txt
Here's what you need to do to start from scratch:
- Locate the default VPC and Subnets or create them.
- Locate or create a Route53 hosted zone for a top-level domain.
- Locate or create a wildcard SSL certificate in the Certificate Manager.
- Build the Web AMI (
packer build packer/web.json
). - Build the application (in vagrant
create_build.py
). - Set SSM parameters (see below).
- Create the CloudFormation stack (see below).
- Deploy the initial build (
deploy_build.py
). - Verify the application is reachable at the configured domain.
Here's how you set secret and plain-text SSM parameters:
aws ssm put-parameter --name '/Frontdesk/DatabaseMasterPassword' \
--description 'RDS DBInstance MasterUserPassword' \
--value 'something_secure_and_secret' \
--type 'SecureString' \
--tags 'Key=Project,Value=Frontdesk'
aws ssm put-parameter --name '/Frontdesk/WebImageId' \
--description 'Web ASG AMI ID' \
--value 'ami-ABCDWXYZ' \
--type 'String' \
--tags 'Key=Project,Value=Frontdesk'
Here's the SSM parameters you need to set:
VpcId
(String) AWS VPC IdPrimarySubnetId
(String) AWS VPC Primary Subnet IdSecondarySubnetId
(String) AWS VPC Secondary Subnet IdCertificateArn
(String) Wildcard SSL Certificate ARN (*.example.com
)HostedZoneId
(String) Route53 hosted zone for top-level domainDomainName
(String) Second level domain (i.e.demo.example.com
)WebImageId
(String) Web ASG AMI Id (i.e.ami-ABCDWXYZ
)KeyName
(String) SSH KeyPair NameSecretKey
(SecureString) DjangoSECRET_KEY
settingDatabaseMasterPassword
(SecureString) Database master user password
Here's how you create the CloudFormation stack:
aws cloudformation create-stack --stack-name Frontdesk \
--capabilities CAPABILITY_NAMED_IAM \
--template-body file://cloudformation/frontdesk.yaml
Build a new AMI using Packer:
packer validate packer/web.json
packer build packer/web.json
Update the WebImageId
parameter in SSM:
aws ssm put-parameter --name '/Frontdesk/WebImageId' \
--value 'ami-ABCDWXYZ' \
--type 'String' \
--overwrite
Trigger a rolling update of web instances by updating the stack:
aws cloudformation update-stack --stack-name Frontdesk \
--capabilities CAPABILITY_NAMED_IAM \
--template-body file://cloudformation/frontdesk.yaml
Update the frontdesk
application and the version in setup.py
to reflect the
changes made. Create a build:
./create_build.py --project-path pkg/frontdesk
Deploy a build:
./deploy_build.py --app-build ./frontdesk-0.1.pex
Generally the exact opposite of provisioning with a few extra steps:
- Delete content of deployment bucket
- Delete stack
- Delete SSM parameters
- Deregister AMIs
- Delete AMI snapshots
Tools and frameworks:
AWS: