From 05a730ea526f285a9f2c7c69f8a96bd99dd73414 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Thu, 28 Sep 2023 12:44:24 +0000 Subject: [PATCH] Immich VM: Initial provision and decommission Immich from Cloud VM (#11) Reviewed-on: https://git.koval.net/cyclane/kovalhome/pulls/11 --- .github/workflows/infra.yaml | 3 +- infra/cloud/0000_proxmox_playbook.yaml | 10 +- infra/cloud/0001_initialise_playbook.yaml | 22 ---- .../0004_decommission_immich_playbook.yaml | 71 +++++++++++ infra/photos/0000_proxmox_playbook.yaml | 116 ++++++++++++++++++ infra/photos/0001_initialise_playbook.yaml | 64 ++++++++++ infra/photos/0002_docker_playbook.yaml | 47 +++++++ .../0003_immich_playbook.yaml} | 12 +- infra/{cloud => photos}/immich/.env | 9 +- infra/{cloud => photos}/immich/.gitignore | 0 .../immich/docker-compose.yml} | 0 inventory/proxmox.yaml | 3 + 12 files changed, 322 insertions(+), 35 deletions(-) create mode 100644 infra/cloud/0004_decommission_immich_playbook.yaml create mode 100644 infra/photos/0000_proxmox_playbook.yaml create mode 100644 infra/photos/0001_initialise_playbook.yaml create mode 100644 infra/photos/0002_docker_playbook.yaml rename infra/{cloud/0004_immich_playbook.yaml => photos/0003_immich_playbook.yaml} (54%) rename infra/{cloud => photos}/immich/.env (80%) rename infra/{cloud => photos}/immich/.gitignore (100%) rename infra/{cloud/immich/docker-compose.yaml => photos/immich/docker-compose.yml} (100%) diff --git a/.github/workflows/infra.yaml b/.github/workflows/infra.yaml index cb0cc9c..0f51db8 100644 --- a/.github/workflows/infra.yaml +++ b/.github/workflows/infra.yaml @@ -11,7 +11,8 @@ on: - main env: - DEPLOY: ${{ github.ref == 'refs/heads/main' && ((startsWith(github.event.head_commit.message, '[deploy-all]') && 'all') || ('some')) || 'none' }} + # DEPLOY: ${{ github.ref == 'refs/heads/main' && ((startsWith(github.event.head_commit.message, '[deploy-all]') && 'all') || ('some')) || 'none' }} + DEPLOY: all jobs: ansible-playbooks: diff --git a/infra/cloud/0000_proxmox_playbook.yaml b/infra/cloud/0000_proxmox_playbook.yaml index c858234..2ed0f49 100644 --- a/infra/cloud/0000_proxmox_playbook.yaml +++ b/infra/cloud/0000_proxmox_playbook.yaml @@ -93,12 +93,6 @@ backup: true storage: nvme size: 2048 - - name: Create media disk - community.general.proxmox_disk: - disk: scsi2 - backup: false - storage: zfs - size: 4096 - name: Update VM community.general.proxmox_kvm: update: true @@ -107,8 +101,8 @@ - debian-12 - managed onboot: true - cores: 16 - memory: 32768 + cores: 8 + memory: 16384 - name: Retart VM community.general.proxmox_kvm: diff --git a/infra/cloud/0001_initialise_playbook.yaml b/infra/cloud/0001_initialise_playbook.yaml index 50c90be..c7a7e5e 100644 --- a/infra/cloud/0001_initialise_playbook.yaml +++ b/infra/cloud/0001_initialise_playbook.yaml @@ -40,25 +40,3 @@ 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 diff --git a/infra/cloud/0004_decommission_immich_playbook.yaml b/infra/cloud/0004_decommission_immich_playbook.yaml new file mode 100644 index 0000000..abdbd12 --- /dev/null +++ b/infra/cloud/0004_decommission_immich_playbook.yaml @@ -0,0 +1,71 @@ +- name: Decommission Immich + hosts: cloud + gather_facts: false + vars: + app: immich + 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') }}" + vmname: "{{ inventory_hostname | regex_replace('^([^\\.]+)\\..+$', '\\1') }}" + node: pve + 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_disk: + api_user: "{{ api_user }}" + api_host: "{{ api_host }}" + api_token_id: "{{ api_token_id }}" + api_token_secret: "{{ api_token_secret }}" + name: "{{ vmname }}" + 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: Remove docker volumes + ansible.builtin.command: docker compose down --volumes + args: + chdir: "{{ user.home }}/{{ app }}" + ignore_errors: true + - name: Remove config directory + ansible.builtin.file: + path: "{{ user.home }}/{{ app }}" + state: absent + + - name: Destroy media disk + community.general.proxmox_disk: + disk: scsi2 + state: absent + delegate_to: localhost + - name: Remove media mount + 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: absent + become: true + - name: Remove media directory + ansible.builtin.file: + path: /mnt/media + state: absent + become: true + - name: Restart VM + community.general.proxmox_kvm: + state: restarted + timeout: 60 + delegate_to: localhost diff --git a/infra/photos/0000_proxmox_playbook.yaml b/infra/photos/0000_proxmox_playbook.yaml new file mode 100644 index 0000000..6804b05 --- /dev/null +++ b/infra/photos/0000_proxmox_playbook.yaml @@ -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: pve + 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 diff --git a/infra/photos/0001_initialise_playbook.yaml b/infra/photos/0001_initialise_playbook.yaml new file mode 100644 index 0000000..0e59aae --- /dev/null +++ b/infra/photos/0001_initialise_playbook.yaml @@ -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 diff --git a/infra/photos/0002_docker_playbook.yaml b/infra/photos/0002_docker_playbook.yaml new file mode 100644 index 0000000..4e8734b --- /dev/null +++ b/infra/photos/0002_docker_playbook.yaml @@ -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 diff --git a/infra/cloud/0004_immich_playbook.yaml b/infra/photos/0003_immich_playbook.yaml similarity index 54% rename from infra/cloud/0004_immich_playbook.yaml rename to infra/photos/0003_immich_playbook.yaml index 238c53c..ce7f5db 100644 --- a/infra/cloud/0004_immich_playbook.yaml +++ b/infra/photos/0003_immich_playbook.yaml @@ -1,5 +1,5 @@ - name: Deploy app - hosts: cloud + hosts: photos gather_facts: false vars: app: immich @@ -21,6 +21,16 @@ 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: diff --git a/infra/cloud/immich/.env b/infra/photos/immich/.env similarity index 80% rename from infra/cloud/immich/.env rename to infra/photos/immich/.env index d943043..e7c8557 100644 --- a/infra/cloud/immich/.env +++ b/infra/photos/immich/.env @@ -7,13 +7,16 @@ UPLOAD_LOCATION=/mnt/media/immich IMMICH_VERSION=release # Connection secrets for postgres and typesense. You should change these to random passwords -TYPESENSE_API_KEY=some-random-text -DB_PASSWORD=postgres +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=immich +DB_USERNAME=postgres DB_DATABASE_NAME=immich REDIS_HOSTNAME=immich_redis diff --git a/infra/cloud/immich/.gitignore b/infra/photos/immich/.gitignore similarity index 100% rename from infra/cloud/immich/.gitignore rename to infra/photos/immich/.gitignore diff --git a/infra/cloud/immich/docker-compose.yaml b/infra/photos/immich/docker-compose.yml similarity index 100% rename from infra/cloud/immich/docker-compose.yaml rename to infra/photos/immich/docker-compose.yml diff --git a/inventory/proxmox.yaml b/inventory/proxmox.yaml index 04520dd..8fbb791 100644 --- a/inventory/proxmox.yaml +++ b/inventory/proxmox.yaml @@ -11,6 +11,9 @@ proxmox: cloud: hosts: cloud.srv.home.local.koval.net: + photos: + hosts: + photos.srv.home.local.koval.net: vars: ansible_user: debian ansible_ssh_private_key_file: ~/.ssh/id_rsa