Immich VM: Initial provision and decommission Immich from Cloud VM #11
							
								
								
									
										116
									
								
								infra/photos/0000_proxmox_playbook.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								infra/photos/0000_proxmox_playbook.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | |||||||
|  | - name: Provision photos Proxmox VM | ||||||
|  |   hosts: photos | ||||||
|  |   connection: ansible.builtin.local | ||||||
|  |   gather_facts: false | ||||||
|  |   vars: | ||||||
|  |     api_user: "{{ lookup('ansible.builtin.env', 'PROXMOX_USER') }}" | ||||||
|  |     api_host: "{{ lookup('ansible.builtin.env', 'PROXMOX_HOST' ) }}" | ||||||
|  |     api_token_id: "{{ lookup('ansible.builtin.env', 'PROXMOX_TOKEN_ID') }}" | ||||||
|  |     api_token_secret: "{{ lookup('ansible.builtin.env', 'PROXMOX_TOKEN_SECRET') }}" | ||||||
|  |     ssh_public: "{{ lookup('ansible.builtin.env', 'SSH_PUBLIC') }}" | ||||||
|  |     vmname: "{{ inventory_hostname | regex_replace('^([^\\.]+)\\..+$', '\\1') }}" | ||||||
|  |     node: pve2 | ||||||
|  |   module_defaults: | ||||||
|  |     community.general.proxmox_kvm: | ||||||
|  |       api_user: "{{ api_user }}" | ||||||
|  |       api_host: "{{ api_host }}" | ||||||
|  |       api_token_id: "{{ api_token_id }}" | ||||||
|  |       api_token_secret: "{{ api_token_secret }}" | ||||||
|  |       name: "{{ vmname }}" | ||||||
|  |       node: "{{ node }}" | ||||||
|  |     community.general.proxmox_nic: | ||||||
|  |       api_user: "{{ api_user }}" | ||||||
|  |       api_host: "{{ api_host }}" | ||||||
|  |       api_token_id: "{{ api_token_id }}" | ||||||
|  |       api_token_secret: "{{ api_token_secret }}" | ||||||
|  |       name: "{{ vmname }}" | ||||||
|  |     community.general.proxmox_disk: | ||||||
|  |       api_user: "{{ api_user }}" | ||||||
|  |       api_host: "{{ api_host }}" | ||||||
|  |       api_token_id: "{{ api_token_id }}" | ||||||
|  |       api_token_secret: "{{ api_token_secret }}" | ||||||
|  |       name: "{{ vmname }}" | ||||||
|  |   tasks: | ||||||
|  |     # Initial setup | ||||||
|  |     - name: Create VM | ||||||
|  |       community.general.proxmox_kvm: | ||||||
|  |         clone: "{{ node }}-debian-12" | ||||||
|  |         storage: nvme | ||||||
|  |       register: create | ||||||
|  |     - name: Wait for status | ||||||
|  |       community.general.proxmox_kvm: | ||||||
|  |         state: current | ||||||
|  |       register: vm | ||||||
|  |       retries: 30 | ||||||
|  |       delay: 10 | ||||||
|  |       until: vm.status is defined | ||||||
|  |  | ||||||
|  |     # Networking and initial config | ||||||
|  |     - name: Add PUB NIC | ||||||
|  |       community.general.proxmox_nic: | ||||||
|  |         interface: net0 | ||||||
|  |         firewall: false | ||||||
|  |         bridge: PUB | ||||||
|  |     - name: Add SRV NIC | ||||||
|  |       community.general.proxmox_nic: | ||||||
|  |         interface: net1 | ||||||
|  |         firewall: false | ||||||
|  |         bridge: SRV | ||||||
|  |     - name: Configure cloud-init | ||||||
|  |       community.general.proxmox_kvm: | ||||||
|  |         update: true | ||||||
|  |         ciuser: debian | ||||||
|  |         sshkeys: "{{ ssh_public }}" | ||||||
|  |         ipconfig: | ||||||
|  |           ipconfig0: ip=dhcp,ip6=auto | ||||||
|  |           ipconfig1: ip=dhcp | ||||||
|  |  | ||||||
|  |     # Initial boot | ||||||
|  |     # For some reason debian cloud images don't use | ||||||
|  |     # cloud-init for networking on first boot (cloud-init files | ||||||
|  |     # are regenerated AFTER networking starts). But we need the | ||||||
|  |     # hostname to be registered with DHCP later on so ¯\_(ツ)_/¯ | ||||||
|  |     - name: Initial boot | ||||||
|  |       when: create.changed is true | ||||||
|  |       block: | ||||||
|  |         - name: Start | ||||||
|  |           community.general.proxmox_kvm: | ||||||
|  |             state: started | ||||||
|  |           register: start | ||||||
|  |         - name: Wait 1.5 min # Initial apt update, apt upgrade, cloud-init | ||||||
|  |           ansible.builtin.wait_for: | ||||||
|  |             timeout: 90 | ||||||
|  |  | ||||||
|  |     # VM Configuration | ||||||
|  |     - name: Resize root disk | ||||||
|  |       community.general.proxmox_disk: | ||||||
|  |         disk: scsi0 | ||||||
|  |         size: 16G | ||||||
|  |         state: resized | ||||||
|  |     - name: Create data disk | ||||||
|  |       community.general.proxmox_disk: | ||||||
|  |         disk: scsi1 | ||||||
|  |         backup: true | ||||||
|  |         storage: nvme | ||||||
|  |         size: 64 | ||||||
|  |     - name: Create media disk | ||||||
|  |       community.general.proxmox_disk: | ||||||
|  |         disk: scsi2 | ||||||
|  |         backup: true | ||||||
|  |         storage: nvme | ||||||
|  |         size: 2048 | ||||||
|  |     - name: Update VM | ||||||
|  |       community.general.proxmox_kvm: | ||||||
|  |         update: true | ||||||
|  |         agent: enabled=1 | ||||||
|  |         tags: | ||||||
|  |           - debian-12 | ||||||
|  |           - managed | ||||||
|  |         onboot: true | ||||||
|  |         cores: 8 | ||||||
|  |         memory: 16384 | ||||||
|  |  | ||||||
|  |     - name: Retart VM | ||||||
|  |       community.general.proxmox_kvm: | ||||||
|  |         state: restarted | ||||||
|  |         timeout: 60 | ||||||
							
								
								
									
										64
									
								
								infra/photos/0001_initialise_playbook.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								infra/photos/0001_initialise_playbook.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | |||||||
|  | - name: Initialise VM | ||||||
|  |   hosts: photos | ||||||
|  |   gather_facts: false | ||||||
|  |   tasks: | ||||||
|  |     - name: Wait for connection | ||||||
|  |       ansible.builtin.wait_for_connection: | ||||||
|  |         timeout: 300 | ||||||
|  |     - name: Install system packages | ||||||
|  |       ansible.builtin.apt: | ||||||
|  |         update_cache: true | ||||||
|  |         pkg: | ||||||
|  |           - qemu-guest-agent | ||||||
|  |           - parted | ||||||
|  |       become: true | ||||||
|  |     - name: Enable qemu-guest-agent | ||||||
|  |       ansible.builtin.systemd: | ||||||
|  |         name: qemu-guest-agent | ||||||
|  |         state: started | ||||||
|  |         enabled: true | ||||||
|  |       become: true | ||||||
|  |  | ||||||
|  |     - name: Create data partition | ||||||
|  |       community.general.parted: | ||||||
|  |         device: /dev/disk/by-path/pci-0000:00:05.0-scsi-0:0:0:1 | ||||||
|  |         label: gpt | ||||||
|  |         name: data | ||||||
|  |         number: 1 | ||||||
|  |         state: present | ||||||
|  |       become: true | ||||||
|  |     - name: Create data filesystem | ||||||
|  |       community.general.filesystem: | ||||||
|  |         dev: /dev/disk/by-path/pci-0000:00:05.0-scsi-0:0:0:1-part1 | ||||||
|  |         fstype: ext4 | ||||||
|  |       become: true | ||||||
|  |     - name: Mount data partition | ||||||
|  |       ansible.posix.mount: | ||||||
|  |         src: /dev/disk/by-path/pci-0000:00:05.0-scsi-0:0:0:1-part1 | ||||||
|  |         path: /var/lib/docker | ||||||
|  |         fstype: ext4 | ||||||
|  |         opts: rw,errors=remount-ro,x-systemd.growfs | ||||||
|  |         state: mounted | ||||||
|  |       become: true | ||||||
|  |  | ||||||
|  |     - name: Create media partition | ||||||
|  |       community.general.parted: | ||||||
|  |         device: /dev/disk/by-path/pci-0000:00:05.0-scsi-0:0:0:2 | ||||||
|  |         label: gpt | ||||||
|  |         name: media | ||||||
|  |         number: 1 | ||||||
|  |         state: present | ||||||
|  |       become: true | ||||||
|  |     - name: Create media filesystem | ||||||
|  |       community.general.filesystem: | ||||||
|  |         dev: /dev/disk/by-path/pci-0000:00:05.0-scsi-0:0:0:2-part1 | ||||||
|  |         fstype: ext4 | ||||||
|  |       become: true | ||||||
|  |     - name: Mount media partition | ||||||
|  |       ansible.posix.mount: | ||||||
|  |         src: /dev/disk/by-path/pci-0000:00:05.0-scsi-0:0:0:2-part1 | ||||||
|  |         path: /mnt/media | ||||||
|  |         fstype: ext4 | ||||||
|  |         opts: rw,errors=remount-ro,x-systemd.growfs | ||||||
|  |         state: mounted | ||||||
|  |       become: true | ||||||
							
								
								
									
										47
									
								
								infra/photos/0002_docker_playbook.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								infra/photos/0002_docker_playbook.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | - name: Install software | ||||||
|  |   hosts: photos | ||||||
|  |   gather_facts: false | ||||||
|  |   tasks: | ||||||
|  |     - name: Wait for connection | ||||||
|  |       ansible.builtin.wait_for_connection: | ||||||
|  |         timeout: 300 | ||||||
|  |     - name: Install dependencies | ||||||
|  |       ansible.builtin.apt: | ||||||
|  |         update_cache: true | ||||||
|  |         pkg: | ||||||
|  |           - curl | ||||||
|  |           - python3-apt | ||||||
|  |           - gpg | ||||||
|  |       become: true | ||||||
|  |     - name: Add docker key | ||||||
|  |       ansible.builtin.apt_key: | ||||||
|  |         url: https://download.docker.com/linux/debian/gpg | ||||||
|  |         keyring: /etc/apt/keyrings/docker.gpg | ||||||
|  |       become: true | ||||||
|  |     - name: Add docker repo | ||||||
|  |       ansible.builtin.apt_repository: | ||||||
|  |         repo: deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian bookworm stable | ||||||
|  |       become: true | ||||||
|  |     - name: Install docker | ||||||
|  |       ansible.builtin.apt: | ||||||
|  |         update_cache: true | ||||||
|  |         pkg: | ||||||
|  |           - docker-ce | ||||||
|  |           - docker-ce-cli | ||||||
|  |           - containerd.io | ||||||
|  |           - docker-buildx-plugin | ||||||
|  |           - docker-compose-plugin | ||||||
|  |       become: true | ||||||
|  |     - name: Add user to docker group | ||||||
|  |       ansible.builtin.user: | ||||||
|  |         user: debian | ||||||
|  |         groups: | ||||||
|  |           - docker | ||||||
|  |         append: true | ||||||
|  |       become: true | ||||||
|  |     - name: Enable docker | ||||||
|  |       ansible.builtin.systemd: | ||||||
|  |         name: docker | ||||||
|  |         state: started | ||||||
|  |         enabled: true | ||||||
|  |       become: true | ||||||
							
								
								
									
										37
									
								
								infra/photos/0003_immich_playbook.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								infra/photos/0003_immich_playbook.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | - name: Deploy app | ||||||
|  |   hosts: photos  | ||||||
|  |   gather_facts: false | ||||||
|  |   vars: | ||||||
|  |     app: immich | ||||||
|  |   tasks: | ||||||
|  |     - name: Wait for connection | ||||||
|  |       ansible.builtin.wait_for_connection: | ||||||
|  |         timeout: 300 | ||||||
|  |     - name: Get user | ||||||
|  |       ansible.builtin.user: | ||||||
|  |         name: debian | ||||||
|  |       register: user | ||||||
|  |     - name: Docker compose down | ||||||
|  |       ansible.builtin.command: docker compose down | ||||||
|  |       args: | ||||||
|  |         chdir: "{{ user.home }}/{{ app }}" | ||||||
|  |       ignore_errors: true | ||||||
|  |     - name: Copy project | ||||||
|  |       ansible.builtin.copy: | ||||||
|  |         src: "./{{ app }}" | ||||||
|  |         dest: "{{ user.home }}" | ||||||
|  |         mode: "0744" | ||||||
|  |     - name: Replace Typesense secret | ||||||
|  |       ansible.builtin.replace: | ||||||
|  |         path: "{{ user.home }}/{{ app }}/.env" | ||||||
|  |         regexp: "TYPESENSE_API_KEY_VALUE" | ||||||
|  |         replace: "{{ lookup('ansible.builtin.password', user.home + '/typesense_secret', length=64, chars=['ascii_letters', 'digits']) }}" | ||||||
|  |     - name: Replace DB secret | ||||||
|  |       ansible.builtin.replace: | ||||||
|  |         path: "{{ user.home }}/{{ app }}/.env" | ||||||
|  |         regexp: "DB_PASSWORD_VALUE" | ||||||
|  |         replace: "{{ lookup('ansible.builtin.password', user.home + '/db_secret', length=64, chars=['ascii_letters', 'digits']) }}" | ||||||
|  |     - name: Docker compose up -d | ||||||
|  |       ansible.builtin.command: docker compose up -d | ||||||
|  |       args: | ||||||
|  |         chdir: "{{ user.home }}/{{ app }}" | ||||||
							
								
								
									
										22
									
								
								infra/photos/immich/.env
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								infra/photos/immich/.env
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | # You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables | ||||||
|  |  | ||||||
|  | # The location where your uploaded files are stored | ||||||
|  | UPLOAD_LOCATION=/mnt/media/immich | ||||||
|  |  | ||||||
|  | # The Immich version to use. You can pin this to a specific version like "v1.71.0" | ||||||
|  | IMMICH_VERSION=release | ||||||
|  |  | ||||||
|  | # Connection secrets for postgres and typesense. You should change these to random passwords | ||||||
|  | TYPESENSE_API_KEY=TYPESENSE_API_KEY_VALUE | ||||||
|  | DB_PASSWORD=DB_PASSWORD_VALUE | ||||||
|  |  | ||||||
|  | # Other | ||||||
|  | PUBLIC_LOGIN_PAGE_MESSAGE="KovalHome Photos & Videos" | ||||||
|  |  | ||||||
|  | # The values below this line do not need to be changed | ||||||
|  | ################################################################################### | ||||||
|  | DB_HOSTNAME=immich_postgres | ||||||
|  | DB_USERNAME=postgres | ||||||
|  | DB_DATABASE_NAME=immich | ||||||
|  |  | ||||||
|  | REDIS_HOSTNAME=immich_redis | ||||||
							
								
								
									
										1
									
								
								infra/photos/immich/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								infra/photos/immich/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | !.env | ||||||
							
								
								
									
										98
									
								
								infra/photos/immich/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								infra/photos/immich/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | |||||||
|  | version: "3.8" | ||||||
|  |  | ||||||
|  | services: | ||||||
|  |   immich-server: | ||||||
|  |     container_name: immich_server | ||||||
|  |     image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} | ||||||
|  |     command: [ "start.sh", "immich" ] | ||||||
|  |     volumes: | ||||||
|  |       - ${UPLOAD_LOCATION}:/usr/src/app/upload | ||||||
|  |     env_file: | ||||||
|  |       - .env | ||||||
|  |     depends_on: | ||||||
|  |       - redis | ||||||
|  |       - database | ||||||
|  |       - typesense | ||||||
|  |     restart: always | ||||||
|  |  | ||||||
|  |   immich-microservices: | ||||||
|  |     container_name: immich_microservices | ||||||
|  |     image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} | ||||||
|  |     # extends: | ||||||
|  |     #   file: hwaccel.yml | ||||||
|  |     #   service: hwaccel | ||||||
|  |     command: [ "start.sh", "microservices" ] | ||||||
|  |     volumes: | ||||||
|  |       - ${UPLOAD_LOCATION}:/usr/src/app/upload | ||||||
|  |     env_file: | ||||||
|  |       - .env | ||||||
|  |     depends_on: | ||||||
|  |       - redis | ||||||
|  |       - database | ||||||
|  |       - typesense | ||||||
|  |     restart: always | ||||||
|  |  | ||||||
|  |   immich-machine-learning: | ||||||
|  |     container_name: immich_machine_learning | ||||||
|  |     image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release} | ||||||
|  |     volumes: | ||||||
|  |       - model-cache:/cache | ||||||
|  |     env_file: | ||||||
|  |       - .env | ||||||
|  |     restart: always | ||||||
|  |  | ||||||
|  |   immich-web: | ||||||
|  |     container_name: immich_web | ||||||
|  |     image: ghcr.io/immich-app/immich-web:${IMMICH_VERSION:-release} | ||||||
|  |     env_file: | ||||||
|  |       - .env | ||||||
|  |     restart: always | ||||||
|  |  | ||||||
|  |   typesense: | ||||||
|  |     container_name: immich_typesense | ||||||
|  |     image: typesense/typesense:0.24.1@sha256:9bcff2b829f12074426ca044b56160ca9d777a0c488303469143dd9f8259d4dd | ||||||
|  |     environment: | ||||||
|  |       - TYPESENSE_API_KEY=${TYPESENSE_API_KEY} | ||||||
|  |       - TYPESENSE_DATA_DIR=/data | ||||||
|  |       # remove this to get debug messages | ||||||
|  |       - GLOG_minloglevel=1 | ||||||
|  |     volumes: | ||||||
|  |       - tsdata:/data | ||||||
|  |     restart: always | ||||||
|  |  | ||||||
|  |   redis: | ||||||
|  |     container_name: immich_redis | ||||||
|  |     image: redis:6.2-alpine@sha256:70a7a5b641117670beae0d80658430853896b5ef269ccf00d1827427e3263fa3 | ||||||
|  |     restart: always | ||||||
|  |  | ||||||
|  |   database: | ||||||
|  |     container_name: immich_postgres | ||||||
|  |     image: postgres:14-alpine@sha256:28407a9961e76f2d285dc6991e8e48893503cc3836a4755bbc2d40bcc272a441 | ||||||
|  |     env_file: | ||||||
|  |       - .env | ||||||
|  |     environment: | ||||||
|  |       POSTGRES_PASSWORD: ${DB_PASSWORD} | ||||||
|  |       POSTGRES_USER: ${DB_USERNAME} | ||||||
|  |       POSTGRES_DB: ${DB_DATABASE_NAME} | ||||||
|  |     volumes: | ||||||
|  |       - pgdata:/var/lib/postgresql/data | ||||||
|  |     restart: always | ||||||
|  |  | ||||||
|  |   immich-proxy: | ||||||
|  |     container_name: immich_proxy | ||||||
|  |     image: ghcr.io/immich-app/immich-proxy:${IMMICH_VERSION:-release} | ||||||
|  |     environment: | ||||||
|  |       # Make sure these values get passed through from the env file | ||||||
|  |       - IMMICH_SERVER_URL | ||||||
|  |       - IMMICH_WEB_URL | ||||||
|  |     ports: | ||||||
|  |       - 2283:8080 | ||||||
|  |     depends_on: | ||||||
|  |       - immich-server | ||||||
|  |       - immich-web | ||||||
|  |     restart: always | ||||||
|  |  | ||||||
|  | volumes: | ||||||
|  |   pgdata: | ||||||
|  |   model-cache: | ||||||
|  |   tsdata: | ||||||
| @@ -11,6 +11,9 @@ proxmox: | |||||||
|             cloud: |             cloud: | ||||||
|               hosts: |               hosts: | ||||||
|                 cloud.srv.home.local.koval.net: |                 cloud.srv.home.local.koval.net: | ||||||
|  |             photos: | ||||||
|  |               hosts: | ||||||
|  |                 photos.srv.home.local.koval.net: | ||||||
|           vars: |           vars: | ||||||
|             ansible_user: debian |             ansible_user: debian | ||||||
|             ansible_ssh_private_key_file: ~/.ssh/id_rsa |             ansible_ssh_private_key_file: ~/.ssh/id_rsa | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user