From 01c1db8ed6556550caa3afd773cdb3ba7f16f8cb Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 26 Jan 2025 01:18:19 +0000 Subject: [PATCH] initial commit --- ansible.cfg | 2 + inventory | 5 + main.yml | 23 ++ tasks/nvidia.yml | 21 ++ tasks/podman.yml | 582 ++++++++++++++++++++++++++++++++++++++++++ tasks/post-podman.yml | 17 ++ tasks/pre-podman.yml | 6 + tasks/setup.yml | 126 +++++++++ vars | 2 + 9 files changed, 784 insertions(+) create mode 100755 ansible.cfg create mode 100755 inventory create mode 100755 main.yml create mode 100755 tasks/nvidia.yml create mode 100755 tasks/podman.yml create mode 100755 tasks/post-podman.yml create mode 100755 tasks/pre-podman.yml create mode 100755 tasks/setup.yml create mode 100755 vars diff --git a/ansible.cfg b/ansible.cfg new file mode 100755 index 0000000..f8fc6cd --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,2 @@ +[defaults] +inventory = inventory diff --git a/inventory b/inventory new file mode 100755 index 0000000..fa88637 --- /dev/null +++ b/inventory @@ -0,0 +1,5 @@ +servers: + hosts: + debian-pods: + ansible_host: 192.168.0.30 + ansible_user: admin diff --git a/main.yml b/main.yml new file mode 100755 index 0000000..f4681b1 --- /dev/null +++ b/main.yml @@ -0,0 +1,23 @@ +--- + +- name: configure host + hosts: all + + vars_files: + - vars + - vault.yml + + tasks: + - import_tasks: tasks/setup.yml + tags: ['setup'] + + - import_tasks: tasks/nvidia.yml + tags: ['nvidia'] + + - import_tasks: tasks/pre-podman.yml + tags: ['podman'] + - import_tasks: tasks/podman.yml + tags: ['podman'] + - import_tasks: tasks/post-podman.yml + tags: ['podman'] + diff --git a/tasks/nvidia.yml b/tasks/nvidia.yml new file mode 100755 index 0000000..8c2e8a2 --- /dev/null +++ b/tasks/nvidia.yml @@ -0,0 +1,21 @@ +- name: install nvidia-container-toolkit repo + become: true + ansible.builtin.shell: + cmd: "curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --yes --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | tee /etc/apt/sources.list.d/nvidia-container-toolkit.list" + +- name: install Nvidia driver + become: true + ansible.builtin.apt: + pkg: + - nvidia-container-toolkit + - nvidia-driver + - firmware-misc-nonfree + state: present + +- name: configure nvidia for rootless podman + become: true + ansible.builtin.shell: + cmd: nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml + register: nvidia_ctk_result + ignore_errors: true + failed_when: nvidia_ctk+result.rc != 1 diff --git a/tasks/podman.yml b/tasks/podman.yml new file mode 100755 index 0000000..c5fe875 --- /dev/null +++ b/tasks/podman.yml @@ -0,0 +1,582 @@ +--- + +- name: mealie + containers.podman.podman_container: + state: quadlet + name: podman_mealie + image: ghcr.io/mealie-recipes/mealie:latest + network: bridge + volumes: + - /home/admin/podman/mealie:/app/data/ + ports: + - 9091:9000 + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: ollama + containers.podman.podman_container: + state: quadlet + name: podman_ollama + image: docker.io/ollama/ollama:latest + network: bridge + volumes: + - "/home/admin/podman/ollama:/root/.ollama" + ports: + - "11434:11434" + env: + OLLAMA_KEEP_ALIVE: "-1" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: open-webui + containers.podman.podman_container: + state: quadlet + name: podman_open-webui + image: ghcr.io/open-webui/open-webui:latest + network: bridge + volumes: + - "/home/admin/podman/open-webui:/app/backend/data" + ports: + - "3000:8080" + env: + ENABLE_RAG_WEB_SEARCH: "True" + RAG_WEB_SEARCH_ENGINE: "searxng" + RAG_WEB_SEARCH_RESULT_COUNT: 3 + RAG_WEB_SEARCH_CONCURRENT_REQUESTS: 10 + SEARXNG_QUERY_URL: "http://192.168.0.30:8880/search?q=" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: searxng + containers.podman.podman_container: + state: quadlet + name: podman_searxng + image: docker.io/searxng/searxng:latest + network: bridge + ports: + - "8880:8080" + volumes: + - "/home/admin/podman/searxng:/etc/searxng" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: jellyfin + containers.podman.podman_container: + state: quadlet + name: podman_jellyfin + image: docker.io/jellyfin/jellyfin + network: bridge + volumes: + - "/home/admin/podman/jellyfin:/config" + - "/mnt/media/video/movies:/movies:ro" + - "/mnt/media/video/tv:/tv:ro" + - "/mnt/media/audio/music/flac:/music:ro" + - "/mnt/media/video/Family:/family:ro" + ports: + - "8096:8096" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: freshrss + containers.podman.podman_container: + state: quadlet + name: podman_freshrss + image: lscr.io/linuxserver/freshrss:latest + network: bridge + volumes: + - "/home/admin/podman/freshrss:/config" + ports: + - "8555:80" + env: + TZ: "Europe/London" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target +- name: eclipse-mosquitto + containers.podman.podman_container: + state: quadlet + name: podman_eclipse-mosquitto + image: docker.io/eclipse-mosquitto + network: bridge + volumes: + - "/home/admin/podman/eclipse-mosquitto:/mosquitto" + ports: + - "1883:1883" + - "9001:9001" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: frigate + containers.podman.podman_container: + state: quadlet + name: podman_frigate + image: "ghcr.io/blakeblackshear/frigate:{{ frigate_version }}" + network: bridge + volumes: + - /etc/localtime:/etc/localtime:ro + - /home/admin/podman/frigate:/config + - /mnt/share/services/cctv:/media/frigate + ports: + - "5005:5000" + - "5001:8971" + - "1935:1935" + - "8554:8554" + env: + FRIGATE_RTSP_PASSWORD: "{{ rtsp_password }}" + quadlet_options: + - "Tmpfs=/tmp/cache" + - "ShmSize=128mb" + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: nginx-proxy-manager + containers.podman.podman_container: + state: quadlet + name: podman_nginx-proxy-manager + image: docker.io/jc21/nginx-proxy-manager:2.10.4 + network: bridge + privileged: true + volumes: + - "/home/admin/podman/nginx-proxy-manager:/data" + - "/home/admin/podman/letsencrypt:/etc/letsencrypt" + ports: + - "5080:80" + - "5443:443" + - "5081:81" + env: + TZ: "Europe/London" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: ddclient + containers.podman.podman_container: + state: quadlet + name: podman_ddclient + image: lscr.io/linuxserver/ddclient:latest + network: bridge + env: + TZ: "Europe/London" + volumes: + - "/home/admin/podman/ddclient:/config" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: gitea + containers.podman.podman_container: + state: quadlet + name: podman_gitea + image: docker.io/gitea/gitea:latest + network: bridge + env: + TZ: "Europe/London" + DISABLE_REGISTRATION: "true" + volumes: + - "/home/admin/podman/gitea:/data" + - "/etc/timezone:/etc/timezone:ro" + - "/etc/localtime:/etc/localtime:ro" + ports: + - "3001:3000" + - "222:22" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: nginx_mektem_com + containers.podman.podman_container: + state: quadlet + name: podman_nginx_mektem_com + image: docker.io/nginx:latest + network: bridge + volumes: + - "/home/admin/podman/nginx/nginx.conf:/etc/nginx/nginx.conf:ro" + - "/home/admin/podman/nginx/html:/usr/share/nginx/html" + ports: + "888:80" + env: + NGINX_HOST: "mektem.com" + NGINX_PORT: "80" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: joplin + containers.podman.podman_container: + state: quadlet + name: podman_joplin + image: docker.io/joplin/server:latest + network: bridge + ports: + "22300:22300" + env: + APP_PORT: "22300" + APP_BASE_URL: "https://notes.mektem.com" + DB_CLIENT: "pg" + POSTGRES_PASSWORD: "{{ joplin_password }}" + POSTGRES_DATABASE: "joplin-db" + POSTGRES_USER: "joplin" + POSTGRES_PORT: "5432" + POSTGRES_HOST: "{{ ansible_ssh_host }}" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: joplin-db + containers.podman.podman_container: + state: quadlet + name: podman_joplin-db + image: docker.io/postgres:15 + network: bridge + volumes: + - "/home/admin/podman/joplin-db:/var/lib/postgresql/data" + ports: + "5432:5432" + env: + TZ: "Europe/London" + POSTGRES_PASSWORD: "{{ joplin_password }}" + POSTGRES_USER: "joplin" + POSTGRES_DB: "joplin-db" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: wireguard + containers.podman.podman_container: + state: quadlet + name: podman_wireguard + image: lscr.io/linuxserver/wireguard:latest + network: bridge + privileged: true + cap_add: + - NET_RAW + - NET_ADMIN + - SYS_MODULE + volumes: + - "/home/admin/podman/wireguard:/config" + - "/lib/modules:/lib/modules" #optional + ports: + - "51820:51820/udp" + env: + TZ: "Europe/London" + SERVERURL: "81.99.39.74" + SERVERPORT: "51820" + PEERS: "FarisIOS,FarisMacbook,SafaPhone" + ALLOWEDIPS: "0.0.0.0/0" + LOG_CONFS: "true" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: vaultwarden + containers.podman.podman_container: + state: quadlet + name: podman_vaultwarden + image: docker.io/vaultwarden/server:latest + network: bridge + volumes: + - "/home/admin/podman/vaultwarden/:/data/" + ports: + - "8000:80" + - "3012:3012" + env: + TZ: "Europe/London" + DOMAIN: "https://vault.mektem.com" + SIGNUPS_ALLOWED: "false" + EXPERIMENTAL_CLIENT_FEATURE_FLAGS: "ssh-key-vault-item,ssh-agent" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: homeassistant + containers.podman.podman_container: + state: quadlet + name: podman_homeassistant + image: ghcr.io/home-assistant/home-assistant:stable + network: bridge + volumes: + - "/home/admin/podman/homeassistant:/config" + - "/etc/localtime:/etc/localtime:ro" + ports: + - "8123:8123" + env: + TZ: "Europe/London" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + + +- name: rutorrent + containers.podman.podman_container: + state: quadlet + name: podman_rutorrent + image: docker.io/crazymax/rtorrent-rutorrent:latest + network: bridge + volumes: + - "/home/admin/podman/rutorrent/passwd:/passwd" + - "/home/admin/podman/rutorrent/data:/data" + - "/mnt/media/torrents:/downloads" + ports: + - "8888:8080" + - "5000:8000" + - "50000:50000" + env: + TZ: "Europe/London" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: prowlarr + containers.podman.podman_container: + state: quadlet + name: podman_prowlarr + image: lscr.io/linuxserver/prowlarr:latest + network: bridge + volumes: + - "/home/admin/podman/prowlarr:/config" + ports: + - "9696:9696" + env: + TZ: "Europe/London" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: sonarr + containers.podman.podman_container: + state: quadlet + name: podman_sonarr + image: lscr.io/linuxserver/sonarr:latest + network: bridge + volumes: + - "/home/admin/podman/sonarr:/config" + - "/mnt/media/video/tv:/tv" + - "/mnt/media/torrents:/downloads" + ports: + - "8989:8989" + env: + TZ: "Europe/London" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: radarr + containers.podman.podman_container: + state: quadlet + name: podman_radarr + image: lscr.io/linuxserver/radarr:latest + network: bridge + volumes: + - "/home/admin/podman/radarr:/config" + - "/mnt/media/video/movies:/movies" + - "/mnt/media/torrents:/downloads" + ports: + - "7878:7878" + env: + TZ: "Europe/London" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: lidarr + containers.podman.podman_container: + state: quadlet + name: podman_lidarr + image: lscr.io/linuxserver/lidarr:latest + network: bridge + volumes: + - "/home/admin/podman/lidarr:/config" + - "/mnt/media/audio/music/flac:/music" + - "/mnt/media/torrents:/downloads" + ports: + - "8686:8686" + env: + TZ: "Europe/London" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + + +- name: kiwix + containers.podman.podman_container: + state: quadlet + name: podman_kiwix + image: ghcr.io/kiwix/kiwix-serve:latest + network: bridge + command: "*.zim" + volumes: + - "/mnt/share/shared/Faris/1 documents/zim:/data" + ports: + - "8088:8080" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + + +- name: immich-server + containers.podman.podman_container: + state: quadlet + name: podman_immich-server + image: "ghcr.io/immich-app/immich-server:{{ immich_version }}" + network: bridge + volumes: + - "/mnt/share/services/immich:/usr/src/app/upload" + - "/etc/localtime:/etc/localtime:ro" + ports: + - "2283:2283" + env_file: + - "/home/admin/podman/.env" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: immich-machine-learning + containers.podman.podman_container: + state: quadlet + name: podman_immich-machine-learning + image: "ghcr.io/immich-app/immich-machine-learning:{{ immich_version }}" + network: bridge + volumes: + - "/home/admin/podman/immich/cache:/cache" + env_file: + - "/home/admin/podman/.env" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: immich-redis + containers.podman.podman_container: + state: quadlet + name: podman_immich-redis + image: registry.hub.docker.com/library/redis:6.2-alpine + network: bridge + ports: + - "6379:6379" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + +- name: immich-db + containers.podman.podman_container: + state: quadlet + name: podman_immich-db + image: registry.hub.docker.com/tensorchord/pgvecto-rs:pg14-v0.2.0 + network: bridge + env: + POSTGRES_PASSWORD: "{{ immich_db_password }}" + POSTGRES_USER: postgres + POSTGRES_DB: immich + volumes: + - "/home/admin/podman/immich/db:/var/lib/postgresql/data" + ports: + - "5433:5432" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target + + +- name: metube + containers.podman.podman_container: + state: quadlet + name: podman_metube + image: ghcr.io/alexta69/metube:latest + volumes: + - "/mnt/media/youtube-dl:/downloads" + - "/mnt/media/audio/music/flac:/music" + ports: + - "8081:8081" + env: + AUDIO_DOWNLOAD_DIR: "/music" + quadlet_options: + - "AutoUpdate=registry" + - "Pull=newer" + - | + [Install] + WantedBy=default.target diff --git a/tasks/post-podman.yml b/tasks/post-podman.yml new file mode 100755 index 0000000..489d7bf --- /dev/null +++ b/tasks/post-podman.yml @@ -0,0 +1,17 @@ +- name: reload systemd daemon + ansible.builtin.systemd_service: + scope: user + daemon_reload: true +- name: get list of all container services + ansible.builtin.shell: + cmd: "systemctl --user list-units --type=service --state=inactive --no-pager --quiet | grep 'podman_' | awk '{print $1}'" + register: inactive_containers + changed_when: false +- name: reload containers + ansible.builtin.systemd_service: + scope: user + state: started + name: "{{ item }}" + with_items: "{{ inactive_containers.stdout_lines }}" + when: inactive_containers.stdout_lines is defined + diff --git a/tasks/pre-podman.yml b/tasks/pre-podman.yml new file mode 100755 index 0000000..bb36dc4 --- /dev/null +++ b/tasks/pre-podman.yml @@ -0,0 +1,6 @@ +--- + +- name: cleanup unused containers + ansible.builtin.file: + state: absent + path: /home/admin/.config/containers/systemd/ diff --git a/tasks/setup.yml b/tasks/setup.yml new file mode 100755 index 0000000..7ccecd0 --- /dev/null +++ b/tasks/setup.yml @@ -0,0 +1,126 @@ +--- + +- name: set localtime (only needed for gitea and frigate) + become: true + ansible.builtin.file: + path: /usr/share/zoneinfo/Europe/London + dest: /etc/localtime + state: link + +- name: set timezone (only neede for gitea) + become: true + ansible.builtin.shell: + cmd: echo "Europe/London" | tee /etc/timezone && dpkg-reconfigure -f noninteractive tzdata + changed_when: false + + +- name: Update apt and install required programs + become: true + ansible.builtin.apt: + pkg: + - gpg + - ansible + - cron + - curl + - git + - tmux + - podman + - neovim + - nfs-common + - fzf + - rsync + state: present + update_cache: true + +- name: create mount directories + become: true + block: + - name: create /mnt/share + ansible.builtin.file: + path: /mnt/share + state: directory + - name: create /mnt/media + ansible.builtin.file: + path: /mnt/media + state: directory + +- name: mount shares + become: true + block: + - name: mount data + ansible.posix.mount: + path: /mnt/share + src: "{{ truenas_ip }}:/mnt/pool/data" + fstype: nfs4 + opts: defaults,auto,rw + state: mounted + - name: mount media + ansible.posix.mount: + path: /mnt/media + src: "{{ truenas_ip }}:/mnt/pool/media" + fstype: nfs4 + opts: defaults,auto,rw + state: mounted + +- name: setup backup + become: true + ansible.builtin.cron: + minute: "0" + hour: "4" + name: "backup" + user: "root" + job: "/bin/bash '/mnt/share/services/scripts/backup.sh'" + cron_file: backup + +- name: check for podman folder + ansible.builtin.file: + path: /home/admin/podman + state: directory +# - name: initialize podman-compose +# become: true +# ignore_errors: true +# ansible.posix.synchronize: +# src: /mnt/share/DUNNO +# dest: /home/admin +# checksum: true + +- name: change podman to overlayfs (system might need to be reset after this) + block: + - name: create directory if doesn't exist + ansible.builtin.file: + state: directory + path: /home/admin/.config/containers/ + - name: create file if doesn't exist + ansible.builtin.file: + state: touch + path: /home/admin/.config/containers/storage.conf + - name: storage + ansible.builtin.lineinfile: + path: /home/admin/.config/containers/storage.conf + search_string: [storage] + line: [storage] + - name: overlay + ansible.builtin.lineinfile: + path: /home/admin/.config/containers/storage.conf + search_string: driver + line: driver = 'overlay' + +- name: allow rootless podman to access ports below 1000 + become: true + ansible.posix.sysctl: + name: net.ipv4.ip_unprivileged_port_start + value: 80 + sysctl_file: /etc/sysctl.d/99-ports.conf + +# this might not be needed, haven't tested +- name: allow rootless podmad (wireguard) to access net src + become: true + ansible.posix.sysctl: + name: net.ipv4.conf.all.src_valid_mark + value: 1 + sysctl_file: /etc/sysctl.d/99-ports.conf + + +- name: enable linger (so user services start without login required) + ansible.builtin.shell: + cmd: loginctl enable-linger diff --git a/vars b/vars new file mode 100755 index 0000000..1ee3939 --- /dev/null +++ b/vars @@ -0,0 +1,2 @@ +immich_version: v1.124.2 +frigate_version: 0.14.1