Initial commit

This commit is contained in:
Oliver Traber 2022-05-12 23:15:51 +02:00
commit 50f2a54331
Signed by: Bluemedia
GPG key ID: C0674B105057136C
21 changed files with 276 additions and 0 deletions

17
README.md Normal file
View file

@ -0,0 +1,17 @@
# Homelab automation
This project contains the ansible and docker based automation of my homelab. The structure is inspired by [Khue Doan's Homelab Project](https://github.com/khuedoan/homelab).
The repo is currently work in progress. Nothing is tested yet, so everything could burst into flames at any time :)
## Hardware
- 4 × Fujitsu Esprimo Q957:
- CPU: `Intel Core i5-7500T @ 2.70 GHz`
- RAM: `16 GB`
- NVMe SSD: `256 GB`
- SATA SSD: `128 GB`
- 1 × Raspberry Pi 4 (4 GB)
## Current features
- Fully automated bare metal provisioning of Debian Bullseye using PXE and installer preseed files

6
metal/README.md Normal file
View file

@ -0,0 +1,6 @@
# Provision hardware
- Download and extract Debian Bullseye netboot installer from the official repository.
- Render config files (PXE config, GRUB config, preseed files etc.) from their corresponding [templates](./roles/pxe-server/templates).
- Spin up an PXE environment (DHCP, TFTP and HTTP server) using Docker compose.
- Wake machines using WoL to install the OS via PXE. Machines will auto reboot into the finished preseeded OS after the installation is complete.

4
metal/ansible.cfg Normal file
View file

@ -0,0 +1,4 @@
[defaults]
host_key_checking=false
stdout_callback=debug
stderr_callback=debug

View file

@ -0,0 +1,3 @@
ansible_user: root
ansible_ssh_private_key_file: ~/.ssh/id_rsa
ssh_public_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"

10
metal/install-os.yml Normal file
View file

@ -0,0 +1,10 @@
- name: Build PXE environment
hosts: localhost
roles:
- pxe-server
- name: Provision OS on machines
hosts: metal
gather_facts: false
roles:
- wol-wake

10
metal/inventories/lab.yml Normal file
View file

@ -0,0 +1,10 @@
metal:
children:
masters:
hosts:
lab-mini-1: {ansible_host: 192.168.1.21, mac: '4c:52:62:1c:bf:6c', disk: '/dev/nvme0n1'}
lab-mini-2: {ansible_host: 192.168.1.22, mac: '4c:52:62:0f:09:6d', disk: '/dev/nvme0n1'}
lab-mini-3: {ansible_host: 192.168.1.23, mac: '4c:52:62:0f:0a:23', disk: '/dev/nvme0n1'}
workers:
hosts:
lab-mini-4: {ansible_host: 192.168.1.24, mac: '90:1b:0e:f8:e8:af', disk: '/dev/nvme0n1'}

View file

@ -0,0 +1,11 @@
os_download_url: "https://deb.debian.org/debian/dists/bullseye/main/installer-amd64/current/images/netboot/netboot.tar.gz"
os_download_checksum: "sha256:ec3b71964457f30a57061ea758c12394bf2b792b461c697e61cc2d47053c5878"
user_fullname: "Lab User"
username: "lab"
domain: "lab.bluemedia.dev"
subnet: "192.168.6.0"
netmask: "255.255.255.0"
gateway: "192.168.6.1"
nameserver: "192.168.6.1"

View file

@ -0,0 +1,2 @@
*
!.gitignore

View file

@ -0,0 +1,2 @@
*
!.gitignore

View file

@ -0,0 +1,2 @@
*
!.gitignore

View file

@ -0,0 +1,2 @@
*
!.gitignore

View file

@ -0,0 +1,7 @@
FROM alpine:latest
RUN apk add dhcp
RUN touch /var/lib/dhcp/dhcpd.leases
CMD [ "dhcpd", "-d", "-f", "-cf", "/etc/dhcp/dhcpd.conf" ]

View file

@ -0,0 +1,22 @@
version: "3"
services:
dhcp:
build: ./dhcp
volumes:
- ./data/pxe-config/dhcpd.conf:/etc/dhcp/dhcpd.conf
network_mode: host
tftp:
build: ./tftp
network_mode: host
volumes:
- ./data/pxe-config/grub.cfg:/var/lib/tftpboot/grub.cfg
- ./data/os/debian-installer/amd64/grubx64.efi:/var/lib/tftpboot/grubx64.efi
- ./data/os/debian-installer/amd64/initrd.gz:/var/lib/tftpboot/initrd.gz
- ./data/os/debian-installer/amd64/linux:/var/lib/tftpboot/linux
http:
image: nginx:latest
network_mode: host
volumes:
- ./data/os:/usr/share/nginx/html/os:ro
- ./data/preseed:/usr/share/nginx/html/preseed:ro

View file

@ -0,0 +1,11 @@
server {
listen 80;
listen [::]:80;
server_name default;
root /var/www/html;
location / {
try_files $uri $uri/ =404;
}
}

View file

@ -0,0 +1,7 @@
FROM alpine:latest
RUN apk add busybox tftp-hpa
ENTRYPOINT [ "/bin/sh", "-c" ]
CMD [ "busybox syslogd -n -O /dev/stdout & in.tftpd -vvv --foreground --secure /var/lib/tftpboot" ]

View file

@ -0,0 +1,37 @@
- name: Download boot image
get_url:
url: "{{ os_download_url }}"
dest: "{{ role_path }}/files/data/source/netboot.tar.gz"
checksum: "{{ os_download_checksum }}"
register: netboot_tar
- name: Extract boot image
unarchive:
src: "{{ netboot_tar.dest }}"
dest: "{{ role_path }}/files/data/os"
- name: Generate DHCP config
template:
src: dhcpd.conf.j2
dest: "{{ role_path }}/files/data/pxe-config/dhcpd.conf"
mode: 0644
- name: Generate GRUB config
template:
src: grub.cfg.j2
dest: "{{ role_path }}/files/data/pxe-config/grub.cfg"
mode: 0644
- name: Generate preseed file for each machine
template:
src: preseed.cfg.j2
dest: "{{ role_path }}/files/data/preseed/{{ hostvars[item]['mac'] }}.cfg"
mode: 0644
loop: "{{ groups['metal'] }}"
- name: Start PXE stack
docker_compose:
project_src: "{{ role_path }}/files"
state: present
restarted: true
build: true

View file

@ -0,0 +1,20 @@
option space pxelinux;
option pxelinux.magic code 208 = string;
option pxelinux.configfile code 209 = text;
option pxelinux.pathprefix code 210 = text;
option pxelinux.reboottime code 211 = unsigned integer 32;
option architecture-type code 93 = unsigned integer 16;
subnet {{ subnet }} netmask {{ netmask }} {
option routers {{ gateway }};
range {{ subnet | ansible.netcommon.ipmath(3) }} {{ subnet | ansible.netcommon.ipmath(254) }};
class "pxeclients" {
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
next-server {{ ansible_default_ipv4.address }};
if option architecture-type = 00:07 {
filename "grubx64.efi";
}
}
}

View file

@ -0,0 +1,10 @@
set timeout=1
menuentry 'Auto install Debian Bullseye (PXE)' {
set background_color=black
linux linux \
vga=788 \
url=http://{{ ansible_default_ipv4.address }}/preseed/${net_default_mac}.conf \
--- auto quiet
initrd initrd.gz
}

View file

@ -0,0 +1,78 @@
# For documentation see: https://www.debian.org/releases/stable/example-preseed.txt
# Set default locale and keyboard layout
d-i debian-installer/locale string {{ locale | default('en_US.UTF-8') }}
d-i keyboard-configuration/xkb-keymap select {{ keyboard_layout | default('de') }}
# Set network interface used by default
d-i netcfg/choose_interface select auto
# Static network config
d-i netcfg/disable_autoconfig boolean true
d-i netcfg/dhcp_failed note
d-i netcfg/dhcp_options select Configure network manually
d-i netcfg/get_ipaddress string {{ hostvars[item]['ansible_host'] }}
d-i netcfg/get_netmask string {{ netmask }}
d-i netcfg/get_gateway string {{ gateway }}
d-i netcfg/get_nameservers string {{ nameserver }}
d-i netcfg/confirm_static boolean true
# These values will be overwritten if set by dhcp, but the entries will get rid of the correscponding questions
d-i netcfg/get_hostname string {{ hostvars[item]['inventory_hostname'] | default('unassigned-hostname') }}
d-i netcfg/get_domain string {{ domain | default('unassigned-domain') }}
# Force hostname regarding of value set by dhcp
d-i netcfg/hostname string {{ hostvars[item]['inventory_hostname'] | default('unassigned-hostname') }}
# Load non-free firmware for hardware by default
d-i hw-detect/load_firmware boolean true
# Setup package mirrror
d-i mirror/protocol string {{ mirror_proto | default('http') }}
d-i mirror/country string manual
d-i mirror/http/hostname string {{ mirror | default('deb.debian.org') }}
d-i mirror/http/directory string {{ mirror_dir | default('/debian') }}
d-i mirror/http/proxy string {{ mirror_proxy | default('') }}
# Disable root user - normal user (see below) will have sudo permissions
d-i passwd/root-login boolean false
# Create new user
d-i passwd/user-fullname string {{ user_fullname | default('Debian User') }}
d-i passwd/username string {{ username | default('debian') }}
d-i passwd/user-password password {{ password | default('insecure') }}
d-i passwd/user-password-again password {{ password | default('insecure') }}
# Setup timezone and NTP server
d-i clock-setup/utc boolean true
d-i time/zone string {{ timezone | default('UTC') }}
d-i clock-setup/ntp-server string {{ ntp_server | default('de.pool.ntp.org') }}
# Autoformat disk
d-i partman-auto/disk string {{ hostvars[item]['disk'] | default('/dev/sda') }}
d-i partman-auto/method string regular
d-i partman-auto/choose_recipe select atomic
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
# Remove install cd sources from /etc/sources.list
d-i apt-setup/cdrom/set-first boolean false
d-i apt-setup/disable-cdrom-entries boolean true
# Install openssh-server and basic system tools
d-i pkgsel/run_tasksel boolean false
d-i pkgsel/include string openssh-server build-essential
d-i pkgsel/upgrade select safe-upgrade
# Disable package reporting
popularity-contest popularity-contest/participate boolean false
# Install grub to specified device
d-i grub-installer/only_debian boolean true
d-i grub-installer/bootdev string {{ hostvars[item]['disk'] | default('/dev/sda') }}
# Reboot to installed system without confirmation
d-i finish-install/reboot_in_progress note

View file

@ -0,0 +1,8 @@
- name: Send magic packets
community.general.wakeonlan:
mac: "{{ hostvars[inventory_hostname]['mac'] }}"
delegate_to: localhost
- name: Wait for machines to come online with installed OS
wait_for_connection:
timeout: 600

7
scripts/pxe-log.sh Executable file
View file

@ -0,0 +1,7 @@
#!/bin/bash
docker-compose \
--project-directory ./metal/roles/pxe-server/files/ \
logs \
--f \
${@}