Skip to content
← DevOps Foundations

Practical lab guide

MicroBank 4: configure and start the application

Render runtime configuration from Terraform outputs and verify repeatable configuration.

  • Ansible
  • Docker
Documentation reviewed2026-10-01 · 3 min read · lab time varies
  1. Why
  2. Predict
  3. Try
  4. Inspect
  5. Explain
  6. Save evidence

Predict before you try

Can Accounts acceptance alone prove this saved deposit reached Ledger exactly once?

Try it: Observe idempotence →
On this page

Configure the local profile with Ansible

This playbook manages files on your Mac through a local connection. It is an application configuration exercise; it does not install Docker or claim to provision an OrbStack VM. Remote host configuration remains in the preceding Ansible lab and later VM deployment track.

Save infra/study/ansible/configure.yml:

yaml
- name: Configure the MicroBank study profile
  hosts: localhost
  connection: local
  gather_facts: false
  vars:
    study_dir: "{{ playbook_dir }}/.."
    runtime: "{{ lookup('ansible.builtin.file', study_dir + '/runtime.json') | from_json }}"
  tasks:
    - name: Check the Terraform runtime contract
      ansible.builtin.assert:
        that:
          - runtime.requested_topic_arn is match('^arn:aws:sns:ca-central-1:000000000000:')
          - runtime.settled_topic_arn is match('^arn:aws:sns:ca-central-1:000000000000:')
          - runtime.ledger_queue_url is match('^http://[^/]+/000000000000/ledger-transactions
#x27;) fail_msg: Expected the dummy-account, single-region local resource outputs. Inspect Floci before proceeding. - name: Render application environment ansible.builtin.template: src: runtime.env.j2 dest: "{{ study_dir }}/runtime.env" mode: "0600" no_log: true

Save infra/study/ansible/templates/runtime.env.j2:

jinja
DATABASE_URL=postgresql://postgres:study-only@accounts-db:5432/accounts_dev
SPRING_DATASOURCE_URL=jdbc:postgresql://ledger-db:5432/ledger_dev
SPRING_DATASOURCE_USERNAME=postgres
SPRING_DATASOURCE_PASSWORD=study-only
AWS_ENDPOINT_URL=http://floci:4566
AWS_ENDPOINT=http://floci:4566
AWS_REGION=ca-central-1
AWS_ACCESS_KEY_ID=test
AWS_SECRET_ACCESS_KEY=test
AWS_ACCESS_KEY=test
AWS_SECRET_KEY=test
SNS_TOPIC_ARN={{ runtime.requested_topic_arn }}
AWS_SNS_TOPIC_ARN={{ runtime.settled_topic_arn }}
AWS_SQS_QUEUE_URL={{ runtime.ledger_queue_url | regex_replace('^http://[^/]+', 'http://floci:4566') }}

The Mac calls Floci through loopback; an application container calls it through the Compose service name. Queue URLs retain account/queue identity within this single-region profile while Ansible changes only the authority for the container network. Do not put localhost in a container's dependency address unless the dependency runs inside that same container.

Trace the data through the playbook

playbook_dir locates the automation file; study_dir reaches the shared study directory. The file lookup reads Terraform's runtime.json, and from_json turns it into structured values. Assertions reject resource identifiers outside the expected local account/Region and queue URL shape. Only then does the template create runtime.env with restricted file permissions.

The queue URL rewrite changes the host/port part for a container's network while preserving its queue path. The Mac uses 127.0.0.1:24666; Accounts and Ledger use floci:4566. Replacing the entire URL with a guessed queue name would lose information from the applied infrastructure.

A missing output file is a failed prerequisite. Return to step 3 instead of weakening the assertion. A successful render establishes the file's state; the later startup checks establish process readiness, and the next lesson establishes the transaction result.

Observe idempotence

bash
ansible-playbook -i localhost, infra/study/ansible/configure.yml --syntax-check
ansible-playbook -i localhost, infra/study/ansible/configure.yml --check
ansible-playbook -i localhost, infra/study/ansible/configure.yml
ansible-playbook -i localhost, infra/study/ansible/configure.yml
./scripts/study/compose.sh config --quiet

With unchanged inputs, the second real run should report changed=0. Check mode is useful here because the template module supports it; it is not an end-to-end application test. The output stays private even though this profile contains only fixture credentials. If configuration changes later, rerun the playbook and recreate the affected containers with compose up -d; compose restart alone does not apply changed environment values.

Build and start the two real services

Build sequentially on the 16 GB host. Commit the application and lab files, then use that commit as the image tag:

bash
export STUDY_TAG="$(git rev-parse HEAD)"
./scripts/study/compose.sh build accounts
./scripts/study/compose.sh build ledger
./scripts/study/compose.sh up -d --no-build --wait accounts ledger
./scripts/study/compose.sh ps
curl --fail --max-time 3 http://127.0.0.1:28080/health
curl --fail --max-time 3 http://127.0.0.1:28081/v1/health

Check git status --short before recording the tag: uncommitted source changes would make it misleading. Persist the selected tag in .study.env when opening a new shell. A Git-derived tag is a naming convention; also record docker image inspect image IDs for actual artifact identity.

The optional Auth0 frontend is outside the downloadable backend starter. Verify login and browser integration separately; sample notifications and the initial zero-balance widget are not Ledger evidence.

Checkpoint and sources

Before continuing, confirm that configuration converges and both backend process checks pass. The next lesson tests the full implemented request-to-Ledger flow. Sources: Ansible template↗, Ansible check mode↗, Compose networking↗, Floci queue URLs↗.

Prove what you learned

Inspect the result

Retain selected source/profile, case identity, expected balance and matching-entry count.

Explain it in your own words

Explain why your observation supports the stated outcome, and name one thing it does not prove.

Try a small variation

Repeat the same check after the documented restart or recovery; preserve the original case instead of creating a replacement.

Your evidence should show

  • Record the context/revision or label the work as a paper or prepared fixture.
  • Compare the prediction with the actual result from “Observe idempotence”.
  • Retain selected source/profile, case identity, expected balance and matching-entry count.
  • Explain the transfer challenge and retain the same verification question.
Hint

Follow the case identifier across the outbox, message route and Ledger result.

Answer guide: compare after predicting

No. Repeat the idempotency key, then verify exactly one matching Ledger entry and the expected balance.

Compare this with your actual observation. A paper answer is useful reasoning practice; record execution separately.

Recall private networking, persistent volumes and bounded Python checks. Revisit the previous lesson.

Save the prediction, result and explanation ↓

Your notes and evidence

Record observations, questions, or links to your work. Keep credentials out of your notes.

Loading saved progress…

Back up or restore this path

Progress and notes stay in this browser. A backup contains only this learning path.