init
This commit is contained in:
commit
ca334ee303
25
Readme.md
Normal file
25
Readme.md
Normal file
@ -0,0 +1,25 @@
|
||||
# Ganeti cluster deployment using Ansible
|
||||
Setup a Ganeti cluster on Debian VMs.
|
||||
|
||||
## How to use
|
||||
- First, edit the inventory file.
|
||||
- Disable secure boot (if using UEFI).
|
||||
- Then:
|
||||
```sh
|
||||
# allow ansible to use the ssh key
|
||||
ssh-agent $SHELL
|
||||
ssh-add ~/.ssh/id_rsa
|
||||
|
||||
# setup nodes
|
||||
ansible-playbook -i inventory -u root node.yml
|
||||
|
||||
# setup master
|
||||
ansible-playbook -i inventory -u root master.yml
|
||||
|
||||
# setup workers
|
||||
ansible-playbook -i inventory -u root worker.yml
|
||||
```
|
||||
|
||||
## Features
|
||||
- static IP using systemd-networkd (using the last IP of the server before running the playbook)
|
||||
- zfs extstorage
|
46
group_vars/all.yml
Normal file
46
group_vars/all.yml
Normal file
@ -0,0 +1,46 @@
|
||||
packages:
|
||||
- git
|
||||
- lvm2
|
||||
- linux-headers-amd64
|
||||
- zfs-dkms
|
||||
- zfsutils-linux
|
||||
- ganeti
|
||||
- drbd-utils
|
||||
- socat
|
||||
- python3
|
||||
- systemd-resolved # needs to be the last one
|
||||
# breaks dns resolution until
|
||||
# systemd-networkd is configured
|
||||
|
||||
# network
|
||||
cluster_name: cluster.ganeti
|
||||
|
||||
interface_name: lan0
|
||||
bridge_name: xenbr0
|
||||
mac_prefix: "02:42:ac"
|
||||
gateway: "192.168.50.254"
|
||||
dns_servers:
|
||||
- "192.168.11.1"
|
||||
- "1.1.1.1"
|
||||
|
||||
# hostnames:
|
||||
# - ip: x.x.x.x
|
||||
# name: example
|
||||
# ...
|
||||
hostnames:
|
||||
- ip: "192.168.50.30"
|
||||
name: "{{ cluster_name }}"
|
||||
- ip: "192.168.50.31"
|
||||
name: test-31.ganeti
|
||||
- ip: "192.168.50.32"
|
||||
name: test-32.ganeti
|
||||
- ip: "192.168.50.33"
|
||||
name: test-33.ganeti
|
||||
|
||||
# storage
|
||||
zpool_name: ganeti-pool
|
||||
zpool_dev: /dev/vdc
|
||||
|
||||
vg_name: xenvg
|
||||
pvs:
|
||||
- /dev/vdb
|
9
inventory
Normal file
9
inventory
Normal file
@ -0,0 +1,9 @@
|
||||
[nodes]
|
||||
192.168.50.20
|
||||
192.168.50.21
|
||||
|
||||
[master]
|
||||
192.168.50.20
|
||||
|
||||
[workers]
|
||||
192.168.50.21
|
6
master.yml
Normal file
6
master.yml
Normal file
@ -0,0 +1,6 @@
|
||||
- name: Cluster master setup
|
||||
hosts: master
|
||||
become: true
|
||||
gather_facts: true
|
||||
roles:
|
||||
- master
|
6
node.yml
Normal file
6
node.yml
Normal file
@ -0,0 +1,6 @@
|
||||
- name: Cluster node setup
|
||||
hosts: nodes
|
||||
become: true
|
||||
gather_facts: true
|
||||
roles:
|
||||
- node
|
37
roles/master/tasks/main.yml
Normal file
37
roles/master/tasks/main.yml
Normal file
@ -0,0 +1,37 @@
|
||||
- name: Check if the cluster is intalized
|
||||
ansible.builtin.command:
|
||||
cmd: gnt-cluster info
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
register: ganeti_cluster_initalized
|
||||
|
||||
- name: Initalize cluster
|
||||
ansible.builtin.command:
|
||||
cmd: |-
|
||||
gnt-cluster init
|
||||
--enabled-hypervisors kvm
|
||||
--no-etc-hosts
|
||||
--master-netdev {{ bridge_name }}
|
||||
--nic-parameters link={{ bridge_name }},mode=bridged
|
||||
--enabled-disk-templates drbd,plain
|
||||
{{ cluster_name }}
|
||||
register: ganeti_cluster_init_result
|
||||
changed_when: ganeti_cluster_init_result.rc == 0
|
||||
when: ganeti_cluster_initalized.rc != 0
|
||||
|
||||
- name: Add worker {{ item }}
|
||||
ansible.builtin.command:
|
||||
cmd: |-
|
||||
bash -c "
|
||||
(gnt-node list | grep 'ganeti-{{ groups['nodes'].index(item) + 1 }}.ganeti') || \
|
||||
gnt-node add \
|
||||
--no-ssh-key-check \
|
||||
--no-node-setup \
|
||||
ganeti-{{ groups['nodes'].index(item) + 1 }}.ganeti"
|
||||
register: node_add_result
|
||||
changed_when: node_add_result.rc == 0
|
||||
loop: "{{ groups['workers'] }}"
|
||||
|
||||
- name: Install ZFS extstorage
|
||||
ansible.builtin.include_role:
|
||||
name: zfs-extstorage
|
0
roles/node/defaults/main.yml
Normal file
0
roles/node/defaults/main.yml
Normal file
12
roles/node/handlers/main.yml
Normal file
12
roles/node/handlers/main.yml
Normal file
@ -0,0 +1,12 @@
|
||||
- name: Update initramfs
|
||||
listen:
|
||||
- update initramfs
|
||||
- update initrd
|
||||
ansible.builtin.command:
|
||||
cmd: >
|
||||
update-initramfs -k all -u
|
||||
|
||||
- name: Reboot
|
||||
listen:
|
||||
- reboot
|
||||
ansible.builtin.reboot:
|
11
roles/node/tasks/hostnames.yml
Normal file
11
roles/node/tasks/hostnames.yml
Normal file
@ -0,0 +1,11 @@
|
||||
- name: Set hostname
|
||||
ansible.builtin.template:
|
||||
src: etc-hostname.j2
|
||||
dest: /etc/hostname
|
||||
mode: "0644"
|
||||
|
||||
- name: Set hosts
|
||||
ansible.builtin.template:
|
||||
src: etc-hosts.j2
|
||||
dest: /etc/hosts
|
||||
mode: "0644"
|
35
roles/node/tasks/keys.yml
Normal file
35
roles/node/tasks/keys.yml
Normal file
@ -0,0 +1,35 @@
|
||||
- name: Check if node has a key
|
||||
ansible.builtin.stat:
|
||||
path: /root/.ssh/id_rsa.pub
|
||||
register: key_check
|
||||
|
||||
- name: Generate an OpenSSH keypair
|
||||
community.crypto.openssh_keypair:
|
||||
path: /root/.ssh/id_rsa
|
||||
when: not key_check.stat.exists
|
||||
|
||||
- name: Fetch keys to local machine
|
||||
ansible.builtin.fetch:
|
||||
src: /root/.ssh/id_rsa.pub
|
||||
dest: /tmp/fetched_keys/
|
||||
|
||||
- name: Copy keys
|
||||
ansible.builtin.copy:
|
||||
src: /tmp/fetched_keys
|
||||
dest: /tmp
|
||||
mode: "0644"
|
||||
|
||||
- name: Add key to authorized_keys
|
||||
ansible.posix.authorized_key:
|
||||
user: root
|
||||
state: present
|
||||
key: "{{ lookup('file', '/tmp/fetched_keys/' + item + '/root/.ssh/id_rsa.pub') }}"
|
||||
loop: "{{ groups['nodes'] }}"
|
||||
|
||||
- name: Add key to known_hosts
|
||||
ansible.builtin.known_hosts:
|
||||
path: /root/.ssh/known_hosts
|
||||
name: "ganeti-{{ groups['nodes'].index(item) + 1 }}.ganeti"
|
||||
key: "ganeti-{{ groups['nodes'].index(item) + 1 }}.ganeti {{ lookup('file', '/tmp/fetched_keys/' + item + '/root/.ssh/id_rsa.pub') }}"
|
||||
state: present
|
||||
loop: "{{ groups['nodes'] }}"
|
27
roles/node/tasks/main.yml
Normal file
27
roles/node/tasks/main.yml
Normal file
@ -0,0 +1,27 @@
|
||||
- name: Update system
|
||||
ansible.builtin.include_tasks:
|
||||
file: update.yml
|
||||
|
||||
- name: Install packages
|
||||
ansible.builtin.include_tasks:
|
||||
file: packages.yml
|
||||
|
||||
- name: Set hostname
|
||||
ansible.builtin.include_tasks:
|
||||
file: hostnames.yml
|
||||
|
||||
- name: Configure network
|
||||
ansible.builtin.include_tasks:
|
||||
file: network.yml
|
||||
|
||||
- name: Enable modules
|
||||
ansible.builtin.include_tasks:
|
||||
file: modules.yml
|
||||
|
||||
- name: Create storages
|
||||
ansible.builtin.include_tasks:
|
||||
file: storage.yml
|
||||
|
||||
- name: Exchange keys
|
||||
ansible.builtin.include_tasks:
|
||||
file: keys.yml
|
18
roles/node/tasks/modules.yml
Normal file
18
roles/node/tasks/modules.yml
Normal file
@ -0,0 +1,18 @@
|
||||
- name: Enable ZFS
|
||||
community.general.modprobe:
|
||||
name: zfs
|
||||
state: present
|
||||
persistent: present
|
||||
|
||||
- name: Enable KVM
|
||||
community.general.modprobe:
|
||||
name: kvm
|
||||
state: present
|
||||
persistent: present
|
||||
|
||||
- name: Enable DRBD
|
||||
community.general.modprobe:
|
||||
name: drbd
|
||||
params: usermode_helper=/bin/true
|
||||
state: present
|
||||
persistent: present
|
69
roles/node/tasks/network.yml
Normal file
69
roles/node/tasks/network.yml
Normal file
@ -0,0 +1,69 @@
|
||||
- name: Check if default interface is configured
|
||||
ansible.builtin.set_fact:
|
||||
interface_configured: "{{ interface_name in ansible_interfaces }}"
|
||||
|
||||
- name: Check if bridge is configured
|
||||
ansible.builtin.set_fact:
|
||||
bridge_configured: "{{ bridge_name in ansible_interfaces }}"
|
||||
|
||||
- name: Configure default interface name
|
||||
ansible.builtin.template:
|
||||
src: etc-systemd-network-10-lan0.link.j2
|
||||
dest: /etc/systemd/network/10-{{ interface_name }}.link
|
||||
mode: "0644"
|
||||
when: not interface_configured
|
||||
notify:
|
||||
- update initramfs
|
||||
- reboot
|
||||
|
||||
- name: Create bridge interface
|
||||
ansible.builtin.template:
|
||||
src: etc-systemd-network-20-xenbr0.netdev.j2
|
||||
dest: /etc/systemd/network/20-{{ bridge_name }}.netdev
|
||||
mode: "0644"
|
||||
when: not bridge_configured
|
||||
notify:
|
||||
- update initramfs
|
||||
- reboot
|
||||
|
||||
- name: Configure bridge interface
|
||||
ansible.builtin.template:
|
||||
src: etc-systemd-network-30-xenbr0.link.j2
|
||||
dest: /etc/systemd/network/30-{{ bridge_name }}.link
|
||||
mode: "0644"
|
||||
when: not bridge_configured
|
||||
notify:
|
||||
- update initramfs
|
||||
- reboot
|
||||
|
||||
- name: Create bridge network
|
||||
ansible.builtin.template:
|
||||
src: etc-systemd-network-40-xenbr0.network.j2
|
||||
dest: /etc/systemd/network/40-{{ bridge_name }}.network
|
||||
mode: "0644"
|
||||
when: not bridge_configured
|
||||
notify:
|
||||
- update initramfs
|
||||
- reboot
|
||||
|
||||
- name: Configure network for default interface
|
||||
ansible.builtin.template:
|
||||
src: etc-systemd-network-50-lan0.network.j2
|
||||
dest: /etc/systemd/network/50-{{ interface_name }}.network
|
||||
mode: "0644"
|
||||
when: not interface_configured
|
||||
notify:
|
||||
- update initramfs
|
||||
- reboot
|
||||
|
||||
- name: Enable systemd-networkd
|
||||
ansible.builtin.systemd_service:
|
||||
name: systemd-networkd
|
||||
enabled: true
|
||||
state: restarted
|
||||
|
||||
- name: Enable systemd-resolved
|
||||
ansible.builtin.systemd_service:
|
||||
name: systemd-resolved
|
||||
enabled: true
|
||||
state: restarted
|
20
roles/node/tasks/packages.yml
Normal file
20
roles/node/tasks/packages.yml
Normal file
@ -0,0 +1,20 @@
|
||||
- name: Add backports
|
||||
ansible.builtin.apt_repository:
|
||||
repo: deb http://deb.debian.org/debian/ bookworm-backports main contrib non-free non-free-firmware
|
||||
state: present
|
||||
|
||||
- name: Add backports src
|
||||
ansible.builtin.apt_repository:
|
||||
repo: deb-src http://deb.debian.org/debian/ bookworm-backports main contrib non-free non-free-firmware
|
||||
state: present
|
||||
|
||||
- name: Install packages
|
||||
ansible.builtin.apt:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
install_recommends: false
|
||||
loop: "{{ packages }}"
|
||||
|
||||
- name: Remove dependencies that are no longer required
|
||||
ansible.builtin.apt:
|
||||
autoremove: true
|
21
roles/node/tasks/storage.yml
Normal file
21
roles/node/tasks/storage.yml
Normal file
@ -0,0 +1,21 @@
|
||||
- name: Create zpool
|
||||
ansible.builtin.command:
|
||||
cmd: zpool create {{ zpool_name }} {{ zpool_dev }}
|
||||
creates: /{{ zpool_name }}
|
||||
|
||||
- name: Check if the folder exists
|
||||
ansible.builtin.stat:
|
||||
path: /usr/share/ganeti/extstorage/zfs
|
||||
register: folder_check
|
||||
|
||||
- name: Reinstall lvm2 if ZFS extstorage is installed
|
||||
ansible.builtin.command:
|
||||
cmd: apt reinstall lvm2
|
||||
register: lvm2_reinstall_result
|
||||
changed_when: lvm2_reinstall_result.rc == 0
|
||||
when: folder_check.stat.exists
|
||||
|
||||
- name: Create LVM vg
|
||||
community.general.lvg:
|
||||
vg: "{{ vg_name }}"
|
||||
pvs: "{{ pvs }}"
|
5
roles/node/tasks/update.yml
Normal file
5
roles/node/tasks/update.yml
Normal file
@ -0,0 +1,5 @@
|
||||
- name: Update and upgrade system
|
||||
ansible.builtin.apt:
|
||||
upgrade: true
|
||||
update_cache: true
|
||||
cache_valid_time: 86400
|
1
roles/node/templates/etc-hostname.j2
Normal file
1
roles/node/templates/etc-hostname.j2
Normal file
@ -0,0 +1 @@
|
||||
ganeti-{{ groups['nodes'].index(inventory_hostname) + 1 }}.ganeti
|
13
roles/node/templates/etc-hosts.j2
Normal file
13
roles/node/templates/etc-hosts.j2
Normal file
@ -0,0 +1,13 @@
|
||||
127.0.0.1 localhost
|
||||
|
||||
::1 localhost ip6-localhost ip6-loopback
|
||||
ff02::1 ip6-allnodes
|
||||
ff02::2 ip6-allrouters
|
||||
|
||||
{% for node in groups['nodes'] %}
|
||||
{{ node }} ganeti-{{ groups['nodes'].index(node) + 1 }}.ganeti
|
||||
{% endfor %}
|
||||
|
||||
{% for item in hostnames %}
|
||||
{{ item.ip }} {{ item.name }}
|
||||
{% endfor %}
|
5
roles/node/templates/etc-systemd-network-10-lan0.link.j2
Normal file
5
roles/node/templates/etc-systemd-network-10-lan0.link.j2
Normal file
@ -0,0 +1,5 @@
|
||||
[Match]
|
||||
MACAddress={{ ansible_default_ipv4.macaddress }}
|
||||
|
||||
[Link]
|
||||
Name={{ interface_name }}
|
@ -0,0 +1,4 @@
|
||||
[NetDev]
|
||||
Name={{ bridge_name }}
|
||||
Kind=bridge
|
||||
MACAddress=none
|
@ -0,0 +1,5 @@
|
||||
[Match]
|
||||
OriginalName={{ bridge_name }}
|
||||
|
||||
[Link]
|
||||
MACAddressPolicy=none
|
@ -0,0 +1,9 @@
|
||||
[Match]
|
||||
Name={{ bridge_name }}
|
||||
|
||||
[Network]
|
||||
Address={{ ansible_default_ipv4.address|default(ansible_all_ipv4_addresses[0]) }}/24
|
||||
Gateway={{ gateway }}
|
||||
{% for dns in dns_servers %}
|
||||
DNS={{ dns }}
|
||||
{% endfor %}
|
@ -0,0 +1,5 @@
|
||||
[Match]
|
||||
Name={{ interface_name }}
|
||||
|
||||
[Network]
|
||||
Bridge={{ bridge_name }}
|
3
roles/worker/tasks/main.yml
Normal file
3
roles/worker/tasks/main.yml
Normal file
@ -0,0 +1,3 @@
|
||||
- name: Install ZFS extstorage
|
||||
ansible.builtin.include_role:
|
||||
name: zfs-extstorage
|
41
roles/zfs-extstorage/tasks/main.yml
Normal file
41
roles/zfs-extstorage/tasks/main.yml
Normal file
@ -0,0 +1,41 @@
|
||||
- name: Clone ZFS extsotarge module
|
||||
ansible.builtin.git:
|
||||
repo: https://github.com/brigriffin/ganeti-extstorage-zfs.git
|
||||
dest: /usr/share/ganeti/extstorage/zfs
|
||||
single_branch: true
|
||||
version: master
|
||||
force: true
|
||||
|
||||
- name: Set zpool for extstorage module
|
||||
ansible.builtin.template:
|
||||
src: exstorage.sh.j2
|
||||
dest: /usr/share/ganeti/extstorage/zfs/etc/ganeti-{{ groups['nodes'].index(inventory_hostname) + 1 }}.sh
|
||||
mode: "0644"
|
||||
|
||||
- name: Make everything executable
|
||||
ansible.builtin.file:
|
||||
dest: /usr/share/ganeti/extstorage/zfs
|
||||
recurse: true
|
||||
mode: "0755"
|
||||
|
||||
- name: Enable ext template
|
||||
ansible.builtin.command:
|
||||
cmd: /usr/share/ganeti/extstorage/zfs/install/1-enable-ext-template.sh
|
||||
chdir: /usr/share/ganeti/extstorage/zfs/install/
|
||||
register: enable_ext_template_result
|
||||
changed_when: enable_ext_template_result.rc == 0
|
||||
when: inventory_hostname in groups['master']
|
||||
|
||||
- name: Create log directory
|
||||
ansible.builtin.command:
|
||||
cmd: /usr/share/ganeti/extstorage/zfs/install/2-create-log-directory.sh
|
||||
chdir: /usr/share/ganeti/extstorage/zfs/install/
|
||||
creates: /var/log/ganeti/extstorage
|
||||
register: create_log_directory_result
|
||||
|
||||
- name: Create lvm wrappers
|
||||
ansible.builtin.command:
|
||||
cmd: /usr/share/ganeti/extstorage/zfs/install/3-lvm-wrappers.sh
|
||||
chdir: /usr/share/ganeti/extstorage/zfs/install/
|
||||
register: lvm_wrappers_result
|
||||
changed_when: lvm_wrappers_result.rc == 0
|
1
roles/zfs-extstorage/templates/exstorage.sh.j2
Normal file
1
roles/zfs-extstorage/templates/exstorage.sh.j2
Normal file
@ -0,0 +1 @@
|
||||
EXTP_ZFS={{ zpool_name }}
|
6
worker.yml
Normal file
6
worker.yml
Normal file
@ -0,0 +1,6 @@
|
||||
- name: Cluster worker setup
|
||||
hosts: workers
|
||||
become: true
|
||||
gather_facts: true
|
||||
roles:
|
||||
- worker
|
Loading…
Reference in New Issue
Block a user