From 79c76accfb2c7d5af40fdf779c63b58a894ba5de Mon Sep 17 00:00:00 2001 From: Maddox Date: Thu, 29 Jan 2026 18:12:28 +0000 Subject: [PATCH] Add phase3-karakeep.sh migration script Co-Authored-By: Claude Opus 4.5 --- migration/phase3-karakeep.sh | 412 +++++++++++++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100755 migration/phase3-karakeep.sh diff --git a/migration/phase3-karakeep.sh b/migration/phase3-karakeep.sh new file mode 100755 index 0000000..17d3690 --- /dev/null +++ b/migration/phase3-karakeep.sh @@ -0,0 +1,412 @@ +#!/bin/bash +# ============================================================================= +# Phase 3 Migration: Karakeep Stack +# Target: databases (.81) +# Services: karakeep-web, meilisearch, chrome, ollama (4 containers) +# Run this on the control server (CT 127) +# ============================================================================= + +set -e + +COMPOSE_DIR=~/clustered-fucks/compose-files/databases/karakeep +PLAYBOOK_DIR=~/clustered-fucks/playbooks + +echo "========================================" +echo "Phase 3: Karakeep Stack Migration" +echo "Target: databases (192.168.1.81)" +echo "========================================" +echo "" + +# Create directories +mkdir -p "$COMPOSE_DIR" +mkdir -p "$PLAYBOOK_DIR" + +# ============================================================================= +# KARAKEEP DOCKER-COMPOSE +# ============================================================================= + +echo "Creating Karakeep docker-compose.yml..." + +cat > "$COMPOSE_DIR/docker-compose.yml" << 'EOF' +services: + # ========================================================================= + # Karakeep Web - Main application + # ========================================================================= + web: + image: ghcr.io/karakeep-app/karakeep:${KARAKEEP_VERSION:-release} + container_name: karakeep-web + hostname: karakeep-web + restart: unless-stopped + volumes: + - ./data:/data + ports: + - "3054:3000" + environment: + - DATA_DIR=/data + - MEILI_ADDR=http://meilisearch:7700 + - MEILI_MASTER_KEY=${MEILI_MASTER_KEY} + - BROWSER_WEB_URL=http://chrome:9222 + - OLLAMA_BASE_URL=http://ollama:11434 + - INFERENCE_TEXT_MODEL=${INFERENCE_TEXT_MODEL:-llama3.2:3b} + - INFERENCE_IMAGE_MODEL=${INFERENCE_IMAGE_MODEL:-llava} + - INFERENCE_LANG=${INFERENCE_LANG:-english} + - NEXTAUTH_URL=${NEXTAUTH_URL:-http://localhost:3000} + - NEXTAUTH_SECRET=${NEXTAUTH_SECRET} + - NODE_ENV=production + - NEXT_TELEMETRY_DISABLED=1 + depends_on: + meilisearch: + condition: service_started + chrome: + condition: service_started + ollama: + condition: service_started + networks: + - karakeep_internal + - proxy + deploy: + resources: + limits: + memory: 1G + cpus: '2.0' + healthcheck: + test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://127.0.0.1:3000/api/health || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + labels: + - "autoheal=true" + - "com.centurylinklabs.watchtower.enable=true" + - "homepage.group=Personal" + - "homepage.name=Karakeep" + - "homepage.icon=karakeep.png" + - "homepage.href=https://karakeep.3ddbrewery.com" + + # ========================================================================= + # Meilisearch - Full-text search engine + # ========================================================================= + meilisearch: + image: getmeili/meilisearch:v1.13.3 + container_name: karakeep-meilisearch + hostname: meilisearch + restart: unless-stopped + volumes: + - ./meilisearch:/meili_data + ports: + - "7700:7700" + environment: + - MEILI_NO_ANALYTICS=true + - MEILI_MASTER_KEY=${MEILI_MASTER_KEY} + networks: + - karakeep_internal + deploy: + resources: + limits: + memory: 1G + cpus: '1.0' + labels: + - "autoheal=true" + - "com.centurylinklabs.watchtower.enable=true" + + # ========================================================================= + # Chrome - Headless browser for screenshots/crawling + # ========================================================================= + chrome: + image: gcr.io/zenika-hub/alpine-chrome:123 + container_name: karakeep-chrome + hostname: chrome + restart: unless-stopped + command: + - --no-sandbox + - --disable-gpu + - --disable-dev-shm-usage + - --remote-debugging-address=0.0.0.0 + - --remote-debugging-port=9222 + - --hide-scrollbars + networks: + - karakeep_internal + deploy: + resources: + limits: + memory: 512M + cpus: '1.0' + labels: + - "autoheal=true" + - "com.centurylinklabs.watchtower.enable=true" + + # ========================================================================= + # Ollama - Local AI inference (CPU-only on databases VM) + # ========================================================================= + ollama: + image: ollama/ollama:latest + container_name: karakeep-ollama + hostname: ollama + restart: unless-stopped + volumes: + - ./ollama:/root/.ollama + ports: + - "11434:11434" + environment: + - OLLAMA_HOST=0.0.0.0:11434 + networks: + - karakeep_internal + deploy: + resources: + limits: + # Ollama needs more memory for models + memory: 4G + cpus: '4.0' + labels: + - "autoheal=true" + - "com.centurylinklabs.watchtower.enable=true" + +networks: + karakeep_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' +# Karakeep Environment Variables +# Copy to .env and fill in the secrets + +# Version +KARAKEEP_VERSION=release + +# Meilisearch +MEILI_MASTER_KEY=your-meilisearch-master-key-here + +# NextAuth +NEXTAUTH_URL=https://karakeep.3ddbrewery.com +NEXTAUTH_SECRET=your-nextauth-secret-here + +# AI Models +INFERENCE_TEXT_MODEL=llama3.2:3b +INFERENCE_IMAGE_MODEL=llava +INFERENCE_LANG=english +EOF + +echo "✅ Created $COMPOSE_DIR/.env.example" + +# ============================================================================= +# ANSIBLE PLAYBOOK +# ============================================================================= + +echo "Creating Ansible playbook..." + +cat > "$PLAYBOOK_DIR/deploy-karakeep.yml" << 'EOF' +--- +# Deploy Karakeep Stack to databases VM +# Containers: web, meilisearch, chrome, ollama +# Target: databases (192.168.1.81) + +- name: Deploy Karakeep Stack + hosts: databases + vars: + appdata_path: /home/docker/appdata + service_name: karakeep + service_dir: "{{ appdata_path }}/{{ service_name }}" + compose_src: "{{ playbook_dir }}/../compose-files/databases/{{ 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 karakeep base directory + ansible.builtin.file: + path: "{{ service_dir }}" + state: directory + mode: '0755' + + - name: Create karakeep data directory + ansible.builtin.file: + path: "{{ service_dir }}/data" + state: directory + mode: '0755' + + - name: Create meilisearch directory + ansible.builtin.file: + path: "{{ service_dir }}/meilisearch" + state: directory + mode: '0755' + + - name: Create ollama directory + ansible.builtin.file: + path: "{{ service_dir }}/ollama" + state: directory + mode: '0755' + + # ========================================================================= + # FILE DEPLOYMENT + # ========================================================================= + - name: Copy docker-compose.yml + ansible.builtin.copy: + src: "{{ compose_src }}/docker-compose.yml" + dest: "{{ service_dir }}/docker-compose.yml" + mode: '0644' + + - name: Copy .env file + ansible.builtin.copy: + src: "{{ compose_src }}/.env" + dest: "{{ service_dir }}/.env" + mode: '0600' + + # ========================================================================= + # CONTAINER DEPLOYMENT + # ========================================================================= + - name: Deploy karakeep stack + community.docker.docker_compose_v2: + project_src: "{{ service_dir }}" + state: present + pull: always + register: karakeep_result + + - name: Show deployment status + ansible.builtin.debug: + msg: "Karakeep stack deployed: {{ karakeep_result.changed }}" + + # ========================================================================= + # VERIFICATION + # ========================================================================= + - name: Wait for karakeep-web to be healthy + ansible.builtin.uri: + url: "http://localhost:3054/api/health" + status_code: 200 + timeout: 10 + register: web_health + retries: 15 + delay: 10 + until: web_health.status == 200 + ignore_errors: true + + - name: Wait for meilisearch to be ready + ansible.builtin.uri: + url: "http://localhost:7700/health" + status_code: 200 + timeout: 5 + register: meili_health + retries: 10 + delay: 5 + until: meili_health.status == 200 + ignore_errors: true + + - name: Wait for ollama to be ready + ansible.builtin.uri: + url: "http://localhost:11434/api/version" + status_code: 200 + timeout: 5 + register: ollama_health + retries: 10 + delay: 5 + until: ollama_health.status == 200 + ignore_errors: true + + - name: Summary + ansible.builtin.debug: + msg: + - "=========================================" + - "Karakeep Stack Deployment Complete" + - "=========================================" + - "✅ Karakeep Web: http://192.168.1.81:3054" + - "✅ Meilisearch: http://192.168.1.81:7700" + - "✅ Ollama: http://192.168.1.81:11434" + - "=========================================" + - "NOTE: Ollama running on CPU only (no GPU)" + - "Models may need to be re-pulled after migration" +EOF + +echo "✅ Created $PLAYBOOK_DIR/deploy-karakeep.yml" + +echo "" +echo "========================================" +echo "FILES CREATED" +echo "========================================" +echo " $COMPOSE_DIR/docker-compose.yml" +echo " $COMPOSE_DIR/.env.example" +echo " $PLAYBOOK_DIR/deploy-karakeep.yml" +echo "" +echo "========================================" +echo "NEXT STEPS" +echo "========================================" +echo "" +echo "1. GET SECRETS from alien .env file:" +echo " ssh alien 'cat /home/maddox/docker/appdata/karakeep/.env'" +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 /home/maddox/docker/appdata/karakeep && docker compose down'" +echo "" +echo "4. CREATE TARGET DIRECTORIES on databases:" +echo " ssh databases 'mkdir -p /home/docker/appdata/karakeep/{data,meilisearch,ollama}'" +echo "" +echo "5. RSYNC DATA (run FROM databases):" +echo " ssh databases" +echo " # Main karakeep data" +echo " rsync -avP maddox@alien:/home/maddox/docker/appdata/karakeep/ /home/docker/appdata/karakeep/" +echo "" +echo " If permission denied, first run on alien:" +echo " ssh alien 'sudo chown -R maddox:maddox /home/maddox/docker/appdata/karakeep/'" +echo "" +echo "6. DEPLOY to databases:" +echo " ansible-playbook playbooks/deploy-karakeep.yml" +echo "" +echo "7. VERIFY services:" +echo " curl http://192.168.1.81:3054/api/health # Karakeep" +echo " curl http://192.168.1.81:7700/health # Meilisearch" +echo " curl http://192.168.1.81:11434/api/version # Ollama" +echo "" +echo "8. UPDATE TRAEFIK config:" +echo " Change karakeep backend IP from alien to databases (192.168.1.81:3054)" +echo "" +echo "9. CLEANUP alien:" +echo " ssh alien 'cd /home/maddox/docker/appdata/karakeep && docker compose rm -f'" +echo "" +echo "10. COMMIT changes:" +echo " cd ~/clustered-fucks" +echo " git add -A" +echo " git commit -m 'Phase 3: Deploy karakeep stack to databases'" +echo " git push" +echo "" +echo "========================================" +echo "IMPORTANT NOTES" +echo "========================================" +echo "- Karakeep has stateful data in:" +echo " - /data (bookmarks, assets)" +echo " - /meilisearch (search index)" +echo " - /ollama (AI models)" +echo "" +echo "- Ollama on databases runs CPU-ONLY (no GPU)" +echo " - AI tagging will be slower than on alien" +echo " - Models (llama3.2:3b, llava) need to be present" +echo "" +echo "- Consider moving ollama to pve-alien later for GPU acceleration" +echo ""