feat: add Gitvana deployment role with configuration and service management
This commit is contained in:
parent
129b7eee1b
commit
9286cdb331
11
ansible/group_vars/all/gitvana_bun.yml
Normal file
11
ansible/group_vars/all/gitvana_bun.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
# Gitvana deployment defaults. Override these in host_vars or via -e as needed.
|
||||||
|
gitvana_repo_url: https://git.castaldifamily.com/nathan/gitvana
|
||||||
|
gitvana_repo_version: main
|
||||||
|
|
||||||
|
# Runtime mode can be dev or preview. Preview is recommended for long-running service.
|
||||||
|
gitvana_run_mode: preview
|
||||||
|
gitvana_service_port: 3000
|
||||||
|
|
||||||
|
# Optional: If repository access requires a dedicated SSH key on target hosts, set this path.
|
||||||
|
# gitvana_git_key_file: /home/chester/.ssh/id_ed25519
|
||||||
87
ansible/playbooks/RUN-GITVANA-BUN.md
Normal file
87
ansible/playbooks/RUN-GITVANA-BUN.md
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
# Run Gitvana Bun Deployment
|
||||||
|
|
||||||
|
This runbook deploys Gitvana directly to Linux VM/LXC hosts using the Ansible role `gitvana_bun_host`.
|
||||||
|
|
||||||
|
## Files added
|
||||||
|
|
||||||
|
- `roles/gitvana_bun_host/*`
|
||||||
|
- `playbooks/deploy-gitvana-bun.yml`
|
||||||
|
- `group_vars/all/gitvana_bun.yml`
|
||||||
|
|
||||||
|
## 1) Prepare control node
|
||||||
|
|
||||||
|
From the repository root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ansible
|
||||||
|
ansible --version
|
||||||
|
ansible-galaxy collection install -r requirements.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2) Confirm target host access
|
||||||
|
|
||||||
|
Use your existing inventory and test connectivity:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible -i inventory/hosts.ini docker_nodes -m ping
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want a single host, replace `docker_nodes` with a host like `heimdall`.
|
||||||
|
|
||||||
|
## 3) Review or override deployment variables
|
||||||
|
|
||||||
|
Default values are in `group_vars/all/gitvana_bun.yml` and role defaults.
|
||||||
|
|
||||||
|
Common overrides:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
-e gitvana_target_hosts=heimdall
|
||||||
|
-e gitvana_repo_version=main
|
||||||
|
-e gitvana_service_port=3000
|
||||||
|
-e gitvana_run_mode=preview
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4) Run deployment
|
||||||
|
|
||||||
|
Deploy to all `docker_nodes`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-playbook -i inventory/hosts.ini playbooks/deploy-gitvana-bun.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Deploy to one host:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-playbook -i inventory/hosts.ini playbooks/deploy-gitvana-bun.yml -e gitvana_target_hosts=heimdall
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5) Verify service
|
||||||
|
|
||||||
|
Check status on target host:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl status gitvana --no-pager
|
||||||
|
sudo journalctl -u gitvana -n 100 --no-pager
|
||||||
|
curl -I http://127.0.0.1:3000/
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6) Day-2 operations
|
||||||
|
|
||||||
|
Redeploy after code updates:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-playbook -i inventory/hosts.ini playbooks/deploy-gitvana-bun.yml -e gitvana_target_hosts=heimdall
|
||||||
|
```
|
||||||
|
|
||||||
|
Restart service only:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible -i inventory/hosts.ini heimdall -b -m ansible.builtin.systemd -a "name=gitvana state=restarted"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting quick checks
|
||||||
|
|
||||||
|
- Ensure Bun is present: `which bun && bun --version`
|
||||||
|
- Ensure app directory is owned by runtime user: `ls -la /opt/gitvana`
|
||||||
|
- Ensure service unit exists: `cat /etc/systemd/system/gitvana.service`
|
||||||
|
- Ensure selected host can access the git repository URL over network
|
||||||
15
ansible/playbooks/deploy-gitvana-bun.yml
Normal file
15
ansible/playbooks/deploy-gitvana-bun.yml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy Gitvana on Linux VM/LXC hosts with Bun
|
||||||
|
hosts: "{{ gitvana_target_hosts | default('docker_nodes') }}"
|
||||||
|
gather_facts: true
|
||||||
|
become: true
|
||||||
|
|
||||||
|
pre_tasks:
|
||||||
|
- name: Validate target host pattern
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- (gitvana_target_hosts | default('docker_nodes')) | length > 0
|
||||||
|
fail_msg: "gitvana_target_hosts must not be empty."
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- role: gitvana_bun_host
|
||||||
40
ansible/roles/gitvana_bun_host/README.md
Normal file
40
ansible/roles/gitvana_bun_host/README.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# gitvana_bun_host
|
||||||
|
|
||||||
|
Ansible role to deploy Gitvana directly on a Linux VM/LXC host using Bun and systemd.
|
||||||
|
|
||||||
|
## What this role does
|
||||||
|
|
||||||
|
- Installs required OS packages
|
||||||
|
- Installs Bun from official GitHub releases
|
||||||
|
- Clones/updates the Gitvana repository
|
||||||
|
- Installs dependencies with Bun
|
||||||
|
- Creates and manages a systemd unit
|
||||||
|
- Verifies service reachability over HTTP
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Target OS: Debian 12+ or Ubuntu 22.04+
|
||||||
|
- Ansible Core 2.16+
|
||||||
|
- SSH access with privilege escalation rights
|
||||||
|
|
||||||
|
## Role variables
|
||||||
|
|
||||||
|
See defaults in defaults/main.yml.
|
||||||
|
|
||||||
|
Most commonly overridden:
|
||||||
|
|
||||||
|
- gitvana_repo_url
|
||||||
|
- gitvana_repo_version
|
||||||
|
- gitvana_service_port
|
||||||
|
- gitvana_run_mode
|
||||||
|
|
||||||
|
## Example playbook
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
- name: Deploy Gitvana with Bun
|
||||||
|
hosts: docker_nodes
|
||||||
|
become: true
|
||||||
|
roles:
|
||||||
|
- role: gitvana_bun_host
|
||||||
|
```
|
||||||
30
ansible/roles/gitvana_bun_host/defaults/main.yml
Normal file
30
ansible/roles/gitvana_bun_host/defaults/main.yml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
gitvana_repo_url: https://git.castaldifamily.com/nathan/gitvana
|
||||||
|
gitvana_repo_version: main
|
||||||
|
|
||||||
|
gitvana_app_user: gitvana
|
||||||
|
gitvana_app_group: gitvana
|
||||||
|
gitvana_app_root: /opt/gitvana
|
||||||
|
|
||||||
|
gitvana_service_name: gitvana
|
||||||
|
gitvana_service_port: 3000
|
||||||
|
gitvana_run_mode: preview
|
||||||
|
|
||||||
|
gitvana_env:
|
||||||
|
NODE_ENV: production
|
||||||
|
PORT: "{{ gitvana_service_port }}"
|
||||||
|
|
||||||
|
gitvana_healthcheck_path: /
|
||||||
|
gitvana_verify_status_codes:
|
||||||
|
- 200
|
||||||
|
- 301
|
||||||
|
- 302
|
||||||
|
|
||||||
|
bun_version: 1.2.15
|
||||||
|
bun_install_root: /opt/bun
|
||||||
|
gitvana_bun_arch_map:
|
||||||
|
x86_64: linux-x64-baseline
|
||||||
|
aarch64: linux-aarch64
|
||||||
|
|
||||||
|
# Optional SSH deploy key for private repositories.
|
||||||
|
gitvana_git_key_file: ""
|
||||||
9
ansible/roles/gitvana_bun_host/handlers/main.yml
Normal file
9
ansible/roles/gitvana_bun_host/handlers/main.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
- name: Reload systemd
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
daemon_reload: true
|
||||||
|
|
||||||
|
- name: Restart Gitvana service
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: "{{ gitvana_service_name }}"
|
||||||
|
state: restarted
|
||||||
26
ansible/roles/gitvana_bun_host/meta/main.yml
Normal file
26
ansible/roles/gitvana_bun_host/meta/main.yml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
galaxy_info:
|
||||||
|
role_name: gitvana_bun_host
|
||||||
|
namespace: homelab
|
||||||
|
author: FrankGPT
|
||||||
|
description: Deploy Gitvana directly on Debian/Ubuntu hosts using Bun and systemd
|
||||||
|
license: MIT
|
||||||
|
min_ansible_version: "2.16"
|
||||||
|
|
||||||
|
platforms:
|
||||||
|
- name: Ubuntu
|
||||||
|
versions:
|
||||||
|
- jammy
|
||||||
|
- noble
|
||||||
|
- name: Debian
|
||||||
|
versions:
|
||||||
|
- bookworm
|
||||||
|
|
||||||
|
galaxy_tags:
|
||||||
|
- bun
|
||||||
|
- web
|
||||||
|
- application
|
||||||
|
- deployment
|
||||||
|
- lxc
|
||||||
|
|
||||||
|
dependencies: []
|
||||||
35
ansible/roles/gitvana_bun_host/tasks/deploy_code.yml
Normal file
35
ansible/roles/gitvana_bun_host/tasks/deploy_code.yml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
- name: Clone or update Gitvana repository
|
||||||
|
ansible.builtin.git:
|
||||||
|
repo: "{{ gitvana_repo_url }}"
|
||||||
|
dest: "{{ gitvana_app_root }}"
|
||||||
|
version: "{{ gitvana_repo_version }}"
|
||||||
|
update: true
|
||||||
|
key_file: "{{ gitvana_git_key_file | default(omit) }}"
|
||||||
|
accept_hostkey: true
|
||||||
|
become: true
|
||||||
|
become_user: "{{ gitvana_app_user }}"
|
||||||
|
register: gitvana_repo_sync
|
||||||
|
|
||||||
|
- name: Ensure repository ownership is correct
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ gitvana_app_root }}"
|
||||||
|
state: directory
|
||||||
|
recurse: true
|
||||||
|
owner: "{{ gitvana_app_user }}"
|
||||||
|
group: "{{ gitvana_app_group }}"
|
||||||
|
|
||||||
|
- name: Check if dependencies directory exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ gitvana_app_root }}/node_modules"
|
||||||
|
register: gitvana_node_modules
|
||||||
|
|
||||||
|
- name: Install application dependencies with Bun
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: /usr/local/bin/bun install --frozen-lockfile
|
||||||
|
chdir: "{{ gitvana_app_root }}"
|
||||||
|
become: true
|
||||||
|
become_user: "{{ gitvana_app_user }}"
|
||||||
|
when: gitvana_repo_sync.changed or not gitvana_node_modules.stat.exists
|
||||||
|
changed_when: true
|
||||||
|
notify: Restart Gitvana service
|
||||||
71
ansible/roles/gitvana_bun_host/tasks/install_bun.yml
Normal file
71
ansible/roles/gitvana_bun_host/tasks/install_bun.yml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
---
|
||||||
|
- name: Ensure Bun install root exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ bun_install_root }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Set Bun artifact values
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
bun_archive_name: "bun-{{ bun_arch_suffix }}.zip"
|
||||||
|
bun_download_url: "https://github.com/oven-sh/bun/releases/download/bun-v{{ bun_version }}/bun-{{ bun_arch_suffix }}.zip"
|
||||||
|
bun_archive_path: "/tmp/bun-v{{ bun_version }}-{{ bun_arch_suffix }}.zip"
|
||||||
|
bun_extract_path: "{{ bun_install_root }}/bun-v{{ bun_version }}-{{ bun_arch_suffix }}"
|
||||||
|
|
||||||
|
- name: Ensure versioned Bun extract directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ bun_extract_path }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Download Bun release archive
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: "{{ bun_download_url }}"
|
||||||
|
dest: "{{ bun_archive_path }}"
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Extract Bun archive
|
||||||
|
ansible.builtin.unarchive:
|
||||||
|
src: "{{ bun_archive_path }}"
|
||||||
|
dest: "{{ bun_extract_path }}"
|
||||||
|
remote_src: true
|
||||||
|
creates: "{{ bun_extract_path }}/.extracted"
|
||||||
|
|
||||||
|
- name: Mark Bun extraction complete
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ bun_extract_path }}/.extracted"
|
||||||
|
state: touch
|
||||||
|
mode: "0644"
|
||||||
|
|
||||||
|
- name: Locate extracted Bun binary
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths: "{{ bun_extract_path }}"
|
||||||
|
recurse: true
|
||||||
|
file_type: file
|
||||||
|
patterns: bun
|
||||||
|
register: bun_binary_find
|
||||||
|
|
||||||
|
- name: Fail when Bun binary is missing
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: "Bun binary was not found under {{ bun_extract_path }} after extraction."
|
||||||
|
when: bun_binary_find.matched | int == 0
|
||||||
|
|
||||||
|
- name: Select Bun binary path
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
bun_binary_path: "{{ (bun_binary_find.files | sort(attribute='path') | first).path }}"
|
||||||
|
|
||||||
|
- name: Ensure Bun binary has execute permission
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ bun_binary_path }}"
|
||||||
|
mode: "0755"
|
||||||
|
|
||||||
|
- name: Link Bun binary into standard PATH
|
||||||
|
ansible.builtin.file:
|
||||||
|
src: "{{ bun_binary_path }}"
|
||||||
|
dest: /usr/local/bin/bun
|
||||||
|
state: link
|
||||||
|
force: true
|
||||||
18
ansible/roles/gitvana_bun_host/tasks/main.yml
Normal file
18
ansible/roles/gitvana_bun_host/tasks/main.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
- name: Validate role input
|
||||||
|
ansible.builtin.import_tasks: validate.yml
|
||||||
|
|
||||||
|
- name: Install base prerequisites
|
||||||
|
ansible.builtin.import_tasks: prereqs.yml
|
||||||
|
|
||||||
|
- name: Install Bun runtime
|
||||||
|
ansible.builtin.import_tasks: install_bun.yml
|
||||||
|
|
||||||
|
- name: Deploy application code
|
||||||
|
ansible.builtin.import_tasks: deploy_code.yml
|
||||||
|
|
||||||
|
- name: Configure and start service
|
||||||
|
ansible.builtin.import_tasks: service.yml
|
||||||
|
|
||||||
|
- name: Verify service reachability
|
||||||
|
ansible.builtin.import_tasks: verify.yml
|
||||||
31
ansible/roles/gitvana_bun_host/tasks/prereqs.yml
Normal file
31
ansible/roles/gitvana_bun_host/tasks/prereqs.yml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
- name: Install prerequisite packages
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- ca-certificates
|
||||||
|
- curl
|
||||||
|
- git
|
||||||
|
- unzip
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
- name: Ensure application group exists
|
||||||
|
ansible.builtin.group:
|
||||||
|
name: "{{ gitvana_app_group }}"
|
||||||
|
system: true
|
||||||
|
|
||||||
|
- name: Ensure application user exists
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: "{{ gitvana_app_user }}"
|
||||||
|
group: "{{ gitvana_app_group }}"
|
||||||
|
system: true
|
||||||
|
create_home: false
|
||||||
|
shell: /usr/sbin/nologin
|
||||||
|
|
||||||
|
- name: Ensure application directory exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ gitvana_app_root }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ gitvana_app_user }}"
|
||||||
|
group: "{{ gitvana_app_group }}"
|
||||||
|
mode: "0755"
|
||||||
17
ansible/roles/gitvana_bun_host/tasks/service.yml
Normal file
17
ansible/roles/gitvana_bun_host/tasks/service.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
- name: Render systemd unit file
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: gitvana.service.j2
|
||||||
|
dest: "/etc/systemd/system/{{ gitvana_service_name }}.service"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify:
|
||||||
|
- Reload systemd
|
||||||
|
- Restart Gitvana service
|
||||||
|
|
||||||
|
- name: Ensure Gitvana service is enabled and running
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: "{{ gitvana_service_name }}"
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
31
ansible/roles/gitvana_bun_host/tasks/validate.yml
Normal file
31
ansible/roles/gitvana_bun_host/tasks/validate.yml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
- name: Assert supported operating system
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- ansible_os_family == "Debian"
|
||||||
|
fail_msg: "This role supports Debian/Ubuntu targets only."
|
||||||
|
|
||||||
|
- name: Assert required role variables
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- gitvana_repo_url | length > 0
|
||||||
|
- gitvana_repo_version | length > 0
|
||||||
|
- gitvana_app_user | length > 0
|
||||||
|
- gitvana_app_group | length > 0
|
||||||
|
- gitvana_app_root | length > 0
|
||||||
|
- gitvana_service_name | length > 0
|
||||||
|
- gitvana_service_port | int > 0
|
||||||
|
- gitvana_service_port | int < 65536
|
||||||
|
- bun_version | length > 0
|
||||||
|
- bun_install_root | length > 0
|
||||||
|
- gitvana_run_mode in ["dev", "preview"]
|
||||||
|
fail_msg: "One or more required variables are missing or invalid."
|
||||||
|
|
||||||
|
- name: Map architecture for Bun release artifact
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
bun_arch_suffix: "{{ gitvana_bun_arch_map.get(ansible_architecture) }}"
|
||||||
|
|
||||||
|
- name: Fail on unsupported architecture
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: "Unsupported architecture for Bun install: {{ ansible_architecture }}"
|
||||||
|
when: bun_arch_suffix is not defined or bun_arch_suffix | length == 0
|
||||||
16
ansible/roles/gitvana_bun_host/tasks/verify.yml
Normal file
16
ansible/roles/gitvana_bun_host/tasks/verify.yml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
- name: Wait for Gitvana service port
|
||||||
|
ansible.builtin.wait_for:
|
||||||
|
port: "{{ gitvana_service_port }}"
|
||||||
|
host: 127.0.0.1
|
||||||
|
timeout: 60
|
||||||
|
|
||||||
|
- name: Verify local HTTP health endpoint
|
||||||
|
ansible.builtin.uri:
|
||||||
|
url: "http://127.0.0.1:{{ gitvana_service_port }}{{ gitvana_healthcheck_path }}"
|
||||||
|
method: GET
|
||||||
|
status_code: "{{ gitvana_verify_status_codes }}"
|
||||||
|
register: gitvana_health_result
|
||||||
|
retries: 3
|
||||||
|
delay: 5
|
||||||
|
until: gitvana_health_result.status in gitvana_verify_status_codes
|
||||||
21
ansible/roles/gitvana_bun_host/templates/gitvana.service.j2
Normal file
21
ansible/roles/gitvana_bun_host/templates/gitvana.service.j2
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Gitvana Bun Service
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User={{ gitvana_app_user }}
|
||||||
|
Group={{ gitvana_app_group }}
|
||||||
|
WorkingDirectory={{ gitvana_app_root }}
|
||||||
|
{% for key, value in gitvana_env.items() %}
|
||||||
|
Environment={{ key }}={{ value }}
|
||||||
|
{% endfor %}
|
||||||
|
ExecStart=/usr/local/bin/bun run {{ gitvana_run_mode }} --host 0.0.0.0 --port {{ gitvana_service_port }}
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
TimeoutStartSec=120
|
||||||
|
TimeoutStopSec=30
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
Loading…
x
Reference in New Issue
Block a user