initial commit
This commit is contained in:
commit
9df999f89f
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"ansible.python.interpreterPath": "/run/current-system/sw/bin/python",
|
||||
"ansible.validation.lint.path": "",
|
||||
"ansible.validation.lint.enabled": false
|
||||
}
|
150
README.md
Normal file
150
README.md
Normal file
@ -0,0 +1,150 @@
|
||||
# Ansible Starter Kit
|
||||
|
||||
Easy way for my homies to start up an ansible project for their homelab or local machine.
|
||||
|
||||
# Prerequisites
|
||||
|
||||
The ideal setup for a homelab is to have:
|
||||
|
||||
- The same username/password in all vms/hosts so you don't have to type a different password for each host
|
||||
- SSH key auth on each host so you don't have to type a password at all
|
||||
|
||||
# Ansible basics
|
||||
|
||||
I'll explain the basic units of an ansible project. For this example we're going to assume you want to mount
|
||||
an NFS share in all your hosts.
|
||||
|
||||
From bottom to top we have:
|
||||
|
||||
## Tasks
|
||||
|
||||
A task is the lowest unit in an ansible project.
|
||||
|
||||
A task could be:
|
||||
|
||||
- Creating a directory
|
||||
- Installing an os package (curl, docker, nfs-common, etc)
|
||||
- Starting a docker container
|
||||
|
||||
### Examples
|
||||
|
||||
```yml
|
||||
- name: Add SSH key for remote user
|
||||
ansible.posix.authorized_key:
|
||||
user: javi
|
||||
state: present
|
||||
key: "{{ lookup('file', '/home/javi/.ssh/homelab_keypair_ed25519.pub') }}"
|
||||
```
|
||||
|
||||
```yml
|
||||
- name: Ensure NFS client is installed
|
||||
ansible.builtin.package:
|
||||
name: nfs-common
|
||||
state: present
|
||||
become: true
|
||||
```
|
||||
|
||||
## Role
|
||||
|
||||
A role is a self contained, re-usable unit that will give a meaningful result. Think of it like a class in a program.
|
||||
|
||||
Roles have a list of tasks, as well as variables and files associated with those tasks. All contained in a folder.
|
||||
|
||||
A role can look like:
|
||||
|
||||
```
|
||||
roles/
|
||||
portainer/
|
||||
├── defaults/
|
||||
│ └── main.yml # Default variables
|
||||
├── files/
|
||||
│ └── ... # Static files to be copied (e.g., configs, scripts)
|
||||
├── handlers/
|
||||
│ └── main.yml # Handlers (e.g., service restart)
|
||||
├── meta/
|
||||
│ └── main.yml # Role metadata (e.g., dependencies)
|
||||
├── tasks/
|
||||
│ └── main.yml # Main list of tasks to execute
|
||||
├── templates/
|
||||
│ └── ... # Jinja2 templates
|
||||
├── vars/
|
||||
│ └── main.yml # Non-overridable variables
|
||||
└── README.md # Optional: Document what this role does
|
||||
sshkey/
|
||||
├── defaults/
|
||||
│ └── main.yml # Default variables
|
||||
├── files/
|
||||
│ └── ... # Static files to be copied (e.g., configs, scripts)
|
||||
├── handlers/
|
||||
│ └── main.yml # Handlers (e.g., service restart)
|
||||
├── meta/
|
||||
│ └── main.yml # Role metadata (e.g., dependencies)
|
||||
├── tasks/
|
||||
│ └── main.yml # Main list of tasks to execute
|
||||
├── templates/
|
||||
│ └── ... # Jinja2 templates
|
||||
├── vars/
|
||||
│ └── main.yml # Non-overridable variables
|
||||
└── README.md # Optional: Document what this role does
|
||||
|
||||
```
|
||||
|
||||
However, only the `defaults` and `tasks` subfolders and subsequent `main.yml` are required. Everything else is optional.
|
||||
|
||||
A role can be:
|
||||
|
||||
- Mounting a share
|
||||
- Deploying a docker container with all its requirements like a database and mapped volumes
|
||||
|
||||
# Playbook
|
||||
|
||||
A playbook combines roles and task to create a final state in a host or group of hosts.
|
||||
|
||||
A playbook can be:
|
||||
|
||||
- Make sure all your hosts have sshkey auth, portainer, docker and an nfs share mounted.
|
||||
- Deploy a suite of apps to a host or multiple hosts
|
||||
|
||||
## Example
|
||||
|
||||
```yml
|
||||
---
|
||||
- name: Deploy apps to apps-1 node
|
||||
hosts: apps
|
||||
become: true
|
||||
roles:
|
||||
- role: apps/kan
|
||||
vars:
|
||||
port: 7070
|
||||
- role: apps/memos
|
||||
vars:
|
||||
port: 7071
|
||||
- role: apps/vaultwarden
|
||||
vars:
|
||||
port: 7072
|
||||
- role: apps/erugo
|
||||
vars:
|
||||
port: 7073
|
||||
- role: apps/tianji
|
||||
vars:
|
||||
port: 7074
|
||||
- role: apps/stirling-pdf o
|
||||
vars:
|
||||
port: 7075
|
||||
- role: apps/dumbware-todo
|
||||
vars:
|
||||
port: 7076
|
||||
pin: 8989
|
||||
- role: apps/dumbware-drop
|
||||
vars:
|
||||
port: 7077
|
||||
pin: "8989"
|
||||
```
|
||||
|
||||
# Setup
|
||||
|
||||
1. Clone this repo `git clone git@gitgud.foo:javif89/ansible-starter-kit.git [your project name]`
|
||||
2. Run `setup.sh` to set up the vault password and become password
|
||||
3. Set up your hosts in `hosts.yml`
|
||||
4. Start making your roles and playbooks
|
||||
|
4
ansible.cfg
Executable file
4
ansible.cfg
Executable file
@ -0,0 +1,4 @@
|
||||
[defaults]
|
||||
inventory = hosts.yml
|
||||
roles_path = ./roles
|
||||
vault_password_file = ~/.ansible-vault-key
|
47
group_vars/all.yml
Executable file
47
group_vars/all.yml
Executable file
@ -0,0 +1,47 @@
|
||||
project_root: "{{ inventory_dir }}" # Useful hack for easier file paths
|
||||
# Postgres
|
||||
# If you have a main database instance all your
|
||||
# services will use (which you should), put
|
||||
# the info here so it's accessible to all
|
||||
# your playbooks.
|
||||
pg_host: prod1.lan.xbazzi.com
|
||||
pg_port: 5432
|
||||
pg_user: postgres
|
||||
pg_password: password
|
||||
|
||||
docker_dir: /data/docker
|
||||
|
||||
# Local paths
|
||||
docker_stacks: "{{ project_root }}/docker"
|
||||
assets: "{{ project_root }}/assets"
|
||||
|
||||
# Remote paths
|
||||
remote_stacks: "/home/javi/docker"
|
||||
remote_app_mounts: "/home/docker"
|
||||
# Sudo password for your servers
|
||||
# Sudo password for your servers
|
||||
ansible_become_pass: !vault |
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
64633661313934656164656164623432366339636334653736383330363662313861633338626437
|
||||
3335386363316431653536373264393537626234306633340a353764396630343664646434636463
|
||||
65613232303363373237626163306261306266363336336130666331376133653733393864663335
|
||||
6335663333336139350a346233373231323238376364663761663461383331366264396665383364
|
||||
6264
|
||||
|
||||
# TrueNAS iSCSI stuff
|
||||
iscsi_target_ip: nas.lan.xbazzi.com # TrueNAS IP
|
||||
iscsi_target_iqn: iqn.2005-10.org.freenas.ctl:pve-iscsi
|
||||
|
||||
# Alma new VM provisioning
|
||||
hostname: "prod3"
|
||||
timezone: "America/Denver"
|
||||
|
||||
network_config:
|
||||
interface: "ens18"
|
||||
address: ""
|
||||
netmask: "255.255.252.0"
|
||||
gateway: "10.133.7.103"
|
||||
dns: ["10.133.7.1"]
|
||||
|
||||
nfs_mounts:
|
||||
- { src: "nas:/mnt/media", path: "/mnt/media", opts: "defaults,nfsvers=4" }
|
2
group_vars/cluster_prep.yml
Normal file
2
group_vars/cluster_prep.yml
Normal file
@ -0,0 +1,2 @@
|
||||
iscsi_target_ip: nas.lan.xbazzi.com # TrueNAS IP
|
||||
iscsi_target_iqn: iqn.2005-10.org.freenas.ctl:pve-iscsi
|
6
host_vars/pve1.yml
Normal file
6
host_vars/pve1.yml
Normal file
@ -0,0 +1,6 @@
|
||||
vmbr0_ip: 10.69.0.21
|
||||
vmbr1_1337_ip: 10.133.7.21
|
||||
vmbr1_666_ip: 10.66.6.21
|
||||
cluster_iface: "vmbr1.999"
|
||||
cluster_ip: 10.99.9.1
|
||||
|
5
host_vars/pve2.yml
Normal file
5
host_vars/pve2.yml
Normal file
@ -0,0 +1,5 @@
|
||||
vmbr0_ip: 10.69.0.22
|
||||
vmbr1_1337_ip: 10.133.7.22
|
||||
vmbr1_666_ip: 10.66.6.22
|
||||
cluster_iface: "vmbr1.999"
|
||||
cluster_ip: 10.99.9.2
|
5
host_vars/pve3.yml
Normal file
5
host_vars/pve3.yml
Normal file
@ -0,0 +1,5 @@
|
||||
vmbr0_ip: 10.69.0.23
|
||||
vmbr1_1337_ip: 10.133.7.23
|
||||
vmbr1_666_ip: 10.66.6.23
|
||||
cluster_iface: "vmbr1.999"
|
||||
cluster_ip: 10.99.9.3
|
28
hosts.yml
Executable file
28
hosts.yml
Executable file
@ -0,0 +1,28 @@
|
||||
---
|
||||
all:
|
||||
children:
|
||||
pve-nodes:
|
||||
hosts:
|
||||
pve1:
|
||||
ansible_host: pve1
|
||||
pve2:
|
||||
ansible_host: pve2
|
||||
pve3:
|
||||
ansible_host: pve3
|
||||
vms:
|
||||
hosts:
|
||||
prod1:
|
||||
ansible_host: prod1
|
||||
prod2:
|
||||
ansible_host: prod2
|
||||
school:
|
||||
ansible_host: school
|
||||
new-vm:
|
||||
ansible_host: 10.133.7.240
|
||||
# alma-provision:
|
||||
# hosts:
|
||||
# new-alma-vm:
|
||||
# ansible_host: <ip>
|
||||
# vars:
|
||||
# ansible_user: root
|
||||
|
6
playbooks/backup-pve.yml
Normal file
6
playbooks/backup-pve.yml
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
- name: Backup /etc/pve from all Proxmox nodes
|
||||
hosts: pve-nodes
|
||||
become: yes
|
||||
roles:
|
||||
- role: utility/pve_backup
|
BIN
playbooks/backups/pve1.tar.gz
Normal file
BIN
playbooks/backups/pve1.tar.gz
Normal file
Binary file not shown.
BIN
playbooks/backups/pve2.tar.gz
Normal file
BIN
playbooks/backups/pve2.tar.gz
Normal file
Binary file not shown.
BIN
playbooks/backups/pve3.tar.gz
Normal file
BIN
playbooks/backups/pve3.tar.gz
Normal file
Binary file not shown.
6
playbooks/configure-pve.yml
Normal file
6
playbooks/configure-pve.yml
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
- name: Configure networking for a new node
|
||||
hosts: pve-nodes
|
||||
become: true
|
||||
roles:
|
||||
- role: pve/setup_networking
|
15
playbooks/deploy-dbgate.yml
Normal file
15
playbooks/deploy-dbgate.yml
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
- name: Deploy DBGate container
|
||||
hosts: prod1
|
||||
become: true
|
||||
roles:
|
||||
- role: apps/dbgate
|
||||
vars:
|
||||
directory: "pg-dev"
|
||||
container_name: "postgres-dev"
|
||||
port: 7000
|
||||
- role: services/postgres
|
||||
vars:
|
||||
directory: "pg-beta"
|
||||
container_name: "postgres-beta"
|
||||
port: 7001
|
16
playbooks/deploy-postgres.yml
Normal file
16
playbooks/deploy-postgres.yml
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
- name: Deploy PostgreSQL container
|
||||
hosts: prod1
|
||||
become: true
|
||||
roles:
|
||||
- role: services/postgres
|
||||
- role: services/postgres
|
||||
vars:
|
||||
directory: "pg-dev"
|
||||
container_name: "postgres-dev"
|
||||
port: 7000
|
||||
- role: services/postgres
|
||||
vars:
|
||||
directory: "pg-beta"
|
||||
container_name: "postgres-beta"
|
||||
port: 7001
|
6
playbooks/example.yml
Normal file
6
playbooks/example.yml
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
- name: Example playbook
|
||||
hosts: vms
|
||||
become: true
|
||||
roles:
|
||||
- role: server/sshkey
|
5
playbooks/prep-pve-for-cluster.yml
Normal file
5
playbooks/prep-pve-for-cluster.yml
Normal file
@ -0,0 +1,5 @@
|
||||
- name: Prep all Proxmox nodes for clustering
|
||||
hosts: pve-nodes
|
||||
become: yes
|
||||
roles:
|
||||
- role: utility/cluster_prep
|
8
playbooks/provision-alma.yml
Normal file
8
playbooks/provision-alma.yml
Normal file
@ -0,0 +1,8 @@
|
||||
- name: Provision AlmaLinux 10 VM
|
||||
hosts: new-vm
|
||||
become: yes
|
||||
roles:
|
||||
- role: provision/alma/common
|
||||
# - role: provision/alma/network
|
||||
# - role: provision/alma/nfs
|
||||
# - role: provision/alma/docker
|
0
roles/app/database/defaults/main.yml
Executable file
0
roles/app/database/defaults/main.yml
Executable file
20
roles/app/database/tasks/main.yml
Executable file
20
roles/app/database/tasks/main.yml
Executable file
@ -0,0 +1,20 @@
|
||||
---
|
||||
- name: Create app database
|
||||
ansible.builtin.include_role:
|
||||
name: postgres/database
|
||||
vars:
|
||||
database: "{{ app_name }}"
|
||||
|
||||
- name: Create app db user
|
||||
ansible.builtin.include_role:
|
||||
name: postgres/user
|
||||
vars:
|
||||
user: "{{ app_name }}"
|
||||
password: "password"
|
||||
|
||||
- name: Give app user full priviledges on DB
|
||||
ansible.builtin.include_role:
|
||||
name: postgres/priviledges
|
||||
vars:
|
||||
database: "{{ app_name }}"
|
||||
user: "{{ app_name }}"
|
4
roles/apps/dbgate/defaults/main.yml
Normal file
4
roles/apps/dbgate/defaults/main.yml
Normal file
@ -0,0 +1,4 @@
|
||||
docker_dir: "/data/docker/dbgate"
|
||||
port: "6001"
|
||||
app_port: "3000"
|
||||
container_name: "postgres"
|
19
roles/apps/dbgate/tasks/main.yml
Normal file
19
roles/apps/dbgate/tasks/main.yml
Normal file
@ -0,0 +1,19 @@
|
||||
- name: Create docker folder
|
||||
ansible.builtin.file:
|
||||
dest: "{{ docker_dir }}"
|
||||
state: directory
|
||||
mode: '0770'
|
||||
|
||||
- name: Put up the postgres container
|
||||
community.docker.docker_container:
|
||||
name: "{{container_name}}"
|
||||
image: postgres:17.4
|
||||
restart_policy: always
|
||||
state: started
|
||||
pull: true
|
||||
ports:
|
||||
- "{{ port }}:{{ app_port }}"
|
||||
env:
|
||||
CONNECTIONS: postgres_con
|
||||
volumes:
|
||||
- "dbgate-data:/root/.dbgate"
|
0
roles/docker/install/defaults/main.yml
Executable file
0
roles/docker/install/defaults/main.yml
Executable file
45
roles/docker/install/tasks/main.yml
Executable file
45
roles/docker/install/tasks/main.yml
Executable file
@ -0,0 +1,45 @@
|
||||
---
|
||||
- name: Update apt cache
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
|
||||
- name: Install prerequisite packages
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- ca-certificates
|
||||
- curl
|
||||
state: present
|
||||
|
||||
- name: Create apt keyrings directory
|
||||
ansible.builtin.file:
|
||||
path: /etc/apt/keyrings
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Download Docker GPG key
|
||||
ansible.builtin.get_url:
|
||||
url: "https://download.docker.com/linux/ubuntu/gpg"
|
||||
dest: /etc/apt/keyrings/docker.asc
|
||||
mode: '0644'
|
||||
|
||||
- name: Add Docker apt repository
|
||||
ansible.builtin.apt_repository:
|
||||
repo: "deb [arch={{ docker_arch }} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
|
||||
filename: docker
|
||||
state: present
|
||||
vars:
|
||||
docker_arch: "{{ ansible_architecture | regex_replace('x86_64', 'amd64') }}"
|
||||
|
||||
- name: Update apt cache after adding Docker repository
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
|
||||
- name: Install Docker packages
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
- containerd.io
|
||||
- docker-buildx-plugin
|
||||
- docker-compose-plugin
|
||||
state: present
|
0
roles/docker/portainer/defaults/main.yml
Executable file
0
roles/docker/portainer/defaults/main.yml
Executable file
22
roles/docker/portainer/tasks/main.yml
Executable file
22
roles/docker/portainer/tasks/main.yml
Executable file
@ -0,0 +1,22 @@
|
||||
- name: Pull Portainer Agent image
|
||||
become: true
|
||||
community.docker.docker_image:
|
||||
name: portainer/agent
|
||||
tag: latest
|
||||
source: pull
|
||||
|
||||
- name: Deploy Portainer Agent container
|
||||
become: true
|
||||
community.docker.docker_container:
|
||||
name: portainer_agent
|
||||
image: portainer/agent
|
||||
pull: false # we already pulled above
|
||||
state: started
|
||||
restart_policy: always
|
||||
ports:
|
||||
- "9001:9001"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /var/lib/docker/volumes:/var/lib/docker/volumes
|
||||
- /:/host
|
||||
timeout: 120 # wait up to 2m for it to come up
|
2
roles/docker/stack/defaults/main.yml
Executable file
2
roles/docker/stack/defaults/main.yml
Executable file
@ -0,0 +1,2 @@
|
||||
apps: []
|
||||
stack_name: "willneverexist"
|
27
roles/docker/stack/tasks/main.yml
Executable file
27
roles/docker/stack/tasks/main.yml
Executable file
@ -0,0 +1,27 @@
|
||||
---
|
||||
- name: Create app mount directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ remote_app_mounts }}/{{ item }}"
|
||||
state: directory
|
||||
mode: '0777'
|
||||
loop: "{{ apps }}"
|
||||
|
||||
- name: Create stack directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ remote_stacks }}/{{ stack_name }}"
|
||||
state: directory
|
||||
mode: '0777'
|
||||
|
||||
- name: Copy docker-compose.yml to server
|
||||
ansible.builtin.copy:
|
||||
src: '{{ docker_stacks }}/{{ stack_name }}/docker-compose.yml'
|
||||
dest: '{{ remote_stacks }}/{{ stack_name }}/docker-compose.yml'
|
||||
owner: javi
|
||||
group: javi
|
||||
mode: '0777'
|
||||
|
||||
- name: Start up the containers
|
||||
ansible.builtin.command: docker compose up -d
|
||||
become: true
|
||||
args:
|
||||
chdir: "{{ remote_stacks }}/{{ stack_name }}"
|
0
roles/postgres/database/defaults/main.yml
Executable file
0
roles/postgres/database/defaults/main.yml
Executable file
10
roles/postgres/database/tasks/main.yml
Executable file
10
roles/postgres/database/tasks/main.yml
Executable file
@ -0,0 +1,10 @@
|
||||
---
|
||||
- name: Create database
|
||||
delegate_to: localhost
|
||||
community.postgresql.postgresql_db:
|
||||
name: "{{ database }}"
|
||||
state: present
|
||||
login_host: "{{ pg_host }}"
|
||||
login_port: "{{ pg_port }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
login_password: "{{ pg_password }}"
|
1
roles/postgres/priviledges/defaults/main.yml
Executable file
1
roles/postgres/priviledges/defaults/main.yml
Executable file
@ -0,0 +1 @@
|
||||
priviledges: ALL
|
28
roles/postgres/priviledges/tasks/main.yml
Executable file
28
roles/postgres/priviledges/tasks/main.yml
Executable file
@ -0,0 +1,28 @@
|
||||
---
|
||||
- name: Grant database-level privileges on "{{ database }}"
|
||||
delegate_to: localhost
|
||||
community.postgresql.postgresql_privs:
|
||||
db: "{{ database }}"
|
||||
type: database
|
||||
objs: "{{ database }}"
|
||||
privs: "CREATE"
|
||||
role: "{{ user }}"
|
||||
state: present
|
||||
login_host: "{{ pg_host }}"
|
||||
login_port: "{{ pg_port }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
login_password: "{{ pg_password }}"
|
||||
|
||||
- name: Give user full priviledges on database
|
||||
delegate_to: localhost
|
||||
community.postgresql.postgresql_privs:
|
||||
db: "{{ database }}"
|
||||
type: schema
|
||||
objs: public
|
||||
privs: "{{ priviledges }}"
|
||||
role: "{{ user }}"
|
||||
state: present
|
||||
login_host: "{{ pg_host }}"
|
||||
login_port: "{{ pg_port }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
login_password: "{{ pg_password }}"
|
1
roles/postgres/user/defaults/main.yml
Executable file
1
roles/postgres/user/defaults/main.yml
Executable file
@ -0,0 +1 @@
|
||||
password: "password"
|
11
roles/postgres/user/tasks/main.yml
Executable file
11
roles/postgres/user/tasks/main.yml
Executable file
@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Create postgres user
|
||||
delegate_to: localhost
|
||||
community.postgresql.postgresql_user:
|
||||
name: "{{ user }}"
|
||||
password: "{{ password }}"
|
||||
state: present
|
||||
login_host: "{{ pg_host }}"
|
||||
login_port: "{{ pg_port }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
login_password: "{{ pg_password }}"
|
0
roles/provision/alma/common/defaults/main.yml
Normal file
0
roles/provision/alma/common/defaults/main.yml
Normal file
0
roles/provision/alma/common/handlers/main.yml
Normal file
0
roles/provision/alma/common/handlers/main.yml
Normal file
26
roles/provision/alma/common/tasks/main.yml
Normal file
26
roles/provision/alma/common/tasks/main.yml
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
- name: Set system timezone
|
||||
ansible.builtin.command: timedatectl set-timezone "America/Denver"
|
||||
register: output
|
||||
changed_when: output.rc != 0
|
||||
|
||||
- name: Set hostname
|
||||
ansible.builtin.hostname:
|
||||
name: "{{ hostname }}"
|
||||
|
||||
- name: Set repo
|
||||
ansible.builtin.dnf:
|
||||
|
||||
- name: Install baseline packages
|
||||
ansible.builtin.dnf:
|
||||
name:
|
||||
- '@Development tools'
|
||||
- vim
|
||||
- curl
|
||||
- git
|
||||
- bash-completion
|
||||
- firewalld
|
||||
# - fastfetch
|
||||
# - btop
|
||||
state: present
|
||||
update_cache: true
|
0
roles/provision/alma/common/templates/main.yml
Normal file
0
roles/provision/alma/common/templates/main.yml
Normal file
0
roles/provision/alma/docker/defaults/main.yml
Normal file
0
roles/provision/alma/docker/defaults/main.yml
Normal file
0
roles/provision/alma/docker/handlers/main.yml
Normal file
0
roles/provision/alma/docker/handlers/main.yml
Normal file
18
roles/provision/alma/docker/tasks/main.yml
Normal file
18
roles/provision/alma/docker/tasks/main.yml
Normal file
@ -0,0 +1,18 @@
|
||||
- name: Add Docker repository
|
||||
ansible.builtin.get_url:
|
||||
url: https://download.docker.com/linux/centos/docker-ce.repo
|
||||
dest: /etc/yum.repos.d/docker-ce.repo
|
||||
|
||||
- name: Install Docker packages
|
||||
ansible.builtin.dnf:
|
||||
name:
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
- containerd.io
|
||||
state: present
|
||||
|
||||
- name: Enable and start Docker
|
||||
ansible.builtin.service:
|
||||
name: docker
|
||||
enabled: yes
|
||||
state: started
|
0
roles/provision/alma/docker/templates/main.yml
Normal file
0
roles/provision/alma/docker/templates/main.yml
Normal file
0
roles/provision/alma/firewall/defaults/main.yml
Normal file
0
roles/provision/alma/firewall/defaults/main.yml
Normal file
0
roles/provision/alma/firewall/handlers/main.yml
Normal file
0
roles/provision/alma/firewall/handlers/main.yml
Normal file
5
roles/provision/alma/firewall/tasks/main.yml
Normal file
5
roles/provision/alma/firewall/tasks/main.yml
Normal file
@ -0,0 +1,5 @@
|
||||
- name: Enable and start firewalld
|
||||
ansible.builtin.service:
|
||||
name: firewalld
|
||||
enabled: yes
|
||||
state: started
|
0
roles/provision/alma/firewall/templates/main.yml
Normal file
0
roles/provision/alma/firewall/templates/main.yml
Normal file
0
roles/provision/alma/network/defaults/main.yml
Normal file
0
roles/provision/alma/network/defaults/main.yml
Normal file
0
roles/provision/alma/network/handlers/main.yml
Normal file
0
roles/provision/alma/network/handlers/main.yml
Normal file
12
roles/provision/alma/network/tasks/main.yml
Normal file
12
roles/provision/alma/network/tasks/main.yml
Normal file
@ -0,0 +1,12 @@
|
||||
- name: Configure static network
|
||||
ansible.builtin.template:
|
||||
src: ifcfg-template.j2
|
||||
dest: "/etc/sysconfig/network-scripts/ifcfg-{{ network_config.interface }}"
|
||||
notify: Restart network
|
||||
|
||||
- name: Ensure NetworkManager is enabled
|
||||
ansible.builtin.service:
|
||||
name: NetworkManager
|
||||
enabled: true
|
||||
state: restarted
|
||||
|
6
roles/provision/alma/network/templates/ifcfg-template.j2
Normal file
6
roles/provision/alma/network/templates/ifcfg-template.j2
Normal file
@ -0,0 +1,6 @@
|
||||
DEVICE={{ network_config.interface }}
|
||||
BOOTPROTO=none
|
||||
ONBOOT=yes
|
||||
IPADDR={{ network_config.address }}
|
||||
NETMASK={{ network_config.netmask }}
|
||||
GATEWAY={{ network_config.gateway }}
|
0
roles/provision/alma/network/templates/main.yml
Normal file
0
roles/provision/alma/network/templates/main.yml
Normal file
0
roles/provision/alma/nfs/defaults/main.yml
Normal file
0
roles/provision/alma/nfs/defaults/main.yml
Normal file
0
roles/provision/alma/nfs/handlers/main.yml
Normal file
0
roles/provision/alma/nfs/handlers/main.yml
Normal file
22
roles/provision/alma/nfs/tasks/main.yml
Normal file
22
roles/provision/alma/nfs/tasks/main.yml
Normal file
@ -0,0 +1,22 @@
|
||||
- name: Install NFS client
|
||||
ansible.builtin.dnf:
|
||||
name: nfs-utils
|
||||
state: present
|
||||
|
||||
- name: Create mount points
|
||||
ansible.builtin.file:
|
||||
path: "{{ item.path }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0755'
|
||||
loop: "{{ nfs_mounts }}"
|
||||
|
||||
- name: Mount NFS shares
|
||||
ansible.posix.mount:
|
||||
src: "{{ item.src }}"
|
||||
path: "{{ item.path }}"
|
||||
fstype: nfs
|
||||
opts: "{{ item.opts }}"
|
||||
state: mounted
|
||||
loop: "{{ nfs_mounts }}"
|
0
roles/provision/alma/nfs/templates/main.yml
Normal file
0
roles/provision/alma/nfs/templates/main.yml
Normal file
0
roles/pve/cluster_prep/defaults/main.yml
Normal file
0
roles/pve/cluster_prep/defaults/main.yml
Normal file
108
roles/pve/cluster_prep/tasks/main.yml
Normal file
108
roles/pve/cluster_prep/tasks/main.yml
Normal file
@ -0,0 +1,108 @@
|
||||
---
|
||||
# - name: Set hostname
|
||||
# hostname:
|
||||
# name: "{{ inventory_hostname }}"
|
||||
# - name: Disable Proxmox Enterprise repo
|
||||
# lineinfile:
|
||||
# path: /etc/apt/sources.list.d/pve-enterprise.list
|
||||
# regexp: '^deb'
|
||||
# line: '# deb ...'
|
||||
# state: present
|
||||
# ignore_errors: yes # In case the file doesn't exist
|
||||
|
||||
- name: Find all sources.list.d files
|
||||
find:
|
||||
paths: /etc/apt/sources.list.d
|
||||
patterns: "*.list"
|
||||
file_type: file
|
||||
register: list_files
|
||||
|
||||
- name: Comment out any line with 'enterprise' in each file
|
||||
lineinfile:
|
||||
path: "{{ item.path }}"
|
||||
regexp: '^(?!#).*enterprise'
|
||||
line: '# \g<0>'
|
||||
backrefs: yes
|
||||
state: present
|
||||
loop: "{{ list_files.files }}"
|
||||
|
||||
- name: Overwrite sources.list with Proxmox-recommended repos
|
||||
copy:
|
||||
dest: /etc/apt/sources.list
|
||||
content: |
|
||||
deb http://ftp.debian.org/debian bookworm main contrib
|
||||
deb http://ftp.debian.org/debian bookworm-updates main contrib
|
||||
|
||||
# Proxmox VE pve-no-subscription repository provided by proxmox.com,
|
||||
# NOT recommended for production use
|
||||
deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription
|
||||
|
||||
# security updates
|
||||
deb http://security.debian.org/debian-security bookworm-security main contrib
|
||||
mode: '0644'
|
||||
|
||||
- name: Add Proxmox no-subscription repo to sources.list.d
|
||||
copy:
|
||||
dest: /etc/apt/sources.list.d/pve-no-subscription.list
|
||||
content: |
|
||||
deb http://download.proxmox.com/debian/pve bullseye pve-no-subscription
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
|
||||
- name: Update apt cache
|
||||
apt:
|
||||
update_cache: yes
|
||||
|
||||
|
||||
- name: Update /etc/hosts with all PVE nodes
|
||||
template:
|
||||
src: hosts.j2
|
||||
dest: /etc/hosts
|
||||
mode: "0644"
|
||||
|
||||
- name: Ensure search domain and nameserver set properly
|
||||
template:
|
||||
src: resolv.j2
|
||||
dest: /etc/resolv.conf
|
||||
mode: "0644"
|
||||
|
||||
- name: Ensure chrony is installed
|
||||
apt:
|
||||
name: chrony
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
- name: Enable and start chronyd
|
||||
service:
|
||||
name: chrony
|
||||
state: started
|
||||
enabled: yes
|
||||
|
||||
- name: Discover iSCSI targets from TrueNAS
|
||||
shell: |
|
||||
iscsiadm -m discovery -t st -p {{ iscsi_target_ip }}
|
||||
register: iscsi_discovery
|
||||
changed_when: false
|
||||
|
||||
- name: Login to discovered iSCSI target (unauthenticated)
|
||||
shell: |
|
||||
iscsiadm -m node -T {{ iscsi_target_iqn }} -p {{ iscsi_target_ip }} --login
|
||||
register: iscsi_login
|
||||
changed_when: "'Login to' in iscsi_login.stdout or 'already present' in iscsi_login.stdout"
|
||||
|
||||
- name: Make iSCSI login persistent across reboots
|
||||
shell: |
|
||||
iscsiadm -m node -T {{ iscsi_target_iqn }} -p {{ iscsi_target_ip }} --op update -n node.startup -v automatic
|
||||
changed_when: false
|
||||
|
||||
# - name: Ensure vg_ha exists
|
||||
# command: vgs vg_ha
|
||||
# register: vg_result
|
||||
# failed_when: vg_result.rc != 0
|
||||
# changed_when: false
|
||||
|
||||
# - name: Debug VG presence
|
||||
# debug:
|
||||
# msg: "VG 'vg_ha' found on {{ inventory_hostname }}"
|
6
roles/pve/cluster_prep/templates/hosts.j2
Normal file
6
roles/pve/cluster_prep/templates/hosts.j2
Normal file
@ -0,0 +1,6 @@
|
||||
127.0.0.1 localhost
|
||||
{% for host in groups['pve-nodes'] %}
|
||||
{{ hostvars[host]['ansible_default_ipv4']['address'] }} {{ host }} {{ host }}.lan.xbazzi.com
|
||||
{{ hostvars[host]['cluster_ip'] }} {{ host }}-cluster
|
||||
{% endfor %}
|
||||
|
2
roles/pve/cluster_prep/templates/resolv.j2
Normal file
2
roles/pve/cluster_prep/templates/resolv.j2
Normal file
@ -0,0 +1,2 @@
|
||||
search lan.xbazzi.com
|
||||
nameserver 10.133.7.1
|
0
roles/pve/pve_backup/defaults/main.yml
Normal file
0
roles/pve/pve_backup/defaults/main.yml
Normal file
26
roles/pve/pve_backup/tasks/main.yml
Normal file
26
roles/pve/pve_backup/tasks/main.yml
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
- name: Copy backup script to PVE node
|
||||
template:
|
||||
src: backup_pve_config.sh.j2
|
||||
dest: /home/xbazzi/backup_pve.sh
|
||||
mode: '0755'
|
||||
|
||||
- name: Run backup script
|
||||
shell: /home/xbazzi/backup_pve.sh
|
||||
|
||||
- name: Find most recent backup directory
|
||||
shell: "ls -td /home/xbazzi/pve_backup_* | head -1"
|
||||
register: latest_backup_dir
|
||||
changed_when: false
|
||||
|
||||
- name: Archive backup folder
|
||||
archive:
|
||||
path: "{{ latest_backup_dir.stdout }}"
|
||||
dest: "{{ latest_backup_dir.stdout }}.tar.gz"
|
||||
format: gz
|
||||
|
||||
- name: Fetch backup archive to control machine
|
||||
fetch:
|
||||
src: "{{ latest_backup_dir.stdout }}.tar.gz"
|
||||
dest: "backups/{{ inventory_hostname }}.tar.gz"
|
||||
flat: yes
|
23
roles/pve/pve_backup/templates/backup_pve_config.sh.j2
Normal file
23
roles/pve/pve_backup/templates/backup_pve_config.sh.j2
Normal file
@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
|
||||
BACKUP_DIR="/home/xbazzi/pve_backup_${TIMESTAMP}"
|
||||
NODE_NAME=$(hostname)
|
||||
|
||||
echo "🔒 Creating backup directory at $BACKUP_DIR..."
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
echo "📁 Backing up /etc/pve..."
|
||||
cp -a /etc/pve "$BACKUP_DIR/etc_pve"
|
||||
|
||||
echo "📄 Saving VM and container config files..."
|
||||
mkdir -p "$BACKUP_DIR/qemu-server" "$BACKUP_DIR/lxc"
|
||||
cp -a /etc/pve/qemu-server/*.conf "$BACKUP_DIR/qemu-server/" 2>/dev/null || true
|
||||
cp -a /etc/pve/lxc/*.conf "$BACKUP_DIR/lxc/" 2>/dev/null || true
|
||||
|
||||
echo "💽 Saving storage.cfg..."
|
||||
cp -a /etc/pve/storage.cfg "$BACKUP_DIR/" 2>/dev/null || true
|
||||
|
||||
echo "📦 Backup complete on $NODE_NAME."
|
||||
echo "🗃️ Location: $BACKUP_DIR"
|
0
roles/pve/setup_networking/defaults/main.yml
Normal file
0
roles/pve/setup_networking/defaults/main.yml
Normal file
5
roles/pve/setup_networking/handlers/main.yml
Normal file
5
roles/pve/setup_networking/handlers/main.yml
Normal file
@ -0,0 +1,5 @@
|
||||
# - name: Restart networking
|
||||
# ansible.builtin.systemd:
|
||||
# name: networking
|
||||
# state: restarted
|
||||
|
46
roles/pve/setup_networking/tasks/main.yml
Normal file
46
roles/pve/setup_networking/tasks/main.yml
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
- name: Set up network interfaces for new PVE node
|
||||
template:
|
||||
src: interfaces-xbazzi.j2
|
||||
# dest: /etc/network/interfaces.d/interfaces-xbazzi
|
||||
dest: /etc/network/interfaces
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
|
||||
- name: Apply correct permissions to interfaces.d
|
||||
file:
|
||||
path: "/etc/network/interfaces.d"
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Find all files in the directory
|
||||
ansible.builtin.find:
|
||||
paths: /etc/network/interfaces.d/
|
||||
file_type: file
|
||||
register: files_to_delete
|
||||
|
||||
- name: Delete all files
|
||||
ansible.builtin.file:
|
||||
path: "{{ item.path }}"
|
||||
state: absent
|
||||
loop: "{{ files_to_delete.files }}"
|
||||
|
||||
- name: Update /etc/hosts with all PVE nodes
|
||||
template:
|
||||
src: hosts.j2
|
||||
dest: /etc/hosts
|
||||
mode: "0644"
|
||||
|
||||
- name: Ensure search domain and nameserver set properly
|
||||
template:
|
||||
src: resolv.j2
|
||||
dest: /etc/resolv.conf
|
||||
mode: "0644"
|
||||
|
||||
|
||||
- name: Restart networking
|
||||
ansible.builtin.systemd:
|
||||
name: networking
|
||||
state: restarted
|
6
roles/pve/setup_networking/templates/hosts.j2
Normal file
6
roles/pve/setup_networking/templates/hosts.j2
Normal file
@ -0,0 +1,6 @@
|
||||
127.0.0.1 localhost
|
||||
{% for host in groups['pve-nodes'] %}
|
||||
{{ hostvars[host]['ansible_default_ipv4']['address'] }} {{ host }} {{ host }}.lan.xbazzi.com
|
||||
{{ hostvars[host]['cluster_ip'] }} {{ host }}-cluster
|
||||
{% endfor %}
|
||||
|
48
roles/pve/setup_networking/templates/interfaces-xbazzi.j2
Normal file
48
roles/pve/setup_networking/templates/interfaces-xbazzi.j2
Normal file
@ -0,0 +1,48 @@
|
||||
auto eno1
|
||||
iface eno1 inet manual
|
||||
mtu 1500
|
||||
|
||||
auto enp1s0f0
|
||||
iface enp1s0f0 inet manual
|
||||
mtu 9000
|
||||
|
||||
iface enp1s0f1 inet manual
|
||||
mtu 9000
|
||||
|
||||
# Mgmt interface
|
||||
auto vmbr0
|
||||
iface vmbr0 inet static
|
||||
address {{ vmbr0_ip }}/22
|
||||
bridge-ports eno1
|
||||
bridge-stp off
|
||||
bridge-fd 0
|
||||
mtu 1500
|
||||
|
||||
auto vmbr1
|
||||
iface vmbr1 inet manual
|
||||
bridge-ports enp1s0f0
|
||||
bridge-stp off
|
||||
bridge-fd 0
|
||||
bridge-vlan-aware yes
|
||||
bridge-vids 2-4094
|
||||
mtu 9000
|
||||
|
||||
# Prod interface
|
||||
auto vmbr1.1337
|
||||
iface vmbr1.1337 inet static
|
||||
address {{ vmbr1_1337_ip }}/22
|
||||
gateway 10.133.7.1
|
||||
mtu 9000
|
||||
|
||||
# DMZ interface
|
||||
auto vmbr1.666
|
||||
iface vmbr1.666 inet static
|
||||
address {{ vmbr1_666_ip }}/22
|
||||
mtu 1500
|
||||
|
||||
# Cluster network
|
||||
auto {{ cluster_iface }}
|
||||
iface {{ cluster_iface }} inet static
|
||||
address {{ cluster_ip }}/28
|
||||
mtu 1500
|
||||
|
2
roles/pve/setup_networking/templates/resolv.j2
Normal file
2
roles/pve/setup_networking/templates/resolv.j2
Normal file
@ -0,0 +1,2 @@
|
||||
search lan.xbazzi.com
|
||||
nameserver 10.133.7.1
|
0
roles/server/ftp/defaults/main.yml
Executable file
0
roles/server/ftp/defaults/main.yml
Executable file
23
roles/server/ftp/tasks/main.yml
Executable file
23
roles/server/ftp/tasks/main.yml
Executable file
@ -0,0 +1,23 @@
|
||||
---
|
||||
- name: Update apt cache
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
|
||||
- name: Install proftpd package
|
||||
ansible.builtin.apt:
|
||||
name: proftpd
|
||||
state: present
|
||||
|
||||
- name: Ensure proftpd is enabled and started
|
||||
ansible.builtin.service:
|
||||
name: proftpd
|
||||
state: started
|
||||
enabled: true
|
||||
become: true
|
||||
|
||||
- name: Allow FTP through UFW firewall (if UFW is enabled)
|
||||
community.general.ufw:
|
||||
rule: allow
|
||||
port: 21
|
||||
proto: tcp
|
||||
ignore_errors: false
|
0
roles/server/sshkey/defaults/main.yml
Executable file
0
roles/server/sshkey/defaults/main.yml
Executable file
6
roles/server/sshkey/tasks/main.yml
Executable file
6
roles/server/sshkey/tasks/main.yml
Executable file
@ -0,0 +1,6 @@
|
||||
---
|
||||
- name: Add SSH key for remote user
|
||||
ansible.posix.authorized_key:
|
||||
user: javi
|
||||
state: present
|
||||
key: "{{ lookup('file', '/home/javi/.ssh/homelab_keypair_ed25519.pub') }}"
|
5
roles/services/postgres/defaults/main.yml
Normal file
5
roles/services/postgres/defaults/main.yml
Normal file
@ -0,0 +1,5 @@
|
||||
directory: "postgres"
|
||||
default_user: "postgres"
|
||||
default_password: "password"
|
||||
port: "5432"
|
||||
container_name: "postgres"
|
23
roles/services/postgres/tasks/main.yml
Normal file
23
roles/services/postgres/tasks/main.yml
Normal file
@ -0,0 +1,23 @@
|
||||
- name: Create data folder
|
||||
ansible.builtin.file:
|
||||
dest: "{{ docker_dir }}/{{ directory }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: docker
|
||||
mode: '0770'
|
||||
recurse: yes
|
||||
|
||||
- name: Put up the postgres container
|
||||
community.docker.docker_container:
|
||||
name: "{{container_name}}"
|
||||
image: postgres:17.4
|
||||
restart_policy: always
|
||||
state: started
|
||||
pull: true
|
||||
ports:
|
||||
- "{{ port }}:5432"
|
||||
env:
|
||||
POSTGRES_USER: "{{ default_user }}"
|
||||
POSTGRES_PASSWORD: "{{ default_password }}"
|
||||
volumes:
|
||||
- "{{ docker_dir }}/{{ directory }}/data:/var/lib/postgresql/data/"
|
3
roles/util/mount_nfs/defaults/main.yml
Executable file
3
roles/util/mount_nfs/defaults/main.yml
Executable file
@ -0,0 +1,3 @@
|
||||
mount_host: "{{ hostvars['nas'].ansible_host }}"
|
||||
share: "/mnt/ALEXANDRIA/"
|
||||
mount_path: "/mnt/unspecifiedshare"
|
21
roles/util/mount_nfs/tasks/main.yml
Executable file
21
roles/util/mount_nfs/tasks/main.yml
Executable file
@ -0,0 +1,21 @@
|
||||
---
|
||||
- name: Ensure NFS client is installed
|
||||
ansible.builtin.package:
|
||||
name: nfs-common
|
||||
state: present
|
||||
become: true
|
||||
|
||||
- name: Create mount point directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ mount_path }}"
|
||||
state: directory
|
||||
mode: '0777'
|
||||
become: true
|
||||
|
||||
- name: Mount share
|
||||
ansible.posix.mount:
|
||||
src: "{{ mount_host }}:{{ share }}"
|
||||
path: "{{ mount_path }}"
|
||||
fstype: nfs
|
||||
state: mounted
|
||||
become: true
|
28
setup.sh
Executable file
28
setup.sh
Executable file
@ -0,0 +1,28 @@
|
||||
echo "**Deleting .git so you can start your own repo"
|
||||
rm -rf .git
|
||||
echo "***Ansible vault password***"
|
||||
echo "This is used to encrypt/descrypt secrets in your vault"
|
||||
echo "We'll save it to a file in ~/.[file name] so it doesn't have to be typed every time"
|
||||
echo
|
||||
read -p "File name (no . prefix): " ansible_vault_pass_filename
|
||||
read -s -p "Password: " ansible_vault_pass
|
||||
|
||||
echo $ansible_vault_pass > ~/.$ansible_vault_pass_filename
|
||||
echo "vault_password_file = ~/.$ansible_vault_pass_filename" >>ansible.cfg
|
||||
|
||||
echo
|
||||
echo
|
||||
|
||||
echo "***Ansible become password***"
|
||||
echo "A lot of actions need sudo. This password will be stored in group_vars/all.yml encrypted"
|
||||
read -s -p "Password: " ansible_become_pass
|
||||
echo "# Sudo password for your servers" >>./group_vars/all.yml
|
||||
ansible-vault encrypt_string "$ansible_become_pass" --name 'ansible_become_pass' >>./group_vars/all.yml
|
||||
|
||||
echo
|
||||
echo
|
||||
|
||||
echo "Setup complete"
|
||||
echo "You can delete setup.sh since running it again would cause issues"
|
||||
echo "Config for vault password was output to ./ansible.cfg"
|
||||
echo "Config for sudo (become) password was output to ./group_vars/all.yml"
|
Loading…
x
Reference in New Issue
Block a user