Skip to content

Commit d9b7a8f

Browse files
committed
Several fixes and address todos in 9. see #281
1 parent 2b8574e commit d9b7a8f

File tree

1 file changed

+67
-38
lines changed

1 file changed

+67
-38
lines changed

chapter_09_docker.asciidoc

Lines changed: 67 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -156,29 +156,27 @@ So when you come to deploy your code to a real server in a datacentre,
156156
it will be using virtualization.
157157
And, actually, you can use virtualization on your own machine,
158158
with software like Virtualbox or KVM.
159+
You can run Windows "inside" a Mac or Linux laptop, for example.
159160

160-
// SEBASTIAN: I'd consider giving a simple example, like:
161-
// "Running virtualized Linux alongside Windows on your MacBook with MacOS? No problem!"
162-
// Not sure how familiar new kids on the block are with virtualization, TBH.
163-
// From the tone of paragraphs I have a feeling that readers' familiarity is assumed.
164-
// While explanation of virtualization is great, I feel we lack relatable example.
165-
166-
But that can be fiddly to set up!
161+
But it can be fiddly to set up!
167162
And nowadays, thanks to containerization, we can do better
168163
because containerization is a kind of even-more-virtual virtualization.
169164

170165
Conceptually, "regular" virtualization works at the hardware level:
171166
it gives you multiple virtual machines (VMs)
172-
that pretend to be physical computers, on a single real machine.
167+
that pretend to be different physical computers, on a single real machine.
173168
So you can run multiple operating systems using separate VMs
174169
on the same physical box.
175170

176171
Containerization works at the operating system level:
177172
it gives you multiple virtual operating systems that
178173
all run on a single real OS.
179-
It lets us pack the source code and its dependencies together--
180-
the entire environment required to run the application.
181-
This allows you to run programs inside separate virtual environments,
174+
(For this reason, containers tend to use the same operating
175+
system as the host OS.)
176+
177+
Containers let us pack the source code and the system dependencies
178+
(like Python, or system libraries) together,
179+
and our programs run inside separate virtual systems,
182180
using a single real host operating system and kernel.
183181

184182
Have a look at
@@ -189,6 +187,26 @@ You can start one up in milliseconds,
189187
and you can run hundreds on the same machine.
190188

191189

190+
==== Why not just use a virtualenv?
191+
192+
You might be thinking, this sounds a lot like a virtualenv,
193+
and you'd be right!
194+
Virtualenvs already let us run different versions of Python,
195+
with different Python packages, on the same machine.
196+
197+
What Docker containers give us over and above virtualenvs,
198+
is the ability to have different _system_ dependencies too;
199+
things you can't `pip install`, in other words.
200+
In the Python world, this could be C libraries,
201+
like `libpq` for PostgreSQL, or `libxml2` for parsing XML.
202+
But you could also run totally different programming languages
203+
in different containers, or even different linux distributions.
204+
So, server administrators or platform people like them,
205+
because it's one system for running any kind of software,
206+
and they don't need to understand the intricacies of any particular
207+
language's packaging systems.
208+
209+
192210
==== Docker and your CV
193211

194212
That's all well and good for the _theoretical_ justification,
@@ -291,29 +309,21 @@ and where testing fits in.
291309

292310
* Learn how to build and run a container on our machine.
293311

294-
* Learn how to run our FTs against our container.
295-
296312
* Get a first cut of our code up and running inside Docker,
297313
with passing tests.
298314

299-
// DAVID: might be worth condensing this bulleted list, it's rather skimmable
300-
// at the moment. For example is there any difference between the first and fourth point?
301315

302-
//RITA: Consider cross-referencing the chapter by number here so we can hyperlink it for convenience.
303-
304-
**Next chapter: Moving to a production-ready configuration**
316+
**<<chapter_10_production_readiness,Next chapter>>: Moving to a production-ready configuration**
305317

306318
* Gradually, incrementally change the container configuration
307319
to make it production-ready.
308320

309321
* Regularly re-run the FTs to check we didn't break anything.
310322

311-
* Address issues to do with the database, static files, and so on.
323+
* Address issues to do with the database, static files, secrets, and so on.
312324

313-
// gunicorn, DEBUG=False, secret key, etc
314325

315-
//RITA: Consider cross-referencing the chapter by number here so we can hyperlink it for convenience.
316-
**Third chapter: Automating deployment to real servers**
326+
**<<chapter_11_ansible,Third chapter>>: Automating deployment to real servers**
317327

318328
* Gradually build up an Ansible playbook to deploy our containers on a real server.
319329

@@ -358,6 +368,7 @@ class NewVisitorTest(StaticLiveServerTestCase):
358368
self.live_server_url = "http://" + test_server #<2>
359369
----
360370
====
371+
361372
// DAVID: could use a walrus operator here?
362373

363374
Do you remember I said that `LiveServerTestCase` had certain limitations?
@@ -402,7 +413,7 @@ TIP: I'm deliberately choosing a different port to run Dockerised Django on (888
402413
we're looking at Docker, when we're actually looking at a local `runserver`
403414
that I've left running in some terminal somewhere.
404415

405-
I'll use the `--failfast` option to exit as soon as a single test fails:
416+
We'll use the `--failfast` option to exit as soon as a single test fails:
406417

407418
// CSANAD: are line breaks necessary below and at other occurrences of
408419
// --failfast? it does keep the asciidoc lines of source below 80
@@ -1061,6 +1072,8 @@ HTTP/1.1 200 OK
10611072
</html>
10621073
----
10631074

1075+
TIP: Use `Ctrl+D` to exit from the `docker exec` bash shell inside the container.
1076+
10641077
That's definitely some HTML! And the `<title>To-Do lists</title>` looks like it's our html, too.
10651078

10661079
So, we can see Django is serving our site _inside_ the container,
@@ -1123,10 +1136,11 @@ $ pass:quotes[*curl -iv localhost:8888*]
11231136
curl: (52) Empty reply from server
11241137
----
11251138

1126-
// CSANAD: I'm getting a different error for some reason:
1127-
// curl: (56) Recv failure: Connection reset by peer
1128-
// Hopefully, just like above, the difference is irrelevantr but somebody please
1129-
// confirm.
1139+
NOTE: Depending on your system, instead of `(52) Empty reply from server`,
1140+
You might see `(56) Recv failure: Connection reset by peer`.
1141+
They mean the same thing.
1142+
1143+
//TODO: double-check what the difference means here.
11301144

11311145

11321146
==== Essential Googling the Error Message
@@ -1321,7 +1335,11 @@ NOTE: If you don't see this error,
13211335
and you should be able to reproduce the error. I promise it's instructive!
13221336

13231337

1324-
==== Should we run "migrate" inside the Dockerfile? No. // JAN: Not sure I understand this line. You're saying that we shouldn't run migrate inside our Dockerfile, but then in the next line you do exactly that
1338+
==== Should we run "migrate" inside the Dockerfile? No.
1339+
1340+
// JAN: Not sure I understand this line.
1341+
// You're saying that we shouldn't run migrate inside our Dockerfile,
1342+
// but then in the next line you do exactly that
13251343

13261344
So, should we include `manage.py migrate` in our Dockerfile?
13271345

@@ -1361,10 +1379,14 @@ Ran 3 tests in 26.965s
13611379
OK
13621380
----
13631381

1382+
The problem is that this saves our database image into our system image,
1383+
which is not what we want,
1384+
because the system image is mean to be something fixed and stateless,
1385+
whereas the database is living, stateful data that should change over time.
1386+
13641387

13651388
=== Mounting files inside the container.
13661389

1367-
But we don't actually want to package up our database _inside_ the image, do we?
13681390
We want the database on the server to have totally separate data from the one on our machine.
13691391
// CSANAD: we need to list `src/db.sqlite3` in the .dockerignore file to achieve this.
13701392
// Otherwise, if the reader did not delete the DB, it would still end up built into
@@ -1390,15 +1412,18 @@ First let's revert our change:
13901412
[source,dockerfile]
13911413
----
13921414
[...]
1415+
COPY src /src
1416+
13931417
WORKDIR /src
13941418
13951419
CMD python manage.py runserver 0.0.0.0:8888
13961420
----
13971421
====
13981422

13991423

1400-
Let's start by re-creating the database with `migrate`
1401-
(when we moved everything into `./src`, we left the database file behind):
1424+
Then let's make sure we _do_ have the database on our own machine,
1425+
by running `migrate`:
1426+
(when we moved everything into `./src`, we left the database file behind).
14021427

14031428
[subs="specialcharacters,quotes"]
14041429
----
@@ -1411,14 +1436,18 @@ Running migrations:
14111436
Applying sessions.0001_initial... OK
14121437
----
14131438

1414-
Let's make sure to .gitignore the new location of the DB file:
1439+
Let's make sure to _.gitignore_ the new location of the DB file,
1440+
and we'll also use a file called https://docs.docker.com/reference/dockerfile/#dockerignore-file[_.dockerignore_]
1441+
to make sure we can't copy our local dev database into our Docker image
1442+
during Docker builds:
14151443

14161444
[subs="specialcharacters,quotes"]
14171445
----
14181446
$ *echo src/db.sqlite3 >> .gitignore*
1447+
$ *echo src/db.sqlite3 >> .dockerignore*
14191448
----
14201449

1421-
Now let's try mounting our database file.
1450+
Now we can rebuild and try mounting our database file.
14221451
The extra flag to add to the Docker run command is `--mount`,
14231452
where we specify `type=bind`, the `source` path on our machine,
14241453
and the `target` path _inside_ the container:
@@ -1455,17 +1484,18 @@ Ran 3 tests in 26.965s
14551484
OK
14561485
----
14571486

1458-
//RITA: I'd rather add exclamation marks than extend the word.
14591487
AMAZING IT ACTUALLY WORKSSSSSSSS.
1488+
//RITA: I'd rather add exclamation marks than extend the word.
14601489

14611490
Ahem, that's definitely good enough for now! Let's commit.
14621491

14631492

14641493
[subs="specialcharacters,quotes"]
14651494
----
1466-
$ *git add Dockerfile*
1467-
$ *git commit -m"First cut of a Dockerfile"*
1495+
$ *git add -A .* # add Dockerfile, .dockerignore, .gitignore
1496+
$ *git commit -am"First cut of a Dockerfile"*
14681497
----
1498+
14691499
// DAVID: This is the second cut really?
14701500

14711501
Phew. Well, it took a bit of hacking about,
@@ -1478,9 +1508,8 @@ or running on port 8888 forever.
14781508
In the next chapter, we'll make our hacky image more production-ready.
14791509

14801510
But first, time for a well-earned tea break I think, and perhaps a
1481-
https://en.wikipedia.org/wiki/Digestive_biscuit[chocolate biscuit].
1511+
https://en.wikipedia.org/wiki/Digestive_biscuit#Chocolate_digestives[chocolate biscuit].
14821512

1483-
// DAVID: That ain't no chocolate biscuit!
14841513

14851514
.Test-Driving Server Configuration and Deployment
14861515
*******************************************************************************

0 commit comments

Comments
 (0)