From 8b46587b015deb3e390b3ed5737040997e705585 Mon Sep 17 00:00:00 2001 From: Maddox Date: Sat, 24 Jan 2026 21:28:38 +0000 Subject: [PATCH] Add Unifi migration to network-services - compose-files/network-services/unifi: Full stack (MongoDB + Unifi app) - compose-files/databases/mongodb: Deprecated, kept for reference - playbooks/deploy-unifi-local.yml: Local deployment with resource limits - playbooks/migrate-unifi.yml: Original migration playbook (deprecated) Stack runs locally on network-services (.121) with: - unifi-db: MongoDB 4.4.29 (512M/1CPU) - unifi: Network Application (1G/1CPU) - Proper labels for autoheal and watchtower --- .../databases/mongodb/docker-compose.yml | 28 +++ .../immich/immich/docker-compose.yml | 21 ++- .../network-services/unifi/docker-compose.yml | 65 +++++++ playbooks/deploy-unifi-local.yml | 153 ++++++++++++++++ playbooks/migrate-unifi.yml | 169 ++++++++++++++++++ 5 files changed, 433 insertions(+), 3 deletions(-) create mode 100644 compose-files/databases/mongodb/docker-compose.yml create mode 100644 compose-files/network-services/unifi/docker-compose.yml create mode 100644 playbooks/deploy-unifi-local.yml create mode 100644 playbooks/migrate-unifi.yml diff --git a/compose-files/databases/mongodb/docker-compose.yml b/compose-files/databases/mongodb/docker-compose.yml new file mode 100644 index 0000000..d5350b4 --- /dev/null +++ b/compose-files/databases/mongodb/docker-compose.yml @@ -0,0 +1,28 @@ +services: + unifi-db: + image: docker.io/mongo:4.4.29 + container_name: unifi-db + restart: unless-stopped + environment: + - MONGO_INITDB_ROOT_USERNAME=root + - MONGO_INITDB_ROOT_PASSWORD=rootpassword + - MONGO_INITDB_DATABASE=unifi + volumes: + - /mnt/nas/docker/unifi/init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro + - /mnt/nas/docker/unifi/db:/data/db + ports: + - "27017:27017" + networks: + - database + labels: + - "autoheal=true" + - "com.centurylinklabs.watchtower.enable=true" + deploy: + resources: + limits: + memory: 512M + cpus: '1.0' + +networks: + database: + external: true diff --git a/compose-files/immich/immich/docker-compose.yml b/compose-files/immich/immich/docker-compose.yml index ceddeec..a0281ce 100644 --- a/compose-files/immich/immich/docker-compose.yml +++ b/compose-files/immich/immich/docker-compose.yml @@ -7,9 +7,9 @@ name: immich services: immich-server: container_name: immich_server - image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} + image: ghcr.io/immich-app/immich-server:\${IMMICH_VERSION:-release} volumes: - - ${UPLOAD_LOCATION}:/usr/src/app/upload + - \${UPLOAD_LOCATION}:/usr/src/app/upload - /etc/localtime:/etc/localtime:ro env_file: - .env @@ -30,10 +30,15 @@ services: - "com.centurylinklabs.watchtower.enable=true" networks: - immich + deploy: + resources: + limits: + memory: 2G + cpus: '2.0' immich-machine-learning: container_name: immich_machine_learning - image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release} + image: ghcr.io/immich-app/immich-machine-learning:\${IMMICH_VERSION:-release} volumes: - model-cache:/cache env_file: @@ -50,6 +55,11 @@ services: - "com.centurylinklabs.watchtower.enable=true" networks: - immich + deploy: + resources: + limits: + memory: 4G + cpus: '2.0' redis: container_name: immich_redis @@ -65,6 +75,11 @@ services: - "com.centurylinklabs.watchtower.enable=true" networks: - immich + deploy: + resources: + limits: + memory: 256M + cpus: '0.5' volumes: model-cache: diff --git a/compose-files/network-services/unifi/docker-compose.yml b/compose-files/network-services/unifi/docker-compose.yml new file mode 100644 index 0000000..d67f84e --- /dev/null +++ b/compose-files/network-services/unifi/docker-compose.yml @@ -0,0 +1,65 @@ +services: + unifi-db: + image: docker.io/mongo:4.4.29 + container_name: unifi-db + restart: unless-stopped + environment: + - MONGO_INITDB_ROOT_USERNAME=root + - MONGO_INITDB_ROOT_PASSWORD=rootpassword + - MONGO_INITDB_DATABASE=unifi + volumes: + - /mnt/nas/docker/unifi/init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro + - /mnt/nas/docker/unifi/db:/data/db + networks: + - unifi-network + labels: + - "autoheal=true" + - "com.centurylinklabs.watchtower.enable=true" + deploy: + resources: + limits: + memory: 512M + cpus: '1.0' + + unifi: + image: lscr.io/linuxserver/unifi-network-application:latest + container_name: unifi + restart: unless-stopped + environment: + - PUID=1000 + - PGID=1000 + - TZ=America/New_York + - MONGO_USER=unifi + - MONGO_PASS=unifipwd + - MONGO_HOST=unifi-db + - MONGO_PORT=27017 + - MONGO_DBNAME=unifi + - MONGO_AUTHSOURCE=admin + - MEM_LIMIT=1024 + - MEM_STARTUP=1024 + volumes: + - /mnt/nas/docker/unifi/config:/config + ports: + - "8080:8080" + - "8443:8443" + - "3478:3478/udp" + - "10001:10001/udp" + - "8880:8880" + - "6790:6789" + - "5514:5514/udp" + depends_on: + - unifi-db + networks: + - unifi-network + labels: + - "autoheal=true" + - "com.centurylinklabs.watchtower.enable=true" + deploy: + resources: + limits: + memory: 1G + cpus: '1.0' + +networks: + unifi-network: + driver: bridge diff --git a/playbooks/deploy-unifi-local.yml b/playbooks/deploy-unifi-local.yml new file mode 100644 index 0000000..c149743 --- /dev/null +++ b/playbooks/deploy-unifi-local.yml @@ -0,0 +1,153 @@ +--- +# Deploy Unifi Stack Locally on network-services +# - Cleans up old MongoDB from databases VM +# - Deploys MongoDB + Unifi together on network-services +# - Uses local bridge network, proper resource limits, labels + +- name: Cleanup old MongoDB from databases VM + hosts: databases + gather_facts: no + tags: [cleanup] + tasks: + - name: Stop and remove MongoDB containers + shell: | + docker stop unifi-db 2>/dev/null || true + docker rm unifi-db 2>/dev/null || true + changed_when: true + + - name: Remove MongoDB image + shell: docker rmi mongo:4.4.29 2>/dev/null || true + changed_when: true + + - name: Remove MongoDB compose directory + file: + path: /home/docker/appdata/mongodb + state: absent + + - name: Prune unused images + shell: docker image prune -f + changed_when: true + + - name: Verify cleanup + shell: | + echo "Containers:" && docker ps -a --filter name=unifi --format "{{'{{'}}.Names{{'}}'}}" + echo "Images:" && docker images | grep -i mongo || echo "No mongo images" + register: cleanup_verify + changed_when: false + + - name: Show cleanup status + debug: + msg: "{{ cleanup_verify.stdout_lines }}" + +- name: Stop existing Unifi on network-services + hosts: network-services + gather_facts: no + tags: [stop] + tasks: + - name: Stop existing containers + shell: | + docker stop unifi unifi-db 2>/dev/null || true + docker rm unifi unifi-db 2>/dev/null || true + changed_when: true + +- name: Deploy Unifi stack on network-services + hosts: network-services + gather_facts: no + tags: [deploy] + tasks: + - name: Ensure appdata directory exists + file: + path: /root/docker/appdata/unifi + state: directory + mode: '0755' + + - name: Verify NFS mount + stat: + path: /mnt/nas/docker/unifi + register: nfs_check + + - name: Fail if NFS not mounted + fail: + msg: "NFS mount /mnt/nas/docker/unifi not accessible" + when: not nfs_check.stat.exists + + - name: Deploy compose file + copy: + src: "../compose-files/network-services/unifi/docker-compose.yml" + dest: /root/docker/appdata/unifi/docker-compose.yml + mode: '0644' + + - name: Pull images + shell: | + cd /root/docker/appdata/unifi + docker compose pull + register: pull_result + + - name: Start stack + shell: | + cd /root/docker/appdata/unifi + docker compose up -d + register: start_result + + - name: Wait for MongoDB to be ready + shell: | + for i in $(seq 1 30); do + if docker exec unifi-db mongo --eval "db.adminCommand('ping')" 2>/dev/null | grep -q "ok"; then + echo "MongoDB ready" + exit 0 + fi + sleep 2 + done + echo "MongoDB timeout" + exit 1 + register: mongo_ready + changed_when: false + + - name: Wait for Unifi startup + pause: + seconds: 90 + prompt: "Waiting for Unifi to initialize (90s)..." + + - name: Check container status + shell: | + docker ps --filter name=unifi --format "table {{'{{'}}.Names{{'}}'}}\t{{'{{'}}.Status{{'}}'}}\t{{'{{'}}.Ports{{'}}'}}" | head -5 + register: container_status + changed_when: false + + - name: Show status + debug: + msg: "{{ container_status.stdout_lines }}" + + - name: Verify resource limits applied + shell: | + echo "=== Resource Limits ===" + docker inspect unifi-db --format '{{'{{'}}.Name{{'}}'}}: Memory={{'{{'}}.HostConfig.Memory}} CPUs={{'{{'}}.HostConfig.NanoCpus}}' + docker inspect unifi --format '{{'{{'}}.Name{{'}}'}}: Memory={{'{{'}}.HostConfig.Memory}} CPUs={{'{{'}}.HostConfig.NanoCpus}}' + register: limits_check + changed_when: false + + - name: Show resource limits + debug: + msg: "{{ limits_check.stdout_lines }}" + +- name: Summary + hosts: localhost + gather_facts: no + tags: [always] + tasks: + - name: Next steps + debug: + msg: + - "============================================" + - "UNIFI DEPLOYMENT COMPLETE" + - "============================================" + - "Stack: network-services (.121)" + - " - unifi-db (MongoDB 4.4.29) - 512M/1CPU" + - " - unifi (Network App) - 1G/1CPU" + - "" + - "Access: https://192.168.1.121:8443" + - "" + - "UPDATE APs:" + - " ssh admin@" + - " set-inform http://192.168.1.121:8080/inform" + - "============================================" diff --git a/playbooks/migrate-unifi.yml b/playbooks/migrate-unifi.yml new file mode 100644 index 0000000..3396390 --- /dev/null +++ b/playbooks/migrate-unifi.yml @@ -0,0 +1,169 @@ +--- +# Unifi Migration Playbook +# MongoDB -> databases (.81), Unifi app -> network-services (.121) +# +# Usage: +# ansible-playbook playbooks/migrate-unifi.yml --tags=setup-nfs +# ansible-playbook playbooks/migrate-unifi.yml --tags=stop-old +# ansible-playbook playbooks/migrate-unifi.yml --tags=deploy +# ansible-playbook playbooks/migrate-unifi.yml # full migration + +- name: Setup NFS mount on network-services + hosts: network-services + gather_facts: no + become: yes + tags: [setup-nfs, deploy] + tasks: + - name: Create mount directory + file: + path: /mnt/nas/docker + state: directory + mode: '0755' + + - name: Check if NFS already in fstab + shell: grep -q "192.168.1.251:/volume1/docker" /etc/fstab + register: fstab_check + ignore_errors: yes + changed_when: false + + - name: Add NFS mount to fstab + lineinfile: + path: /etc/fstab + line: "192.168.1.251:/volume1/docker /mnt/nas/docker nfs defaults 0 0" + state: present + when: fstab_check.rc != 0 + + - name: Mount NFS + shell: mount -a + changed_when: false + + - name: Verify mount + stat: + path: /mnt/nas/docker/unifi + register: mount_check + + - name: Fail if mount not working + fail: + msg: "NFS mount failed - /mnt/nas/docker/unifi not accessible" + when: not mount_check.stat.exists + +- name: Stop Unifi on docker666 + hosts: docker666 + gather_facts: no + tags: [stop-old] + tasks: + - name: Stop old Unifi stack + shell: | + cd /volume1/docker/unifi + docker compose down + register: stop_result + ignore_errors: yes + + - name: Show result + debug: + msg: "{{ stop_result.stdout_lines | default(['Stopped']) }}" + +- name: Deploy MongoDB on databases + hosts: databases + gather_facts: no + tags: [deploy, deploy-mongo] + tasks: + - name: Ensure database network exists + shell: docker network inspect database >/dev/null 2>&1 || docker network create database + changed_when: false + + - name: Create compose directory + file: + path: /home/docker/appdata/mongodb + state: directory + mode: '0755' + + - name: Copy MongoDB compose + copy: + src: "../compose-files/databases/mongodb/docker-compose.yml" + dest: /home/docker/appdata/mongodb/docker-compose.yml + mode: '0644' + + - name: Deploy MongoDB + shell: | + cd /home/docker/appdata/mongodb + docker compose pull + docker compose up -d + + - name: Wait for MongoDB + shell: | + for i in $(seq 1 30); do + if docker exec unifi-db mongo --eval "db.adminCommand('ping')" 2>/dev/null | grep -q "ok"; then + echo "MongoDB ready" + exit 0 + fi + sleep 2 + done + exit 1 + register: mongo_wait + changed_when: false + +- name: Deploy Unifi on network-services + hosts: network-services + gather_facts: no + tags: [deploy, deploy-unifi] + tasks: + - name: Ensure proxy network exists + shell: docker network inspect proxy >/dev/null 2>&1 || docker network create proxy + changed_when: false + + - name: Create compose directory + file: + path: /root/docker/appdata/unifi + state: directory + mode: '0755' + + - name: Copy Unifi compose + copy: + src: "../compose-files/network-services/unifi/docker-compose.yml" + dest: /root/docker/appdata/unifi/docker-compose.yml + mode: '0644' + + - name: Deploy Unifi + shell: | + cd /root/docker/appdata/unifi + docker compose pull + docker compose up -d + + - name: Wait for Unifi startup + pause: + seconds: 60 + prompt: "Waiting for Unifi to initialize..." + + - name: Check Unifi status + shell: docker ps --filter name=unifi --format "table {{'{{'}}.Names{{'}}'}}\t{{'{{'}}.Status{{'}}'}}" + register: unifi_status + + - name: Show status + debug: + msg: "{{ unifi_status.stdout_lines }}" + +- name: Migration summary + hosts: localhost + gather_facts: no + tags: [always] + tasks: + - name: Next steps + debug: + msg: + - "============================================" + - "UNIFI MIGRATION SUMMARY" + - "============================================" + - "MongoDB: 192.168.1.81:27017" + - "Unifi: https://192.168.1.121:8443" + - "" + - "UPDATE YOUR 4 APs:" + - " ssh admin@" + - " set-inform http://192.168.1.121:8080/inform" + - "" + - "Or from Unifi UI: Settings > System > Advanced" + - " Set 'Inform Host' to: 192.168.1.121" + - "" + - "CLEANUP (after APs reconnect):" + - " ssh docker666 'cd /volume1/docker/unifi && docker compose down'" + - "============================================"