From 5e85050e79ee5ccce924805f00d5ec07f7a48dbc Mon Sep 17 00:00:00 2001 From: Patryk Hegenberg Date: Wed, 7 May 2025 20:28:49 +0200 Subject: [PATCH] ci: add changed config --- ansible/inventory.ini | 11 +++ ansible/k3s_setup.yml | 67 ++++++++++++++++++ boostrap-homelab.sh | 50 ++++++++++++++ bootstrap.yaml | 99 +++++++++++++++++++++++++++ grafana-secrets.sh | 6 ++ tofu/{inventory.ini.tpl => inventory} | 0 tofu/main.tf | 56 +++++++-------- tofu/{outputs.tf => outputs} | 7 +- 8 files changed, 260 insertions(+), 36 deletions(-) create mode 100644 ansible/inventory.ini create mode 100755 boostrap-homelab.sh create mode 100644 bootstrap.yaml create mode 100755 grafana-secrets.sh rename tofu/{inventory.ini.tpl => inventory} (100%) rename tofu/{outputs.tf => outputs} (58%) diff --git a/ansible/inventory.ini b/ansible/inventory.ini new file mode 100644 index 0000000..b0a23ab --- /dev/null +++ b/ansible/inventory.ini @@ -0,0 +1,11 @@ +[k3s_server] +192.168.124.100 + +[k3s_agents] +192.168.124.101 +192.168.124.102 + +[all:vars] +ansible_user=fedora +ansible_ssh_private_key_file=~/.ssh/id_cluster +ansible_python_interpreter=/usr/bin/python3 diff --git a/ansible/k3s_setup.yml b/ansible/k3s_setup.yml index 98d5fdd..a3e5e11 100644 --- a/ansible/k3s_setup.yml +++ b/ansible/k3s_setup.yml @@ -1,9 +1,43 @@ --- +- name: Remove old and add new SSH host keys for all nodes + hosts: localhost + vars: + nodes: + - 192.168.124.100 + - 192.168.124.101 + - 192.168.124.102 + tasks: + - name: Remove old host key for all nodes + ansible.builtin.known_hosts: + path: "~/.ssh/known_hosts" + name: "{{ item }}" + state: absent + loop: "{{ nodes }}" + - name: Prepare K3s Nodes (Disable conflicting services) hosts: all become: yes gather_facts: no tasks: + - name: Installiere iSCSI-Initiator (Longhorn-Voraussetzung) + become: true + ansible.builtin.package: + name: iscsi-initiator-utils + state: present + + - name: Enable iSCSI-Initiator + become: true + ansible.builtin.systemd_service: + name: iscsid + enabled: true + masked: no + + - name: Make sure a service unit is running + become: true + ansible.builtin.systemd_service: + state: started + name: iscsid + - name: Check if nm-cloud-setup service exists ansible.builtin.systemd: name: nm-cloud-setup.service @@ -224,3 +258,36 @@ flat: yes become: yes when: k3s_service_active | default(false) + +- name: Replace server IP in kubeconfig with current server IP + hosts: localhost + gather_facts: no + vars: + kubeconfig_path: "../kubeconfig" + server_ip: "{{ hostvars[groups['k3s_server'][0]].k3s_server_ip }}" + tasks: + - name: Replace server IP in kubeconfig file + ansible.builtin.replace: + path: "{{ kubeconfig_path }}" + regexp: "server: https://.*:6443" + replace: "server: https://{{ server_ip }}:6443" + +- name: Update /etc/hosts with k3s-server.local + hosts: localhost + become: yes + vars: + server_ip: "{{ hostvars[groups['k3s_server'][0]].k3s_server_ip }}" + service_hosts: + - sonarqube.local + - gitea.local + - prometheus.local + - grafana.local + - longhorn.local + tasks: + - name: Ensure all service hostnames point to the server IP in /etc/hosts + ansible.builtin.lineinfile: + path: /etc/hosts + regexp: '^{{ server_ip }}\s+sonarqube\.local gitea\.local prometheus\.local grafana\.local longhorn\.local$' + line: "{{ server_ip }} {{ service_hosts | join(' ') }}" + state: present + create: yes diff --git a/boostrap-homelab.sh b/boostrap-homelab.sh new file mode 100755 index 0000000..a6febdb --- /dev/null +++ b/boostrap-homelab.sh @@ -0,0 +1,50 @@ +#!/bin/bash +set -e + +# 1. Libvirt Volumes prüfen und ggf. löschen +VOLUMES=("k3s-server-disk.qcow2" "k3s-agent-1-disk.qcow2" "k3s-agent-2-disk.qcow2" "k3s-common-init.iso" "fedora-cloud-base.qcow2") +POOL="default" + +echo "Prüfe und lösche ggf. alte Libvirt-Volumes..." +for vol in "${VOLUMES[@]}"; do + if sudo virsh vol-list $POOL | grep -q "$vol"; then + echo "Lösche Volume: $vol" + sudo virsh vol-delete --pool $POOL "$vol" + fi +done + +# 2. OpenTofu initialisieren und anwenden +echo "Initialisiere OpenTofu..." +cd ./tofu +rm -rf .terraform/ .terraform.lock.hcl terraform.tfstate terraform.tfstate.backup tofu.tfstate tofu.tfstate.backup +tofu init + +echo "Plane Infrastruktur..." +tofu plan + +echo "Wende Infrastruktur an..." +tofu apply -auto-approve + +cd .. + +# 3. Ansible-Playbook +if [ -f ./ansible/k3s_setup.yml ]; then + echo "Starte K3s-Ansible-Playbook..." + ansible-playbook -i ./ansible/inventory.ini ./ansible/k3s_setup.yml -e 'ansible_ssh_common_args="-o StrictHostKeyChecking=accept-new"' --ask-become-pass +fi + +# 4. Kubeconfig setzen +echo "Setze KUBECONFIG..." +export KUBECONFIG=$(realpath ./kubeconfig) +echo "KUBECONFIG ist gesetzt auf $KUBECONFIG" + +# 5. Flux Bootstrap +echo "Starte Flux-Bootstrap..." +echo $GIT_TOKEN +flux bootstrap git \ + --url=https://codeberg.org/Pata1704/homelab_gitops.git \ + --branch=main \ + --path=./clusters/production \ + --token-auth + +echo "Cluster-Bootstrap abgeschlossen!" diff --git a/bootstrap.yaml b/bootstrap.yaml new file mode 100644 index 0000000..4ba2e25 --- /dev/null +++ b/bootstrap.yaml @@ -0,0 +1,99 @@ +--- +- name: Bootstrap Homelab Environment + hosts: localhost + connection: local + gather_facts: false + + vars: + libvirt_pool: "default" + libvirt_volumes: + - "k3s-server-disk.qcow2" + - "k3s-agent-1-disk.qcow2" + - "k3s-agent-2-disk.qcow2" + - "k3s-common-init.iso" + - "fedora-cloud-base.qcow2" + tofu_dir: "{{ playbook_dir }}/tofu" + ansible_dir: "{{ playbook_dir }}/ansible" + kubeconfig_path: "{{ playbook_dir }}/kubeconfig" + flux_git_url: "https://codeberg.org/Pata1704/homelab_gitops.git" + flux_git_branch: "main" + flux_git_path: "./clusters/production" + flux_git_token: "{{ lookup('env', 'GIT_TOKEN') }}" + + tasks: + # --- 1. Libvirt Volumes prüfen und ggf. löschen --- + # Builtin-Only: Nicht möglich, daher als Hinweis ein Shell-Task: + - name: Remove old Libvirt volumes (Shell workaround, no builtin) + ansible.builtin.shell: | + for vol in {{ libvirt_volumes | join(' ') }}; do + if virsh vol-list {{ libvirt_pool }} | grep -q "$vol"; then + virsh vol-delete --pool {{ libvirt_pool }} "$vol" + fi + done + become: yes + changed_when: false # Setze auf true, wenn du das nachverfolgen willst + + # --- 2. OpenTofu initialisieren und anwenden --- + # Builtin-Only: Nicht möglich, daher command-Module verwenden: + - name: Remove old OpenTofu state and lock files + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - "{{ tofu_dir }}/.terraform" + - "{{ tofu_dir }}/.terraform.lock.hcl" + - "{{ tofu_dir }}/terraform.tfstate" + - "{{ tofu_dir }}/terraform.tfstate.backup" + - "{{ tofu_dir }}/tofu.tfstate" + - "{{ tofu_dir }}/tofu.tfstate.backup" + + - name: Initialize OpenTofu + ansible.builtin.command: + cmd: tofu init + chdir: "{{ tofu_dir }}" + changed_when: true + + - name: Plan OpenTofu infrastructure + ansible.builtin.command: + cmd: tofu plan -out=tfplan + chdir: "{{ tofu_dir }}" + changed_when: false + + - name: Apply OpenTofu infrastructure + ansible.builtin.command: + cmd: tofu apply -auto-approve + chdir: "{{ tofu_dir }}" + changed_when: true + + # --- 3. K3s-Setup --- + - name: Run K3s Ansible Playbook + ansible.builtin.command: + cmd: 'ansible-playbook -i {{ ansible_dir }}/inventory.ini {{ ansible_dir }}/k3s_setup.yml -e ''ansible_ssh_common_args="-o StrictHostKeyChecking=accept-new"'' --ask-become-pass' + changed_when: true + + # --- 4. Kubeconfig Hinweis --- + - name: Display KUBECONFIG info + ansible.builtin.debug: + msg: + - "K3s cluster setup should be complete." + - "To interact with your cluster, export the KUBECONFIG environment variable:" + - " export KUBECONFIG={{ kubeconfig_path }}" + - "Alternatively, copy '{{ kubeconfig_path }}' to '~/.kube/config' or merge it." + + # --- 5. Flux Bootstrap --- + - name: Bootstrap Flux + ansible.builtin.command: + cmd: > + flux bootstrap git + --url={{ flux_git_url }} + --branch={{ flux_git_branch }} + --path={{ flux_git_path }} + --token-auth + environment: + KUBECONFIG: "{{ kubeconfig_path }}" + GIT_TOKEN: "{{ flux_git_token | default(lookup('env', 'GIT_TOKEN')) }}" + changed_when: true + + - name: Final Bootstrap Message + ansible.builtin.debug: + msg: "Cluster-Bootstrap mit Ansible abgeschlossen!" diff --git a/grafana-secrets.sh b/grafana-secrets.sh new file mode 100755 index 0000000..4dce86f --- /dev/null +++ b/grafana-secrets.sh @@ -0,0 +1,6 @@ +# Benutzername: +kubectl get secret kube-prometheus-stack-grafana -n monitoring -o jsonpath="{.data.admin-user}" | base64 -d && echo + +# Passwort: +kubectl get secret kube-prometheus-stack-grafana -n monitoring -o jsonpath="{.data.admin-password}" | base64 -d && echo + diff --git a/tofu/inventory.ini.tpl b/tofu/inventory similarity index 100% rename from tofu/inventory.ini.tpl rename to tofu/inventory diff --git a/tofu/main.tf b/tofu/main.tf index b24d522..5a7fe3e 100644 --- a/tofu/main.tf +++ b/tofu/main.tf @@ -12,7 +12,6 @@ provider "libvirt" { } # --- Base Image Handling --- -# Download the base cloud image if it doesn't exist locally resource "libvirt_volume" "base_image" { name = var.base_image_name pool = var.libvirt_pool @@ -21,7 +20,6 @@ resource "libvirt_volume" "base_image" { } # --- Cloud-Init Configuration --- -# Common cloud-init data for all nodes data "cloudinit_config" "common_init" { gzip = false base64_encode = false @@ -35,38 +33,31 @@ data "cloudinit_config" "common_init" { } } -# Create a cloud-init ISO disk using the common config resource "libvirt_cloudinit_disk" "common_iso" { - name = "${var.cluster_name}-common-init.iso" - user_data = data.cloudinit_config.common_init.rendered - pool = var.libvirt_pool + name = "${var.cluster_name}-common-init.iso" + user_data = data.cloudinit_config.common_init.rendered + pool = var.libvirt_pool } -# # --- Network --- -# # Use the default libvirt network -# data "libvirt_network" "default_network" { -# name = var.libvirt_network_name -# } - # --- K3s Server Node --- -# Create a volume for the server node based on the base image resource "libvirt_volume" "server_disk" { name = "${var.server_hostname}-disk.qcow2" base_volume_id = libvirt_volume.base_image.id pool = var.libvirt_pool - size = var.vm_disk_size + size = var.server_disk_size format = "qcow2" } resource "libvirt_domain" "server" { name = var.server_hostname - memory = var.vm_memory - vcpu = var.vm_vcpu + memory = var.server_memory + vcpu = var.server_vcpu cloudinit = libvirt_cloudinit_disk.common_iso.id network_interface { network_name = var.libvirt_network_name + addresses = [var.server_ip] wait_for_lease = true } @@ -80,35 +71,38 @@ resource "libvirt_domain" "server" { target_type = "serial" } graphics { - type = "spice" - listen_type = "address" - autoport = true + type = "spice" + listen_type = "address" + autoport = true } } -# --- K3s Agent Node --- +# --- K3s Agent Nodes --- resource "libvirt_volume" "agent_disk" { - name = "${var.agent_hostname}-disk.qcow2" + count = var.agent_count + name = "${var.agent_hostname_prefix}-${count.index + 1}-disk.qcow2" base_volume_id = libvirt_volume.base_image.id pool = var.libvirt_pool - size = var.vm_disk_size + size = var.agent_disk_size format = "qcow2" } - resource "libvirt_domain" "agent" { - name = var.agent_hostname - memory = var.vm_memory - vcpu = var.vm_vcpu +resource "libvirt_domain" "agent" { + count = var.agent_count + name = "${var.agent_hostname_prefix}-${count.index + 1}" + memory = var.agent_memory + vcpu = var.agent_vcpu cloudinit = libvirt_cloudinit_disk.common_iso.id network_interface { network_name = var.libvirt_network_name + addresses = [var.agent_ips[count.index]] wait_for_lease = true } disk { - volume_id = libvirt_volume.agent_disk.id + volume_id = libvirt_volume.agent_disk[count.index].id } console { @@ -116,9 +110,9 @@ resource "libvirt_volume" "agent_disk" { target_port = "0" target_type = "serial" } - graphics { - type = "spice" - listen_type = "address" - autoport = true + graphics { + type = "spice" + listen_type = "address" + autoport = true } } diff --git a/tofu/outputs.tf b/tofu/outputs similarity index 58% rename from tofu/outputs.tf rename to tofu/outputs index a5596f5..04874d8 100644 --- a/tofu/outputs.tf +++ b/tofu/outputs @@ -1,17 +1,14 @@ output "server_ip" { - description = "IP address of the K3s server node." value = libvirt_domain.server.network_interface[0].addresses[0] } - output "agent_ips" { - description = "List of IP addresses of the K3s agent nodes." - value = [libvirt_domain.agent.network_interface[0].addresses[0]] + value = [for i in range(var.agent_count) : libvirt_domain.agent[i].network_interface[0].addresses[0]] } resource "local_file" "ansible_inventory" { content = templatefile("${path.module}/inventory.ini.tpl", { server_ip = libvirt_domain.server.network_interface[0].addresses[0] - agent_ips = [libvirt_domain.agent.network_interface[0].addresses[0]] + agent_ips = [for i in range(var.agent_count) : libvirt_domain.agent[i].network_interface[0].addresses[0]] ssh_user = var.vm_user }) filename = "../ansible/inventory.ini"