diff --git a/README.md b/README.md index 70e836a..d5775ed 100644 --- a/README.md +++ b/README.md @@ -17,25 +17,31 @@ This implementation is built on easily accessible consumer based hardware and wi ### Phase 1: Foundation 1. **[Overview & Hardware Allocation](./docs/01-overview.md)** - Complete architecture overview 2. **[Networking Plan](./docs/02-networking.md)** - VLAN strategy and network design -3. **[Core Services Setup](./docs/03-core-services.md)** *(TBD)* - k0s cluster, DNS, monitoring +3. **[Core Services Setup](./docs/03-core-services.md)** *(TBD)* - Ansible, DNS, monitoring 4. **[Storage Configuration](./docs/04-storage.md)** *(TBD)* - Synology, democratic-csi ### Phase 2: Proxmox Platform -11. **[Proxmox Installation](./docs/11-vsphere-setup.md)** *(TBD)* - Dell 7050 virtualization -12. **[Windows Infrastructure](./docs/12-windows-infrastructure.md)** *(TBD)* - AD, SQL Server -13. **[VM Templates & Automation](./docs/13-vm-automation.md)** *(TBD)* - Template creation +5. **[Proxmox Installation](./docs/11-vsphere-setup.md)** *(TBD)* - Dell 7050 virtualization +6. **[VM Templates & Automation](./docs/13-vm-automation.md)** *(TBD)* - Template creation -### Phase 3: OpenShift Clusters -8. **[OpenShift Compact Cluster](./docs/08-openshift-compact.md)** *(TBD)* - 3-node production-like -9. **[OpenShift SNO + Worker](./docs/09-openshift-sno.md)** *(TBD)* - Edge computing setup +### Phase 3: Infrastructure Services +7. **[Recursive DNS](./docs/09-openshift-sno.md)** *(TBD)* - ACM Hub Cluster +8. **[Authoritative DNS](./docs/08-openshift-compact.md)** *(TBD)* - 3 Master/3 Worker node (production-like) +9. **[Identity Management](./docs/10-acm-setup.md)** *(TBD)* - Multi-cluster management +10. **[Matchbox](./docs/10-acm-setup.md)** *(TBD)* - External app cluster + +### Phase 4: OpenShift Clusters +8. **[OpenShift SNO + Worker](./docs/09-openshift-sno.md)** *(TBD)* - ACM Hub Cluster +9. **[OpenShift Cluster](./docs/08-openshift-compact.md)** *(TBD)* - 3 Master/3 Worker node (production-like) 10. **[ACM Configuration](./docs/10-acm-setup.md)** *(TBD)* - Multi-cluster management +11. **[HCP Cluster](./docs/10-acm-setup.md)** *(TBD)* - External app cluster -### Phase 4: Container Platform +### Phase 5: Container Platform 5. **[Container Registry Setup](./docs/05-container-registry.md)** *(TBD)* - Harbor deployment 6. **[Git Repository Setup](./docs/06-git-repository.md)** *(TBD)* - Gitea/GitLab on Synology 7. **[Artifact Repository](./docs/07-artifact-repository.md)** *(TBD)* - Nexus/Artifactory -### Phase 5: Advanced Services +### Phase 6: Advanced Services 14. **[Monitoring & Observability](./docs/14-monitoring.md)** *(TBD)* - Prometheus, Grafana, Splunk 15. **[Security & Compliance](./docs/15-security.md)** *(TBD)* - ACS, certificates, auditing 16. **[Backup & DR](./docs/16-backup-dr.md)** *(TBD)* - Backup strategies @@ -47,7 +53,7 @@ This implementation is built on easily accessible consumer based hardware and wi - Hardware powered and networked - Initial VLAN setup (see [networking plan](./docs/02-networking.md)) -Ansible Collections +### Ansible Collections - ansible-galaxy collection install freeipa.ansible_freeipa ### Deployment Scripts @@ -66,8 +72,8 @@ source ~/venv-ansible/bin/activate ./deployment/openshift/compact-cluster/ ./deployment/openshift/sno-cluster/ -# Phase 4: vSphere -./deployment/vsphere/ +# Phase 4: Proxmox +./deployment/proxmox/ ``` ## 📁 Repository Structure @@ -79,7 +85,9 @@ homelab/ │ ├── 01-overview.md │ ├── 02-networking.md │ └── ... -├── deployment/ # Deployment configurations +├── ansible/ # Directory structure for Ansible +├── deployment/ # Deployment +configurations │ ├── synology/ # Docker Compose files for Synology │ ├── k0s/ # k0s cluster manifests │ ├── openshift/ # OpenShift installation configs diff --git a/ansible/group_vars/hub_cluster/vars b/ansible/group_vars/hub_cluster/vars index 82fba77..dc42b10 100644 --- a/ansible/group_vars/hub_cluster/vars +++ b/ansible/group_vars/hub_cluster/vars @@ -9,7 +9,7 @@ cluster_name: "hub" # Version of OpenShift to install. All available versions can be found at: https://mirror.openshift.com/pub/openshift-v4/x86_64/clients/ocp/ -cluster_version: "4.17.20" +cluster_version: "4.18.21" # Type of cluster. # - none (Single Node Cluster) @@ -29,13 +29,13 @@ worker_node_count: 0 machine_network: "10.1.71.0/24" -# OpenShift API IP Address (Comment out for Single Node Cluster) +# OpenShift API IP Address (Reference host IP address for Single Node Cluster) -# api_address: "10.1.71.10" +api_address: "{{ ip_address }}" # "10.1.71.10" -# OpenShift Apps Wildcard IP Address (Comment out for Single Node Cluster) +# OpenShift Apps Wildcard IP Address (Reference host IP address for Single Node Cluster) -# app_address: "10.1.71.10" +app_address: "{{ ip_address }}" # "10.1.71.10" # These are internal networks to the cluster and should not need to be changed. diff --git a/ansible/host_vars/int-worker01/vars b/ansible/host_vars/int-worker01/vars new file mode 100644 index 0000000..8c439ca --- /dev/null +++ b/ansible/host_vars/int-worker01/vars @@ -0,0 +1,29 @@ +--- +# file: host_vars/int-worker02/vars +# Ansible vars template for OpenShift nodes created via Ansible (configure_openshift_cluster). + +# Cluster deployed via Agent Installer and Matchbox (iPXE): + +# Role of this node in the cluster. +# - master +# - worker + +node_role: "worker" + +# IP address assigned to this node on the Primary Interface + +ip_address: 10.1.71.164 + +# Ansible Playbook supports booting node via one interface, but installing on a +# different interface. (Disabling the boot interface on install) All these fields +# are necessary. In the case of a single NIC node, interfaces and MAC addresses +# should be the same. + +boot_interface: "enp87s0" +boot_mac_address: "36:47:ca:76:13:49" +primary_interface: "enp2s0f0" +install_mac_address: "36:47:ca:76:13:47" + +# --- + +hostname: "{{ inventory_hostname }}.{{ base_domain }}" diff --git a/ansible/host_vars/ocp-hub/vars b/ansible/host_vars/ocp-hub/vars index 322d5d6..1ee4390 100644 --- a/ansible/host_vars/ocp-hub/vars +++ b/ansible/host_vars/ocp-hub/vars @@ -1,5 +1,31 @@ --- -mac_address: "98:b7:85:1e:c6:f1" -ip_address: "10.1.71.10" -hostname: "ocp-hub" +# file: host_vars/ocp-hub/vars + +# file: host_vars/int-master01/vars +# Ansible vars template for OpenShift nodes created via Ansible (configure_openshift_cluster). + +# Cluster deployed via Agent Installer and Matchbox (iPXE): + +# Role of this node in the cluster. +# - master +# - worker + +node_role: "master" + +# IP address assigned to this node on the Primary Interface + +ip_address: 10.1.71.10 + +# Ansible Playbook supports booting node via one interface, but installing on a +# different interface. (Disabling the boot interface on install) All these fields +# are necessary. In the case of a single NIC node, interfaces and MAC addresses +# should be the same. + +boot_interface: "enp0s31f6" +boot_mac_address: "50:9A:4C:52:A8:5D" primary_interface: "enp1s0f0" +install_mac_address: "98:b7:85:1e:c6:f1" + +# Static Variables + +hostname: "{{ inventory_hostname }}.{{ base_domain }}" diff --git a/ansible/inventory.yml b/ansible/inventory.yml index f55c9c6..3e37f12 100644 --- a/ansible/inventory.yml +++ b/ansible/inventory.yml @@ -53,6 +53,7 @@ internal_cluster: int-master01: int-master02: int-master03: +# int-worker01: int-worker02: sql_servers: diff --git a/ansible/playbooks/configure_openshift_hub.yml b/ansible/playbooks/configure_openshift_hub.yml new file mode 100644 index 0000000..6ff58f8 --- /dev/null +++ b/ansible/playbooks/configure_openshift_hub.yml @@ -0,0 +1,221 @@ +--- +- name: Configure DNS entries for cluster nodes + hosts: hub_cluster + gather_facts: false + become: true + tasks: + - name: Create DNS entry for each cluster node + ansible.builtin.include_tasks: tasks/create_dns_record.yml + vars: + host_ip_address: "{{ ip_address }}" + +- name: Configure DNS entries for OpenShift cluster services + hosts: hub_cluster[0] + gather_facts: false + become: true + tasks: + - name: Create DNS entries for OpenShift cluster services + ansible.builtin.include_tasks: tasks/create_dns_record.yml + vars: + dns_name: "{{ item.name }}" + dns_address: "{{ item.address }}" + loop: + - name: "api.{{ cluster_name }}" + address: "{{ api_address }}" + - name: "api-int.{{ cluster_name }}" + address: "{{ api_address }}" + - name: "*.apps.{{ cluster_name }}" + address: "{{ app_address }}" + loop_control: + label: "{{ item.name }}" + +- name: Configure DHCP entries for cluster nodes + hosts: hub_cluster + gather_facts: false + become: true + tasks: + - name: Configure DHCP entry for node + ansible.builtin.include_tasks: tasks/configure_dhcp_entry.yml + vars: + host_mac_address: "{{ install_mac_address }}" + host_ip_address: "{{ ip_address }}" + + handlers: + - name: Restart dnsmasq + delegate_to: "{{ dhcp_server }}" + become: true + ansible.builtin.service: + name: dnsmasq + state: restarted + +- name: Create OpenShift installer files + hosts: matchbox + gather_facts: true + + vars: + cluster_group: "hub_cluster" + download_dir: "/var/cache/openshift-install" + + tasks: + - name: Remove previous directory + ansible.builtin.file: + path: ~/homelab/terraform/{{ cluster_group }} + state: absent + + - name: Create directory + ansible.builtin.file: + path: ~/homelab/terraform/{{ cluster_group }} + state: directory + mode: '0755' + + - name: OpenShift Installer install-config.yaml + ansible.builtin.template: + src: templates/install-config.yaml.j2 + dest: ~/homelab/terraform/{{ cluster_group }}/install-config.yaml + mode: '0644' + + - name: OpenShift Installer agent-config.yaml + ansible.builtin.template: + src: templates/agent-config.yaml.j2 + dest: ~/homelab/terraform/{{ cluster_group }}/agent-config.yaml + mode: '0644' + + # - name: Quit + # ansible.builtin.meta: end_play + + - name: Create directory for OpenShift Installer files + become: true + ansible.builtin.file: + path: "{{ download_dir }}/{{ hostvars[groups[cluster_group][0]].cluster_version }}" + state: directory + mode: '0755' + owner: root + group: root + + - name: Check if OpenShift installer file exists + ansible.builtin.stat: + path: "{{ download_dir }}/{{ hostvars[groups[cluster_group][0]].cluster_version }}/{{ hostvars[groups[cluster_group][0]].openshift_installer_file }}" + register: openshift_installer_file + + - name: Download and install OpenShift installer package + when: not openshift_installer_file.stat.exists + block: + - name: Download OpenShift Installer file + become: true + ansible.builtin.get_url: + url: "{{ hostvars[groups[cluster_group][0]].openshift_installer_download_url }}" + dest: /var/cache/openshift-install/{{ hostvars[groups[cluster_group][0]].cluster_version }} + mode: '0644' + + - name: Unarchive installer file + become: true + ansible.builtin.unarchive: + src: /var/cache/openshift-install/{{ hostvars[groups[cluster_group][0]].cluster_version }}/openshift-install-linux.tar.gz + dest: /var/cache/openshift-install/{{ hostvars[groups[cluster_group][0]].cluster_version }} + remote_src: true + + - name: Copy install binary + become: true + ansible.builtin.copy: + src: /var/cache/openshift-install/{{ hostvars[groups[cluster_group][0]].cluster_version }}/openshift-install + dest: /usr/local/bin + remote_src: true + owner: wed + group: wed + mode: '0755' + + - name: Check if OpenShift client file exists + ansible.builtin.stat: + path: "{{ download_dir }}/{{ hostvars[groups[cluster_group][0]].cluster_version }}/{{ hostvars[groups[cluster_group][0]].openshift_client_file }}" + register: openshift_client_file + + - name: Download and install OpenShift client package + when: not openshift_client_file.stat.exists + block: + - name: Download OpenShift Client file + become: true + ansible.builtin.get_url: + url: "{{ hostvars[groups[cluster_group][0]].openshift_client_download_url }}" + dest: /var/cache/openshift-install/{{ hostvars[groups[cluster_group][0]].cluster_version }} + mode: '0644' + + - name: Unarchive client file + become: true + ansible.builtin.unarchive: + src: /var/cache/openshift-install/{{ hostvars[groups[cluster_group][0]].cluster_version }}/openshift-client-linux.tar.gz + dest: /var/cache/openshift-install/{{ hostvars[groups[cluster_group][0]].cluster_version }} + remote_src: true + + - name: Copy client binary + become: true + ansible.builtin.copy: + src: /var/cache/openshift-install/{{ hostvars[groups[cluster_group][0]].cluster_version }}/oc + dest: /usr/local/bin + remote_src: true + owner: wed + group: wed + mode: '0755' + + - name: Check if OpenShift image exists + ansible.builtin.stat: + path: ~/homelab/terraform/{{ cluster_group }}/boot-artifacts/agent.x86_64-initrd.img + register: openshift_image_exists + + - name: OpenShift image creation + ansible.builtin.command: /usr/local/bin/openshift-install agent create pxe-files + args: + chdir: ~/homelab/terraform/{{ cluster_group }} + when: not openshift_image_exists.stat.exists + changed_when: true + + - name: Create a directory if it does not exist + become: true + ansible.builtin.file: + path: "{{ hostvars[groups['matchbox_server'][0]].assets }}/{{ hostvars[groups[cluster_group][0]].cluster_name }}" + state: directory + owner: matchbox + group: matchbox + mode: '0755' + + - name: Copy file with owner and permissions + become: true + ansible.builtin.copy: + src: "{{ ansible_env['HOME'] }}/homelab/terraform/{{ cluster_group }}/boot-artifacts/" + dest: "{{ hostvars[groups['matchbox_server'][0]].assets }}/{{ hostvars[groups[cluster_group][0]].cluster_name }}/" + remote_src: true + owner: matchbox + group: matchbox + mode: '0644' + + - name: Verify directory permissions + become: true + ansible.builtin.file: + path: "{{ hostvars[groups['matchbox_server'][0]].assets }}/{{ hostvars[groups[cluster_group][0]].cluster_name }}" + state: directory + owner: matchbox + group: matchbox + mode: '0755' + + - name: Create Terraform matchbox groups file from template + ansible.builtin.template: + src: templates/groups.tf.j2 + dest: ~/homelab/terraform/{{ cluster_group }}/groups.tf + mode: '0644' + + - name: Create Terraform matchbox profiles file from template + ansible.builtin.template: + src: templates/profiles.tf.j2 + dest: ~/homelab/terraform/{{ cluster_group }}/profiles.tf + mode: '0644' + + - name: Create Terraform matchbox provider file from template + ansible.builtin.template: + src: templates/provider.tf.j2 + dest: ~/homelab/terraform/{{ cluster_group }}/provider.tf + mode: '0644' + + - name: Configure Matchbox via Terraform + community.general.terraform: + project_path: ~/homelab/terraform/{{ cluster_group }} + state: present + force_init: true diff --git a/ansible/playbooks/templates/agent-config.yaml.j2 b/ansible/playbooks/templates/agent-config.yaml.j2 index 82c2cde..9e0535b 100644 --- a/ansible/playbooks/templates/agent-config.yaml.j2 +++ b/ansible/playbooks/templates/agent-config.yaml.j2 @@ -21,11 +21,13 @@ hosts: ipv4: enabled: true dhcp: true +{% if hostvars[host].boot_mac_address != hostvars[host].install_mac_address %} - name: {{ hostvars[host].boot_interface }} type: ethernet state: down identifier: mac-address mac-address: {{ hostvars[host].boot_mac_address }} +{% endif %} dns-resolver: config: server: diff --git a/ansible/playbooks/templates/install-config.yaml.j2 b/ansible/playbooks/templates/install-config.yaml.j2 index 6328bd8..da50372 100644 --- a/ansible/playbooks/templates/install-config.yaml.j2 +++ b/ansible/playbooks/templates/install-config.yaml.j2 @@ -20,9 +20,14 @@ networking: serviceNetwork: - {{ hostvars[groups[cluster_group][0]].service_network }} platform: +{% if hostvars[groups[cluster_group][0]].platform_type == 'none' %} + {{ hostvars[groups['hub_cluster'][0]].platform_type }}: {} +{% endif %} +{% if hostvars[groups[cluster_group][0]].platform_type == 'baremetal' %} {{ hostvars[groups[cluster_group][0]].platform_type }}: apiVIP: {{ hostvars[groups[cluster_group][0]].api_address }} ingressVIP: {{ hostvars[groups[cluster_group][0]].app_address }} +{% endif %} fips: false pullSecret: '{{ vault_pull_secret }}' sshKey: '{{ vault_ssh_key }}' diff --git a/ansible/playbooks/test.yml b/ansible/playbooks/test.yml new file mode 100644 index 0000000..8fc21c5 --- /dev/null +++ b/ansible/playbooks/test.yml @@ -0,0 +1,27 @@ +--- +- name: Interactively configure an OpenShift cluster + # Run this play on the controller to orchestrate the changes + hosts: localhost + gather_facts: false + + vars_prompt: + - name: cluster_group + prompt: "What is the name of the Cluster Group?" + private: false + + tasks: + - name: Create DNS entry for each cluster node + # Loop over every hostname in the user-provided group + loop: "{{ groups[cluster_group] }}" + loop_control: + # Use a descriptive name for the loop variable instead of 'item' + loop_var: node_hostname + + ansible.builtin.debug: + msg: "Using {{ item, dns_address }}" + +# ansible.builtin.include_tasks: tasks/create_dns_record.yml + vars: + # Access the 'ip_address' variable of the specific host in the loop + dns_address: "{{ hostvars[node_hostname]['ip_address'] }}" + dns_name: "{{ hostvars[node_hostname] }}"