Skip to content

Commit a603a53

Browse files
committed
Progress docker-ifying 11
1 parent 13d2c05 commit a603a53

File tree

2 files changed

+168
-93
lines changed

2 files changed

+168
-93
lines changed

chapter_11_ansible.asciidoc

Lines changed: 168 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,8 @@ At my registrar, the control screens looked a bit like <<registrar-control-scree
189189

190190
[[registrar-control-screens]]
191191
.Domain setup
192-
image::images/twp2_0902.png["Registrar control screens for two domains"]
192+
image::images/gandi_add_dns_a_record.png["Registrar control screen for adding a DNS record"]
193193

194-
//TODO: adjust illustration to show "superlists" not "book-example"
195194

196195
((("A-Records")))
197196
In the DNS system, pointing a domain at a specific IP address is called an "A-Record".
@@ -263,42 +262,20 @@ relationship with.
263262
264263
tasks:
265264
266-
- name: Install docker <1>
265+
- name: Install docker #<1>
266+
ansible.builtin.apt: #<2>
267+
name: docker #<3>
268+
state: latest
269+
update_cache: true
267270
become: true
268-
block:
269-
- name: Add Docker GPG apt Key
270-
ansible.builtin.apt_key: <2>
271-
url: https://download.docker.com/linux/ubuntu/gpg
272-
state: present
273-
274-
- name: Add Docker Repository
275-
ansible.builtin.apt_repository:
276-
repo: deb https://download.docker.com/linux/ubuntu jammy stable
277-
state: present
278-
279-
- name: Update apt and install docker-ce
280-
ansible.builtin.apt:
281-
name: docker-ce
282-
state: latest
283-
update_cache: true
284-
285-
- name: Install Docker Module for Python
286-
ansible.builtin.pip:
287-
name: docker
288-
289-
- name: Add our user to Docker allowed users
290-
ansible.builtin.user:
291-
name: elspeth
292-
groups: docker
293-
append: true
294271
295272
- name: Run test container
296273
community.docker.docker_container:
297274
name: testcontainer
298275
state: started
299276
image: busybox
300277
command: echo hello world
301-
become: true
278+
become: true
302279
----
303280
====
304281

@@ -322,56 +299,55 @@ https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.h
322299

323300

324301
[subs="specialcharacters,quotes"]
325-
326302
----
327-
$ *ansible-playbook --user=elspeth -i 192.168.56.10, infra/ansible-provision.yaml -vv*
303+
$ *ansible-playbook --user=elspeth -i staging.ottg.co.uk, infra/ansible-provision.yaml -vv*
304+
ansible-playbook [core 2.16.3]
305+
config file = None
306+
[...]
307+
No config file found; using defaults
308+
Skipping callback 'default', as we already have a stdout callback.
309+
Skipping callback 'minimal', as we already have a stdout callback.
310+
Skipping callback 'oneline', as we already have a stdout callback.
311+
328312
PLAYBOOK: ansible-provision.yaml **********************************************
329313
1 plays in infra/ansible-provision.yaml
330314
331315
PLAY [all] ********************************************************************
332316
333317
TASK [Gathering Facts] ********************************************************
334-
task path: ...goat-book/infra/ansible-provision.yaml:2
335-
ok: [192.168.56.10]
336-
337-
TASK [Add Docker GPG apt Key] *************************************************
338-
task path: ...goat-book/infra/ansible-provision.yaml:9
339-
changed: [192.168.56.10] => {"after": ["8D81803C0EBFCD88", "7EA0A9C3F273FCD8", "D94AA3F0EFE21092", "871920D1991BC93C"], "before": ["D94AA3F0EFE21092", "871920D1991BC93C"], "changed": true, "fp": "8D81803C0EBFCD88", "id": "8D81803C0EBFCD88", "key_id": "8D81803C0EBFCD88", "short_id": "0EBFCD88"}
340-
341-
TASK [Add Docker Repository] **************************************************
342-
task path: ...goat-book/infra/ansible-provision.yaml:14
343-
changed: [192.168.56.10] => {"changed": true, "repo": "deb https://download.docker.com/linux/ubuntu jammy stable", "sources_added": ["/etc/apt/sources.list.d/download_docker_com_linux_ubuntu.list"], "sources_removed": [], "state": "present"}
344-
345-
TASK [Update apt and install docker-ce] ***************************************
346-
task path: ...goat-book/infra/ansible-provision.yaml:19
347-
changed: [192.168.56.10] => {"cache_update_time": [...]
348-
changed: [192.168.56.10] => {"cache_update_time": 1706583891, "cache_updated":
349-
true, "changed": true, "stderr": "", "stderr_lines": [], "stdout": "Reading
350-
package lists...\nBuilding dependency tree...\nReading state
318+
task path: ...goat-book/superlists/infra/ansible-provision.yaml:2
319+
ok: [staging.ottg.co.uk]
320+
PLAYBOOK: ansible-provision.yaml **********************************************
321+
1 plays in infra/ansible-provision.yaml
322+
323+
TASK [Install docker] *********************************************************
324+
task path: ...goat-book/superlists/infra/ansible-provision.yaml:6
325+
ok: [staging.ottg.co.uk] => {"cache_update_time": 1708981325, "cache_updated": true, "changed": false}
326+
327+
328+
TASK [Install docker] *************************************************************************************************************
329+
task path: ...goat-book/superlists/infra/ansible-provision.yaml:6
330+
changed: [staging.ottg.co.uk] => {"cache_update_time": [...]
331+
"cache_updated": true, "changed": true, "stderr": "", "stderr_lines": [],
332+
"stdout": "Reading package lists...\nBuilding dependency tree...\nReading [...]
351333
information...\nThe following additional packages will be installed:\n
352-
containerd.io docker-buildx-plugin docker-ce-cli docker-ce-rootless-extras\n
353-
[...]
354-
TASK [Add our user to Docker allowed users] ***********************************
355-
changed: [192.168.56.10] => {"append": true, "changed": true, "comment": "",
356-
"group": 1001, "groups": "docker", "home": "/home/elspeth", "move_home": false,
357-
"name": "elspeth", "shell": "/bin/bash", "state": "present", "uid": 1001}
334+
wmdocker\nThe following NEW packages will be installed:\n docker wmdocker\n0
335+
358336
TASK [Run test container] *****************************************************
359-
task path: ...goat-book/infra/ansible-provision.yaml:31
360-
changed: [192.168.56.10] => {"changed": true, "container": {"AppArmorProfile":
361-
"docker-default", "Args": ["hello", "world"], "Config": {"AttachStderr": true,
362-
"AttachStdin": false, "AttachStdout": true, "Cmd": ["echo", "hello", "world"],
337+
task path: ...goat-book/superlists/infra/ansible-provision.yaml:13
338+
changed: [staging.ottg.co.uk] => {"changed": true, "container":
339+
{"AppArmorProfile": "docker-default", "Args": ["hello", "world"], "Config":
363340
[...]
364341
365-
PLAY RECAP ***********************************************************
366-
192.168.56.10 : ok=6 changed=6 unreachable=0 failed=0
342+
PLAY RECAP ********************************************************************
343+
staging.ottg.co.uk : ok=3 changed=2 unreachable=0 failed=0
367344
skipped=0 rescued=0 ignored=0
368345
----
369346

370-
TODO: stop using local ip
371347

372348

373349
////
374-
350+
old error message when trying to use elspeth user to run docker.
375351
this goes wrong because groups don't work immediately:
376352
377353
TASK [Run test container] *****************************************************
@@ -382,30 +358,41 @@ PermissionError(13, 'Permission denied'))"}
382358
waiting a few minutes fixes it
383359
384360
for now i'll just put become:true
385-
386-
387361
////
388362

389363

390364
=== SSHing Into the Server and Viewing Container Logs
391365

392-
Now ssh into the server, check it worked
366+
Time to get into some good old-fashioned sysadmin!
367+
Let's SSH in to our server and see if we can see any evidence that our container has run.
368+
369+
We use `docker ps -a` to view all containers, including old/stopped ones,
370+
and we can use `docker logs` to view the output from one of them:
393371

394-
TODO: forget podman, just use docker.
395372

396373
[role="server-commands"]
397374
[subs="specialcharacters,quotes"]
398375
----
399-
elspeth@server:$ *podman ps -a*
400-
elspeth@server:$ *podman logs testcontainer*
401-
hello, world
376+
377+
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-67-generic x86_64)
378+
[...]
379+
380+
elspeth@server$ *docker ps -a*
381+
CONTAINER ID IMAGE COMMAND CREATED STATUS
382+
PORTS NAMES
383+
3a2e600fbe77 busybox "echo hello world" 2 days ago Exited (0) 10
384+
minutes ago testcontainer
385+
386+
elspeth@server:$ *docker logs testcontainer*
387+
hello world
402388
----
403389

404390
TIP: Look out for that `elspeth@server`
405391
in the command-line listings in this chapter.
406392
It indicates commands that must be run on the server,
407393
as opposed to commands you run on your own PC.
408394

395+
409396
SSHing in to check things worked is a key server debugging skill!
410397
It's something we want to practice on our staging server,
411398
because ideally we'll want to avoid doing it on production machines.
@@ -419,12 +406,11 @@ and organisations will often run private ones,
419406
hosted by cloud providers like AWS.
420407

421408
So your process of getting an image onto a server is usually
422-
* push the image from your machine to the registry
423-
* pull the image from the registry onto the server.
409+
* Push the image from your machine to the registry
410+
* Pull the image from the registry onto the server.
424411
Usually this step is implicit,
425-
in that you just specifying the image name
426-
in the format registry-url/image-name:tag,
427-
and then `docker run` takes care of pulling down the image for you.
412+
in that you just specifying the image name in the format registry-url/image-name:tag,
413+
and then `docker run` takes care of pulling down the image for you.
428414

429415
But I don't want to ask you to create a DockerHub account,
430416
or implicitly endorse any particular provider,
@@ -443,43 +429,132 @@ In ansible config, it looks like this:
443429
- hosts: all
444430
445431
tasks:
446-
- name: Install podman
432+
- name: Install docker
447433
ansible.builtin.apt:
448-
name: podman
449-
update_cache: yes
434+
name: docker
435+
state: latest
450436
become: true
451437
452-
- name: Export container image locally
453-
containers.podman.podman_save:
454-
image: superlists
455-
dest: /tmp/superlists-img.oci
456-
format: oci-archive
457-
force: true
438+
- name: Export container image locally #<1>
439+
community.docker.docker_image:
440+
name: superlists
441+
archive_path: /tmp/superlists-img.tar
442+
source: local
458443
delegate_to: 127.0.0.1
459444
460-
- name: Upload image to server
445+
- name: Upload image to server #<2>
461446
ansible.builtin.copy:
462-
src: /tmp/superlists-img.oci
463-
dest: /tmp/superlists-img.oci
447+
src: /tmp/superlists-img.tar
448+
dest: /tmp/superlists-img.tar
464449
465-
- name: Import container image on server
466-
containers.podman.podman_load:
467-
input: /tmp/superlists-img.oci
450+
- name: Import container image on server #<3>
451+
community.docker.docker_image:
452+
name: superlists
453+
load_path: /tmp/superlists-img.tar
454+
source: load
455+
state: present
456+
become: true
468457
469458
- name: Run container
470-
containers.podman.podman_container:
459+
community.docker.docker_container:
471460
name: superlists
472461
image: superlists
473462
state: started
474463
recreate: true
475464
----
476465
====
477466

467+
<1> We export the docker image to a `.tar` file by using the `docker_image` module
468+
with the `archive_path` set to temp file, and setting the `delegate_to` attribute
469+
to say we're running that command on our local machine rather than the server.
478470

479-
Let's see if that worked!
471+
<2> We then use the `copy` module to upload the tarfile to the server
480472

473+
<3> And we use `docker_image` again but this time with `load_path` and `source: load`
474+
to import the image back on the server
475+
476+
[subs="specialcharacters,quotes"]
477+
----
478+
$ *ansible-playbook --user=elspeth -i staging.ottg.co.uk, infra/ansible-provision.yaml -vv*
479+
[...]
480+
481+
PLAYBOOK: ansible-provision.yaml **********************************************
482+
1 plays in infra/ansible-provision.yaml
483+
484+
PLAY [all] ********************************************************************
485+
486+
TASK [Gathering Facts] ********************************************************
487+
task path: ...goat-book/superlists/infra/ansible-provision.yaml:2
488+
ok: [staging.ottg.co.uk]
489+
490+
TASK [Install docker] *********************************************************
491+
task path: ...goat-book/superlists/infra/ansible-provision.yaml:5
492+
ok: [staging.ottg.co.uk] => {"cache_update_time": 1708982855, "cache_updated": false, "changed": false}
493+
494+
TASK [Export container image locally] *****************************************
495+
task path: ...goat-book/superlists/infra/ansible-provision.yaml:11
496+
changed: [staging.ottg.co.uk -> 127.0.0.1] => {"actions": ["Archived image
497+
superlists:latest to /tmp/superlists-img.tar, overwriting archive with image
498+
11ff3b83873f0fea93f8ed01bb4bf8b3a02afa15637ce45d71eca1fe98beab34 named
499+
superlists:latest"], "changed": true, "image": {"Architecture": "amd64",
500+
[...]
501+
502+
TASK [Upload image to server] *************************************************
503+
task path: ...goat-book/superlists/infra/ansible-provision.yaml:18
504+
changed: [staging.ottg.co.uk] => {"changed": true, "checksum":
505+
"313602fc0c056c9255eec52e38283522745b612c", "dest": "/tmp/superlists-img.tar",
506+
[...]
507+
508+
TASK [Import container image on server] ***************************************
509+
task path: ...goat-book/superlists/infra/ansible-provision.yaml:23
510+
changed: [staging.ottg.co.uk] => {"actions": ["Loaded image superlists:latest
511+
from /tmp/superlists-img.tar"], "changed": true, "image": {"Architecture":
512+
"amd64", "Author": "", "Comment": "buildkit.dockerfile.v0", "Config":
513+
[...]
514+
515+
TASK [Run container] **********************************************************
516+
task path: ...goat-book/superlists/infra/ansible-provision.yaml:32
517+
changed: [staging.ottg.co.uk] => {"changed": true, "container":
518+
{"AppArmorProfile": "docker-default", "Args": ["--bind", ":8888",
519+
"superlists.wsgi:application"], "Config": {"AttachStderr": true, "AttachStdin":
520+
false, "AttachStdout": true, "Cmd": ["gunicorn", "--bind", ":8888",
521+
"superlists.wsgi:application"], "Domainname": "", "Entrypoint": null, "Env":
522+
[...]
523+
----
524+
525+
TODO: sort out macos M1/arch issues, `docker build --platform linux/amd64` etc.
526+
527+
Looks ok! Let's see if that worked?
528+
529+
[subs="specialcharacters,quotes"]
530+
----
531+
532+
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-67-generic x86_64)
533+
[...]
534+
535+
elspeth@server$ *docker ps -a*
536+
CONTAINER ID IMAGE COMMAND CREATED STATUS
537+
PORTS NAMES
538+
3a2e600fbe77 busybox "echo hello world" 2 days ago Exited (0) 10
539+
minutes ago testcontainer
540+
541+
elspeth@server:$ *docker logs testcontainer*
542+
[2024-02-26 22:19:15 +0000] [1] [INFO] Starting gunicorn 21.2.0
543+
[2024-02-26 22:19:15 +0000] [1] [INFO] Listening at: http://0.0.0.0:8888 (1)
544+
[2024-02-26 22:19:15 +0000] [1] [INFO] Using worker: sync
545+
[...]
546+
File "/src/superlists/settings.py", line 22, in <module>
547+
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
548+
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
549+
File "<frozen os>", line 685, in __getitem__
550+
KeyError: 'DJANGO_SECRET_KEY'
551+
[2024-02-26 22:19:15 +0000] [7] [INFO] Worker exiting (pid: 7)
552+
[2024-02-26 22:19:15 +0000] [1] [ERROR] Worker (pid:7) exited with code 3
553+
[2024-02-26 22:19:15 +0000] [1] [ERROR] Shutting down: Master
554+
[2024-02-26 22:19:15 +0000] [1] [ERROR] Reason: Worker failed to boot.
555+
----
481556

482-
Nope. TODO: debug, ssh into the server, show missing env vars.
557+
Ah woops, we need to set those environment variables on the server too.
483558

484559

485560
=== Using an env File to Store Our Environment Variables

images/gandi_add_dns_a_record.png

103 KB
Loading

0 commit comments

Comments
 (0)