feat: solidtime VM
Some checks failed
Infrastructure / Check and run Ansbile playbooks (push) Failing after 5m34s

This commit is contained in:
Gleb Koval 2025-02-16 00:25:51 +00:00
parent 784a10b1b5
commit e96d712e1d
Signed by: cyclane
GPG Key ID: 15E168A8B332382C
9 changed files with 422 additions and 0 deletions

View File

@ -0,0 +1,112 @@
- name: Provision solidtime Proxmox VM
hosts: solidtime
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
notify:
- Start VM
- Wait
- 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
- name: Force all notified handlers to run
ansible.builtin.meta: flush_handlers
# 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: Update VM
community.general.proxmox_kvm:
update: true
agent: enabled=1
tags:
- debian-12
- managed
onboot: true
cores: 4
memory: 8192
- name: Retart VM
community.general.proxmox_kvm:
state: restarted
timeout: 60
handlers:
# 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: Start VM
community.general.proxmox_kvm:
state: started
register: start
- name: Wait # Initial apt update, apt upgrade, cloud-init
ansible.builtin.wait_for:
timeout: 90

View File

@ -0,0 +1,43 @@
- name: Initialise VM
hosts: solidtime
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

View File

@ -0,0 +1,48 @@
- name: Install docker
hosts: solidtime
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

View File

@ -0,0 +1,65 @@
- name: Deploy app
hosts: solidtime
gather_facts: false
vars:
app: solidtime
tasks:
- name: Wait for connection
ansible.builtin.wait_for_connection:
timeout: 300
- name: Check if project exists
ansible.builtin.stat:
path: "$HOME/{{ app }}"
register: project
- name: Docker compose down
when: project.stat.exists
community.docker.docker_compose_v2:
project_src: "$HOME/{{ app }}"
state: absent
- name: Copy project
ansible.builtin.copy:
src: "./{{ app }}"
dest: "$HOME"
mode: "0744"
- name: Replace APP_KEY secret
ansible.builtin.replace:
path: "$HOME/{{ app }}/laravel.env"
regexp: "APP_KEY_VALUE"
replace: "{{ lookup('infisical.vault.read_secrets', project_id=infisical_project, env_slug='prod',
path='/solidtime', secret_name='APP_KEY')['value'] }}"
- name: Replace SMTP Password secret
ansible.builtin.replace:
path: "$HOME/{{ app }}/laravel.env"
regexp: "SMTP_PASSWORD_VALUE"
replace: "{{ lookup('ansible.builtin.env', 'SMTP_PASSWORD') }}"
- name: Replace PASSPORT_PRIVATE_KEY secret
ansible.builtin.replace:
path: "$HOME/{{ app }}/laravel.env"
regexp: "PASSPORT_PRIVATE_KEY_VALUE"
replace: "{{ lookup('infisical.vault.read_secrets', project_id=infisical_project, env_slug='prod',
path='/solidtime', secret_name='PASSPORT_PRIVATE_KEY')['value'] }}"
- name: Replace PASSPORT_PUBLIC_KEY secret
ansible.builtin.replace:
path: "$HOME/{{ app }}/laravel.env"
regexp: "PASSPORT_PUBLIC_KEY_VALUE"
replace: "{{ lookup('infisical.vault.read_secrets', project_id=infisical_project, env_slug='prod',
path='/solidtime', secret_name='PASSPORT_PUBLIC_KEY')['value'] }}"
- name: Replace DB Password secret (app)
ansible.builtin.replace:
path: "$HOME/{{ app }}/laravel.env"
regexp: "DB_PASSWORD_VALUE"
replace: "{{ lookup('infisical.vault.read_secrets', project_id=infisical_project, env_slug='prod',
path='/solidtime', secret_name='DB_PASSWORD')['value'] }}"
- name: Replace DB Password secret (db)
ansible.builtin.replace:
path: "$HOME/{{ app }}/.env"
regexp: "DB_PASSWORD_VALUE"
replace: "{{ lookup('infisical.vault.read_secrets', project_id=infisical_project, env_slug='prod',
path='/solidtime', secret_name='DB_PASSWORD')['value'] }}"
- name: Docker compose up
community.docker.docker_compose_v2:
project_src: "$HOME/{{ app }}"

View File

@ -0,0 +1,7 @@
APP_DOMAIN=solidtime.koval.net
DB_DATABASE=solidtime
DB_USERNAME=solidtime
FORWARD_APP_PORT=8000
FORWARD_DB_PORT=5432
DB_PASSWORD=DB_PASSWORD_VALUE
SOLIDTIME_IMAGE_TAG=latest

1
infra/solidtime/solidtime/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
!*.env

View File

@ -0,0 +1,96 @@
services:
app:
restart: always
image: "solidtime/solidtime:${SOLIDTIME_IMAGE_TAG:-latest}"
user: "1000:1000"
ports:
- '${FORWARD_APP_PORT:-8000}:8000'
networks:
- internal
volumes:
- "app-storage:/var/www/html/storage"
- "./logs:/var/www/html/storage/logs"
- "app-storage-app:/var/www/html/storage/app"
environment:
CONTAINER_MODE: http
AUTO_DB_MIGRATE: "true"
healthcheck:
test: [ "CMD-SHELL", "curl --fail http://localhost:8000/health-check/up || exit 1" ]
env_file:
- laravel.env
depends_on:
- database
scheduler:
restart: always
image: "solidtime/solidtime:${SOLIDTIME_IMAGE_TAG:-latest}"
user: "1000:1000"
networks:
- internal
volumes:
- "app-storage:/var/www/html/storage"
- "./logs:/var/www/html/storage/logs"
- "app-storage-app:/var/www/html/storage/app"
environment:
CONTAINER_MODE: scheduler
healthcheck:
test: [ "CMD-SHELL", "supervisorctl status scheduler:scheduler_00" ]
env_file:
- laravel.env
depends_on:
- database
queue:
restart: always
image: "solidtime/solidtime:${SOLIDTIME_IMAGE_TAG:-latest}"
user: "1000:1000"
networks:
- internal
volumes:
- "app-storage:/var/www/html/storage"
- "./logs:/var/www/html/storage/logs"
- "app-storage-app:/var/www/html/storage/app"
environment:
CONTAINER_MODE: worker
WORKER_COMMAND: "php /var/www/html/artisan queue:work"
healthcheck:
test: [ "CMD-SHELL", "supervisorctl status worker:worker_00" ]
env_file:
- laravel.env
depends_on:
- database
database:
restart: always
image: 'postgres:15'
# ports:
# - '${FORWARD_DB_PORT:-5432}:5432'
environment:
PGPASSWORD: '${DB_PASSWORD:-secret}'
POSTGRES_DB: '${DB_DATABASE}'
POSTGRES_USER: '${DB_USERNAME}'
POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}'
volumes:
- 'database-storage:/var/lib/postgresql/data'
networks:
- internal
healthcheck:
test:
- CMD
- pg_isready
- '-q'
- '-d'
- '${DB_DATABASE}'
- '-U'
- '${DB_USERNAME}'
retries: 3
timeout: 5s
gotenberg:
image: gotenberg/gotenberg:8
networks:
- internal
healthcheck:
test: [ "CMD", "curl", "--silent", "--fail", "http://localhost:3000/health" ]
networks:
internal:
volumes:
database-storage:
app-storage:
app-storage-app:

View File

@ -0,0 +1,47 @@
APP_NAME="solidtime"
VITE_APP_NAME="solidtime"
APP_ENV="production"
APP_DEBUG="false"
APP_URL="https://solidtime.koval.net"
APP_FORCE_HTTPS="true"
APP_ENABLE_REGISTRATION="false"
TRUSTED_PROXIES="10.4.0.1/32"
# Authentication
APP_KEY="APP_KEY_VALUE"
PASSPORT_PRIVATE_KEY="PASSPORT_PRIVATE_KEY_VALUE"
PASSPORT_PUBLIC_KEY="PASSPORT_PUBLIC_KEY_VALUE"
SUPER_ADMINS="gleb@koval.net"
# Logging
LOG_CHANNEL="stderr_daily"
LOG_LEVEL="debug"
# Database
DB_CONNECTION="pgsql"
DB_HOST="database"
DB_PORT="5432"
DB_SSLMODE="require"
DB_DATABASE="solidtime"
DB_USERNAME="solidtime"
DB_PASSWORD="DB_PASSWORD_VALUE"
# Mail
MAIL_MAILER="smtp"
MAIL_HOST="mx.koval.net"
MAIL_PORT="587"
MAIL_ENCRYPTION="tls"
MAIL_FROM_ADDRESS="no-reply@koval.net"
MAIL_FROM_NAME="solidtime"
MAIL_USERNAME="no-reply@koval.net"
MAIL_PASSWORD="SMTP_PASSWORD_VALUE"
# Queue
QUEUE_CONNECTION="database"
# File storage
FILESYSTEM_DISK="local"
PUBLIC_FILESYSTEM_DISK="public"
# Services
GOTENBERG_URL="http://gotenberg:3000"

View File

@ -26,6 +26,9 @@ proxmox:
finance: finance:
hosts: hosts:
finance.srv.home.local.koval.net: finance.srv.home.local.koval.net:
solidtime:
hosts:
solidtime.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