@@ -523,22 +523,40 @@ false, "AttachStdout": true, "Cmd": ["gunicorn", "--bind", ":8888",
523
523
----
524
524
525
525
526
- TODO: sort out macos M1/arch issues, `docker build --platform linux/amd64` etc.
526
+ For completeness, let's also add a step to explicitly build the image locally.
527
+ This means we don't have a dependency on having run `docker build` locally.
527
528
529
+
530
+ [role="sourcecode"]
531
+ .infra/ansible-provision.yaml (ch11l003)
532
+ ====
533
+ [source,yaml]
528
534
----
535
+ - name: Install docker
536
+ [...]
537
+
529
538
- name: Build container image locally
530
539
community.docker.docker_image:
531
540
name: superlists
532
541
source: build
533
542
state: present
534
543
build:
535
544
path: ../Dockerfile
536
- platform: linux/amd64
545
+ platform: linux/amd64 # <1>
537
546
delegate_to: 127.0.0.1
547
+
548
+ - name: Export container image locally
538
549
----
550
+ ====
539
551
552
+ <1> Having this step also allows us to work around an issue
553
+ with compatility between Apple's new ARM-based chips and
554
+ our server's x86/amd64 architecture.
555
+ You could also use this `platform:` to cross-build docker images
556
+ for a rasbperry pi from a regular PC, or vice-versa.
540
557
541
- Looks ok! Let's see if that worked?
558
+
559
+ In any case, let's see if it works!
542
560
543
561
[subs="specialcharacters,quotes"]
544
562
----
@@ -573,12 +591,28 @@ Ah woops, we need to set those environment variables on the server too.
573
591
574
592
=== Using an env File to Store Our Environment Variables
575
593
576
- We don't want to save secrets like SECRET_KEY into our ansible
577
- config either.
594
+ When we run our container manually locally, we can pass in environment variables with the `-e` flag.
595
+ But we don't want to hard-code secrets like SECRET_KEY into our ansible files
596
+ and commit them to our repo!
597
+
598
+ Instead, we can use ansible to automate the creation of a secret key,
599
+ and then save it to a file on the server, where it will be relatively secure
600
+ (better than saving it to version contorl and pushing it to GitHub in any case!)
601
+
602
+ We can use a so-called "env file" to store environment variables,
603
+ which are essentially a list of key-value pairs using shell syntax,
604
+ a bit like you'd use with `export`.
578
605
579
- * explain env files.
606
+ One extra subtlety is that we want to vary the actual contents of the env file,
607
+ depending on where we're deploying to.
608
+ Each server should get its own unique secret key,
609
+ adn we want different config for staging and prod, for example.
580
610
581
- * explain jinja2.
611
+ So, just as we inject variables into our html templates in Django,
612
+ we can use a templating language called "jinja2" to have variables in our env file.
613
+ It's a common tool in ansible scripts, and the syntax is very similar to Django's.
614
+
615
+ Here's what our template for the env file will looks like:
582
616
583
617
[role="sourcecode"]
584
618
.infra/env.j2 (ch11l003)
@@ -588,10 +622,11 @@ config either.
588
622
DJANGO_DEBUG_FALSE=1
589
623
DJANGO_SECRET_KEY="{{ secret_key }}"
590
624
DJANGO_ALLOWED_HOST="{{ host }}"
591
-
592
625
----
593
626
====
594
627
628
+ And here's how we use it in the provisioning script:
629
+
595
630
596
631
[role="sourcecode"]
597
632
.infra/ansible-provision.yaml (ch11l004)
@@ -602,13 +637,13 @@ DJANGO_ALLOWED_HOST="{{ host }}"
602
637
[...]
603
638
604
639
- name: Ensure .env file exists
605
- ansible.builtin.template:
640
+ ansible.builtin.template: #<1>
606
641
src: env.j2
607
642
dest: ~/superlists.env
608
- vars:
609
- host: "{{ inventory_hostname }}"
643
+ force: false # do not recreate file if it already exists. <2>
644
+ vars: # <3>
645
+ host: "{{ inventory_hostname }}" # <4>
610
646
secret_key: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}"
611
- force: false # do not recreate file if it already exists.
612
647
613
648
- name: Run container
614
649
community.docker.docker_container:
@@ -620,17 +655,34 @@ DJANGO_ALLOWED_HOST="{{ host }}"
620
655
----
621
656
====
622
657
623
- The `inventory_hostname` variable is the domain name of the server we're running against.
624
- I'm using the `vars` section to rename it to "host", just for convenience.
658
+ <1> We use `ansible.builtin.template` to specify the local template file to use (`src`),
659
+ and the destination (`dst`) on the server
660
+
661
+ <2> `force: false` means we will only write the file once.
662
+ So after the first time we generate our secret key, it won't change.
663
+
664
+ <3> The `vars` section defines the variables we'll inject into our template.
665
+
666
+ <4> We actually use a built-in ansible variable called `inventory_hostname`.
667
+ This variable woul actually be available in the template already,
668
+ but I'm renaming it for clarity.
669
+
670
+
671
+ .Idempotency
672
+ *******************************************************************************
673
+ * TODO: explain idempotency
674
+
675
+ *******************************************************************************
625
676
626
- * explain idempotency
677
+ NOTE: Using an env file to store secrets is definitely better than committing
678
+ it to version control, but it's maybe not the state of the art either.
679
+ TODO: mention other secret management tools. vault
627
680
628
- * mention other secret management tools. vault??
629
681
630
682
631
683
==== More debugging
632
684
633
- forgot ports
685
+ forgot ports!
634
686
635
687
show ssh, curl localhosts maybe.
636
688
0 commit comments