Compare commits
3 commits
77b153a054
...
0e3d0e3228
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e3d0e3228 | ||
|
|
800166c2ac | ||
|
|
394a973d6c |
8 changed files with 566 additions and 2 deletions
|
|
@ -52,6 +52,11 @@ services:
|
||||||
labels:
|
labels:
|
||||||
- "com.centurylinklabs.watchtower.enable=true"
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
- "autoheal=true"
|
- "autoheal=true"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
cpus: '1.0'
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
proxy:
|
proxy:
|
||||||
|
|
|
||||||
34
compose-files/databases/phpmyadmin/docker-compose.yml
Normal file
34
compose-files/databases/phpmyadmin/docker-compose.yml
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
services:
|
||||||
|
phpmyadmin:
|
||||||
|
image: phpmyadmin:latest
|
||||||
|
container_name: phpmyadmin
|
||||||
|
hostname: phpmyadmin
|
||||||
|
environment:
|
||||||
|
# Multiple MySQL hosts: Hetzner (im), NAS (different ports)
|
||||||
|
- PMA_HOSTS=192.168.12.3,192.168.1.251,192.168.1.251
|
||||||
|
- PMA_PORTS=3306,33306,3306
|
||||||
|
- MAX_EXECUTION_TIME=300
|
||||||
|
- MEMORY_LIMIT=512M
|
||||||
|
- UPLOAD_LIMIT=2048K
|
||||||
|
- TZ=America/Indiana/Indianapolis
|
||||||
|
ports:
|
||||||
|
- "2500:80"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
cpus: '1.0'
|
||||||
|
labels:
|
||||||
|
- "autoheal=true"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
- "homepage.group=Infrastructure"
|
||||||
|
- "homepage.name=Phpmyadmin"
|
||||||
|
- "homepage.icon=phpmyadmin.png"
|
||||||
|
- "homepage.href=https://php.3ddbrewery.com"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
34
compose-files/databases/phppgadmin/docker-compose.yml
Normal file
34
compose-files/databases/phppgadmin/docker-compose.yml
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
services:
|
||||||
|
phppgadmin:
|
||||||
|
image: dockage/phppgadmin:latest
|
||||||
|
container_name: phppgadmin
|
||||||
|
hostname: phppgadmin
|
||||||
|
environment:
|
||||||
|
# PostgreSQL on Hetzner (im)
|
||||||
|
- PHP_PG_ADMIN_SERVER_HOST=192.168.12.2
|
||||||
|
- PHP_PG_ADMIN_SERVER_PORT=55432
|
||||||
|
- PHP_PG_ADMIN_SERVER_SSL_MODE=allow
|
||||||
|
ports:
|
||||||
|
- "5183:80"
|
||||||
|
- "4433:443"
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
cpus: '0.5'
|
||||||
|
labels:
|
||||||
|
- "autoheal=true"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
- "homepage.group=Infrastructure"
|
||||||
|
- "homepage.name=PhpPGadmin"
|
||||||
|
- "homepage.icon=postgres.png"
|
||||||
|
- "homepage.href=https://phppgadmin.3ddbrewery.com"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
|
@ -64,6 +64,12 @@ services:
|
||||||
- /mnt/nas/downloads/nzbget:/downloads
|
- /mnt/nas/downloads/nzbget:/downloads
|
||||||
- /mnt/nas/media:/media
|
- /mnt/nas/media:/media
|
||||||
network_mode: service:gluetun
|
network_mode: service:gluetun
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -sf --max-time 5 http://1.1.1.1 || exit 1"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 60s
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|
@ -72,7 +78,8 @@ services:
|
||||||
reservations:
|
reservations:
|
||||||
memory: 256M
|
memory: 256M
|
||||||
depends_on:
|
depends_on:
|
||||||
- gluetun
|
gluetun:
|
||||||
|
condition: service_healthy
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
labels:
|
labels:
|
||||||
- "autoheal=true"
|
- "autoheal=true"
|
||||||
|
|
@ -96,8 +103,15 @@ services:
|
||||||
- /mnt/nas/downloads/rutorrent:/downloads
|
- /mnt/nas/downloads/rutorrent:/downloads
|
||||||
- /mnt/nas/media:/media
|
- /mnt/nas/media:/media
|
||||||
network_mode: service:gluetun
|
network_mode: service:gluetun
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -sf --max-time 5 http://1.1.1.1 || exit 1"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 60s
|
||||||
depends_on:
|
depends_on:
|
||||||
- gluetun
|
gluetun:
|
||||||
|
condition: service_healthy
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
|
|
|
||||||
142
compose-files/replicant/mixarr/docker-compose.yml
Normal file
142
compose-files/replicant/mixarr/docker-compose.yml
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
services:
|
||||||
|
# =========================================================================
|
||||||
|
# MySQL Database
|
||||||
|
# =========================================================================
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: mixarr_mysql
|
||||||
|
hostname: mysql
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
|
||||||
|
- MYSQL_DATABASE=${MYSQL_DATABASE}
|
||||||
|
- MYSQL_USER=${MYSQL_USER}
|
||||||
|
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- ./mysql_data:/var/lib/mysql
|
||||||
|
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||||
|
networks:
|
||||||
|
- mixarr_internal
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 1G
|
||||||
|
cpus: '1.0'
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
labels:
|
||||||
|
- "autoheal=true"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# Redis Cache
|
||||||
|
# =========================================================================
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: mixarr_redis
|
||||||
|
hostname: redis
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ./redis_data:/data
|
||||||
|
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
|
||||||
|
networks:
|
||||||
|
- mixarr_internal
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
cpus: '0.5'
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
labels:
|
||||||
|
- "autoheal=true"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# Mixarr API
|
||||||
|
# =========================================================================
|
||||||
|
api:
|
||||||
|
image: ghcr.io/aquantumofdonuts/mixarr:latest
|
||||||
|
container_name: mixarr_api
|
||||||
|
hostname: api
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "3005:3005"
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@mysql:3306/${MYSQL_DATABASE}
|
||||||
|
- REDIS_URL=redis://redis:6379
|
||||||
|
- SESSION_SECRET=${SESSION_SECRET}
|
||||||
|
- PORT=3005
|
||||||
|
- NODE_ENV=production
|
||||||
|
volumes:
|
||||||
|
- ./api_data:/data
|
||||||
|
depends_on:
|
||||||
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
command: >
|
||||||
|
sh -c "npx prisma migrate deploy && node apps/api/dist/index.js"
|
||||||
|
networks:
|
||||||
|
- mixarr_internal
|
||||||
|
- proxy
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
cpus: '1.0'
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -f http://localhost:3005/api/health || exit 1"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 120s
|
||||||
|
labels:
|
||||||
|
- "autoheal=true"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# Mixarr Web Frontend
|
||||||
|
# =========================================================================
|
||||||
|
web:
|
||||||
|
image: ghcr.io/aquantumofdonuts/mixarr:latest
|
||||||
|
container_name: mixarr_web
|
||||||
|
hostname: web
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "3006:3000"
|
||||||
|
environment:
|
||||||
|
- NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
|
||||||
|
- SESSION_SECRET=${SESSION_SECRET}
|
||||||
|
- NODE_ENV=production
|
||||||
|
volumes:
|
||||||
|
- ./web_data:/data
|
||||||
|
depends_on:
|
||||||
|
- api
|
||||||
|
networks:
|
||||||
|
- mixarr_internal
|
||||||
|
- proxy
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
cpus: '1.0'
|
||||||
|
labels:
|
||||||
|
- "autoheal=true"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
- "homepage.group=Media"
|
||||||
|
- "homepage.name=Mixarr"
|
||||||
|
- "homepage.icon=lidarr.png"
|
||||||
|
- "homepage.href=https://mixarr.3ddbrewery.com"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
mixarr_internal:
|
||||||
|
driver: bridge
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
104
playbooks/deploy-db-admin-tools.yml
Normal file
104
playbooks/deploy-db-admin-tools.yml
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
---
|
||||||
|
# Deploy Database Admin Tools to databases VM
|
||||||
|
# Deploys: phpmyadmin, phppgadmin
|
||||||
|
# Target: databases (192.168.1.81)
|
||||||
|
|
||||||
|
- name: Deploy Database Admin Tools
|
||||||
|
hosts: databases
|
||||||
|
vars:
|
||||||
|
appdata_path: /home/docker/appdata
|
||||||
|
compose_src: "{{ playbook_dir }}/../compose-files/databases"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
# =========================================================================
|
||||||
|
# PHPMYADMIN
|
||||||
|
# =========================================================================
|
||||||
|
- name: Create phpmyadmin directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ appdata_path }}/phpmyadmin"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Copy phpmyadmin docker-compose.yml
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ compose_src }}/phpmyadmin/docker-compose.yml"
|
||||||
|
dest: "{{ appdata_path }}/phpmyadmin/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Deploy phpmyadmin container
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ appdata_path }}/phpmyadmin"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: phpmyadmin_result
|
||||||
|
|
||||||
|
- name: Show phpmyadmin status
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "phpMyAdmin deployed: {{ phpmyadmin_result.changed }}"
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# PHPPGADMIN
|
||||||
|
# =========================================================================
|
||||||
|
- name: Create phppgadmin directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ appdata_path }}/phppgadmin"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create phppgadmin data directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ appdata_path }}/phppgadmin/data"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create phppgadmin logs directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ appdata_path }}/phppgadmin/logs"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Copy phppgadmin docker-compose.yml
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ compose_src }}/phppgadmin/docker-compose.yml"
|
||||||
|
dest: "{{ appdata_path }}/phppgadmin/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Deploy phppgadmin container
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ appdata_path }}/phppgadmin"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: phppgadmin_result
|
||||||
|
|
||||||
|
- name: Show phppgadmin status
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "phpPgAdmin deployed: {{ phppgadmin_result.changed }}"
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# VERIFICATION
|
||||||
|
# =========================================================================
|
||||||
|
- name: Wait for phpmyadmin to be ready
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "http://localhost:2500"
|
||||||
|
status_code: 200
|
||||||
|
timeout: 5
|
||||||
|
register: pma_health
|
||||||
|
retries: 10
|
||||||
|
delay: 5
|
||||||
|
until: pma_health.status == 200
|
||||||
|
|
||||||
|
- name: Wait for phppgadmin to be ready
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "http://localhost:5183"
|
||||||
|
status_code: [200, 302]
|
||||||
|
timeout: 5
|
||||||
|
register: pga_health
|
||||||
|
retries: 10
|
||||||
|
delay: 5
|
||||||
|
until: pga_health.status in [200, 302]
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg:
|
||||||
|
- "✅ phpMyAdmin: http://192.168.1.81:2500"
|
||||||
|
- "✅ phpPgAdmin: http://192.168.1.81:5183"
|
||||||
71
playbooks/deploy-download-stack.yml
Normal file
71
playbooks/deploy-download-stack.yml
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
---
|
||||||
|
- name: Deploy Download Stack (gluetun + nzbget + rutorrent)
|
||||||
|
hosts: download-stack
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
service_dir: /home/docker/appdata/download-stack
|
||||||
|
compose_src: "{{ playbook_dir }}/../compose-files/download-stack/download-stack"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create download-stack directory
|
||||||
|
file:
|
||||||
|
path: "{{ service_dir }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Ensure download network exists
|
||||||
|
shell: docker network inspect download >/dev/null 2>&1 || docker network create download
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Copy docker-compose.yml
|
||||||
|
copy:
|
||||||
|
src: "{{ compose_src }}/docker-compose.yml"
|
||||||
|
dest: "{{ service_dir }}/docker-compose.yml"
|
||||||
|
mode: '0644'
|
||||||
|
backup: yes
|
||||||
|
|
||||||
|
- name: Check if local .env exists
|
||||||
|
delegate_to: localhost
|
||||||
|
become: no
|
||||||
|
stat:
|
||||||
|
path: "{{ compose_src }}/.env"
|
||||||
|
register: local_env
|
||||||
|
|
||||||
|
- name: Copy .env file (if local copy exists)
|
||||||
|
copy:
|
||||||
|
src: "{{ compose_src }}/.env"
|
||||||
|
dest: "{{ service_dir }}/.env"
|
||||||
|
mode: '0600'
|
||||||
|
when: local_env.stat.exists
|
||||||
|
|
||||||
|
- name: Pull images
|
||||||
|
shell: docker compose pull
|
||||||
|
args:
|
||||||
|
chdir: "{{ service_dir }}"
|
||||||
|
|
||||||
|
- name: Start gluetun first
|
||||||
|
shell: docker compose up -d --force-recreate gluetun
|
||||||
|
args:
|
||||||
|
chdir: "{{ service_dir }}"
|
||||||
|
|
||||||
|
- name: Wait for gluetun to become healthy
|
||||||
|
shell: docker inspect --format '{{ '{{' }}.State.Health.Status{{ '}}' }}' gluetun
|
||||||
|
register: gluetun_health
|
||||||
|
until: gluetun_health.stdout == "healthy"
|
||||||
|
retries: 30
|
||||||
|
delay: 5
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Start nzbget and rutorrent
|
||||||
|
shell: docker compose up -d --force-recreate nzbget rutorrent
|
||||||
|
args:
|
||||||
|
chdir: "{{ service_dir }}"
|
||||||
|
|
||||||
|
- name: Check container status
|
||||||
|
shell: docker ps --filter name=gluetun --filter name=nzbget --filter name=rutorrent --format "table {{ '{{' }}.Names{{ '}}' }}\t{{ '{{' }}.Status{{ '}}' }}" | head -10
|
||||||
|
register: container_status
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Show status
|
||||||
|
debug:
|
||||||
|
msg: "{{ container_status.stdout_lines }}"
|
||||||
160
playbooks/deploy-mixarr.yml
Normal file
160
playbooks/deploy-mixarr.yml
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
---
|
||||||
|
# Deploy Mixarr Stack to replicant VM
|
||||||
|
# Containers: mysql, redis, api, web
|
||||||
|
# Target: replicant (192.168.1.80)
|
||||||
|
|
||||||
|
- name: Deploy Mixarr Stack
|
||||||
|
hosts: replicant
|
||||||
|
vars:
|
||||||
|
appdata_path: /home/maddox/docker/appdata
|
||||||
|
service_name: mixarr
|
||||||
|
service_dir: "{{ appdata_path }}/{{ service_name }}"
|
||||||
|
compose_src: "{{ playbook_dir }}/../compose-files/replicant/{{ service_name }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
# =========================================================================
|
||||||
|
# PRE-FLIGHT CHECKS
|
||||||
|
# =========================================================================
|
||||||
|
- name: Check if .env file exists on control server
|
||||||
|
delegate_to: localhost
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ compose_src }}/.env"
|
||||||
|
register: env_file
|
||||||
|
|
||||||
|
- name: Fail if .env is missing
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: |
|
||||||
|
.env file not found at {{ compose_src }}/.env
|
||||||
|
Copy .env.example to .env and fill in the secrets!
|
||||||
|
when: not env_file.stat.exists
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# DIRECTORY SETUP
|
||||||
|
# =========================================================================
|
||||||
|
- name: Create mixarr base directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create mysql_data directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}/mysql_data"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create redis_data directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}/redis_data"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create api_data directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}/api_data"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create web_data directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}/web_data"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# FILE DEPLOYMENT
|
||||||
|
# =========================================================================
|
||||||
|
- name: Copy docker-compose.yml
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ compose_src }}/docker-compose.yml"
|
||||||
|
dest: "{{ service_dir }}/docker-compose.yml"
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Copy .env file
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ compose_src }}/.env"
|
||||||
|
dest: "{{ service_dir }}/.env"
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: '0600'
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# CONTAINER DEPLOYMENT
|
||||||
|
# =========================================================================
|
||||||
|
- name: Deploy mixarr stack
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ service_dir }}"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: mixarr_result
|
||||||
|
|
||||||
|
- name: Show deployment status
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Mixarr stack deployed: {{ mixarr_result.changed }}"
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# VERIFICATION
|
||||||
|
# =========================================================================
|
||||||
|
- name: Wait for MySQL to be ready
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: docker exec mixarr_mysql mysqladmin ping -h localhost
|
||||||
|
register: mysql_check
|
||||||
|
retries: 30
|
||||||
|
delay: 5
|
||||||
|
until: mysql_check.rc == 0
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Wait for Redis to be ready
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: docker exec mixarr_redis redis-cli ping
|
||||||
|
register: redis_check
|
||||||
|
retries: 10
|
||||||
|
delay: 3
|
||||||
|
until: "'PONG' in redis_check.stdout"
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Wait for API to be healthy (may take up to 2 minutes for Prisma migrations)
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "http://localhost:3005/api/health"
|
||||||
|
status_code: 200
|
||||||
|
timeout: 10
|
||||||
|
register: api_health
|
||||||
|
retries: 30
|
||||||
|
delay: 10
|
||||||
|
until: api_health.status == 200
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Wait for Web frontend to be ready
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "http://localhost:3006"
|
||||||
|
status_code: [200, 302]
|
||||||
|
timeout: 10
|
||||||
|
register: web_health
|
||||||
|
retries: 15
|
||||||
|
delay: 5
|
||||||
|
until: web_health.status in [200, 302]
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg:
|
||||||
|
- "========================================="
|
||||||
|
- "Mixarr Stack Deployment Complete"
|
||||||
|
- "========================================="
|
||||||
|
- "✅ MySQL: Running on internal network"
|
||||||
|
- "✅ Redis: Running on internal network"
|
||||||
|
- "✅ API: http://192.168.1.80:3005"
|
||||||
|
- "✅ Web: http://192.168.1.80:3006"
|
||||||
|
- "========================================="
|
||||||
Loading…
Reference in a new issue