Initial commit: VM Creation done
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
.vault_pass
|
||||||
|
*.retry
|
||||||
@@ -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') }}"
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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 }}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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 }}"
|
||||||
@@ -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 }}"
|
||||||
@@ -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
|
||||||
@@ -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 }}"
|
||||||
@@ -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"
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
- name: Create app directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/data/{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- paperless
|
||||||
|
- nextcloud
|
||||||
|
- mealie
|
||||||
|
- outline
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
- name: Create infra directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/data/{{ item }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
loop:
|
||||||
|
- vaultwarden
|
||||||
|
- pi-hole
|
||||||
|
- uptime-kuma
|
||||||
@@ -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'
|
||||||
Reference in New Issue
Block a user