Add mixarr traefik config and migration scripts
- configs/mixarr.yml: Traefik routing for mixarr web + API - migration/phase3-mixarr.sh: Migration script for mixarr stack - migration/phase3-db-admin-tools.sh: Migration script for db admin tools Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
116be081b7
commit
9a97beeaf9
3 changed files with 768 additions and 0 deletions
48
configs/mixarr.yml
Normal file
48
configs/mixarr.yml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
http:
|
||||
routers:
|
||||
# Mixarr Web Frontend - with auth
|
||||
mixarr-web:
|
||||
entryPoints:
|
||||
- web-secure
|
||||
tls:
|
||||
certResolver: default
|
||||
service: mixarr-web
|
||||
rule: (Host(`mixarr.fails.me`) || Host(`mixarr.3ddbrewery.com`)) && !PathPrefix(`/api`)
|
||||
middlewares:
|
||||
- secure-headers
|
||||
- authentik
|
||||
|
||||
# Mixarr Web API paths - no auth (app handles session auth)
|
||||
mixarr-web-api:
|
||||
entryPoints:
|
||||
- web-secure
|
||||
tls:
|
||||
certResolver: default
|
||||
service: mixarr-web
|
||||
rule: (Host(`mixarr.fails.me`) || Host(`mixarr.3ddbrewery.com`)) && PathPrefix(`/api`)
|
||||
middlewares:
|
||||
- secure-headers
|
||||
|
||||
# Mixarr Backend API - no auth (called by frontend)
|
||||
mixarr-api:
|
||||
entryPoints:
|
||||
- web-secure
|
||||
tls:
|
||||
certResolver: default
|
||||
service: mixarr-api
|
||||
rule: Host(`api.mixarr.fails.me`) || Host(`api.mixarr.3ddbrewery.com`)
|
||||
middlewares:
|
||||
- secure-headers
|
||||
|
||||
services:
|
||||
mixarr-web:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: http://192.168.1.80:3006
|
||||
passHostHeader: false
|
||||
|
||||
mixarr-api:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: http://192.168.1.80:3005
|
||||
passHostHeader: false
|
||||
275
migration/phase3-db-admin-tools.sh
Executable file
275
migration/phase3-db-admin-tools.sh
Executable file
|
|
@ -0,0 +1,275 @@
|
|||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Phase 3 Migration: Database Admin Tools
|
||||
# Target: databases (.81)
|
||||
# Services: phpmyadmin, phppgadmin
|
||||
# Run this on the control server (CT 127)
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
COMPOSE_DIR_PMA=~/clustered-fucks/compose-files/databases/phpmyadmin
|
||||
COMPOSE_DIR_PGA=~/clustered-fucks/compose-files/databases/phppgadmin
|
||||
PLAYBOOK_DIR=~/clustered-fucks/playbooks
|
||||
|
||||
echo "========================================"
|
||||
echo "Phase 3: Database Admin Tools Migration"
|
||||
echo "Target: databases (192.168.1.81)"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# Create directories
|
||||
mkdir -p "$COMPOSE_DIR_PMA"
|
||||
mkdir -p "$COMPOSE_DIR_PGA"
|
||||
mkdir -p "$PLAYBOOK_DIR"
|
||||
|
||||
# =============================================================================
|
||||
# PHPMYADMIN
|
||||
# =============================================================================
|
||||
|
||||
echo "Creating phpMyAdmin compose file..."
|
||||
|
||||
cat > "$COMPOSE_DIR_PMA/docker-compose.yml" << 'EOF'
|
||||
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
|
||||
EOF
|
||||
|
||||
echo "✅ Created $COMPOSE_DIR_PMA/docker-compose.yml"
|
||||
|
||||
# =============================================================================
|
||||
# PHPPGADMIN
|
||||
# =============================================================================
|
||||
|
||||
echo "Creating phpPgAdmin compose file..."
|
||||
|
||||
cat > "$COMPOSE_DIR_PGA/docker-compose.yml" << 'EOF'
|
||||
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
|
||||
- ./logs:/var/log
|
||||
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
|
||||
EOF
|
||||
|
||||
echo "✅ Created $COMPOSE_DIR_PGA/docker-compose.yml"
|
||||
|
||||
# =============================================================================
|
||||
# ANSIBLE PLAYBOOK - Combined Deployment
|
||||
# =============================================================================
|
||||
|
||||
echo "Creating combined Ansible playbook..."
|
||||
|
||||
cat > "$PLAYBOOK_DIR/deploy-db-admin-tools.yml" << 'EOF'
|
||||
---
|
||||
# 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"
|
||||
EOF
|
||||
|
||||
echo "✅ Created $PLAYBOOK_DIR/deploy-db-admin-tools.yml"
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "FILES CREATED"
|
||||
echo "========================================"
|
||||
echo " $COMPOSE_DIR_PMA/docker-compose.yml"
|
||||
echo " $COMPOSE_DIR_PGA/docker-compose.yml"
|
||||
echo " $PLAYBOOK_DIR/deploy-db-admin-tools.yml"
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "NEXT STEPS"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "1. STOP OLD CONTAINERS on alien:"
|
||||
echo " ssh alien 'docker stop phpmyadmin phppgadmin-phppgadmin-1'"
|
||||
echo ""
|
||||
echo "2. DEPLOY to databases:"
|
||||
echo " ansible-playbook playbooks/deploy-db-admin-tools.yml"
|
||||
echo ""
|
||||
echo "3. VERIFY services:"
|
||||
echo " curl -I http://192.168.1.81:2500 # phpMyAdmin"
|
||||
echo " curl -I http://192.168.1.81:5183 # phpPgAdmin"
|
||||
echo ""
|
||||
echo "4. UPDATE TRAEFIK config on Hetzner:"
|
||||
echo " Change backend IPs from alien (192.168.1.252) to databases (192.168.1.81)"
|
||||
echo " - phpmyadmin: port 2500"
|
||||
echo " - phppgadmin: port 5183"
|
||||
echo ""
|
||||
echo "5. CLEANUP alien:"
|
||||
echo " ssh alien 'docker rm phpmyadmin phppgadmin-phppgadmin-1'"
|
||||
echo ""
|
||||
echo "6. COMMIT changes:"
|
||||
echo " cd ~/clustered-fucks"
|
||||
echo " git add -A"
|
||||
echo " git commit -m 'Phase 3: Deploy phpmyadmin + phppgadmin to databases'"
|
||||
echo " git push"
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "NOTES"
|
||||
echo "========================================"
|
||||
echo "- Both services are STATELESS (phpmyadmin has no mounts)"
|
||||
echo "- phppgadmin had anonymous Docker volumes on alien (not important)"
|
||||
echo "- phpMyAdmin connects to MySQL on: Hetzner (192.168.12.3:3306), NAS (192.168.1.251:33306 & :3306)"
|
||||
echo "- phpPgAdmin connects to PostgreSQL on: Hetzner (192.168.12.2:55432)"
|
||||
echo ""
|
||||
445
migration/phase3-mixarr.sh
Executable file
445
migration/phase3-mixarr.sh
Executable file
|
|
@ -0,0 +1,445 @@
|
|||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Phase 3 Migration: Mixarr Stack
|
||||
# Target: replicant (.80)
|
||||
# Services: mixarr_mysql, mixarr_redis, mixarr_api, mixarr_web (4 containers)
|
||||
# Run this on the control server (CT 127)
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
COMPOSE_DIR=~/clustered-fucks/compose-files/replicant/mixarr
|
||||
PLAYBOOK_DIR=~/clustered-fucks/playbooks
|
||||
|
||||
echo "========================================"
|
||||
echo "Phase 3: Mixarr Stack Migration"
|
||||
echo "Target: replicant (192.168.1.80)"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# Create directories
|
||||
mkdir -p "$COMPOSE_DIR"
|
||||
mkdir -p "$PLAYBOOK_DIR"
|
||||
|
||||
# =============================================================================
|
||||
# MIXARR DOCKER-COMPOSE
|
||||
# =============================================================================
|
||||
|
||||
echo "Creating Mixarr docker-compose.yml..."
|
||||
|
||||
cat > "$COMPOSE_DIR/docker-compose.yml" << 'EOF'
|
||||
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
|
||||
EOF
|
||||
|
||||
echo "✅ Created $COMPOSE_DIR/docker-compose.yml"
|
||||
|
||||
# =============================================================================
|
||||
# ENVIRONMENT FILE TEMPLATE
|
||||
# =============================================================================
|
||||
|
||||
echo "Creating .env template..."
|
||||
|
||||
cat > "$COMPOSE_DIR/.env.example" << 'EOF'
|
||||
# Mixarr Environment Variables
|
||||
# Copy to .env and fill in the secrets
|
||||
|
||||
# MySQL Database
|
||||
MYSQL_ROOT_PASSWORD=changeme_root_password
|
||||
MYSQL_DATABASE=mixarr
|
||||
MYSQL_USER=mixarr
|
||||
MYSQL_PASSWORD=changeme_mixarr_password
|
||||
|
||||
# Session Secret (generate with: openssl rand -hex 32)
|
||||
SESSION_SECRET=changeme_session_secret
|
||||
|
||||
# API URL (used by frontend)
|
||||
NEXT_PUBLIC_API_URL=https://api.mixarr.3ddbrewery.com
|
||||
EOF
|
||||
|
||||
echo "✅ Created $COMPOSE_DIR/.env.example"
|
||||
|
||||
# =============================================================================
|
||||
# ANSIBLE PLAYBOOK
|
||||
# =============================================================================
|
||||
|
||||
echo "Creating Ansible playbook..."
|
||||
|
||||
cat > "$PLAYBOOK_DIR/deploy-mixarr.yml" << 'EOF'
|
||||
---
|
||||
# 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"
|
||||
- "========================================="
|
||||
EOF
|
||||
|
||||
echo "✅ Created $PLAYBOOK_DIR/deploy-mixarr.yml"
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "FILES CREATED"
|
||||
echo "========================================"
|
||||
echo " $COMPOSE_DIR/docker-compose.yml"
|
||||
echo " $COMPOSE_DIR/.env.example"
|
||||
echo " $PLAYBOOK_DIR/deploy-mixarr.yml"
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "NEXT STEPS"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "1. GET SECRETS from alien (check .env or compose file):"
|
||||
echo " ssh alien 'cat /mnt/docker-storage/appdata/mixarr/.env || cat /mnt/docker-storage/appdata/mixarr/docker-compose.yml'"
|
||||
echo ""
|
||||
echo " Look for:"
|
||||
echo " - MYSQL_ROOT_PASSWORD"
|
||||
echo " - MYSQL_PASSWORD"
|
||||
echo " - SESSION_SECRET"
|
||||
echo ""
|
||||
echo "2. CREATE .env file with secrets:"
|
||||
echo " cp $COMPOSE_DIR/.env.example $COMPOSE_DIR/.env"
|
||||
echo " nano $COMPOSE_DIR/.env"
|
||||
echo ""
|
||||
echo "3. STOP OLD CONTAINERS on alien:"
|
||||
echo " ssh alien 'cd /mnt/docker-storage/appdata/mixarr && docker compose down'"
|
||||
echo ""
|
||||
echo "4. CREATE TARGET DIRECTORIES on replicant:"
|
||||
echo " ssh replicant 'mkdir -p /home/maddox/docker/appdata/mixarr/{mysql_data,redis_data,api_data,web_data}'"
|
||||
echo ""
|
||||
echo "5. EXPORT MySQL DATA (if preserving existing data):"
|
||||
echo " ssh alien 'docker exec mixarr_mysql mysqldump -u root -pROOT_PASSWORD mixarr > /tmp/mixarr_backup.sql'"
|
||||
echo " scp alien:/tmp/mixarr_backup.sql /tmp/"
|
||||
echo ""
|
||||
echo "6. DEPLOY to replicant:"
|
||||
echo " ansible-playbook playbooks/deploy-mixarr.yml"
|
||||
echo ""
|
||||
echo "7. IMPORT MySQL DATA (if applicable):"
|
||||
echo " scp /tmp/mixarr_backup.sql replicant:/tmp/"
|
||||
echo " ssh replicant 'docker exec -i mixarr_mysql mysql -u root -pROOT_PASSWORD mixarr < /tmp/mixarr_backup.sql'"
|
||||
echo ""
|
||||
echo "8. VERIFY services:"
|
||||
echo " curl http://192.168.1.80:3005/api/health # API"
|
||||
echo " curl -I http://192.168.1.80:3006 # Web frontend"
|
||||
echo ""
|
||||
echo "9. UPDATE TRAEFIK config:"
|
||||
echo " Change mixarr API backend from alien to replicant (192.168.1.80:3005)"
|
||||
echo " Change mixarr Web backend from alien to replicant (192.168.1.80:3006)"
|
||||
echo ""
|
||||
echo "10. CLEANUP alien:"
|
||||
echo " ssh alien 'cd /mnt/docker-storage/appdata/mixarr && docker compose rm -f'"
|
||||
echo ""
|
||||
echo "11. COMMIT changes:"
|
||||
echo " cd ~/clustered-fucks"
|
||||
echo " git add -A"
|
||||
echo " git commit -m 'Phase 3: Deploy mixarr stack to replicant'"
|
||||
echo " git push"
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "IMPORTANT NOTES"
|
||||
echo "========================================"
|
||||
echo "- Mixarr uses MySQL - DATABASE STATE MATTERS"
|
||||
echo " - Export/import database if you have existing data"
|
||||
echo " - Or start fresh with Prisma migrations"
|
||||
echo ""
|
||||
echo "- Original location on alien: /mnt/docker-storage/appdata/mixarr"
|
||||
echo " (Not the usual /home/maddox/docker/appdata path)"
|
||||
echo ""
|
||||
echo "- API has 2-minute startup period for Prisma migrations"
|
||||
echo " - First deploy may be slow, subsequent restarts faster"
|
||||
echo ""
|
||||
echo "- Docker volumes are replaced with bind mounts for easier backup/migration"
|
||||
echo ""
|
||||
Loading…
Reference in a new issue