Compare commits
2 Commits
632aee934f
...
ansible-ro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
364e59343f | ||
|
|
6d90e131b2 |
49
README.md
49
README.md
@@ -33,18 +33,35 @@ does.
|
|||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
```
|
```
|
||||||
playbook.yml Ansible deployment (hosts: webservers)
|
playbook.yml Example play using the role (hosts: webservers)
|
||||||
inventory.ini Inventory (localhost + commented remote example)
|
inventory.ini Inventory (localhost + commented remote example)
|
||||||
trade-hub/
|
teardown.yml Removes this project's containers and data
|
||||||
|
roles/trade_hub/
|
||||||
|
README.md Role usage and variables
|
||||||
|
defaults/main.yml Configurable defaults
|
||||||
|
tasks/main.yml Stage source, build images, run containers
|
||||||
|
files/trade-hub/
|
||||||
podman-compose.yml Local three-service stack (db + backend + frontend)
|
podman-compose.yml Local three-service stack (db + backend + frontend)
|
||||||
backend/ FastAPI app, tests, data fetch script, Dockerfile
|
backend/ FastAPI app, tests, data fetch script, Dockerfile
|
||||||
frontend/ nginx config + static inventory UI
|
frontend/ nginx config + static inventory UI
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The Ansible deployment is a self-contained role. To deploy it from an existing
|
||||||
|
playbook, copy `roles/trade_hub` into that repository's `roles/` directory and
|
||||||
|
add the role to the play:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- role: trade_hub
|
||||||
|
tags: [trade_hub]
|
||||||
|
```
|
||||||
|
|
||||||
|
See `roles/trade_hub/README.md` for the variables. The play-level `become: true`
|
||||||
|
used by a typical server play makes podman run as root.
|
||||||
|
|
||||||
## Run locally with Podman Compose
|
## Run locally with Podman Compose
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd trade-hub
|
cd roles/trade_hub/files/trade-hub
|
||||||
podman-compose up -d --build
|
podman-compose up -d --build
|
||||||
# or: podman compose up -d --build
|
# or: podman compose up -d --build
|
||||||
```
|
```
|
||||||
@@ -60,7 +77,8 @@ POSTGRES_PASSWORD='choose-something-strong' podman-compose up -d --build
|
|||||||
|
|
||||||
## Deploy with Ansible
|
## Deploy with Ansible
|
||||||
|
|
||||||
Deploys to every host in the `webservers` group (defaults to localhost):
|
The example play deploys the role to every host in the `webservers` group
|
||||||
|
(defaults to localhost):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
POSTGRES_PASSWORD='choose-something-strong' ansible-playbook playbook.yml
|
POSTGRES_PASSWORD='choose-something-strong' ansible-playbook playbook.yml
|
||||||
@@ -73,16 +91,22 @@ To deploy to a remote server, edit `inventory.ini`:
|
|||||||
server1 ansible_host=203.0.113.10 ansible_user=deploy
|
server1 ansible_host=203.0.113.10 ansible_user=deploy
|
||||||
```
|
```
|
||||||
|
|
||||||
Then run the same command from this directory. The playbook:
|
Then run the same command from this directory. The role:
|
||||||
|
|
||||||
1. installs podman if missing,
|
1. installs podman if missing (only when `trade_hub_install_podman: true`),
|
||||||
2. removes the legacy `my-apache-server` container if present,
|
2. optionally removes the legacy `my-apache-server` container
|
||||||
3. builds `sc-inventory-backend` / `sc-inventory-frontend` images (skipped when
|
(`trade_hub_remove_legacy_apache: true`),
|
||||||
they already exist; set `-e force_rebuild=true` to rebuild),
|
3. stages the application source in `/opt/trade-hub` and builds the
|
||||||
|
`sc-inventory-backend` / `sc-inventory-frontend` images (skipped when the
|
||||||
|
source is unchanged and the images already exist; set
|
||||||
|
`-e trade_hub_force_rebuild=true` to force it),
|
||||||
4. creates the `sc-inventory` podman network and the `sc-inventory-data` volume,
|
4. creates the `sc-inventory` podman network and the `sc-inventory-data` volume,
|
||||||
5. runs PostgreSQL, the backend, and the frontend containers (only the frontend
|
5. runs PostgreSQL, the backend, and the frontend containers (only the frontend
|
||||||
publishes a port: 8080),
|
publishes a port: 8080),
|
||||||
6. verifies `http://localhost:8080/healthz` returns 200.
|
6. verifies `http://127.0.0.1:8080/healthz` returns 200.
|
||||||
|
|
||||||
|
The old standalone playbook's variables (`force_rebuild`, `cookie_secure`, …)
|
||||||
|
became `trade_hub_*` variables; see `roles/trade_hub/README.md`.
|
||||||
|
|
||||||
## Reset for testing (remove everything)
|
## Reset for testing (remove everything)
|
||||||
|
|
||||||
@@ -165,7 +189,8 @@ The stack publishes plain HTTP on port 8080. Session cookies therefore travel
|
|||||||
in cleartext, and `COOKIE_SECURE` defaults to `false` so local development works.
|
in cleartext, and `COOKIE_SECURE` defaults to `false` so local development works.
|
||||||
Before putting this on the open internet, terminate TLS in front of the
|
Before putting this on the open internet, terminate TLS in front of the
|
||||||
frontend (Caddy, nginx with certificates, or a load balancer) and set
|
frontend (Caddy, nginx with certificates, or a load balancer) and set
|
||||||
`COOKIE_SECURE=true` (compose env var) or `-e cookie_secure=true` (Ansible).
|
`COOKIE_SECURE=true` (compose env var) or
|
||||||
|
`-e trade_hub_cookie_secure=true` (Ansible).
|
||||||
Also change `POSTGRES_PASSWORD` from its development default.
|
Also change `POSTGRES_PASSWORD` from its development default.
|
||||||
|
|
||||||
## Verify
|
## Verify
|
||||||
@@ -195,7 +220,7 @@ curl -fsS -b cookies.txt http://localhost:8080/api/v1/me/inventory
|
|||||||
## Backend development
|
## Backend development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd trade-hub/backend
|
cd roles/trade_hub/files/trade-hub/backend
|
||||||
python3 -m venv .venv
|
python3 -m venv .venv
|
||||||
.venv/bin/pip install -r requirements.txt -r requirements-dev.txt
|
.venv/bin/pip install -r requirements.txt -r requirements-dev.txt
|
||||||
.venv/bin/python -m pytest tests/ -q # 83 tests, no database needed
|
.venv/bin/python -m pytest tests/ -q # 83 tests, no database needed
|
||||||
|
|||||||
137
playbook.yml
137
playbook.yml
@@ -1,126 +1,23 @@
|
|||||||
---
|
---
|
||||||
|
# Example play that exercises the trade_hub role against the local inventory.
|
||||||
|
# To use the role in an existing playbook, copy roles/trade_hub into that
|
||||||
|
# repository's roles/ directory and add:
|
||||||
|
#
|
||||||
|
# roles:
|
||||||
|
# - role: trade_hub
|
||||||
|
# tags: [trade_hub]
|
||||||
|
#
|
||||||
- name: Deploy Star Citizen Inventory (trade-hub)
|
- name: Deploy Star Citizen Inventory (trade-hub)
|
||||||
hosts: webservers
|
hosts: webservers
|
||||||
|
|
||||||
vars:
|
vars:
|
||||||
backend_image: sc-inventory-backend
|
# The standalone play used to install podman; in a larger playbook the
|
||||||
frontend_image: sc-inventory-frontend
|
# "packages" role normally provides it instead.
|
||||||
postgres_image: docker.io/library/postgres:16-alpine
|
trade_hub_install_podman: true
|
||||||
image_tag: latest
|
trade_hub_postgres_password: "{{ lookup('env', 'POSTGRES_PASSWORD') | default('sc_inventory_dev', true) }}"
|
||||||
network_name: sc-inventory
|
trade_hub_cookie_secure: "false"
|
||||||
frontend_port: "8080:80"
|
trade_hub_force_rebuild: false
|
||||||
postgres_volume: sc-inventory-data
|
|
||||||
postgres_password: "{{ lookup('env', 'POSTGRES_PASSWORD') | default('sc_inventory_dev', true) }}"
|
|
||||||
database_url: "postgresql+psycopg://sc_inventory:{{ postgres_password }}@db:5432/sc_inventory"
|
|
||||||
# Set to true once the site is served over TLS.
|
|
||||||
cookie_secure: "false"
|
|
||||||
# Set to true to force image rebuilds even when the images already exist
|
|
||||||
force_rebuild: false
|
|
||||||
|
|
||||||
tasks:
|
roles:
|
||||||
- name: Check whether podman is installed
|
- role: trade_hub
|
||||||
ansible.builtin.command: podman --version
|
tags: [trade_hub]
|
||||||
register: podman_check
|
|
||||||
failed_when: false
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Install podman if missing
|
|
||||||
become: true
|
|
||||||
ansible.builtin.package:
|
|
||||||
name: podman
|
|
||||||
state: present
|
|
||||||
when: podman_check.rc != 0
|
|
||||||
|
|
||||||
- name: Remove legacy Apache container if present
|
|
||||||
containers.podman.podman_container:
|
|
||||||
name: my-apache-server
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Check if backend image exists
|
|
||||||
ansible.builtin.command: podman image exists {{ backend_image }}:{{ image_tag }}
|
|
||||||
register: backend_image_check
|
|
||||||
failed_when: false
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Check if frontend image exists
|
|
||||||
ansible.builtin.command: podman image exists {{ frontend_image }}:{{ image_tag }}
|
|
||||||
register: frontend_image_check
|
|
||||||
failed_when: false
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Build backend image
|
|
||||||
ansible.builtin.command: >
|
|
||||||
podman build -t {{ backend_image }}:{{ image_tag }}
|
|
||||||
{{ playbook_dir }}/trade-hub/backend
|
|
||||||
when: backend_image_check.rc != 0 or force_rebuild | bool
|
|
||||||
|
|
||||||
- name: Build frontend image
|
|
||||||
ansible.builtin.command: >
|
|
||||||
podman build -t {{ frontend_image }}:{{ image_tag }}
|
|
||||||
{{ playbook_dir }}/trade-hub/frontend
|
|
||||||
when: frontend_image_check.rc != 0 or force_rebuild | bool
|
|
||||||
|
|
||||||
- name: Create podman network
|
|
||||||
containers.podman.podman_network:
|
|
||||||
name: "{{ network_name }}"
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Create PostgreSQL data volume
|
|
||||||
containers.podman.podman_volume:
|
|
||||||
name: "{{ postgres_volume }}"
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Run PostgreSQL container (internal only)
|
|
||||||
containers.podman.podman_container:
|
|
||||||
name: sc-inventory-db
|
|
||||||
image: "{{ postgres_image }}"
|
|
||||||
state: started
|
|
||||||
network: "{{ network_name }}"
|
|
||||||
network_aliases:
|
|
||||||
- db
|
|
||||||
env:
|
|
||||||
POSTGRES_USER: sc_inventory
|
|
||||||
POSTGRES_PASSWORD: "{{ postgres_password }}"
|
|
||||||
POSTGRES_DB: sc_inventory
|
|
||||||
volumes:
|
|
||||||
- "{{ postgres_volume }}:/var/lib/postgresql/data:Z"
|
|
||||||
restart_policy: unless-stopped
|
|
||||||
|
|
||||||
- name: Run backend container (internal only)
|
|
||||||
containers.podman.podman_container:
|
|
||||||
name: sc-inventory-backend
|
|
||||||
image: "{{ backend_image }}:{{ image_tag }}"
|
|
||||||
state: started
|
|
||||||
# podman does not recreate a container when its image tag resolves to
|
|
||||||
# a new ID, so without this a rebuilt image would be ignored.
|
|
||||||
recreate: true
|
|
||||||
network: "{{ network_name }}"
|
|
||||||
# Network alias "backend" matches the compose service name, so the
|
|
||||||
# nginx upstream (http://backend:8000) resolves in both deployments.
|
|
||||||
network_aliases:
|
|
||||||
- backend
|
|
||||||
env:
|
|
||||||
DATABASE_URL: "{{ database_url }}"
|
|
||||||
DB_WAIT_SECONDS: "60"
|
|
||||||
COOKIE_SECURE: "{{ cookie_secure }}"
|
|
||||||
restart_policy: unless-stopped
|
|
||||||
|
|
||||||
- name: Run frontend container (published port)
|
|
||||||
containers.podman.podman_container:
|
|
||||||
name: sc-inventory-frontend
|
|
||||||
image: "{{ frontend_image }}:{{ image_tag }}"
|
|
||||||
state: started
|
|
||||||
recreate: true
|
|
||||||
network: "{{ network_name }}"
|
|
||||||
ports:
|
|
||||||
- "{{ frontend_port }}"
|
|
||||||
restart_policy: unless-stopped
|
|
||||||
|
|
||||||
- name: Verify the stack responds
|
|
||||||
ansible.builtin.uri:
|
|
||||||
url: http://localhost:8080/healthz
|
|
||||||
status_code: 200
|
|
||||||
register: health_result
|
|
||||||
until: health_result.status == 200
|
|
||||||
retries: 8
|
|
||||||
delay: 10
|
|
||||||
|
|||||||
85
roles/trade_hub/README.md
Normal file
85
roles/trade_hub/README.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
# trade_hub
|
||||||
|
|
||||||
|
Deploys the Free People of the Verse trade hub: a FastAPI backend, an nginx
|
||||||
|
frontend and PostgreSQL, all run by podman on the target host. The role stages
|
||||||
|
its own copy of the application source from `files/trade-hub/` and builds the
|
||||||
|
backend and frontend images locally, so it does not need a registry.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Add the role to an existing play. It is safe to run after a `packages` role that
|
||||||
|
already installs podman:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- hosts: internal-apps
|
||||||
|
become: true
|
||||||
|
vars_files:
|
||||||
|
- ./vars.yml
|
||||||
|
roles:
|
||||||
|
- role: packages
|
||||||
|
tags: [packages]
|
||||||
|
# ...
|
||||||
|
- role: trade_hub
|
||||||
|
tags: [trade_hub]
|
||||||
|
```
|
||||||
|
|
||||||
|
The play-level `become: true` makes podman run as root. If you run the role
|
||||||
|
without become, podman runs rootless and the containers belong to the connecting
|
||||||
|
user.
|
||||||
|
|
||||||
|
The playbook's `Pull images` task is unrelated to this role: the role builds its
|
||||||
|
own backend/frontend images from the staged source. The PostgreSQL image is
|
||||||
|
pulled by the role if it is not already present.
|
||||||
|
|
||||||
|
## Required variables
|
||||||
|
|
||||||
|
Set a real database password in `vars.yml` (or the environment of the control
|
||||||
|
node):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
trade_hub_postgres_password: "choose-something-strong"
|
||||||
|
```
|
||||||
|
|
||||||
|
If it is omitted, the role falls back to the play variable `POSTGRES_PASSWORD`,
|
||||||
|
then to `POSTGRES_PASSWORD` from the control node environment, then to the
|
||||||
|
development default `sc_inventory_dev`. If the password contains characters
|
||||||
|
that are significant in a URL (`@`, `:`, `/`, …), set `trade_hub_database_url`
|
||||||
|
explicitly as well.
|
||||||
|
|
||||||
|
## Common variables
|
||||||
|
|
||||||
|
| Variable | Default | Purpose |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `trade_hub_app_dir` | `/opt/trade-hub` | Where the build context is staged |
|
||||||
|
| `trade_hub_install_podman` | `false` | Install podman if it is missing |
|
||||||
|
| `trade_hub_build_images` | `true` | Build backend/frontend images on the target |
|
||||||
|
| `trade_hub_force_rebuild` | `false` | Rebuild images and restart containers |
|
||||||
|
| `trade_hub_image_tag` | `latest` | Tag applied to built images |
|
||||||
|
| `trade_hub_backend_image` | `localhost/sc-inventory-backend` | Backend image name |
|
||||||
|
| `trade_hub_frontend_image` | `localhost/sc-inventory-frontend` | Frontend image name |
|
||||||
|
| `trade_hub_postgres_image` | `docker.io/library/postgres:16-alpine` | Database image |
|
||||||
|
| `trade_hub_postgres_user` | `sc_inventory` | Database user |
|
||||||
|
| `trade_hub_postgres_db` | `sc_inventory` | Database name |
|
||||||
|
| `trade_hub_postgres_password` | play var/env `POSTGRES_PASSWORD` or `sc_inventory_dev` | Database password |
|
||||||
|
| `trade_hub_network` | `sc-inventory` | Podman network name |
|
||||||
|
| `trade_hub_volume` | `sc-inventory-data` | PostgreSQL data volume |
|
||||||
|
| `trade_hub_frontend_bind` | `0.0.0.0` | Address the frontend publishes on |
|
||||||
|
| `trade_hub_frontend_port` | `8080` | Host port for the frontend |
|
||||||
|
| `trade_hub_cookie_secure` | `false` | Mark session cookies `Secure` (enable behind TLS) |
|
||||||
|
| `trade_hub_healthcheck_url` | `http://127.0.0.1:<port>/healthz` | Post-deploy check |
|
||||||
|
| `trade_hub_remove_legacy_apache` | `false` | Remove a container named `my-apache-server` |
|
||||||
|
| `trade_hub_enable_restart_service` | `false` | Enable `podman-restart.service` |
|
||||||
|
|
||||||
|
The container names also default to `sc-inventory-db`, `sc-inventory-backend`
|
||||||
|
and `sc-inventory-frontend`, matching the previous standalone playbook so an
|
||||||
|
existing installation is upgraded in place.
|
||||||
|
|
||||||
|
## Example deployment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-playbook site.yml --tags trade_hub -e trade_hub_postgres_password='...'
|
||||||
|
```
|
||||||
|
|
||||||
|
The role verifies `http://127.0.0.1:8080/healthz` after starting the containers.
|
||||||
|
Only the frontend publishes a port; the database and backend stay on the
|
||||||
|
internal podman network.
|
||||||
51
roles/trade_hub/defaults/main.yml
Normal file
51
roles/trade_hub/defaults/main.yml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
# Where the application build context is staged on the target host.
|
||||||
|
trade_hub_app_dir: /opt/trade-hub
|
||||||
|
|
||||||
|
# Install podman as part of this role. Leave false when another role (for
|
||||||
|
# example "packages") already provides podman.
|
||||||
|
trade_hub_install_podman: false
|
||||||
|
|
||||||
|
# Images. These are built locally by default; point them at a registry if you
|
||||||
|
# prefer to pull prebuilt images.
|
||||||
|
trade_hub_image_tag: latest
|
||||||
|
trade_hub_backend_image: localhost/sc-inventory-backend
|
||||||
|
trade_hub_frontend_image: localhost/sc-inventory-frontend
|
||||||
|
trade_hub_postgres_image: docker.io/library/postgres:16-alpine
|
||||||
|
trade_hub_build_images: true
|
||||||
|
trade_hub_force_rebuild: false
|
||||||
|
|
||||||
|
# Container names. Kept compatible with the previous standalone playbook so an
|
||||||
|
# existing installation is upgraded in place.
|
||||||
|
trade_hub_db_container: sc-inventory-db
|
||||||
|
trade_hub_backend_container: sc-inventory-backend
|
||||||
|
trade_hub_frontend_container: sc-inventory-frontend
|
||||||
|
|
||||||
|
# Database.
|
||||||
|
trade_hub_postgres_user: sc_inventory
|
||||||
|
trade_hub_postgres_db: sc_inventory
|
||||||
|
trade_hub_postgres_password: "{{ POSTGRES_PASSWORD | default(lookup('env', 'POSTGRES_PASSWORD'), true) | default('sc_inventory_dev', true) }}"
|
||||||
|
trade_hub_database_url: "postgresql+psycopg://{{ trade_hub_postgres_user }}:{{ trade_hub_postgres_password }}@db:5432/{{ trade_hub_postgres_db }}"
|
||||||
|
trade_hub_db_wait_seconds: 60
|
||||||
|
|
||||||
|
# Networking.
|
||||||
|
trade_hub_network: sc-inventory
|
||||||
|
trade_hub_volume: sc-inventory-data
|
||||||
|
trade_hub_frontend_bind: 0.0.0.0
|
||||||
|
trade_hub_frontend_port: 8080
|
||||||
|
# Set to true (or "true") once the site is served over TLS.
|
||||||
|
trade_hub_cookie_secure: "false"
|
||||||
|
|
||||||
|
# Post-deploy health check.
|
||||||
|
trade_hub_healthcheck_url: "http://127.0.0.1:{{ trade_hub_frontend_port }}/healthz"
|
||||||
|
trade_hub_healthcheck_retries: 12
|
||||||
|
trade_hub_healthcheck_delay: 5
|
||||||
|
|
||||||
|
# The original standalone playbook removed an ad-hoc Apache container that
|
||||||
|
# used the same host. Disabled by default so the role never touches unrelated
|
||||||
|
# containers.
|
||||||
|
trade_hub_remove_legacy_apache: false
|
||||||
|
trade_hub_legacy_apache_container: my-apache-server
|
||||||
|
|
||||||
|
# Enable podman-restart.service so the containers come back after a reboot.
|
||||||
|
trade_hub_enable_restart_service: false
|
||||||
16
roles/trade_hub/meta/main.yml
Normal file
16
roles/trade_hub/meta/main.yml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
galaxy_info:
|
||||||
|
role_name: trade_hub
|
||||||
|
author: boxswapper
|
||||||
|
description: Deploy the Free People of the Verse trade hub (FastAPI, nginx, PostgreSQL) with Podman.
|
||||||
|
license: MIT
|
||||||
|
min_ansible_version: "2.15"
|
||||||
|
platforms:
|
||||||
|
- name: GenericLinux
|
||||||
|
versions:
|
||||||
|
- all
|
||||||
|
galaxy_tags:
|
||||||
|
- podman
|
||||||
|
- fastapi
|
||||||
|
- postgresql
|
||||||
|
dependencies: []
|
||||||
215
roles/trade_hub/tasks/main.yml
Normal file
215
roles/trade_hub/tasks/main.yml
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
---
|
||||||
|
- name: Check whether podman is installed
|
||||||
|
ansible.builtin.command: podman --version
|
||||||
|
register: trade_hub_podman_check
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
check_mode: false
|
||||||
|
|
||||||
|
- name: Install podman when requested
|
||||||
|
ansible.builtin.package:
|
||||||
|
name: podman
|
||||||
|
state: present
|
||||||
|
become: true
|
||||||
|
when:
|
||||||
|
- trade_hub_podman_check.rc != 0
|
||||||
|
- trade_hub_install_podman | bool
|
||||||
|
|
||||||
|
- name: Re-check podman after installation
|
||||||
|
ansible.builtin.command: podman --version
|
||||||
|
register: trade_hub_podman_recheck
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
check_mode: false
|
||||||
|
when: trade_hub_podman_check.rc != 0
|
||||||
|
|
||||||
|
- name: Require podman to be available
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- trade_hub_podman_check.rc == 0 or (trade_hub_podman_recheck.rc | default(1)) == 0
|
||||||
|
fail_msg: >-
|
||||||
|
podman is not installed on {{ inventory_hostname }}. Install it first
|
||||||
|
(for example with the "packages" role) or run this role with
|
||||||
|
-e trade_hub_install_podman=true.
|
||||||
|
|
||||||
|
- name: Remove the legacy Apache container when requested
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: "{{ trade_hub_legacy_apache_container }}"
|
||||||
|
state: absent
|
||||||
|
when: trade_hub_remove_legacy_apache | bool
|
||||||
|
|
||||||
|
- name: Create the application directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ trade_hub_app_dir }}"
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Stage the application build context
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ role_path }}/files/trade-hub/{{ item.src }}"
|
||||||
|
dest: "{{ trade_hub_app_dir }}/{{ item.dest }}"
|
||||||
|
mode: preserve
|
||||||
|
loop:
|
||||||
|
# Only the files needed by the two Dockerfiles are staged. Copying the
|
||||||
|
# whole tree would also ship local development artefacts such as .venv.
|
||||||
|
- { src: "backend/Dockerfile", dest: "backend/Dockerfile" }
|
||||||
|
- { src: "backend/requirements.txt", dest: "backend/requirements.txt" }
|
||||||
|
- { src: "backend/main.py", dest: "backend/main.py" }
|
||||||
|
- { src: "backend/app/", dest: "backend/app/" }
|
||||||
|
- { src: "backend/scripts/", dest: "backend/scripts/" }
|
||||||
|
- { src: "frontend/Dockerfile", dest: "frontend/Dockerfile" }
|
||||||
|
- { src: "frontend/nginx.conf", dest: "frontend/nginx.conf" }
|
||||||
|
- { src: "frontend/src/", dest: "frontend/src/" }
|
||||||
|
register: trade_hub_source
|
||||||
|
|
||||||
|
- name: Check whether the backend image exists
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- podman
|
||||||
|
- image
|
||||||
|
- exists
|
||||||
|
- "{{ trade_hub_backend_image }}:{{ trade_hub_image_tag }}"
|
||||||
|
register: trade_hub_backend_image_check
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
check_mode: false
|
||||||
|
|
||||||
|
- name: Check whether the frontend image exists
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- podman
|
||||||
|
- image
|
||||||
|
- exists
|
||||||
|
- "{{ trade_hub_frontend_image }}:{{ trade_hub_image_tag }}"
|
||||||
|
register: trade_hub_frontend_image_check
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
check_mode: false
|
||||||
|
|
||||||
|
- name: Build the backend image
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- podman
|
||||||
|
- build
|
||||||
|
- --tag
|
||||||
|
- "{{ trade_hub_backend_image }}:{{ trade_hub_image_tag }}"
|
||||||
|
- "{{ trade_hub_app_dir }}/backend"
|
||||||
|
when:
|
||||||
|
- trade_hub_build_images | bool
|
||||||
|
- trade_hub_force_rebuild | bool or trade_hub_source.changed or trade_hub_backend_image_check.rc != 0
|
||||||
|
register: trade_hub_backend_build
|
||||||
|
|
||||||
|
- name: Build the frontend image
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- podman
|
||||||
|
- build
|
||||||
|
- --tag
|
||||||
|
- "{{ trade_hub_frontend_image }}:{{ trade_hub_image_tag }}"
|
||||||
|
- "{{ trade_hub_app_dir }}/frontend"
|
||||||
|
when:
|
||||||
|
- trade_hub_build_images | bool
|
||||||
|
- trade_hub_force_rebuild | bool or trade_hub_source.changed or trade_hub_frontend_image_check.rc != 0
|
||||||
|
register: trade_hub_frontend_build
|
||||||
|
|
||||||
|
- name: Require prebuilt images when image builds are disabled
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- trade_hub_backend_image_check.rc == 0
|
||||||
|
- trade_hub_frontend_image_check.rc == 0
|
||||||
|
fail_msg: >-
|
||||||
|
trade_hub_build_images is false but {{ trade_hub_backend_image }}:{{
|
||||||
|
trade_hub_image_tag }} and/or {{ trade_hub_frontend_image }}:{{
|
||||||
|
trade_hub_image_tag }} are missing on {{ inventory_hostname }}.
|
||||||
|
when: not trade_hub_build_images | bool
|
||||||
|
|
||||||
|
- name: Record whether the application containers need to be recreated
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
trade_hub_recreate_containers: >-
|
||||||
|
{{ (trade_hub_force_rebuild | bool)
|
||||||
|
or ((trade_hub_build_images | bool) and (trade_hub_source.changed | default(false)))
|
||||||
|
or (trade_hub_backend_build.changed | default(false))
|
||||||
|
or (trade_hub_frontend_build.changed | default(false)) }}
|
||||||
|
|
||||||
|
- name: Ensure the PostgreSQL image is present
|
||||||
|
containers.podman.podman_image:
|
||||||
|
name: "{{ trade_hub_postgres_image }}"
|
||||||
|
state: present
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Create the podman network
|
||||||
|
containers.podman.podman_network:
|
||||||
|
name: "{{ trade_hub_network }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create the PostgreSQL data volume
|
||||||
|
containers.podman.podman_volume:
|
||||||
|
name: "{{ trade_hub_volume }}"
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Run the PostgreSQL container
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: "{{ trade_hub_db_container }}"
|
||||||
|
image: "{{ trade_hub_postgres_image }}"
|
||||||
|
state: started
|
||||||
|
recreate: "{{ trade_hub_force_rebuild | bool }}"
|
||||||
|
network: "{{ trade_hub_network }}"
|
||||||
|
network_aliases:
|
||||||
|
- db
|
||||||
|
env:
|
||||||
|
POSTGRES_USER: "{{ trade_hub_postgres_user }}"
|
||||||
|
POSTGRES_PASSWORD: "{{ trade_hub_postgres_password }}"
|
||||||
|
POSTGRES_DB: "{{ trade_hub_postgres_db }}"
|
||||||
|
volumes:
|
||||||
|
- "{{ trade_hub_volume }}:/var/lib/postgresql/data:Z"
|
||||||
|
restart_policy: unless-stopped
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Run the backend container
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: "{{ trade_hub_backend_container }}"
|
||||||
|
image: "{{ trade_hub_backend_image }}:{{ trade_hub_image_tag }}"
|
||||||
|
state: started
|
||||||
|
# podman does not recreate a container when its image tag resolves to a new
|
||||||
|
# ID, so recreate whenever the image was rebuilt or the app changed.
|
||||||
|
recreate: "{{ trade_hub_recreate_containers | bool }}"
|
||||||
|
network: "{{ trade_hub_network }}"
|
||||||
|
# The nginx upstream is http://backend:8000, so this alias must match.
|
||||||
|
network_aliases:
|
||||||
|
- backend
|
||||||
|
env:
|
||||||
|
DATABASE_URL: "{{ trade_hub_database_url }}"
|
||||||
|
DB_WAIT_SECONDS: "{{ trade_hub_db_wait_seconds }}"
|
||||||
|
COOKIE_SECURE: "{{ trade_hub_cookie_secure | bool | lower }}"
|
||||||
|
restart_policy: unless-stopped
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Run the frontend container
|
||||||
|
containers.podman.podman_container:
|
||||||
|
name: "{{ trade_hub_frontend_container }}"
|
||||||
|
image: "{{ trade_hub_frontend_image }}:{{ trade_hub_image_tag }}"
|
||||||
|
state: started
|
||||||
|
recreate: "{{ trade_hub_recreate_containers | bool }}"
|
||||||
|
network: "{{ trade_hub_network }}"
|
||||||
|
ports:
|
||||||
|
- "{{ trade_hub_frontend_bind }}:{{ trade_hub_frontend_port }}:80"
|
||||||
|
restart_policy: unless-stopped
|
||||||
|
when: not ansible_check_mode
|
||||||
|
|
||||||
|
- name: Enable podman-restart so containers survive a reboot
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: podman-restart.service
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
when: trade_hub_enable_restart_service | bool
|
||||||
|
|
||||||
|
- name: Wait for the application to answer health checks
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "{{ trade_hub_healthcheck_url }}"
|
||||||
|
status_code: 200
|
||||||
|
register: trade_hub_health
|
||||||
|
until: trade_hub_health.status == 200
|
||||||
|
retries: "{{ trade_hub_healthcheck_retries }}"
|
||||||
|
delay: "{{ trade_hub_healthcheck_delay }}"
|
||||||
|
changed_when: false
|
||||||
|
when: not ansible_check_mode
|
||||||
Reference in New Issue
Block a user