--- # Reference production deploy playbook for containerized web apps. # Per-project playbooks derive from this. Additions-only to sam/semaphore.git /playbook. # # Required extra-vars: # prefix: project prefix (e.g. church-site) # version: image tag to deploy (e.g. v2026.08.27-abc1234) — enables rollback by passing a prior tag # Optional: # node: proxmox node for prod LXC (default pve4) # port: container port to expose (default 80) # # Deploy: -e "prefix=church-site version=v2026.08.27-abc1234" # Rollback: re-run with a prior version tag. - name: Deploy {{ prefix }}:{{ version }} to production hosts: "{{ node | default('pve4') }}" gather_facts: false vars: registry: "192.168.122.103:3000" image: "192.168.122.103:3000/sam/{{ prefix }}:{{ version }}" ctname: "{{ prefix }}-prod" cport: "{{ port | default('80') }}" tasks: - name: Require version argument ansible.builtin.assert: that: - version is defined - version | length > 0 fail_msg: "version is required (pass -e version=vX.Y.Z). Rollback = pass a prior tag." - name: Ensure prod LXC exists (create on first deploy) ansible.builtin.shell: | if ! pct status "$(pct list | awk -v n={{ ctname }} '$0 ~ n {print $1}')" >/dev/null 2>&1; then echo "prod LXC {{ ctname }} must be provisioned by Semaphore before first deploy" exit 3 fi changed_when: false - name: Log in to Gitea registry (creds injected from Infisical, never printed) ansible.builtin.shell: > echo "{{ lookup('env','REGISTRY_TOKEN') }}" | docker login {{ registry }} -u "{{ lookup('env','REGISTRY_USER') }}" --password-stdin no_log: true - name: Pull versioned image ansible.builtin.command: "docker pull {{ image }}" - name: Stop/remove previous container (idempotent) ansible.builtin.shell: "docker rm -f {{ prefix }} 2>/dev/null || true" changed_when: false - name: Run the versioned image ansible.builtin.command: > docker run -d --name {{ prefix }} --restart unless-stopped -p {{ cport }}:{{ cport }} {{ image }} - name: Verify container is running ansible.builtin.command: "docker ps --filter name={{ prefix }} --filter status=running -q" register: running changed_when: false failed_when: running.stdout | length == 0 - name: Record deploy result ansible.builtin.debug: msg: "Deployed {{ image }} to {{ ctname }} (port {{ cport }}). Rollback: re-run with a prior version tag."