157 lines
5.8 KiB
YAML
157 lines
5.8 KiB
YAML
---
|
|
# ============================================================================
|
|
# deploy-homarr.yml — deploy Homarr as the `ansible` user
|
|
# ============================================================================
|
|
# PLAY 1 (precheck, runner): pull HOMARR_SECRET_ENCRYPTION_KEY from Infisical,
|
|
# validate it. Stops with a reason if missing/invalid — no target change.
|
|
# PLAY 2: connect as `ansible`, create ~/docker/homarr/, write compose, start it.
|
|
#
|
|
# Prereq: host already bootstrapped (bootstrap.yml) so `ansible` user + key exist.
|
|
# Infisical auth env vars: same as bootstrap.yml (INFISICAL_CLIENT_ID/SECRET/PROJECT_ID).
|
|
#
|
|
# Usage: playbook playbooks/deploy-homarr.yml, extra vars: target=racknerd1
|
|
# ============================================================================
|
|
|
|
- name: "PRECHECK — fetch Homarr secret from Infisical"
|
|
hosts: localhost
|
|
gather_facts: false
|
|
vars:
|
|
infisical_url: "{{ lookup('env','INFISICAL_URL') | default('http://192.168.122.41:8080', true) }}"
|
|
infisical_env_slug: "{{ lookup('env','INFISICAL_ENV_SLUG') | default('dev', true) }}"
|
|
tasks:
|
|
- name: "[precheck] Infisical auth vars present?"
|
|
ansible.builtin.assert:
|
|
that:
|
|
- lookup('env','INFISICAL_CLIENT_ID') | length > 0
|
|
- lookup('env','INFISICAL_CLIENT_SECRET') | length > 0
|
|
- lookup('env','INFISICAL_PROJECT_ID') | length > 0
|
|
fail_msg: "Missing INFISICAL_CLIENT_ID / _SECRET / _PROJECT_ID in Semaphore Environment."
|
|
|
|
- name: "[precheck] Login to Infisical"
|
|
infisical.vault.login:
|
|
url: "{{ infisical_url }}"
|
|
auth_method: universal_auth
|
|
universal_auth_client_id: "{{ lookup('env','INFISICAL_CLIENT_ID') }}"
|
|
universal_auth_client_secret: "{{ lookup('env','INFISICAL_CLIENT_SECRET') }}"
|
|
register: infisical_login
|
|
|
|
- name: "[precheck] Read secrets"
|
|
infisical.vault.read_secrets:
|
|
login_data: "{{ infisical_login.login_data }}"
|
|
project_id: "{{ lookup('env','INFISICAL_PROJECT_ID') }}"
|
|
env_slug: "{{ infisical_env_slug }}"
|
|
path: "/"
|
|
as_dict: true
|
|
register: infisical_secrets
|
|
|
|
- name: "[precheck] Validate Homarr key (64 hex)"
|
|
ansible.builtin.assert:
|
|
that:
|
|
- infisical_secrets.secrets.HOMARR_SECRET_ENCRYPTION_KEY is defined
|
|
- infisical_secrets.secrets.HOMARR_SECRET_ENCRYPTION_KEY | length == 64
|
|
fail_msg: "HOMARR_SECRET_ENCRYPTION_KEY missing or not 64 hex chars in env '{{ infisical_env_slug }}'."
|
|
|
|
- name: "[precheck] stash secrets for deploy play"
|
|
ansible.builtin.set_fact:
|
|
pc_homarr_key: "{{ infisical_secrets.secrets.HOMARR_SECRET_ENCRYPTION_KEY }}"
|
|
pc_ssh_privkey: "{{ infisical_secrets.secrets.SSH_PRIVATE_KEY }}"
|
|
no_log: true
|
|
|
|
- name: "[precheck] write deploy private key to runner temp (0600)"
|
|
ansible.builtin.copy:
|
|
dest: "/tmp/homarr_deploy_key"
|
|
content: "{{ pc_ssh_privkey }}\n"
|
|
mode: "0600"
|
|
no_log: true
|
|
|
|
- name: "[precheck] OK"
|
|
ansible.builtin.debug:
|
|
msg: "Homarr secret retrieved + valid. Proceeding to deploy."
|
|
|
|
- name: "Deploy Homarr (rootless, as ansible user)"
|
|
hosts: "{{ target | default('racknerd1') }}"
|
|
gather_facts: false
|
|
vars:
|
|
deploy_user: ansible
|
|
homarr_dir: "/home/{{ deploy_user }}/docker/homarr"
|
|
homarr_port: 7575
|
|
homarr_image: ghcr.io/homarr-labs/homarr:latest
|
|
homarr_encryption_key: "{{ hostvars['localhost'].pc_homarr_key }}"
|
|
# Connect AS the ansible user (created by bootstrap) using the deploy key. NOT root.
|
|
ansible_user: ansible
|
|
ansible_ssh_private_key_file: "/tmp/homarr_deploy_key"
|
|
ansible_ssh_common_args: "-o StrictHostKeyChecking=accept-new -o IdentitiesOnly=yes"
|
|
tasks:
|
|
- name: Reset connection so docker group membership is active in this session
|
|
ansible.builtin.meta: reset_connection
|
|
|
|
- name: Gather facts (after connection reset)
|
|
ansible.builtin.setup:
|
|
|
|
- name: Docker available (rootless, via docker group)?
|
|
ansible.builtin.command: docker version
|
|
register: dv
|
|
changed_when: false
|
|
failed_when: dv.rc != 0
|
|
|
|
- name: Create ~/docker/homarr tree
|
|
ansible.builtin.file:
|
|
path: "{{ item }}"
|
|
state: directory
|
|
owner: "{{ deploy_user }}"
|
|
group: "{{ deploy_user }}"
|
|
mode: "0755"
|
|
loop:
|
|
- "/home/{{ deploy_user }}/docker"
|
|
- "{{ homarr_dir }}"
|
|
- "{{ homarr_dir }}/appdata"
|
|
|
|
- name: Write docker-compose.yml
|
|
ansible.builtin.copy:
|
|
dest: "{{ homarr_dir }}/docker-compose.yml"
|
|
owner: "{{ deploy_user }}"
|
|
group: "{{ deploy_user }}"
|
|
mode: "0644"
|
|
content: |
|
|
services:
|
|
homarr:
|
|
container_name: homarr
|
|
image: {{ homarr_image }}
|
|
restart: unless-stopped
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
- {{ homarr_dir }}/appdata:/appdata
|
|
environment:
|
|
- SECRET_ENCRYPTION_KEY={{ homarr_encryption_key }}
|
|
ports:
|
|
- "{{ homarr_port }}:7575"
|
|
no_log: true
|
|
|
|
- name: Pull + start Homarr
|
|
community.docker.docker_compose_v2:
|
|
project_src: "{{ homarr_dir }}"
|
|
pull: always
|
|
state: present
|
|
|
|
- name: Wait for Homarr
|
|
ansible.builtin.uri:
|
|
url: "http://127.0.0.1:{{ homarr_port }}/"
|
|
status_code: [200, 302, 307]
|
|
register: health
|
|
retries: 15
|
|
delay: 5
|
|
until: health.status is defined and health.status in [200, 302, 307]
|
|
|
|
- name: Result
|
|
ansible.builtin.debug:
|
|
msg: "Homarr up on {{ inventory_hostname }}:{{ homarr_port }} (HTTP {{ health.status }})"
|
|
|
|
- name: "Cleanup runner temp key"
|
|
hosts: localhost
|
|
gather_facts: false
|
|
tasks:
|
|
- name: "remove temp deploy key from runner"
|
|
ansible.builtin.file:
|
|
path: /tmp/homarr_deploy_key
|
|
state: absent
|