1
1
[[chapter_17_second_deploy]]
2
- Deploying Our New Code
3
- ----------------------
2
+ == Deploying Our New Code
4
3
5
4
((("deployment", "procedure for", id="Dpro17")))
6
5
It's time to deploy our brilliant new validation code to our live servers.
7
6
This will be a chance to see our automated deploy scripts in action for the
8
7
second time.
9
8
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.
10
18
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!
15
19
16
-
17
- .🚧 Warning, Content not updated
20
+ .🚧 Warning, Under construction
18
21
*******************************************************************************
19
22
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!
21
25
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.
25
27
26
28
*******************************************************************************
27
29
28
30
29
- Staging Deploy
30
- ~~~~~~~~~~~~~~
31
+ === Staging Deploy
31
32
32
33
33
34
We start with the staging server:
34
35
35
- [role="against-server"]
36
+ [role="against-server small-code "]
36
37
[subs="specialcharacters,macros"]
37
38
----
38
39
$ pass:quotes[*ansible-playbook --user=elspeth -i staging.ottg.co.uk, infra/ansible-provision.yaml -vv*]
39
40
[...]
40
- Disconnecting from staging.ottg.co.uk... done.
41
- ----
42
41
43
- Restart Gunicorn:
42
+ PLAYBOOK: ansible-provision.yaml ***********************************************
43
+ 1 plays in infra/ansible-provision.yaml
44
44
45
- [role="server-commands skipme"]
46
- [subs="specialcharacters,quotes"]
47
- ----
48
- 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.
49
85
----
50
86
87
+
51
88
And run the tests against staging:
52
89
53
90
[role="small-code"]
54
91
[subs="specialcharacters,macros"]
55
92
----
56
- $ 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*]
57
94
OK
58
95
----
59
96
60
97
98
+ Hooray!
99
+
100
+
61
101
62
102
[role="pagebreak-before less_space"]
63
- Live Deploy
64
- ~~~~~~~~~~~
103
+ === Live Deploy
65
104
66
105
67
106
Assuming all is well, we then run our deploy against live:
@@ -70,33 +109,39 @@ Assuming all is well, we then run our deploy against live:
70
109
[role="against-server"]
71
110
[subs="specialcharacters,macros"]
72
111
----
73
- $ 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 *]
74
113
----
75
114
76
- [role="server-commands"]
77
- [subs="specialcharacters,quotes"]
78
- ----
79
- elspeth@server:$ *sudo service gunicorn-superlists.ottg.co.uk restart*
80
- ----
81
115
82
116
83
- What to Do If You See a Database Error
84
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117
+ === What to Do If You See a Database Error
85
118
86
119
87
120
Because our migrations introduce a new integrity constraint, you may find
88
121
that it fails to apply because some existing data violates that constraint.
89
122
90
123
At this point you have two choices:
91
124
92
- * Delete the database on the server and try again. After all, it's only a
93
- 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.
94
141
95
- * Learn about data migrations. See <<data-migrations-appendix>>.
96
142
97
143
98
- Wrap-Up: git tag the New Release
99
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
144
+ === Wrap-Up: git tag the New Release
100
145
101
146
102
147
The last thing to do is to tag the release in our VCS--it's important that
@@ -123,8 +168,8 @@ topics that comprise <<part3>>. Can't wait!
123
168
124
169
We've done a couple of deploys now, so this is a good time for a little recap:
125
170
126
- * `git push` latest code
127
- * Deploy to staging and run functional tests against staging
171
+ * Deploy to staging first
172
+ * Run our FTs against staging.
128
173
* Deploy to live
129
174
* Tag the release
130
175
0 commit comments