Initial commit: VM Creation done

This commit is contained in:
Lino Silva
2026-03-30 10:54:16 +01:00
commit 97e7d65f42
27 changed files with 474 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
.vault_pass
*.retry
View File
+4
View File
@@ -0,0 +1,4 @@
[defaults]
roles_path = ./roles
inventory = ./inventories/production.yml
host_key_checking = False
@@ -0,0 +1,18 @@
proxmox_api_host: "10.0.2.2"
proxmox_api_user: "root@pam"
proxmox_api_token_id: "ansible"
proxmox_api_token_secret: "{{ vault_proxmox_api_token_secret }}"
proxmox_node: "pve"
template_name: "debian-13-cloudinit"
ansible_user: root
ansible_python_interpreter: /opt/homebrew/bin/python3
docker_packages:
- docker.io
- docker-compose-plugin
# Traefik configuration
domain: "example.com" # Change to your domain
letsencrypt_email: "admin@example.com" # Change to your email
@@ -0,0 +1,9 @@
$ANSIBLE_VAULT;1.1;AES256
30633439346434353439346639633764626635653563666538653835633838643731666435303334
3661326333363964633038303533316334363830303236350a393538306461356533636565353031
30643036363662376661656462386235383438623533303139343037616436666161653530376639
3063343131616333620a336430323062383738663130623139323633613035643539333565663730
30613964353338653663373234616365303165306166373034633264303235366433396130616435
66636161373639393166386331346639666361316237353965373562643761613064666566343436
65353164316262313234653764353837643763363132383935323231376538383933316563326537
35343235336163653435
@@ -0,0 +1,53 @@
vms:
# infra-core-1:
# vmid: 410
# node: purah
# cores: 4
# memory: 8192
# disk: 50G
# ip: 10.0.4.10
# network_bridge: "vmbr0"
# storage: purah-mirror-860gb
# media-1:
# vmid: 420
# node: purah
# cores: 8
# memory: 16384
# disk: 200G
# ip: 10.0.4.20
# igpu: true
# network_bridge: "vmbr0"
# storage: purah-mirror-860gb
# apps-1:
# vmid: 430
# node: yunobo
# cores: 6
# memory: 16384
# disk: 100G
# ip: 10.0.4.30
# network_bridge: "vmbr2"
# storage: nvme-2tb
edge-1:
vmid: 401
node: mipha
template_vmid: 9001
cores: 2
memory: 4096
disk: 30G
ip: 10.0.4.1
network_bridge: "vmbr0"
storage: "local-lvm"
edge-2:
vmid: 402
node: sidon
template_vmid: 9002
cores: 2
memory: 4096
disk: 30G
ip: 10.0.4.2
network_bridge: "vmbr0"
storage: "local-lvm"
@@ -0,0 +1,8 @@
---
# Keepalived configuration for edge-1 (PRIMARY)
keepalived_state: MASTER
keepalived_priority: 100
keepalived_interface: eth0
keepalived_router_id: 51
keepalived_vip: 10.0.4.254
keepalived_password: "{{ vault_keepalived_password | default('changeme') }}"
@@ -0,0 +1,8 @@
---
# Keepalived configuration for edge-2 (BACKUP)
keepalived_state: BACKUP
keepalived_priority: 50
keepalived_interface: eth0
keepalived_router_id: 51
keepalived_vip: 10.0.4.254
keepalived_password: "{{ vault_keepalived_password | default('changeme') }}"
+17
View File
@@ -0,0 +1,17 @@
[ms01]
purah ansible_host=10.0.2.5
yunobo ansible_host=10.0.3.4
[nuc]
mipha ansible_host=10.0.2.3
sidon ansible_host=10.0.2.2
yuga ansible_host=10.0.2.7
[infra]
infra-core-1 ansible_host=10.0.4.1
[media]
media-1 ansible_host=10.0.4.10
[apps]
apps-1 ansible_host=10.0.4.20
+30
View File
@@ -0,0 +1,30 @@
all:
hosts:
localhost:
ansible_connection: local
children:
edge:
hosts:
edge-1:
ansible_host: 10.0.4.1
edge-2:
ansible_host: 10.0.4.2
purah:
hosts:
infra-core-1:
ansible_host: 10.0.4.10
yunobo:
hosts:
media-1:
ansible_host: 10.0.4.20
apps-1:
ansible_host: 10.0.4.30
mipha:
hosts:
edge-1:
ansible_host: 10.0.4.1
sidon:
hosts:
edge-2:
ansible_host: 10.0.4.2
+31
View File
@@ -0,0 +1,31 @@
---
- hosts: localhost
gather_facts: no
roles:
- proxmox_vm
- hosts: edge
become: yes
roles:
- base
- docker
- keepalived
- traefik
# - hosts: all
# become: yes
# roles:
# - base
# - docker
# - komodo
# - hosts: purah
# become: yes
# roles:
# - vm_infra
# - vm_plex
# - hosts: yunobo
# become: yes
# roles:
# - vm_apps
+20
View File
@@ -0,0 +1,20 @@
---
- name: Update apt cache
ansible.builtin.apt:
update_cache: yes
- name: Install essential packages
ansible.builtin.apt:
name:
- sudo
- vim
- curl
- git
- software-properties-common
state: present
- name: Ensure user is in docker group
ansible.builtin.user:
name: "{{ ansible_user }}"
groups: docker
append: yes
+11
View File
@@ -0,0 +1,11 @@
---
- name: Install Docker & Compose
ansible.builtin.apt:
name: "{{ docker_packages }}"
state: present
- name: Ensure Docker service is started
ansible.builtin.service:
name: docker
state: started
enabled: yes
@@ -0,0 +1,5 @@
---
- name: restart keepalived
systemd:
name: keepalived
state: restarted
+19
View File
@@ -0,0 +1,19 @@
---
- name: Install keepalived
apt:
name: keepalived
state: present
update_cache: yes
- name: Create keepalived config
template:
src: keepalived.conf.j2
dest: /etc/keepalived/keepalived.conf
mode: '0644'
notify: restart keepalived
- name: Enable and start keepalived
systemd:
name: keepalived
enabled: yes
state: started
@@ -0,0 +1,16 @@
vrrp_instance VI_1 {
state {{ keepalived_state | default('MASTER') }}
interface {{ keepalived_interface | default('eth0') }}
virtual_router_id {{ keepalived_router_id | default('51') }}
priority {{ keepalived_priority | default('100') }}
advert_int 1
authentication {
auth_type PASS
auth_pass {{ keepalived_password | default('secret') }}
}
virtual_ipaddress {
{{ keepalived_vip }}
}
}
+6
View File
@@ -0,0 +1,6 @@
---
- name: Install Komodo agent
ansible.builtin.shell: |
curl -sSL https://komodo.install/script.sh | bash
args:
creates: /usr/local/bin/komodo
+11
View File
@@ -0,0 +1,11 @@
- name: Resize disk
community.proxmox.proxmox_disk:
api_host: "{{ proxmox_api_host }}"
api_user: "{{ proxmox_api_user }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
vmid: "{{ item.value.vmid }}"
disk: scsi0
size: "{{ item.value.disk }}"
state: resized
loop: "{{ vms | dict2items }}"
+5
View File
@@ -0,0 +1,5 @@
- name: Enable iGPU passthrough (media VM)
ansible.builtin.shell: |
qm set {{ item.value.vmid }} -hostpci0 00:02.0
when: item.value.igpu is defined and item.value.igpu
loop: "{{ vms | dict2items }}"
+53
View File
@@ -0,0 +1,53 @@
---
- name: Clone VM from template
community.proxmox.proxmox_kvm:
api_host: "{{ proxmox_api_host }}"
api_user: "{{ proxmox_api_user }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
node: "{{ item.value.node }}"
clone: "debian-13-cloudinit"
vmid: "{{ item.value.template_vmid }}"
newid: "{{ item.value.vmid }}"
storage: "{{ item.value.storage }}"
name: "{{ item.key }}"
full: yes
loop: "{{ vms | dict2items }}"
- name: Configure VM hardware and cloud-init
community.proxmox.proxmox_kvm:
api_host: "{{ proxmox_api_host }}"
api_user: "{{ proxmox_api_user }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
node: "{{ item.value.node }}"
vmid: "{{ item.value.vmid }}"
cores: "{{ item.value.cores }}"
memory: "{{ item.value.memory }}"
scsihw: virtio-scsi-pci
net:
net0: "virtio,bridge={{ item.value.network_bridge }}"
ipconfig:
ipconfig0: "ip={{ item.value.ip }}/24,gw=10.0.0.1"
nameservers: "10.0.2.49 10.0.2.50 10.0.2.51"
ciuser: "{{ ansible_user }}"
sshkeys: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
update: yes
loop: "{{ vms | dict2items }}"
- name: Wait for clone to complete
pause:
seconds: 10
- include_tasks: disk.yml
- include_tasks: start.yml
- name: Wait for VMs to be ready
wait_for:
host: "{{ item.value.ip }}"
port: 22
delay: 10
timeout: 300
loop: "{{ vms | dict2items }}"
delegate_to: localhost
+9
View File
@@ -0,0 +1,9 @@
- name: Start VMs
community.proxmox.proxmox_kvm:
api_host: "{{ proxmox_api_host }}"
api_user: "{{ proxmox_api_user }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
vmid: "{{ item.value.vmid }}"
state: started
loop: "{{ vms | dict2items }}"
+39
View File
@@ -0,0 +1,39 @@
---
- name: Create traefik directory
file:
path: /opt/traefik
state: directory
mode: '0755'
- name: Create traefik data directory
file:
path: /opt/traefik/data
state: directory
mode: '0755'
- name: Create proxy network
docker_network:
name: proxy
- name: Create acme.json for Let's Encrypt
file:
path: /opt/traefik/data/acme.json
state: touch
mode: '0600'
- name: Create traefik config file
template:
src: traefik.yml.j2
dest: /opt/traefik/data/traefik.yml
mode: '0644'
- name: Create docker-compose file
template:
src: docker-compose.yml.j2
dest: /opt/traefik/docker-compose.yml
mode: '0644'
- name: Start Traefik
community.docker.docker_compose_v2:
project_src: /opt/traefik
state: present
@@ -0,0 +1,36 @@
version: '3.8'
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- proxy
ports:
- "80:80"
- "443:443"
- "8080:8080" # Dashboard
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/traefik.yml:/traefik.yml:ro
- ./data/acme.json:/acme.json
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.entrypoints=http"
- "traefik.http.routers.traefik.rule=Host(`traefik.{{ domain | default('local') }}`)"
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
- "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
- "traefik.http.routers.traefik-secure.entrypoints=https"
- "traefik.http.routers.traefik-secure.rule=Host(`traefik.{{ domain | default('local') }}`)"
- "traefik.http.routers.traefik-secure.tls=true"
- "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
- "traefik.http.routers.traefik-secure.service=api@internal"
networks:
proxy:
external: true
@@ -0,0 +1,33 @@
api:
dashboard: true
debug: true
entryPoints:
http:
address: ":80"
http:
redirections:
entryPoint:
to: https
scheme: https
https:
address: ":443"
serversTransport:
insecureSkipVerify: true
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
certificatesResolvers:
cloudflare:
acme:
email: {{ letsencrypt_email | default('admin@example.com') }}
storage: acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
+11
View File
@@ -0,0 +1,11 @@
---
- name: Create app directories
ansible.builtin.file:
path: "/data/{{ item }}"
state: directory
mode: '0755'
loop:
- paperless
- nextcloud
- mealie
- outline
+10
View File
@@ -0,0 +1,10 @@
---
- name: Create infra directories
ansible.builtin.file:
path: "/data/{{ item }}"
state: directory
mode: '0755'
loop:
- vaultwarden
- pi-hole
- uptime-kuma
+10
View File
@@ -0,0 +1,10 @@
---
- name: Ensure VM has iGPU passthrough (requires Proxmox pre-config)
ansible.builtin.debug:
msg: "Ensure /dev/dri is passed through on this VM: {{ inventory_hostname }}"
- name: Mount media storage
ansible.builtin.file:
path: /data/media
state: directory
mode: '0755'