Deploying Our New Code
It’s time to deploy our brilliant new validation code to our live servers. This will be a chance to see our automated deploy scripts in action for the second time.
At this point I always want to say a huge thanks to Andrew Godwin and the whole Django team. Up until Django 1.7, I used to have a whole long section, entirely devoted to migrations. Migrations now "just work", so I was able to drop it altogether. I mean yes this all happened nearly ten years ago, but still—open source software is a gift. We get such amazing things, entirely for free. It’s worth taking a moment to be grateful, now and again. |
Staging Deploy
We start with the staging server:
$ ansible-playbook --user=elspeth -i staging.ottg.co.uk, infra/ansible-provision.yaml -vv [...] PLAYBOOK: ansible-provision.yaml *********************************************** 1 plays in infra/ansible-provision.yaml PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* [...] ok: [staging.ottg.co.uk] TASK [Install docker] ********************************************************** [...] ok: [staging.ottg.co.uk] => {"cache_update_time": [...] TASK [Build container image locally] ******************************************* [...] ok: [staging.ottg.co.uk -> 127.0.0.1] => {"actions": ["Built image superlists:latest [...] TASK [Export container image locally] ****************************************** ok: [staging.ottg.co.uk -> 127.0.0.1] => {"actions": [], "changed": false, "image": [...] TASK [Upload image to server] ************************************************** ok: [staging.ottg.co.uk] => {"changed": false, "checksum": [...] TASK [Import container image on server] **************************************** ok: [staging.ottg.co.uk] => {"actions": ["Loaded image superlists:latest [...] TASK [Ensure .env file exists] ************************************************* ok: [staging.ottg.co.uk] => {"changed": false, "dest": "/home/elspeth/superlists.env", [...] TASK [Ensure db.sqlite3 file exists outside container] ************************* changed: [staging.ottg.co.uk] => {"changed": true, "dest": "/home/elspeth/db.sqlite3", [...] TASK [Run container] *********************************************************** changed: [staging.ottg.co.uk] => {"changed": true, "container": [...] TASK [Run migration inside container] ****************************************** changed: [staging.ottg.co.uk] => {"changed": true, "rc": 0, "stderr": "", [...] PLAY RECAP ********************************************************************* staging.ottg.co.uk : ok=10 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [...] Disconnecting from staging.ottg.co.uk... done.
And run the tests against staging:
$ TEST_SERVER=staging.ottg.co.uk python src/manage.py test functional_tests OK
Hooray!
Live Deploy
Assuming all is well, we then run our deploy against live:
$ ansible-playbook --user=elspeth -i www.ottg.co.uk, infra/ansible-provision.yaml -vv
What to Do If You See a Database Error
Because our migrations introduce a new integrity constraint, you may find that it fails to apply because some existing data violates that constraint.
sqlite3.IntegrityError: columns list_id, text are not unique
At this point you have two choices:
-
Delete the database on the server and try again. After all, it’s only a toy project!
-
Learn about data migrations. See [data-migrations-appendix].
How to Delete the Database on the Staging Server
Here’s how you might do option (1):
ssh [email protected] rm db.sqlite3
The ssh
command takes an arbitrary shell command to run as its last argument,
so we pass in rm db.sqlite3
.
We don’t need a full path because we keep the sqlite database in elspeth’s home folder.
Don’t do this in prod! |
Wrap-Up: git tag the New Release
The last thing to do is to tag the release in our VCS—it’s important that we’re always able to keep track of what’s live:
$ git tag -f LIVE # needs the -f because we are replacing the old tag $ export TAG=`date +DEPLOYED-%F/%H%M` $ git tag $TAG $ git push -f origin LIVE $TAG
Some people don’t like to use push -f and update an existing tag,
and will instead use some kind of version number to tag their releases.
Use whatever works for you.
|
Comments