1
1
[[chapter_09_docker]]
2
2
== Deployment Part 1: Containerization aka Docker
3
+ // RITA: I'm not keen on including the word "part" in chapter titles especially when the chapter is also within something called a "part." Would it make sense to put the deployment chapters into its own Part? So, ch8 might go into Part 1, chs 9-11 would go into the new Part 2 called something like "Deployment," and Part 3 would start with ch 12.
3
4
4
5
[quote, 'http://bit.ly/2uhCXnH[Devops Borat]']
5
6
______________________________________________________________
@@ -97,7 +98,7 @@ Security and Configuration::
97
98
(because they expose our source code in tracebacks).
98
99
99
100
100
- One way to approach the problem is to get a server,
101
+ One way to approach the problem is to get a server
101
102
and start manually configuring and installing everything,
102
103
hacking about until it works,
103
104
and maybe think about automating things laterfootnote:[
@@ -109,8 +110,8 @@ in the world of agile/lean software development,
109
110
it's that taking smaller steps usually pays off.
110
111
111
112
How can we take smaller, safer steps towards a production deployment?
112
- Can we _simulate_ the process of moving to a server,
113
- so that we can iron out all the bugs,
113
+ Can we _simulate_ the process of moving to a server
114
+ so that we can iron out all the bugs
114
115
before we actually take the plunge?
115
116
Can we then make small changes one at a time,
116
117
solving problems one by one,
@@ -134,7 +135,7 @@ sometimes referred to as "containerization".
134
135
You may have already heard of the idea of "virtualization",
135
136
which allows a single physical computer to pretend to be several machines.
136
137
Pioneered by IBM (amongst others) on mainframes in the 1960s,
137
- it rose to mainstream adoption in the 90s ,
138
+ it rose to mainstream adoption in the 1990s ,
138
139
where it was sold as a way to optimise resource usage in datacentres.
139
140
AWS, for example, was an offshoot of Amazon,
140
141
who were using virtualization already,
@@ -143,46 +144,46 @@ to customers outside the business.
143
144
144
145
So when you come to deploy your code to a real server in a datacentre,
145
146
it will be using virtualization.
146
- And actually you can use virtualization on your own machine,
147
+ And, actually, you can use virtualization on your own machine,
147
148
with software like Virtualbox or KVM.
148
149
149
150
But that can be fiddly to set up!
150
- And nowadays, thanks to containerization, we can do better.
151
- Because containerization is a kind of even-more-virtual virtualization.
151
+ And nowadays, thanks to containerization, we can do better
152
+ because containerization is a kind of even-more-virtual virtualization.
152
153
153
154
Conceptually, "regular" virtualization works at the hardware level:
154
155
it gives you multiple virtual machines (VMs)
155
156
that pretend to be physical computers, on a single real machine.
156
157
So you can run multiple operating systems using separate VMs
157
158
on the same physical box.
158
159
159
- Containerization work at the operating system level:
160
+ Containerization works at the operating system level:
160
161
it gives you multiple virtual operating systems that
161
162
all run on a single real OS.
162
- It lets us pack the source code and its dependencies together,
163
+ It lets us pack the source code and its dependencies together--
163
164
the entire environment required to run the application.
164
- So you can run programs inside separate virtual environments,
165
+ This allows you to run programs inside separate virtual environments,
165
166
using a single real host operating system and kernel.
166
167
167
168
Have a look at
168
169
https://www.docker.com/resources/what-container/[Docker's resources on containers]
169
- for more explanation,
170
+ for more explanation.
170
171
The upshot of this is that containers are much "cheaper".
171
172
You can start one up in milliseconds,
172
173
and you can run hundreds on the same machine.
173
174
174
175
175
176
==== Docker and your CV
176
177
177
- That's all well and good for the _theoretical_ justification.
178
- But let's get to the _real_ reason for using this technology,
178
+ That's all well and good for the _theoretical_ justification,
179
+ but let's get to the _real_ reason for using this technology,
179
180
which, as always, is:
180
181
"it's fashionable so it's going to look good on my CV."
181
182
182
183
For the purposes of this book,
183
184
that's not such a bad justification really!
184
185
185
- Yes I think it's going to be a nice way to have a "pretend"
186
+ Yes, I think it's going to be a nice way to have a "pretend"
186
187
deployment on our own machine, before we try the real one--but
187
188
also, containers are so popular nowadays,
188
189
that it's very likely that you're going to encounter them at work
@@ -257,7 +258,7 @@ But there are solutions to all of these. In order:
257
258
258
259
=== An Overview of Our Deployment Procedure
259
260
260
- Over these three chapters, I'm going to go through _a_ deployment procedure.
261
+ Over the next three chapters, I'm going to go through _a_ deployment procedure.
261
262
It isn't meant to be the _perfect_ deployment procedure,
262
263
so please don't take it as being best practice,
263
264
or a recommendation--it's meant to be an illustration,
@@ -280,7 +281,7 @@ and where testing fits in.
280
281
281
282
282
283
283
-
284
+ //RITA: Consider cross-referencing the chapter by number here so we can hyperlink it for convenience.
284
285
**Next chapter: Moving to a production-ready configuration**
285
286
286
287
* Gradually, incrementally change the container configuration
@@ -292,7 +293,7 @@ and where testing fits in.
292
293
293
294
// gunicorn, DEBUG=False, secret key, etc
294
295
295
-
296
+ //RITA: Consider cross-referencing the chapter by number here so we can hyperlink it for convenience.
296
297
**Third chapter: Automating deployment to real servers**
297
298
298
299
* Gradually build up an Ansible playbook to deploy our containers on a real server.
@@ -354,8 +355,8 @@ and to use a real server instead.
354
355
<2> Here's the hack: we replace `self.live_server_url` with the address of
355
356
our "real" server.
356
357
357
-
358
- NOTE: A clarification: in these chapters,
358
+ // RITA: In the next three chapters or the chapters in the book as a whole?
359
+ NOTE: A clarification: In these chapters,
359
360
we run tests _against_ our Docker container, or _against_ our staging server,
360
361
but that doesn't mean we run the tests _from_ Docker or _from_ our staging server.
361
362
We still run the tests from our own laptop,
@@ -481,7 +482,7 @@ Status: Downloaded newer image for busybox:latest
481
482
hello world
482
483
----
483
484
484
- What's happened there is that Docker has
485
+ What's happened there is that Docker has:
485
486
486
487
* Searched for a local copy of the "busybox" image and not found it
487
488
* Downloaded the image from DockerHub
@@ -497,7 +498,7 @@ Cool! We'll find out more about all of these steps as the chapter progresses.
497
498
Impartiality commands me to also recommend https://podman.io/[Podman],
498
499
which is a like-for-like replacement for Docker.
499
500
500
- It's pretty much exactly the same as docker ,
501
+ It's pretty much exactly the same as Docker ,
501
502
arguably with a few advantages even, but I won't go into detail here.
502
503
503
504
I actually tried it out on early drafts of this chapter and it worked perfectly well.
@@ -576,10 +577,10 @@ CMD python manage.py runserver <4>
576
577
<2> The `COPY` instruction (the uppercase words are called "instructions")
577
578
lets you copy files from your own computer into the container image.
578
579
We use it to copy all our source code from the newly-created _src_ folder,
579
- into a similarly-named folder at the root of the container image
580
+ into a similarly-named folder at the root of the container image.
580
581
581
582
<3> `WORKDIR` sets the current working directory for all subsequent commands.
582
- It's a bit like doing `cd /src`
583
+ It's a bit like doing `cd /src`.
583
584
584
585
<4> Finally the `CMD` instruction tells docker which command you want it to run
585
586
by default, when you start a container based on that image.
@@ -723,7 +724,7 @@ $ *git commit -m "Add requirements.txt for virtualenv"*
723
724
You may be wondering why we didn't add our other dependency,
724
725
Selenium, to our requirements,
725
726
or why we didn't just add _all_ the dependencies,
726
- including the "transitive" ones (eg , Django has its own dependencies of `asgiref` and `sqlparse`).
727
+ including the "transitive" ones (e.g. , Django has its own dependencies of `asgiref` and `sqlparse`).
727
728
728
729
As always, I have to gloss over some nuance and tradeoffs,
729
730
but the short answer is first, Selenium is only a dependency for the tests,
@@ -734,7 +735,7 @@ in more tools, and I didn't want to do that for this book.footnote:[
734
735
When you have a moment, you might want to do some further reading
735
736
on "lockfiles", pyproject.toml, hard pinning vs soft pining,
736
737
and immediate vs transitive dependencies. If I absolutely _had_
737
- to recommend a python dependency management tool,
738
+ to recommend a Python dependency management tool,
738
739
it would be https://github.com/jazzband/pip-tools[pip-tools],
739
740
which is a fairly minimal one.]
740
741
@@ -791,8 +792,8 @@ TIP: Forgetting the `-r` and running `pip install requirements.txt`
791
792
==== Successful Run
792
793
793
794
Let's do the `build` and `run` in a single line.
794
- This is a pattern I used quite often when developing a Dockerfile,
795
- to be able to quickly rebuild and see the effect of a change:
795
+ This is a pattern I used quite often when developing a Dockerfile so I can
796
+ quickly rebuild and see the effect of a change:
796
797
797
798
[subs="specialcharacters,quotes"]
798
799
----
@@ -876,7 +877,7 @@ you should find the docker process has been terminated.
876
877
877
878
=== Using the FT to Check That Our Container Works
878
879
879
- Let's see what our FTs think about this Docker version of our site.
880
+ Let's see what our FTs think about this Docker version of our site:
880
881
881
882
882
883
[role="small-code"]
@@ -889,13 +890,13 @@ selenium.common.exceptions.WebDriverException: Message: Reached error page:
889
890
about:neterror?e=connectionFailure&u=http%3A//localhost%3A8888/[...]
890
891
----
891
892
892
- Nope! What's going on here? Time for a little debugging.
893
+ What's going on here? Time for a little debugging.
893
894
894
895
895
896
896
897
=== Debugging a Container Networking Problems
897
898
898
- First let's try and take a look ourselves, in our browser, by going to http://localhost:8888/:
899
+ First, let's try and take a look ourselves, in our browser, by going to http://localhost:8888/:
899
900
900
901
[[firefox-unable-to-connect-screenshot]]
901
902
.Cannot connect on that port
@@ -927,7 +928,7 @@ WORKDIR /src
927
928
CMD python manage.py runserver 8888
928
929
----
929
930
====
930
-
931
+ //RITA: Newbie question. What does Ctrl+C do again? Add a couple of words to give us some quick context. "Use Ctrl+C to kill the current..."
931
932
Ctrl+C the current dockerized container process if it's still running in your terminal,
932
933
then give it another `build && run`:
933
934
@@ -1066,6 +1067,7 @@ $ *docker build -t superlists . && docker run -p 8888:8888 -it superlists*
1066
1067
Now that will _change_ the error we see, but only quite subtly (see <<firefox-connection-reset>>).
1067
1068
Things clearly aren't working yet.
1068
1069
1070
+ //RITA: If at all possible, I suggest using the light or daytime theme for all browser screenshots to make them easier to read.
1069
1071
[[firefox-connection-reset]]
1070
1072
.Cannot connect on that port
1071
1073
image::images/firefox-connection-reset.png["Firefox showing the 'Connection reset' error"]
@@ -1150,7 +1152,7 @@ $ *docker build -t superlists . && docker run -p 8888:8888 -it superlists*
1150
1152
Starting development server at http://0.0.0.0:8888/
1151
1153
----
1152
1154
1153
- We can verify it's working with `curl:
1155
+ We can verify it's working with `curl` :
1154
1156
1155
1157
[subs="specialcharacters,macros"]
1156
1158
----
@@ -1179,7 +1181,7 @@ and say "well, this is hopeless, it can't be fixed",
1179
1181
and give up.
1180
1182
1181
1183
Thankfully I have had some good role models over the years
1182
- who are much better at it than me (hi Glenn!).
1184
+ who are much better at it than me (hi, Glenn!).
1183
1185
Debugging needs the patience and tenacity of a bloodhound.
1184
1186
If at first you don't succeed,
1185
1187
you need to systematically rule out options,
@@ -1268,7 +1270,7 @@ Run 'python manage.py migrate' to apply them.
1268
1270
NOTE: If you don't see this error,
1269
1271
it's because your src folder had the database file in it, unlike mine.
1270
1272
For the sake of argument, run `rm src/db.sqlite3` and re-run the build & run commands,
1271
- and you should be able to repro the error. I promise it's instructive!
1273
+ and you should be able to reproduce the error. I promise it's instructive!
1272
1274
1273
1275
1274
1276
==== Should we run "migrate" inside the Dockerfile? No.
@@ -1324,6 +1326,7 @@ is to access the database from the filesystem outside the container.
1324
1326
1325
1327
That also gives us a convenient excuse to talk about mounting files in Docker,
1326
1328
which is a very useful thing to be able to do (TM).
1329
+ //RITA: If you're going to be funny with a (TM), then I suggest you take it further by using caps for the term. "A Very Useful Thing to Be Able to Do (TM)."
1327
1330
1328
1331
1329
1332
First let's revert our change:
@@ -1369,7 +1372,7 @@ ERRO[0000] error waiting for container: context canceled
1369
1372
////
1370
1373
1371
1374
1372
- TIP: if you see an error saying: `django.db.utils.OperationalError`: "unable to open database file",
1375
+ TIP: If you see an error saying: `django.db.utils.OperationalError`: "unable to open database file",
1373
1376
try stopping the container, `rm -rf src/db.sqlite3`, then re-run the migrate command
1374
1377
_outside_ the container, and then rebuild and run your image.
1375
1378
@@ -1391,7 +1394,8 @@ Ran 3 tests in 26.965s
1391
1394
OK
1392
1395
----
1393
1396
1394
- AMAZING IT ACTUALLY WORKSSSSSSSS.
1397
+ //RITA: I'd rather add exclamation marks than extend the word.
1398
+ AMAZING! IT ACTUALLY WORKS!
1395
1399
1396
1400
Ahem, that's definitely good enough for now! Let's commit.
1397
1401
@@ -1408,7 +1412,7 @@ but now we can be reassured that the basic Docker plumbing works.
1408
1412
Notice that the FT was able to guide us incrementally towards a working config,
1409
1413
and spot problems early on (like the missing database).
1410
1414
1411
- But we really can't be using the Django dev server in production,
1415
+ However, we really can't be using the Django dev server in production,
1412
1416
or running on port 8888 forever.
1413
1417
In the next chapter, we'll make our hacky image more production-ready.
1414
1418
0 commit comments