Phase 2: migrate calibre stack + audiobookshelf
This commit is contained in:
parent
d8b21df92b
commit
575e6b7e21
6 changed files with 488 additions and 0 deletions
|
|
@ -91,3 +91,9 @@ ansible-playbook playbooks/deploy-<service>.yml
|
||||||
- `inventory/hosts.yml` - All managed hosts with IPs and connection settings
|
- `inventory/hosts.yml` - All managed hosts with IPs and connection settings
|
||||||
- `inventory/group_vars/all.yml` - Global variables (timezone, NAS paths, ntfy topics)
|
- `inventory/group_vars/all.yml` - Global variables (timezone, NAS paths, ntfy topics)
|
||||||
- `docs/control-server-guide.md` - Detailed operations guide
|
- `docs/control-server-guide.md` - Detailed operations guide
|
||||||
|
|
||||||
|
## Additional Context Paths
|
||||||
|
|
||||||
|
The following external directories are part of this project's context:
|
||||||
|
|
||||||
|
- `~/scripts/` - Utility scripts for homelab management (add-host.sh, control-menu.sh, ssh-manager.sh, sync-dyno.sh)
|
||||||
|
|
|
||||||
25
compose-files/replicant/audiobookshelf/docker-compose.yml
Normal file
25
compose-files/replicant/audiobookshelf/docker-compose.yml
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
services:
|
||||||
|
audiobookshelf:
|
||||||
|
image: ghcr.io/advplyr/audiobookshelf:latest
|
||||||
|
container_name: audiobookshelf
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "13378:80"
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
- ./metadata:/metadata
|
||||||
|
- /mnt/nas/media/audiobooks:/audiobooks
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- "autoheal=true"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 1G
|
||||||
|
cpus: "1.0"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
66
compose-files/replicant/calibre/docker-compose.yml
Normal file
66
compose-files/replicant/calibre/docker-compose.yml
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
services:
|
||||||
|
calibre-server:
|
||||||
|
image: linuxserver/calibre:latest
|
||||||
|
container_name: calibre-server
|
||||||
|
restart: unless-stopped
|
||||||
|
security_opt:
|
||||||
|
- seccomp:unconfined
|
||||||
|
ports:
|
||||||
|
- "28080:8080"
|
||||||
|
- "28081:8081"
|
||||||
|
- "28181:8181"
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
- /mnt/nas/media/Books:/books
|
||||||
|
environment:
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
- TZ=America/Indiana/Indianapolis
|
||||||
|
- GUAC_USER=calibre
|
||||||
|
- GUAC_PASS=calibre
|
||||||
|
- CALIBRE_SERVERSIDE_BROWSE=1
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- "autoheal=true"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 1G
|
||||||
|
cpus: "1.0"
|
||||||
|
|
||||||
|
calibre-web:
|
||||||
|
image: linuxserver/calibre-web:latest
|
||||||
|
container_name: calibre-web
|
||||||
|
restart: unless-stopped
|
||||||
|
security_opt:
|
||||||
|
- seccomp:unconfined
|
||||||
|
ports:
|
||||||
|
- "28083:8083"
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
- /mnt/nas/media/Books:/books:ro
|
||||||
|
environment:
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
- TZ=America/Indiana/Indianapolis
|
||||||
|
- DOCKER_MODS=linuxserver/mods:calibre-web-calibre
|
||||||
|
- CALIBRE_DBPATH=/books
|
||||||
|
- OAUTHLIB_RELAX_TOKEN_SCOPE=1
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- "autoheal=true"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
cpus: "0.5"
|
||||||
|
depends_on:
|
||||||
|
- calibre-server
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
56
playbooks/deploy-audiobookshelf.yml
Normal file
56
playbooks/deploy-audiobookshelf.yml
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
---
|
||||||
|
- name: Deploy Audiobookshelf
|
||||||
|
hosts: replicant
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
service_dir: /home/maddox/docker/appdata/audiobookshelf
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create audiobookshelf directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Create config subdirectory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}/config"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Create metadata subdirectory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}/metadata"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Copy docker-compose.yml
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: ../compose-files/replicant/audiobookshelf/docker-compose.yml
|
||||||
|
dest: "{{ service_dir }}/docker-compose.yml"
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Ensure proxy network exists
|
||||||
|
community.docker.docker_network:
|
||||||
|
name: proxy
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Deploy audiobookshelf
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ service_dir }}"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: compose_result
|
||||||
|
|
||||||
|
- name: Show deployment result
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Audiobookshelf deployed successfully"
|
||||||
|
when: compose_result.changed
|
||||||
48
playbooks/deploy-calibre.yml
Normal file
48
playbooks/deploy-calibre.yml
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
---
|
||||||
|
- name: Deploy Calibre Stack (calibre-server + calibre-web)
|
||||||
|
hosts: replicant
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
service_dir: /home/maddox/docker/appdata/calibre
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create calibre directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Create config subdirectory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}/config"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Copy docker-compose.yml
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: ../compose-files/replicant/calibre/docker-compose.yml
|
||||||
|
dest: "{{ service_dir }}/docker-compose.yml"
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Ensure proxy network exists
|
||||||
|
community.docker.docker_network:
|
||||||
|
name: proxy
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Deploy calibre stack
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ service_dir }}"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: compose_result
|
||||||
|
|
||||||
|
- name: Show deployment result
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Calibre stack deployed successfully"
|
||||||
|
when: compose_result.changed
|
||||||
287
scripts/migrate-phase2-books.sh
Executable file
287
scripts/migrate-phase2-books.sh
Executable file
|
|
@ -0,0 +1,287 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Phase 2 Migration: Calibre Stack + Audiobookshelf
|
||||||
|
# Target: replicant (.80)
|
||||||
|
# Run from control server (CT 127)
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
REPO_DIR="$HOME/clustered-fucks"
|
||||||
|
COMPOSE_DIR="$REPO_DIR/compose-files/replicant"
|
||||||
|
PLAYBOOK_DIR="$REPO_DIR/playbooks"
|
||||||
|
|
||||||
|
echo "=== Phase 2: Calibre Stack + Audiobookshelf Migration ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create directories
|
||||||
|
mkdir -p "$COMPOSE_DIR/calibre"
|
||||||
|
mkdir -p "$COMPOSE_DIR/audiobookshelf"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Calibre Stack (calibre-server + calibre-web)
|
||||||
|
# =============================================================================
|
||||||
|
cat > "$COMPOSE_DIR/calibre/docker-compose.yml" << 'EOF'
|
||||||
|
services:
|
||||||
|
calibre-server:
|
||||||
|
image: linuxserver/calibre:latest
|
||||||
|
container_name: calibre-server
|
||||||
|
restart: unless-stopped
|
||||||
|
security_opt:
|
||||||
|
- seccomp:unconfined
|
||||||
|
ports:
|
||||||
|
- "28080:8080"
|
||||||
|
- "28081:8081"
|
||||||
|
- "28181:8181"
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
- /mnt/nas/media/Books:/books
|
||||||
|
environment:
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
- TZ=America/Indiana/Indianapolis
|
||||||
|
- GUAC_USER=calibre
|
||||||
|
- GUAC_PASS=calibre
|
||||||
|
- CALIBRE_SERVERSIDE_BROWSE=1
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- "autoheal=true"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 1G
|
||||||
|
cpus: "1.0"
|
||||||
|
|
||||||
|
calibre-web:
|
||||||
|
image: linuxserver/calibre-web:latest
|
||||||
|
container_name: calibre-web
|
||||||
|
restart: unless-stopped
|
||||||
|
security_opt:
|
||||||
|
- seccomp:unconfined
|
||||||
|
ports:
|
||||||
|
- "28083:8083"
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
- /mnt/nas/media/Books:/books:ro
|
||||||
|
environment:
|
||||||
|
- PUID=1000
|
||||||
|
- PGID=1000
|
||||||
|
- TZ=America/Indiana/Indianapolis
|
||||||
|
- DOCKER_MODS=linuxserver/mods:calibre-web-calibre
|
||||||
|
- CALIBRE_DBPATH=/books
|
||||||
|
- OAUTHLIB_RELAX_TOKEN_SCOPE=1
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- "autoheal=true"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
cpus: "0.5"
|
||||||
|
depends_on:
|
||||||
|
- calibre-server
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "[OK] Created $COMPOSE_DIR/calibre/docker-compose.yml"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Audiobookshelf
|
||||||
|
# =============================================================================
|
||||||
|
cat > "$COMPOSE_DIR/audiobookshelf/docker-compose.yml" << 'EOF'
|
||||||
|
services:
|
||||||
|
audiobookshelf:
|
||||||
|
image: ghcr.io/advplyr/audiobookshelf:latest
|
||||||
|
container_name: audiobookshelf
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "13378:80"
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
- ./metadata:/metadata
|
||||||
|
- /mnt/nas/media/audiobooks:/audiobooks
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- "autoheal=true"
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 1G
|
||||||
|
cpus: "1.0"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "[OK] Created $COMPOSE_DIR/audiobookshelf/docker-compose.yml"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Ansible Playbook: deploy-calibre.yml
|
||||||
|
# =============================================================================
|
||||||
|
cat > "$PLAYBOOK_DIR/deploy-calibre.yml" << 'EOF'
|
||||||
|
---
|
||||||
|
- name: Deploy Calibre Stack (calibre-server + calibre-web)
|
||||||
|
hosts: replicant
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
service_dir: /home/maddox/docker/appdata/calibre
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create calibre directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Create config subdirectory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}/config"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Copy docker-compose.yml
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: ../compose-files/replicant/calibre/docker-compose.yml
|
||||||
|
dest: "{{ service_dir }}/docker-compose.yml"
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Ensure proxy network exists
|
||||||
|
community.docker.docker_network:
|
||||||
|
name: proxy
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Deploy calibre stack
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ service_dir }}"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: compose_result
|
||||||
|
|
||||||
|
- name: Show deployment result
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Calibre stack deployed successfully"
|
||||||
|
when: compose_result.changed
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "[OK] Created $PLAYBOOK_DIR/deploy-calibre.yml"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Ansible Playbook: deploy-audiobookshelf.yml
|
||||||
|
# =============================================================================
|
||||||
|
cat > "$PLAYBOOK_DIR/deploy-audiobookshelf.yml" << 'EOF'
|
||||||
|
---
|
||||||
|
- name: Deploy Audiobookshelf
|
||||||
|
hosts: replicant
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
service_dir: /home/maddox/docker/appdata/audiobookshelf
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create audiobookshelf directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Create config subdirectory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}/config"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Create metadata subdirectory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ service_dir }}/metadata"
|
||||||
|
state: directory
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Copy docker-compose.yml
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: ../compose-files/replicant/audiobookshelf/docker-compose.yml
|
||||||
|
dest: "{{ service_dir }}/docker-compose.yml"
|
||||||
|
owner: maddox
|
||||||
|
group: maddox
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Ensure proxy network exists
|
||||||
|
community.docker.docker_network:
|
||||||
|
name: proxy
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Deploy audiobookshelf
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ service_dir }}"
|
||||||
|
state: present
|
||||||
|
pull: always
|
||||||
|
register: compose_result
|
||||||
|
|
||||||
|
- name: Show deployment result
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Audiobookshelf deployed successfully"
|
||||||
|
when: compose_result.changed
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "[OK] Created $PLAYBOOK_DIR/deploy-audiobookshelf.yml"
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Summary
|
||||||
|
# =============================================================================
|
||||||
|
echo ""
|
||||||
|
echo "=== Files Created ==="
|
||||||
|
echo " Compose files:"
|
||||||
|
echo " - $COMPOSE_DIR/calibre/docker-compose.yml"
|
||||||
|
echo " - $COMPOSE_DIR/audiobookshelf/docker-compose.yml"
|
||||||
|
echo " Playbooks:"
|
||||||
|
echo " - $PLAYBOOK_DIR/deploy-calibre.yml"
|
||||||
|
echo " - $PLAYBOOK_DIR/deploy-audiobookshelf.yml"
|
||||||
|
echo ""
|
||||||
|
echo "=== Migration Steps ==="
|
||||||
|
echo ""
|
||||||
|
echo "1. Stop containers on alien:"
|
||||||
|
echo " ssh alien 'docker stop calibre-server calibre-web audiobookshelf'"
|
||||||
|
echo ""
|
||||||
|
echo "2. Rsync data FROM replicant (SSH into replicant first):"
|
||||||
|
echo " ssh replicant"
|
||||||
|
echo " rsync -avP maddox@192.168.1.252:/home/maddox/docker/appdata/calibre/ /home/maddox/docker/appdata/calibre/"
|
||||||
|
echo " rsync -avP maddox@192.168.1.252:/home/maddox/docker/appdata/audiobookshelf/ /home/maddox/docker/appdata/audiobookshelf/"
|
||||||
|
echo ""
|
||||||
|
echo "3. Deploy services:"
|
||||||
|
echo " cd ~/clustered-fucks"
|
||||||
|
echo " ansible-playbook playbooks/deploy-calibre.yml"
|
||||||
|
echo " ansible-playbook playbooks/deploy-audiobookshelf.yml"
|
||||||
|
echo ""
|
||||||
|
echo "4. Verify services:"
|
||||||
|
echo " curl -s -o /dev/null -w '%{http_code}' http://192.168.1.80:28080/ # calibre desktop"
|
||||||
|
echo " curl -s -o /dev/null -w '%{http_code}' http://192.168.1.80:28083/ # calibre-web"
|
||||||
|
echo " curl -s -o /dev/null -w '%{http_code}' http://192.168.1.80:13378/ # audiobookshelf"
|
||||||
|
echo ""
|
||||||
|
echo "5. Update Traefik backends to point to 192.168.1.80"
|
||||||
|
echo ""
|
||||||
|
echo "6. Cleanup alien (after verification):"
|
||||||
|
echo " ssh alien 'docker rm calibre-server calibre-web audiobookshelf'"
|
||||||
|
echo ""
|
||||||
|
echo "7. Commit changes:"
|
||||||
|
echo " git add -A && git commit -m 'Phase 2: migrate calibre stack + audiobookshelf' && git push"
|
||||||
|
echo ""
|
||||||
|
echo "=== IMPORTANT ==="
|
||||||
|
echo "Change GUAC_PASS in calibre compose before deploying!"
|
||||||
Loading…
Reference in a new issue