11[[chapter_17_second_deploy]]
2- Deploying Our New Code
3- ----------------------
2+ == Deploying Our New Code
43
5- ((("deployment", "procedure for", id="Dpro17"))) It's
6- time to deploy our brilliant new validation code to our live servers.
4+ ((("deployment", "procedure for", id="Dpro17")))
5+ It's time to deploy our brilliant new validation code to our live servers.
76This will be a chance to see our automated deploy scripts in action for the
87second time.
98
9+ NOTE: At this point I always want to say a huge thanks to Andrew Godwin
10+ and the whole Django team.
11+ Up until Django 1.7, I used to have a whole long section,
12+ entirely devoted to migrations.
13+ Migrations now "just work", so I was able to drop it altogether.
14+ I mean yes this all happened nearly ten years ago,
15+ but still--open source software is a gift.
16+ We get such amazing things, entirely for free.
17+ It's worth taking a moment to be grateful, now and again.
1018
11- NOTE: At this point I want to say a huge thanks to Andrew Godwin and the whole
12- Django team. Up until Django 1.7, I used to have a whole long section,
13- entirely devoted to migrations. Migrations now "just work", so I was able to
14- drop it altogether. Thanks for all the great work, gang!
1519
16-
17- .🚧 Warning, Content not updated
20+ .🚧 Warning, Under construction
1821*******************************************************************************
1922
20- This chapter has not been rewritten as part of the third edition.
23+ This chapter has only just been rewritten as part of the third edition.
24+ Please send feedback!
2125
22- By all means refer back to <<chapter_11_ansible>>
23- and try and do a deployment,
24- but otherwise, go ahead and check out <<chapter_18_spiking_custom_au,the next chapter>>, which has been (mostly) updated.
26+ You can refer back to <<chapter_11_ansible>> for reminders on Ansible commands.
2527
2628*******************************************************************************
2729
2830
29- Staging Deploy
30- ~~~~~~~~~~~~~~
31+ === Staging Deploy
3132
3233
3334We start with the staging server:
3435
35- [role="against-server"]
36+ [role="against-server small-code "]
3637[subs="specialcharacters,macros"]
3738----
38- $ pass:quotes[*git push*]
39- $ pass:quotes[*cd deploy_tools*]
40- $ pass:quotes[*fab deploy:[email protected] *] 39+ $ pass:quotes[*ansible-playbook --user=elspeth -i staging.ottg.co.uk, infra/ansible-provision.yaml -vv*]
4140[...]
42- Disconnecting from staging.ottg.co.uk... done.
43- ----
4441
45- Restart Gunicorn:
42+ PLAYBOOK: ansible-provision.yaml ***********************************************
43+ 1 plays in infra/ansible-provision.yaml
4644
47- [role="server-commands skipme"]
48- [subs="specialcharacters,quotes"]
49- ----
50- elspeth@server:$ *sudo systemctl restart gunicorn-staging.ottg.co.uk*
45+ PLAY [all] *********************************************************************
46+
47+ TASK [Gathering Facts] *********************************************************
48+ [...]
49+ ok: [staging.ottg.co.uk]
50+
51+ TASK [Install docker] **********************************************************
52+ [...]
53+ ok: [staging.ottg.co.uk] => {"cache_update_time": [...]
54+
55+ TASK [Build container image locally] *******************************************
56+ [...]
57+ ok: [staging.ottg.co.uk -> 127.0.0.1] => {"actions": ["Built image superlists:latest [...]
58+
59+ TASK [Export container image locally] ******************************************
60+ ok: [staging.ottg.co.uk -> 127.0.0.1] => {"actions": [], "changed": false, "image": [...]
61+
62+ TASK [Upload image to server] **************************************************
63+ ok: [staging.ottg.co.uk] => {"changed": false, "checksum": [...]
64+
65+ TASK [Import container image on server] ****************************************
66+ ok: [staging.ottg.co.uk] => {"actions": ["Loaded image superlists:latest [...]
67+
68+ TASK [Ensure .env file exists] *************************************************
69+ ok: [staging.ottg.co.uk] => {"changed": false, "dest": "/home/elspeth/superlists.env", [...]
70+
71+ TASK [Ensure db.sqlite3 file exists outside container] *************************
72+ changed: [staging.ottg.co.uk] => {"changed": true, "dest": "/home/elspeth/db.sqlite3", [...]
73+
74+ TASK [Run container] ***********************************************************
75+ changed: [staging.ottg.co.uk] => {"changed": true, "container": [...]
76+
77+ TASK [Run migration inside container] ******************************************
78+ changed: [staging.ottg.co.uk] => {"changed": true, "rc": 0, "stderr": "", [...]
79+
80+ PLAY RECAP *********************************************************************
81+ staging.ottg.co.uk : ok=10 changed=3 unreachable=0 failed=0
82+ skipped=0 rescued=0 ignored=0
83+ [...]
84+ Disconnecting from staging.ottg.co.uk... done.
5185----
5286
87+
5388And run the tests against staging:
5489
5590[role="small-code"]
5691[subs="specialcharacters,macros"]
5792----
58- $ pass:quotes[*STAGING_SERVER =staging.ottg.co.uk python manage.py test functional_tests*]
93+ $ pass:quotes[*TEST_SERVER =staging.ottg.co.uk python src/ manage.py test functional_tests*]
5994OK
6095----
6196
6297
98+ Hooray!
99+
100+
63101
64102[role="pagebreak-before less_space"]
65- Live Deploy
66- ~~~~~~~~~~~
103+ === Live Deploy
67104
68105
69106Assuming all is well, we then run our deploy against live:
@@ -72,33 +109,39 @@ Assuming all is well, we then run our deploy against live:
72109[role="against-server"]
73110[subs="specialcharacters,macros"]
74111----
75- $ pass:quotes[*fab deploy:host =elspeth@superlists .ottg.co.uk*]
112+ $ pass:quotes[*ansible-playbook --user =elspeth -i www .ottg.co.uk, infra/ansible-provision.yaml -vv *]
76113----
77114
78- [role="server-commands"]
79- [subs="specialcharacters,quotes"]
80- ----
81- elspeth@server:$ *sudo service gunicorn-superlists.ottg.co.uk restart*
82- ----
83115
84116
85- What to Do If You See a Database Error
86- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117+ === What to Do If You See a Database Error
87118
88119
89120Because our migrations introduce a new integrity constraint, you may find
90121that it fails to apply because some existing data violates that constraint.
91122
92123At this point you have two choices:
93124
94- * Delete the database on the server and try again. After all, it's only a
95- toy project!
125+ 1. Delete the database on the server and try again.
126+ After all, it's only a toy project!
127+
128+ 2. Learn about data migrations. See <<data-migrations-appendix>>.
129+
130+
131+ Here's how you might do option (1):
132+
133+ [role="skipme"]
134+ ----
135+ ssh [email protected] rm db.sqlite3 136+ ----
137+
138+ The `ssh` command takes an arbitrary shell command to run as its last argument,
139+ so we pass in `rm db.sqlite3`.
140+ We don't need a full path because we keep the sqlite database in elspeth's home folder.
96141
97- * Learn about data migrations. See <<data-migrations-appendix>>.
98142
99143
100- Wrap-Up: git tag the New Release
101- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
144+ === Wrap-Up: git tag the New Release
102145
103146
104147The last thing to do is to tag the release in our VCS--it's important that
@@ -125,8 +168,8 @@ topics that comprise <<part3>>. Can't wait!
125168
126169We've done a couple of deploys now, so this is a good time for a little recap:
127170
128- * `git push` latest code
129- * Deploy to staging and run functional tests against staging
171+ * Deploy to staging first
172+ * Run our FTs against staging.
130173* Deploy to live
131174* Tag the release
132175
0 commit comments