Skip to content

Commit 8c29ad4

Browse files
committed
tweak warnings in 9+10, polishingin 10, extra screenshot
1 parent 420bd04 commit 8c29ad4

File tree

3 files changed

+109
-75
lines changed

3 files changed

+109
-75
lines changed

chapter_09_docker.asciidoc

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,21 @@ on the actual internet.
4242
Give it a buzzword name like "DevOps"
4343
if that's what it takes to convince you it's worth it.
4444

45-
.🚧 Warning, this chapter is under construction
45+
.🚧 Warning, chapter under construction 🚧
4646
*******************************************************************************
4747
As part of my work on the third edition of the book,
48-
I'm rewriting the deployment chapters,
49-
and this chapter is still an early draft I'm afraid.
50-
Sorry!
48+
I'm making big changes to the deployment chapters,
49+
and this is a very new draft.
5150
52-
Still, the broad outline is complete, so I'd love it if you had a go at following along!
51+
What that means is that I'd, really, really love feedback from readers.
52+
Please have a go at following along and let me know how you got on!
53+
I'm [email protected], or you can open up
54+
https://github.com/hjwp/Book-TDD-Web-Dev-Python/issues[GitHub Issue]
55+
or Pull Requests.
5356
54-
Most importantly, please please send your feedback to [email protected],
55-
or as a https://github.com/hjwp/Book-TDD-Web-Dev-Python/issues[GitHub Issue]
56-
57-
The next two chapters are even more rough, so if you prefer,
58-
you are welcome to skip all the deployment stuff and go straight to
59-
<<chapter_12_organising_test_files>>
57+
Let me know how you got on, if you get stuck on anything,
58+
if any explanations don't make sense,
59+
or if any of the instructions don't work for you.
6060
6161
*******************************************************************************
6262

@@ -1313,7 +1313,10 @@ Running migrations:
13131313
[...]
13141314
Applying sessions.0001_initial... OK
13151315
[...]
1316-
$ pass:quotes[*docker build -t superlists . && docker run -p 8888:8888 -v ./src/db.sqlite3:/src/db.sqlite3 -it superlists*]
1316+
$ pass:quotes[*docker build -t superlists . && docker run \
1317+
-p 8888:8888 \
1318+
-v ./src/db.sqlite3:/src/db.sqlite3 \
1319+
-it superlists*]
13171320
----
13181321

13191322
TIP: if you see an error saying: `django.db.utils.OperationalError`: "unable to open database file",

chapter_10_production_readiness.asciidoc

Lines changed: 94 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,19 @@ trying to move from working state to working state,
1111
and using the FTs to detect any regressions.
1212

1313

14-
.🚧 Warning, this chapter is heavily under construction
14+
.🚧 Warning, chapter under construction 🚧
1515
*******************************************************************************
1616
As part of my work on the third edition of the book,
17-
I'm rewriting the deployment chapters,
18-
but this chapter is far from ready I'm afraid.
19-
Sorry!
17+
I'm making big changes to the deployment chapters,
18+
and this is a very new draft.
2019
21-
Following along with this chapter is going to be pretty
22-
much impossible while I'm still half-done.
20+
This chapter still has a couple of TODOS in,
21+
but its content is mostly there, so you should be able to follow along.
2322
24-
It might be best to skip ahead to <<chapter_12_organising_test_files>>
23+
But as always I really, really need fedback.
24+
So please hit me up at [email protected], or via
25+
https://github.com/hjwp/Book-TDD-Web-Dev-Python/issues[GitHub Issues]
26+
and Pull Requests.
2527
2628
*******************************************************************************
2729

@@ -72,10 +74,13 @@ CMD ["gunicorn", "--bind", ":8888", "superlists.wsgi:application"]
7274

7375

7476
As in the previous chapter, we can use the `docker build && docker run`
75-
in a single line to try out our changes by rebuilding and rerunning our container:
77+
pattern to try out our changes by rebuilding and rerunning our container:
7678

7779
----
78-
docker build -t superlists . && docker run -p 8888:8888 -v ./src/db.sqlite3:/src/db.sqlite3 -it superlists
80+
$ *docker build -t superlists . && docker run \
81+
-p 8888:8888 \
82+
-v ./src/db.sqlite3:/src/db.sqlite3 \
83+
-it superlists*
7984
----
8085

8186
==== The FTs catch a problem with static files
@@ -183,18 +188,18 @@ _settings.py_ that we want to change for production:
183188
(_localhost_ for now, but someday soon, a real domain).
184189
////
185190

186-
* +DEBUG+ mode is all very well for hacking about on your own server,
191+
* `DEBUG` mode is all very well for hacking about on your own server,
187192
but it https://docs.djangoproject.com/en/1.11/ref/settings/#debug[isn't secure].
188193
For example, exposing raw tracebacks to the world is a bad idea.
189194

190195
* `SECRET_KEY` is used by Django for some of its crypto--things
191-
like cookies and CSRF protection.
192-
It's good practice to make sure the secret key in production is different
193-
from the one in your source code repo,
194-
because that code might be visible to strangers.
195-
We'll want to generate a new, random one
196-
but then keep it the same for the foreseeable future
197-
(find out more in the https://docs.djangoproject.com/en/4.2/topics/signing/[Django docs]).
196+
like cookies and CSRF protection.
197+
It's good practice to make sure the secret key in production is different
198+
from the one in your source code repo,
199+
because that code might be visible to strangers.
200+
We'll want to generate a new, random one
201+
but then keep it the same for the foreseeable future
202+
(find out more in the https://docs.djangoproject.com/en/4.2/topics/signing/[Django docs]).
198203

199204
Development, staging and production sites always have some differences
200205
in their configuration.
@@ -244,13 +249,16 @@ else:
244249
are useful for Dev.
245250

246251
The end result is that you don't need to set any env vars for dev,
247-
but production needs both , and it will error if any are missing.
252+
but production needs both to be set explicitly,
253+
and it will error if any are missing.
248254
I think this gives us a little bit of protection
249255
against accidentally forgetting to set one.
250256

251257
TIP: Better to fail hard than allow a typo in an environment variable name to
252258
leave you running with insecure settings.
253259

260+
==== Setting environment variables inside the Dockerfile
261+
254262
Now let's set that environment variable in our Dockerfile using then `ENV` directive:
255263

256264
[role="sourcecode"]
@@ -265,31 +273,43 @@ CMD ["gunicorn", "--bind", ":8888", "superlists.wsgi:application"]
265273
----
266274
====
267275

276+
And try it out...
268277

269-
==== Setting environment variables at the docker command-line
270-
271-
Ooops, and I forgot to set that secret key env var,
272-
mere moments after having dreamt it up.
273278

274279

275280
----
281+
$ *docker build -t superlists . && docker run \
282+
-p 8888:8888 \
283+
-v ./src/db.sqlite3:/src/db.sqlite3 \
284+
-it superlists*
285+
286+
[...]
276287
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
277288
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
289+
# TODO: show more of traceback
278290
----
279291

292+
Ooops, and I forgot to set said secret key env var,
293+
mere seconds after having dreamt it up!
294+
295+
296+
==== Setting environment variables at the docker command-line
297+
298+
We've said we can't keep the secret key in our source code,
299+
so the Dockerfile isn't an option; where else can we put it?
280300

281-
Now, we've said we can't keep the secret key in our source code,
282-
where else can we put it?
283301
For now, we can set it at the command line using the `-e` flag for `docker run`:
284302

285303
[subs="specialcharacters,quotes"]
286304
----
287-
$ *docker build -t superlists . && \
288-
docker run -p 8888:8888 -v ./src/db.sqlite3:/src/db.sqlite3 -e DJANGO_SECRET_KEY=sekrit -it superlists*
305+
$ *docker build -t superlists . && docker run \
306+
-p 8888:8888 \
307+
-v ./src/db.sqlite3:/src/db.sqlite3 \
308+
-e DJANGO_SECRET_KEY=sekrit \
309+
-it superlists*
289310
----
290311

291-
292-
And use a test run to reassure ourselves that things still work...
312+
With that running, we can use our FT again to see if we're back to a working state.
293313

294314
[role="small-code"]
295315
[subs="specialcharacters,macros"]
@@ -300,24 +320,33 @@ AssertionError: 'To-Do' not found in 'Bad Request (400)'
300320
----
301321

302322

323+
303324
==== ALLOWED_HOSTS is Required When Debug Mode is Turned Off
304325

305-
Oops. Let's take a look manually: <<django-400-error>>.
326+
Not quite! Let's take a look manually: <<django-400-error>>.
306327

307328
[[django-400-error]]
308329
.An ugly 400 error
309330
image::images/twp2_1002.png["An unfriendly page showing 400 Bad Request"]
310331

311-
Something's gone wrong. But once again, by running our FTs frequently,
312-
we're able to identify the problem early, before we've changed too many things.
313-
In this case the only thing we've changed is _settings.py_. We've changed three
314-
settings—which one might be at fault?
332+
We've set our two environment variables but doing so seems to have broken things.
333+
But once again, by running our FTs frequently,
334+
we're able to identify the problem early,
335+
before we've changed too many things at the same time.
336+
We've only changed two settings—which one might be at fault?
337+
338+
Let's use the "Googling the error message" technique again,
339+
with the search terms "django debug false" and "400 bad request".
315340

316-
Let's use the "Googling the error message" technique again.
341+
Well, the very first link in my https://duckduckgo.com/?q=django+400+bad+request[search results]
342+
was Stackoverflow suggesting that a 400 error is usually to do with `ALLOWED_HOSTS`,
343+
and the second was the official Django docs,
344+
which takes a bit more scrolling, but confirms it
345+
(see <<search-results-400-bad-request>>).
317346

318-
The very first link in my search results for
319-
https://duckduckgo.com/?q=django+400+bad+request[Django 400 Bad Request]
320-
suggests that a 400 error is usually to do with `ALLOWED_HOSTS`.
347+
[[search-results-400-bad-request]]
348+
.Search results for "django debug false 400 bad request"
349+
image::images/search-results-400-bad-request.png["Duckduckgo search results with stackoverflow and django docs"]
321350

322351

323352
`ALLOWED_HOSTS` is a security setting
@@ -360,12 +389,13 @@ or on a server, so we'll use the `-e` flag again:
360389
----
361390
$ *docker build -t superlists . && \
362391
docker run -p 8888:8888 -v ./src/db.sqlite3:/src/db.sqlite3 \
363-
-e DJANGO_SECRET_KEY=sekrit -e DJANGO_ALLOWED_HOST=localhost \
392+
-e DJANGO_SECRET_KEY=sekrit \
393+
-e DJANGO_ALLOWED_HOST=localhost \
364394
-it superlists*
365395
----
366396

367397

368-
==== Collectstatic is required when Debug is Turned off
398+
==== Collectstatic is Required when Debug is Turned Off
369399

370400
An FT run (or just looking at the site) reveals that we've had a regression
371401
in our static files.
@@ -381,7 +411,8 @@ FAILED (failures=1)
381411

382412

383413
We saw this before when switching from the Django dev server to Gunicorn,
384-
so we introduced Whitenoise. Similarly, when we switch DEBUG off,
414+
so we introduced Whitenoise.
415+
Similarly, when we switch DEBUG off,
385416
Whitenoise stops automagically finding static files in our code,
386417
and instead we need to run `collectstatic`:
387418

@@ -429,40 +460,40 @@ provoke a 500 error somehow and make sure we see tracebacks for it
429460
A few things to think about when trying to prepare a production-ready configuration:
430461
431462
Don't use the Django dev server in production::
432-
Something like Gunicorn or uWSGI is a better tool for running Django;
433-
it will let you run multiple workers, for example.
434-
((("Gunicorn", "benefits of")))
463+
Something like Gunicorn or uWSGI is a better tool for running Django;
464+
it will let you run multiple workers, for example.
465+
((("Gunicorn", "benefits of")))
435466
436467
Decide how to serve your static files::
437468
Static files aren't the same kind of things as the dynamic content
438469
that comes from Django and your webapp, so they need to be treated differently.
439470
WhiteNoise is just one example of how you might do that.
440471
441472
Check your settings.py for dev-only settings::
442-
`DEBUG=True`, `ALLOWED_HOSTS` and `SECRET_KEY` are the ones we came across,
443-
but you will probably have others (we'll see more when we start to send
444-
emails from the server).
473+
`DEBUG=True`, `ALLOWED_HOSTS` and `SECRET_KEY` are the ones we came across,
474+
but you will probably have others
475+
(we'll see more when we start to send emails from the server).
445476
446477
Change things one at a time and rerun your tests frequently::
447-
Whenever we make a change to our server configuration,
448-
we can rerun the test suite,
449-
and either be confident that everything works as well as it did before,
450-
or find out immediately if we did something wrong.
478+
Whenever we make a change to our server configuration,
479+
we can rerun the test suite,
480+
and either be confident that everything works as well as it did before,
481+
or find out immediately if we did something wrong.
451482
452483
Security::
453-
A serious discussion of server security is beyond the scope of this book,
454-
and I'd warn against running your own servers
455-
without learning a good bit more about it.
456-
(One reason people choose to use a PaaS to host their code
457-
is that it means a slightly fewer security issues to worry about.)
458-
If you'd like a place to start, here's as good a place as any:
459-
https://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers[My first 5 minutes on a server].
460-
I can definitely recommend the eye-opening experience of installing
461-
fail2ban and watching its logfiles to see just how quickly it picks up on
462-
random drive-by attempts to brute force your SSH login. The internet is a
463-
wild place!
464-
((("security issues and settings", "server security")))
465-
((("Platform-As-A-Service (PaaS)")))
484+
A serious discussion of server security is beyond the scope of this book,
485+
and I'd warn against running your own servers
486+
without learning a good bit more about it.
487+
(One reason people choose to use a PaaS to host their code
488+
is that it means a slightly fewer security issues to worry about.)
489+
If you'd like a place to start, here's as good a place as any:
490+
https://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers[My first 5 minutes on a server].
491+
I can definitely recommend the eye-opening experience of installing
492+
fail2ban and watching its logfiles to see just how quickly it picks up on
493+
random drive-by attempts to brute force your SSH login. The internet is a
494+
wild place!
495+
((("security issues and settings", "server security")))
496+
((("Platform-As-A-Service (PaaS)")))
466497
467498
TODO: that last one probably belongs in the next chapter.
468499
366 KB
Loading

0 commit comments

Comments
 (0)