Skip to content

Commit 5d96514

Browse files
committed
some fiddling about in 11
1 parent b4d653e commit 5d96514

File tree

5 files changed

+90
-64
lines changed

5 files changed

+90
-64
lines changed

bibliography.asciidoc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@ TODO remove this chapter entirely,
88
or remove links from text (they dont work),
99
and strip down to just the most important books.
1010

11-
- [[[lpthw]]] Zed A. Shaw, 'Learn Python the Hard Way': http://learnpythonthehardway.org/
12-
- [[[iwp]]] Al Sweigart, 'Invent Your Own Computer Games with Python': http://inventwithpython.com
1311
- [[[tddbe]]] Kent Beck, 'Test Driven Development: By Example', Addison-Wesley
1412
- [[[refactoring]]] Martin Fowler, 'Refactoring', Addison-Wesley
1513
- [[[seceng]]] Ross Anderson, 'Security Engineering, Second Edition',
1614
Addison-Wesley: http://www.cl.cam.ac.uk/~rja14/book.html
1715
- [[[jsgoodparts]]] Douglas Crockford,
1816
http://oreil.ly/SuXjXq['JavaScript: The Good Parts'], O'Reilly
1917
- [[[twoscoops]]] Daniel Greenfeld and Audrey Roy, 'Two Scoops of Django', http://twoscoopspress.com/products/two-scoops-of-django-1-6
20-
- [[[mockfakestub]]] Emily Bache, 'Mocks, Fakes and Stubs', https://leanpub.com/mocks-fakes-stubs
2118
- [[[GOOSGBT]]] Steve Freeman and Nat Pryce, 'Growing
2219
Object-Oriented Software Guided by Tests', Addison-Wesley
2320

chapter_09_docker.asciidoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,8 @@ Ah, we forgot that we need to install Django.
667667

668668
=== Virtualenv and requirements.txt
669669

670+
// TODO: move to next chapter
671+
670672
Just like on our own machine,
671673
a virtualenv is useful in a deployed environment to make
672674
sure we have full control over the packages installed for a particular

chapter_10_production_readiness.asciidoc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ it's not designed for real-life workloads.
3838
Instead, we'll use the popular Gunicorn Python/WSGI server.
3939

4040
((("DEBUG settings")))
41-
In addition, several options in 'settings.py' are currently unacceptable.
41+
In addition, several options in _settings.py_ are currently unacceptable.
4242
`DEBUG=True`, is strongly recommended against for production,
4343
we'll want to set a unique `SECRET_KEY`,
4444
and as we'll see, other things will come up.
@@ -58,8 +58,6 @@ an ORM, all sorts of middleware, the admin site...
5858
which I guess is what you'd want next if you already had a pony...
5959

6060
//001
61-
cmdg
62-
6361

6462
[subs="specialcharacters,quotes"]
6563
----

chapter_11_ansible.asciidoc

Lines changed: 83 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,15 @@ We can separate out "deployment" into two tasks:
8181
- _Provisioning_ a new server to be able to host the code
8282
- _Deploying_ a new version of the code to an existing server
8383

84-
Ultimately, infrastructure-as-code tools can let you automate both of these,
85-
but for the purposes of this book, we can live with manual provisioning.
84+
Infrastructure-as-code tools can let you automate both of these,
85+
but the provisioning parts tend to be quite vendor-specific,
86+
so for the purposes of this book, we can live with manual provisioning.
8687

87-
I should probably stress once more that deployment is something that varies a lot,
88-
and that as a result there are few universal best practices for how to do it.
89-
So, rather than trying to remember the specifics of what I'm doing here,
90-
you should be trying to understand the rationale,
91-
so that you can apply the same kind of thinking in the specific future circumstances you encounter.
88+
NOTE: I should probably stress once more that deployment is something that varies a lot,
89+
and that as a result there are few universal best practices for how to do it.
90+
So, rather than trying to remember the specifics of what I'm doing here,
91+
you should be trying to understand the rationale,
92+
so that you can apply the same kind of thinking in the specific future circumstances you encounter.
9293

9394

9495
==== Choosing Where to Host Our Site
@@ -136,7 +137,7 @@ any solution should be fine, as long as:
136137

137138
I'm recommending Ubuntu as a distro because it's popular and I'm used to it.
138139
If you know what you're doing, you can probably get away with using
139-
something else, but you're on your own.
140+
something else, but I won't be able to help you as much if you get stuck.
140141

141142
((("Linux servers")))
142143
If you've never started a Linux server before and you have absolutely no idea
@@ -158,7 +159,7 @@ NOTE: Some people get to this chapter, and are tempted to skip the domain bit,
158159
In these instructions, I'm assuming that you have a nonroot user account set up,
159160
and that it has "sudo" privileges,
160161
so whenever we need to do something that requires root access, we use sudo,
161-
(or "become" in ansible terminology),
162+
(or "become" in Ansible terminology),
162163
and I'm explicit about that in the various instructions that follow.
163164

164165
My user is called "elspeth", but you can call yours whatever you like!
@@ -168,6 +169,7 @@ See the guide linked above if you need tips on creating a sudo user.
168169

169170
.General Server Debugging Tips
170171
*******************************************************************************
172+
// TODO: good advice but not quite sure it's phrased quite right for the new version of the chapter.
171173
172174
The most important lesson to remember from this chapter is,
173175
as always but more than ever, to work incrementally,
@@ -237,32 +239,34 @@ rather than specifying a procedural series of steps to be followed one by one.
237239
Take a look at the instructions here:
238240
https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html
239241

240-
----
241-
pipx install --include-deps ansible
242-
pipx inject ansible docker
243-
244-
# or
242+
The simplest thing to do is to install them into the virtualenv
243+
on our local machine:
245244

246-
pip install ansible docker
245+
[subs="specialcharacters,quotes"]
246+
----
247+
$ *pip install ansible*
248+
# we also need the Docker SDK for the ansible/docker integration to work:
249+
$ *pip install docker*
247250
----
248251

249252
// TODO: consider introducing an explicit requirements.dev.txt here,
250253
// with -r requirements.txt and put ansible, docker, and selenium in there.
254+
// or, maybe get that in place in the previous chapter, keep this one shorter.
251255

252256

253257
==== A First Cut of an Ansible Playbook
254258

255259
Let's dip our toes into Ansible,
256260
and see if we can get it to run a simple "hello world" container on our server.
257261

258-
Here's what's called a "playbook" in ansible terminology.
262+
Here's what's called a "playbook" in Ansible terminology.
259263
It's in a format called YAML (Yet Another Markup Language),
260264
which, if you've never come across before,
261-
you will soon develop a love-hatefootnote:[
265+
you will soon develop a love-hate relationshipfootnote:[
262266
The "love" part is that yaml is very easy to _read_ and scan through at a glance.
263267
The "hate" part is that the actual syntax is surprisingly fiddly to get right:
264268
the difference between lists and key/value maps is subtle and I can never quite remember it honestly.]
265-
relationship with.
269+
for.
266270

267271

268272
[role="sourcecode"]
@@ -292,20 +296,20 @@ relationship with.
292296
----
293297
====
294298

295-
<1> An ansible playbook is a series of "tasks"
299+
<1> An Ansible playbook is a series of "tasks"
296300
(so in that sense it's still quite sequential and procedural),
297301
but the individual tasks themselves are quite declarative.
298302
Each one usually has a human-readable `name` attribute.
299303

300-
<2> Each tasks uses an ansible "module" to do its work.
301-
The next few use the `builtin.apt` module which provides
302-
a wrapper around the `apt` Debian & Ubuntu package management tool.
304+
<2> Each tasks uses an Ansible "module" to do its work.
305+
This one uses the `builtin.apt` module which provides a wrapper
306+
around the `apt` Debian & Ubuntu package management tool.
303307

304308
<3> Each module then provides a bunch of parameters which control how it works.
305309
Here we specify the `name` of the package we want to install ("docker")
306310
and tell it update its cache first, which is required on a fresh server.
307311

308-
Most ansible modules have pretty good documentation,
312+
Most Ansible modules have pretty good documentation,
309313
check out the `builtin.apt` one for example.
310314
I often skip to the
311315
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html#examples[Examples section].
@@ -400,6 +404,14 @@ SSHing in to check things worked is a key server debugging skill!
400404
It's something we want to practice on our staging server,
401405
because ideally we'll want to avoid doing it on production machines.
402406

407+
Let's move on to trying to get our actual docker container running on the server.
408+
As we go through, you'll see that we're going to work through very similar issues
409+
to the ones we've already figured our way through in the last couple of chapters:
410+
411+
* Configuration
412+
* Networking
413+
* And the database.
414+
403415

404416
=== Getting our image onto the server
405417

@@ -421,7 +433,7 @@ so we're going to "simulate" this process by doing it manually.
421433

422434
It turns out you can "export" a container image to an archive format,
423435
manually copy that to the server, and then re-import it.
424-
In ansible config, it looks like this:
436+
In Ansible config, it looks like this:
425437

426438
[role="sourcecode"]
427439
.infra/ansible-provision.yaml (ch11l002)
@@ -550,17 +562,19 @@ This means we don't have a dependency on having run `docker build` locally.
550562
delegate_to: 127.0.0.1
551563
552564
- name: Export container image locally
565+
[...]
553566
----
554567
====
555568

556-
<1> Having this step also allows us to work around an issue
557-
with compatility between Apple's new ARM-based chips and
558-
our server's x86/amd64 architecture.
569+
<1> I needed this `platform` attribute to work around an issue
570+
with compatibility between Apple's new ARM-based chips and our server's
571+
x86/amd64 architecture.
559572
You could also use this `platform:` to cross-build docker images
560573
for a rasbperry pi from a regular PC, or vice-versa.
574+
It does no harm in any case.
561575

562576

563-
In any case, let's see if it works!
577+
Now let's see if it works!
564578

565579
[subs="specialcharacters,quotes"]
566580
----
@@ -596,25 +610,25 @@ Ah woops, we need to set those environment variables on the server too.
596610
=== Using an env File to Store Our Environment Variables
597611

598612
When we run our container manually locally, we can pass in environment variables with the `-e` flag.
599-
But we don't want to hard-code secrets like SECRET_KEY into our ansible files
613+
But we don't want to hard-code secrets like SECRET_KEY into our Ansible files
600614
and commit them to our repo!
601615

602-
Instead, we can use ansible to automate the creation of a secret key,
603-
and then save it to a file on the server, where it will be relatively secure
604-
(better than saving it to version contorl and pushing it to GitHub in any case!)
616+
Instead, we can use Ansible to automate the creation of a secret key,
617+
and then save it to a file on the server, where it _ill be _relatively_ secure
618+
(better than saving it to version control and pushing it to GitHub in any case!)
605619

606-
We can use a so-called "env file" to store environment variables,
607-
which are essentially a list of key-value pairs using shell syntax,
620+
We can use a so-called "env file" to store environment variables.
621+
Env files are essentially a list of key-value pairs using shell syntax,
608622
a bit like you'd use with `export`.
609623

610624
One extra subtlety is that we want to vary the actual contents of the env file,
611625
depending on where we're deploying to.
612626
Each server should get its own unique secret key,
613-
adn we want different config for staging and prod, for example.
627+
and we want different config for staging and prod, for example.
614628

615629
So, just as we inject variables into our html templates in Django,
616630
we can use a templating language called "jinja2" to have variables in our env file.
617-
It's a common tool in ansible scripts, and the syntax is very similar to Django's.
631+
It's a common tool in Ansible scripts, and the syntax is very similar to Django's.
618632

619633
Here's what our template for the env file will looks like:
620634

@@ -632,7 +646,7 @@ DJANGO_ALLOWED_HOST="{{ host }}"
632646
And here's how we use it in the provisioning script:
633647

634648

635-
[role="sourcecode"]
649+
[role="sourcecode small-code"]
636650
.infra/ansible-provision.yaml (ch11l004)
637651
====
638652
[source,yaml]
@@ -647,7 +661,7 @@ And here's how we use it in the provisioning script:
647661
force: false # do not recreate file if it already exists. <2>
648662
vars: # <3>
649663
host: "{{ inventory_hostname }}" # <4>
650-
secret_key: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}"
664+
secret_key: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}" # <5>
651665
652666
- name: Run container
653667
community.docker.docker_container:
@@ -667,14 +681,19 @@ And here's how we use it in the provisioning script:
667681

668682
<3> The `vars` section defines the variables we'll inject into our template.
669683

670-
<4> We actually use a built-in ansible variable called `inventory_hostname`.
684+
<4> We actually use a built-in Ansible variable called `inventory_hostname`.
671685
This variable woul actually be available in the template already,
672686
but I'm renaming it for clarity.
673687

688+
<5> This `lookup('password')` thing I copy-pasted from Stackoverflow.
689+
Come on there's no shame in that.
690+
674691

675692
NOTE: Using an env file to store secrets is definitely better than committing
676693
it to version control, but it's maybe not the state of the art either.
677-
TODO: mention other secret management tools. vault
694+
You'll probably come across more advanced alternatives from various cloud providers,
695+
or Hashicorp's "vault" tool.
696+
678697

679698

680699
.Idempotency and Declarative Configuration
@@ -685,8 +704,8 @@ meaning that, as much as possible, you specify the desired state that you want,
685704
rather than specifying a series of steps to get there.
686705
687706
This concept goes along with the idea of "idempotency",
688-
which means that you get the same result when you run something once,
689-
as when you run it multiple times.
707+
which is wanting to get the same result when you run something for the first time,
708+
vs running it again on later occations.
690709
691710
An example is the `apt` module that we used to install docker.
692711
It doesn't crash if docker is already installed, and in fact,
@@ -749,6 +768,7 @@ skipped=0 rescued=0 ignored=0
749768

750769
Looks good! What do our tests think?
751770

771+
752772
==== More debugging
753773

754774
We run our tests as usual and run into a new problem:
@@ -901,6 +921,9 @@ Here's how
901921
community.docker.docker_container_exec: # <3>
902922
container: superlists
903923
command: ./manage.py migrate
924+
925+
- name: Run container
926+
[...]
904927
----
905928
====
906929

@@ -955,11 +978,15 @@ Podman and Systemd into the mix, should things not go according to plan:
955978
956979
- You can get detailed info on the Container using
957980
`docker inspect superlists`.
981+
This is a good place to go check on environment variables,
982+
port mappings, and exactly which image was running, for example.
958983
959984
- And you can inspect the image with
960985
`docker image inspect superlists`.
961-
((("debugging", "Docker")))
986+
You might need this to check the exact image hash,
987+
to make sure it's the same one you built locally.
962988
989+
((("debugging", "Docker")))
963990
964991
*******************************************************************************
965992

@@ -985,7 +1012,6 @@ Rewire the FT runner to be able to test against the local VM.
9851012
Having a Vagrant config file is particularly helpful when working
9861013
in a team--it helps new developers to spin up servers that look exactly
9871014
like yours.((("", startref="ansible29")))
988-
////
9891015
9901016
9911017
@@ -1045,6 +1071,8 @@ $ *git log --graph --oneline --decorate*
10451071
[...]
10461072
----
10471073
1074+
////
1075+
10481076

10491077
Anyway, you now have a live website! Tell all your friends! Tell your mum, if
10501078
no one else is interested! And, in the next chapter, it's back to coding
@@ -1057,26 +1085,26 @@ Further Reading
10571085

10581086

10591087
((("automated deployment", "additional resources")))
1060-
There's no such thing as the One True Way in deployment,
1061-
and I'm no grizzled expert in any case.
1088+
There's no such thing as the One True Way in deployment;
10621089
I've tried to set you off on a reasonably sane path,
10631090
but there's plenty of things you could do differently,
1064-
and lots, lots more to learn besides.q
1091+
and lots, lots more to learn besides.
10651092
Here are some resources I used for inspiration:
10661093

10671094

10681095
* http://12factor.net/[The 12-factor App] by the Heroku team
10691096

10701097
* http://hynek.me/talks/python-deployments[Solid Python Deployments for Everybody] by Hynek Schlawack
10711098

1072-
* The deployment chapter of <<twoscoops,Two Scoops of Django>> by Dan
1073-
Greenfeld and Audrey Roy
1099+
* The deployment chapter of
1100+
https://www.feldroy.com/books/two-scoops-of-django-3-x[Two Scoops of Django]
1101+
by Dan Greenfeld and Audrey Roy
10741102

10751103

10761104

10771105

10781106
[role="pagebreak-before less_space"]
1079-
.Automated Deployments
1107+
.Automated Deployment Recap
10801108
*******************************************************************************
10811109
10821110
TODO Maybe recap the key steps of any deployment:
@@ -1102,6 +1130,10 @@ Automating provisioning::
11021130
brand new servers.
11031131
This will involve interacting with the API of your hosting provider.
11041132
1133+
////
1134+
1135+
TODO: find a place for this
1136+
11051137
Security::
11061138
A serious discussion of server security is beyond the scope of this book,
11071139
and I'd warn against running your own servers
@@ -1116,5 +1148,6 @@ Security::
11161148
wild place!
11171149
((("security issues and settings", "server security")))
11181150
((("Platform-As-A-Service (PaaS)")))
1151+
////
11191152
11201153
*******************************************************************************

0 commit comments

Comments
 (0)