diff --git a/ansible/Playbooks/Docker-Portainer/inventory.yaml b/ansible/Playbooks/Docker-Portainer/inventory.yaml
new file mode 100644
index 0000000..80c494d
--- /dev/null
+++ b/ansible/Playbooks/Docker-Portainer/inventory.yaml
@@ -0,0 +1,8 @@
+---
+docker:
+ hosts:
+ docker01:
+ ansible_host: 192.168.200.222
+ ansible_user: 'ubuntu'
+ ansible_become: true
+ ansible_become_method: sudo
diff --git a/ansible/Playbooks/Docker-Portainer/playbook.yaml b/ansible/Playbooks/Docker-Portainer/playbook.yaml
new file mode 100644
index 0000000..6609da0
--- /dev/null
+++ b/ansible/Playbooks/Docker-Portainer/playbook.yaml
@@ -0,0 +1,7 @@
+---
+- name: Install Docker on Ubuntu
+ hosts: all
+ become: true
+ roles:
+ - docker_install
+ - portainer_deploy
diff --git a/ansible/Playbooks/Docker-Portainer/roles/docker_install/handlers/main.yaml b/ansible/Playbooks/Docker-Portainer/roles/docker_install/handlers/main.yaml
new file mode 100644
index 0000000..303ef11
--- /dev/null
+++ b/ansible/Playbooks/Docker-Portainer/roles/docker_install/handlers/main.yaml
@@ -0,0 +1,5 @@
+---
+- name: Restart Docker
+ ansible.builtin.systemd:
+ name: docker
+ state: restarted
diff --git a/ansible/Playbooks/Docker-Portainer/roles/docker_install/tasks/main.yaml b/ansible/Playbooks/Docker-Portainer/roles/docker_install/tasks/main.yaml
new file mode 100644
index 0000000..a8cc071
--- /dev/null
+++ b/ansible/Playbooks/Docker-Portainer/roles/docker_install/tasks/main.yaml
@@ -0,0 +1,41 @@
+---
+- name: Ensure apt is using HTTPS
+ ansible.builtin.apt:
+ name: "{{ item }}"
+ state: present
+ loop:
+ - apt-transport-https
+ - ca-certificates
+ - curl
+ - software-properties-common
+
+- name: Add Docker GPG key
+ ansible.builtin.apt_key:
+ url: "https://download.docker.com/linux/ubuntu/gpg"
+ state: present
+
+- name: Add Docker repository
+ ansible.builtin.apt_repository:
+ repo: "{{ docker_apt_repository }}"
+ state: present
+
+- name: Install Docker CE
+ ansible.builtin.apt:
+ name: docker-ce
+ state: present
+ update_cache: true
+
+- name: Configure Docker daemon options
+ ansible.builtin.template:
+ src: "templates/docker_daemon.json.j2"
+ dest: "/etc/docker/daemon.json"
+ owner: 'root'
+ group: 'root'
+ mode: '0755' # Optional file permissions
+ notify: Restart Docker
+
+- name: Ensure Docker service is enabled and running
+ ansible.builtin.systemd:
+ name: docker
+ enabled: true
+ state: started
diff --git a/ansible/Playbooks/Docker-Portainer/roles/docker_install/templates/docker_daemon.json.j2 b/ansible/Playbooks/Docker-Portainer/roles/docker_install/templates/docker_daemon.json.j2
new file mode 100644
index 0000000..7858f8e
--- /dev/null
+++ b/ansible/Playbooks/Docker-Portainer/roles/docker_install/templates/docker_daemon.json.j2
@@ -0,0 +1,3 @@
+{
+ "storage-driver": "{{ docker_daemon_options['storage-driver'] }}"
+}
diff --git a/ansible/Playbooks/Docker-Portainer/roles/docker_install/vars/main.yaml b/ansible/Playbooks/Docker-Portainer/roles/docker_install/vars/main.yaml
new file mode 100644
index 0000000..5105d78
--- /dev/null
+++ b/ansible/Playbooks/Docker-Portainer/roles/docker_install/vars/main.yaml
@@ -0,0 +1,5 @@
+---
+docker_apt_release_channel: "stable"
+docker_apt_repository: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
+docker_daemon_options:
+ storage-driver: "overlay2"
diff --git a/ansible/Playbooks/Docker-Portainer/roles/portainer_deploy/handlers/main.yaml b/ansible/Playbooks/Docker-Portainer/roles/portainer_deploy/handlers/main.yaml
new file mode 100644
index 0000000..c2c1aae
--- /dev/null
+++ b/ansible/Playbooks/Docker-Portainer/roles/portainer_deploy/handlers/main.yaml
@@ -0,0 +1,6 @@
+---
+- name: Start Portainer
+ community.docker.docker_compose:
+ project_src: /home/ubuntu/docker-compose/portainer
+ state: present
+ restarted: true
diff --git a/ansible/Playbooks/Docker-Portainer/roles/portainer_deploy/tasks/main.yaml b/ansible/Playbooks/Docker-Portainer/roles/portainer_deploy/tasks/main.yaml
new file mode 100644
index 0000000..483ebae
--- /dev/null
+++ b/ansible/Playbooks/Docker-Portainer/roles/portainer_deploy/tasks/main.yaml
@@ -0,0 +1,34 @@
+---
+- name: Ensure docker-compose is installed
+ ansible.builtin.package:
+ name: docker-compose
+ state: present
+
+- name: Ensure Docker service is running
+ ansible.builtin.service:
+ name: docker
+ state: started
+ enabled: true
+
+- name: Setup Portainer directory
+ ansible.builtin.file:
+ path: /home/ubuntu/docker-compose/portainer
+ state: directory
+ mode: '0755' # Optional file permissions
+ owner: ubuntu # Optional ownership
+ group: ubuntu # Optional group ownership
+
+- name: Deploy Portainer using Docker Compose
+ ansible.builtin.template:
+ src: "templates/docker_compose.yaml.j2"
+ dest: "/home/ubuntu/docker-compose/portainer/docker-compose.yaml"
+ mode: '0755' # Optional file permissions
+ owner: ubuntu # Optional ownership
+ group: ubuntu # Optional group ownership
+ notify:
+ - Start Portainer
+
+- name: Run Portainer docker-compose up
+ community.docker.docker_compose:
+ project_src: /home/ubuntu/docker-compose/portainer
+ state: present
diff --git a/ansible/Playbooks/Docker-Portainer/roles/portainer_deploy/templates/docker_compose.yaml.j2 b/ansible/Playbooks/Docker-Portainer/roles/portainer_deploy/templates/docker_compose.yaml.j2
new file mode 100644
index 0000000..00a105f
--- /dev/null
+++ b/ansible/Playbooks/Docker-Portainer/roles/portainer_deploy/templates/docker_compose.yaml.j2
@@ -0,0 +1,13 @@
+version: '3.3'
+services:
+ portainer:
+ image: portainer/portainer-ce:{{ portainer_version }}
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+ - portainer_data:/data
+ ports:
+ - "9000:9000"
+ restart: always
+
+volumes:
+ portainer_data:
diff --git a/ansible/Playbooks/Docker-Portainer/roles/portainer_deploy/vars/main.yaml b/ansible/Playbooks/Docker-Portainer/roles/portainer_deploy/vars/main.yaml
new file mode 100644
index 0000000..204bbe2
--- /dev/null
+++ b/ansible/Playbooks/Docker-Portainer/roles/portainer_deploy/vars/main.yaml
@@ -0,0 +1,2 @@
+---
+portainer_version: "latest"
diff --git a/ansible/Playbooks/File-Copy/File-Copy-Playbook.yaml b/ansible/Playbooks/File-Copy/File-Copy-Playbook.yaml
new file mode 100644
index 0000000..4eaf2ea
--- /dev/null
+++ b/ansible/Playbooks/File-Copy/File-Copy-Playbook.yaml
@@ -0,0 +1,52 @@
+---
+- name: Deploy Docker Container with Docker Compose
+ hosts: all
+ become: true
+ tasks:
+ - name: Ensure Docker is installed
+ ansible.builtin.package:
+ name: docker
+ state: present
+
+ - name: Ensure Docker service is running
+ ansible.builtin.service:
+ name: docker
+ state: started
+ enabled: true
+
+ - name: Create a directory for Docker Compose files
+ ansible.builtin.file:
+ path: /home/ubuntu/ansible-docker/docker-compose
+ state: directory
+ mode: '0755' # Optional file permissions
+ owner: ubuntu # Optional ownership
+ group: ubuntu # Optional group ownership
+
+ - name: Create a directory for Nginx website files
+ ansible.builtin.file:
+ path: /home/ubuntu/docker/nginx/web
+ state: directory
+ mode: '0755' # Optional file permissions
+ owner: ubuntu # Optional ownership
+ group: ubuntu # Optional group ownership
+
+ - name: Copy docker-compose to remote host
+ ansible.builtin.copy:
+ src: /home/ubuntu/nginx/docker-compose.yaml
+ dest: /home/ubuntu/ansible-docker/docker-compose/docker-compose.yaml
+ mode: '0755' # Optional file permissions
+ owner: ubuntu # Optional ownership
+ group: ubuntu # Optional group ownership
+
+ - name: Copy Nginx website folder to remote host # copies a folder - note no file extension
+ ansible.builtin.copy:
+ src: /home/ubuntu/nginx/website
+ dest: /home/ubuntu/docker/nginx/web
+ mode: '0755' # Optional file permissions
+ owner: ubuntu # Optional ownership
+ group: ubuntu # Optional group ownership
+
+ - name: Start Docker Compose
+ community.docker.docker_compose:
+ project_src: /home/ubuntu/ansible-docker/docker-compose
+ state: present
diff --git a/ansible/Playbooks/File-Copy/File-Copy-Undo-Playbook.yaml b/ansible/Playbooks/File-Copy/File-Copy-Undo-Playbook.yaml
new file mode 100644
index 0000000..52118a1
--- /dev/null
+++ b/ansible/Playbooks/File-Copy/File-Copy-Undo-Playbook.yaml
@@ -0,0 +1,24 @@
+---
+- name: Undo Docker Compose Deployment
+ hosts: all
+ become: true
+ tasks:
+ - name: Stop Docker Container
+ community.docker.docker_compose:
+ project_src: /home/ubuntu/ansible-docker/docker-compose
+ state: absent
+
+ - name: Remove Docker Compose file
+ ansible.builtin.file:
+ path: /home/ubuntu/ansible-docker/docker-compose/docker-compose.yml
+ state: absent
+
+ - name: Remove Docker Compose directory
+ ansible.builtin.file:
+ path: /home/ubuntu/ansible-docker
+ state: absent
+
+ - name: Remove Website directory
+ ansible.builtin.file:
+ path: /home/ubuntu/docker/nginx/web
+ state: absent
diff --git a/ansible/Playbooks/File-Copy/inventory.yaml b/ansible/Playbooks/File-Copy/inventory.yaml
new file mode 100644
index 0000000..34d1a72
--- /dev/null
+++ b/ansible/Playbooks/File-Copy/inventory.yaml
@@ -0,0 +1,8 @@
+---
+docker:
+ hosts:
+ docker01:
+ ansible_host: 192.168.200.50
+ ansible_user: 'ubuntu'
+ ansible_become: true
+ ansible_become_method: sudo
diff --git a/ansible/Playbooks/File-Copy/nginx/docker-compose.yaml b/ansible/Playbooks/File-Copy/nginx/docker-compose.yaml
new file mode 100644
index 0000000..b0812b9
--- /dev/null
+++ b/ansible/Playbooks/File-Copy/nginx/docker-compose.yaml
@@ -0,0 +1,31 @@
+version: "3.9"
+services:
+ web:
+ image: nginx
+ container_name: jimsgarage
+ volumes:
+ - /home/ubuntu/docker/nginx/templates:/etc/nginx/templates
+ - /home/ubuntu/docker/nginx/web/website:/usr/share/nginx/html
+ environment:
+ - NGINX_HOST=nginx.jimsgarage.co.uk
+ - NGINX_PORT=80
+ labels:
+ - "traefik.enable=true"
+ - "traefik.http.routers.nginx.entrypoints=http"
+ - "traefik.http.routers.nginx.rule=Host(`nginx.jimsgarage.co.uk`)"
+ - "traefik.http.middlewares.nginx-https-redirect.redirectscheme.scheme=https"
+ - "traefik.http.routers.nginx.middlewares=nginx-https-redirect"
+ - "traefik.http.routers.nginx-secure.entrypoints=https"
+ - "traefik.http.routers.nginx-secure.rule=Host(`nginx.jimsgarage.co.uk`)"
+ - "traefik.http.routers.nginx-secure.tls=true"
+ - "traefik.http.routers.nginx-secure.service=nginx"
+ - "traefik.http.services.nginx.loadbalancer.server.port=80"
+ - "traefik.docker.network=proxy"
+ networks:
+ proxy:
+ security_opt:
+ - no-new-privileges:true
+
+networks:
+ proxy:
+ external: true
\ No newline at end of file
diff --git a/ansible/Playbooks/File-Copy/nginx/website/Jims-Garage-1.png b/ansible/Playbooks/File-Copy/nginx/website/Jims-Garage-1.png
new file mode 100644
index 0000000..d5491ac
Binary files /dev/null and b/ansible/Playbooks/File-Copy/nginx/website/Jims-Garage-1.png differ
diff --git a/ansible/Playbooks/File-Copy/nginx/website/index.html b/ansible/Playbooks/File-Copy/nginx/website/index.html
new file mode 100644
index 0000000..9deb299
--- /dev/null
+++ b/ansible/Playbooks/File-Copy/nginx/website/index.html
@@ -0,0 +1,108 @@
+
+
+
+
+ Jim's Garage Ansible Demo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Welcome to Jim's Garage Ansible Demo
+
+
+
+
+
Our Features
+
+
+
+
+
Feature 1
+
Dynamic and interactive elements.
+
+
+
+
+
+
Feature 2
+
Responsive design and transitions.
+
+
+
+
+
+
Feature 3
+
Engaging user experiences.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ansible/Playbooks/Multi-OS-Update/Update-Playbook.yaml b/ansible/Playbooks/Multi-OS-Update/Update-Playbook.yaml
new file mode 100644
index 0000000..62275fc
--- /dev/null
+++ b/ansible/Playbooks/Multi-OS-Update/Update-Playbook.yaml
@@ -0,0 +1,57 @@
+---
+- name: Update Windows, Arch Linux, and Ubuntu
+ hosts: all
+ tasks:
+ - name: Gather facts
+ ansible.builtin.setup:
+
+ - name: Update Windows
+ when: ansible_facts['os_family'] == 'Windows'
+ ansible.windows.win_updates:
+ category_names:
+ - SecurityUpdates
+ - UpdateRollups
+ - CriticalUpdates
+ state: installed
+ register: win_update_result
+
+ - name: Check if Windows requires a reboot
+ when: win_update_result.changed and win_update_result.reboot_required | default(false)
+ ansible.windows.win_reboot:
+ reboot_timeout: 600
+ register: win_reboot_result
+
+ - name: Update Arch Linux
+ when: ansible_facts['os_family'] == 'Arch'
+ community.general.pacman:
+ update_cache: true
+ upgrade: true
+ register: arch_update_result
+
+ - name: Check if Arch Linux requires a reboot
+ when: ansible_facts['os_family'] == 'Arch' and arch_update_result.changed
+ ansible.builtin.stat:
+ path: /run/reboot-required
+ register: arch_reboot_required
+
+ - name: Reboot Arch Linux if required
+ when: arch_reboot_required.stat.exists | default(false)
+ ansible.builtin.reboot:
+ reboot_timeout: 600
+
+ - name: Update Ubuntu
+ when: ansible_facts['os_family'] == 'Debian'
+ ansible.builtin.apt:
+ upgrade: dist
+ update_cache: true
+
+ - name: Check if a reboot is required on Ubuntu
+ when: ansible_facts['os_family'] == 'Debian'
+ ansible.builtin.stat:
+ path: /var/run/reboot-required
+ register: ubuntu_reboot_required
+
+ - name: Reboot Ubuntu if required
+ when: ubuntu_reboot_required.stat.exists | default(false)
+ ansible.builtin.reboot:
+ reboot_timeout: 600
diff --git a/ansible/Playbooks/Multi-OS-Update/inventory.yaml b/ansible/Playbooks/Multi-OS-Update/inventory.yaml
new file mode 100644
index 0000000..a7632b8
--- /dev/null
+++ b/ansible/Playbooks/Multi-OS-Update/inventory.yaml
@@ -0,0 +1,14 @@
+arch:
+ hosts:
+ arch01:
+ ansible_host: 192.168.200.214
+ ansible_user: 'root'
+ ansible_python_interpreter: /usr/bin/python3
+
+docker:
+ hosts:
+ docker01:
+ ansible_host: 192.168.200.50
+ ansible_user: 'ubuntu'
+ ansible_become: true
+ ansible_become_method: sudo
\ No newline at end of file
diff --git a/ansible/Playbooks/RKE2/collections/requirements.yaml b/ansible/Playbooks/RKE2/collections/requirements.yaml
new file mode 100644
index 0000000..3ffb535
--- /dev/null
+++ b/ansible/Playbooks/RKE2/collections/requirements.yaml
@@ -0,0 +1,6 @@
+---
+collections:
+ - name: ansible.utils
+ - name: community.general
+ - name: ansible.posix
+ - name: kubernetes.core
\ No newline at end of file
diff --git a/ansible/Playbooks/RKE2/inventory/group_vars/all.yaml b/ansible/Playbooks/RKE2/inventory/group_vars/all.yaml
new file mode 100644
index 0000000..458b16e
--- /dev/null
+++ b/ansible/Playbooks/RKE2/inventory/group_vars/all.yaml
@@ -0,0 +1,18 @@
+os: "linux"
+arch: "amd64"
+
+kube_vip_version: "v0.8.0"
+vip_interface: eth0
+vip: 192.168.3.50
+
+metallb_version: v0.13.12
+lb_range: 192.168.3.80-192.168.3.90
+lb_pool_name: first-pool
+
+rke2_version: "v1.29.4+rke2r1"
+rke2_install_dir: "/usr/local/bin"
+rke2_binary_url: "https://github.com/rancher/rke2/releases/download/{{ rke2_version }}/rke2.linux-amd64"
+
+ansible_user: ubuntu
+ansible_become: true
+ansible_become_method: sudo
diff --git a/ansible/Playbooks/RKE2/inventory/hosts.ini b/ansible/Playbooks/RKE2/inventory/hosts.ini
new file mode 100644
index 0000000..2ebbc5d
--- /dev/null
+++ b/ansible/Playbooks/RKE2/inventory/hosts.ini
@@ -0,0 +1,11 @@
+# Make sure Ansible host has access to these devices
+# Good idea to snapshot all machines and deploy uing cloud-init
+
+[servers]
+server1 ansible_host=192.168.3.21
+server2 ansible_host=192.168.3.22
+server3 ansible_host=192.168.3.23
+
+[agents]
+agent1 ansible_host=192.168.3.24
+agent2 ansible_host=192.168.3.25
diff --git a/ansible/Playbooks/RKE2/roles/add-agent/tasks/main.yaml b/ansible/Playbooks/RKE2/roles/add-agent/tasks/main.yaml
new file mode 100644
index 0000000..edd2aed
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/add-agent/tasks/main.yaml
@@ -0,0 +1,17 @@
+# Copy agent config to all agents - we need to change agent2 & 3 later with the token
+- name: Deploy RKE2 Agent Configuration
+ ansible.builtin.template:
+ src: templates/rke2-agent-config.j2
+ dest: /etc/rancher/rke2/config.yaml
+ owner: root
+ group: root
+ mode: '0644'
+ when: inventory_hostname in groups['agents']
+
+# Check agents have restarted to pick up config
+- name: Ensure RKE2 agents are enabled and running
+ ansible.builtin.systemd:
+ name: rke2-agent
+ enabled: true
+ state: restarted
+ daemon_reload: true
diff --git a/ansible/Playbooks/RKE2/roles/add-agent/templates/rke2-agent-config.j2 b/ansible/Playbooks/RKE2/roles/add-agent/templates/rke2-agent-config.j2
new file mode 100644
index 0000000..3dafb3d
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/add-agent/templates/rke2-agent-config.j2
@@ -0,0 +1,5 @@
+write-kubeconfig-mode: "0644"
+token: {{ hostvars['server1']['token'] }}
+server: https://{{ hostvars['server1']['ansible_host'] }}:9345
+node-label:
+ - "agent=true"
diff --git a/ansible/Playbooks/RKE2/roles/add-server/tasks/main.yaml b/ansible/Playbooks/RKE2/roles/add-server/tasks/main.yaml
new file mode 100644
index 0000000..3acb216
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/add-server/tasks/main.yaml
@@ -0,0 +1,53 @@
+# Copy server config with token to all servers except server 1 (this has token)
+- name: Deploy RKE2 server Configuration
+ ansible.builtin.template:
+ src: templates/rke2-server-config.j2
+ dest: /etc/rancher/rke2/config.yaml
+ owner: root
+ group: root
+ mode: '0644'
+ when: inventory_hostname != groups['servers'][0]
+
+# Keep checking the cluster API until it's functioning (deployed)
+- name: Wait for cluster API to be ready (can take 5-10 mins depending on internet/hardware)
+ ansible.builtin.command:
+ cmd: "kubectl get nodes"
+ register: kubectl_output
+ until: "'connection refused' not in kubectl_output.stderr"
+ retries: 120
+ delay: 10
+ changed_when: true
+ become_user: "{{ ansible_user }}"
+ when: inventory_hostname == groups['servers'][0]
+
+# Use kubectl to deploy yaml. Perhaps this can be added to the manifest folder initially
+- name: Apply kube vip configuration file
+ ansible.builtin.command:
+ cmd: kubectl --kubeconfig /etc/rancher/rke2/rke2.yaml apply -f https://kube-vip.io/manifests/rbac.yaml
+ changed_when: true
+ when: inventory_hostname == groups['servers'][0]
+
+# Apply the kube-vip configration. Perhaps this can be added to the manifest folder initially
+- name: Apply kube vip configuration file
+ ansible.builtin.command:
+ cmd: kubectl --kubeconfig /etc/rancher/rke2/rke2.yaml apply -f https://raw.githubusercontent.com/kube-vip/kube-vip-cloud-provider/main/manifest/kube-vip-cloud-controller.yaml
+ changed_when: true
+ when: inventory_hostname == groups['servers'][0]
+
+# Check that additional servers are restarted
+- name: Ensure additional RKE2 servers are enabled and running
+ ansible.builtin.systemd:
+ name: rke2-server
+ enabled: true
+ state: restarted
+ daemon_reload: true
+ when: inventory_hostname != groups['servers'][0]
+
+# enable additional servers
+- name: Ensure RKE2 server is enabled and running
+ ansible.builtin.systemd:
+ name: rke2-server
+ enabled: true
+ state: restarted
+ daemon_reload: true
+ when: inventory_hostname != groups['servers'][0]
diff --git a/ansible/Playbooks/RKE2/roles/add-server/templates/rke2-server-config.j2 b/ansible/Playbooks/RKE2/roles/add-server/templates/rke2-server-config.j2
new file mode 100644
index 0000000..d7a51e8
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/add-server/templates/rke2-server-config.j2
@@ -0,0 +1,10 @@
+write-kubeconfig-mode: "0644"
+token: {{ hostvars['server1']['token'] }}
+server: https://{{ hostvars['server1']['ansible_host'] }}:9345
+tls-san:
+ - {{ vip }}
+ - {{ hostvars['server1']['ansible_host'] }}
+ - {{ hostvars['server2']['ansible_host'] }}
+ - {{ hostvars['server3']['ansible_host'] }}
+node-label:
+ - server=true
\ No newline at end of file
diff --git a/ansible/Playbooks/RKE2/roles/apply-manifests/tasks/main.yaml b/ansible/Playbooks/RKE2/roles/apply-manifests/tasks/main.yaml
new file mode 100644
index 0000000..bf5ea47
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/apply-manifests/tasks/main.yaml
@@ -0,0 +1,60 @@
+# Wait for Server 1 to be ready before continuing with metallb deployment
+- name: Wait for k8s nodes with node label 'server=true' to be ready, otherwise we cannot start metallb deployment
+ ansible.builtin.command:
+ cmd: "kubectl wait --for=condition=Ready nodes --selector server=true --timeout=600s"
+ register: nodes_ready
+ retries: 120
+ delay: 10
+ changed_when: true
+ become_user: "{{ ansible_user }}"
+ when: inventory_hostname == groups['servers'][0]
+
+# Create namespace so that we can deploy metallb
+- name: Apply metallb namespace
+ ansible.builtin.command:
+ cmd: kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
+ become_user: "{{ ansible_user }}"
+ changed_when: true
+ when: inventory_hostname == groups['servers'][0]
+
+# Apply metallb manifest
+- name: Apply metallb manifest
+ ansible.builtin.command:
+ cmd: kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/{{ metallb_version }}/config/manifests/metallb-native.yaml
+ become_user: "{{ ansible_user }}"
+ changed_when: true
+ when: inventory_hostname == groups['servers'][0]
+
+# Wait for metallb deployment pods to be alive before deploying metallb manifests
+- name: Wait for metallb pods to be ready, otherwise we cannot start metallb deployment
+ ansible.builtin.command:
+ cmd: "kubectl wait --namespace metallb-system --for=condition=ready pod --selector=component=controller --timeout=1800s"
+ changed_when: true
+ become_user: "{{ ansible_user }}"
+ when: inventory_hostname == groups['servers'][0]
+
+# Apply L2 Advertisement for metallb
+- name: Apply metallb L2 Advertisement
+ ansible.builtin.command:
+ cmd: kubectl apply -f https://raw.githubusercontent.com/JamesTurland/JimsGarage/main/Kubernetes/RKE2/l2Advertisement.yaml
+ become_user: "{{ ansible_user }}"
+ changed_when: true
+ when: inventory_hostname == groups['servers'][0]
+
+# Deploy metal IP Pool to Server 1
+- name: Copy metallb IPPool to server 1
+ ansible.builtin.template:
+ src: templates/metallb-ippool.j2
+ dest: /home/{{ ansible_user }}/ippool.yaml
+ owner: "{{ ansible_user }}"
+ group: "{{ ansible_user }}"
+ mode: '0755'
+ when: inventory_hostname == groups['servers'][0]
+
+# don't think this will work as nodes are no execute, might need agents first
+- name: Apply metallb ipppool
+ ansible.builtin.command:
+ cmd: kubectl apply -f /home/{{ ansible_user }}/ippool.yaml
+ become_user: "{{ ansible_user }}"
+ changed_when: true
+ when: inventory_hostname == groups['servers'][0]
diff --git a/ansible/Playbooks/RKE2/roles/apply-manifests/templates/metallb-ippool.j2 b/ansible/Playbooks/RKE2/roles/apply-manifests/templates/metallb-ippool.j2
new file mode 100644
index 0000000..6673b63
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/apply-manifests/templates/metallb-ippool.j2
@@ -0,0 +1,8 @@
+apiVersion: metallb.io/v1beta1
+kind: IPAddressPool
+metadata:
+ name: {{ lb_pool_name }}
+ namespace: metallb-system
+spec:
+ addresses:
+ - {{ lb_range }}
\ No newline at end of file
diff --git a/ansible/Playbooks/RKE2/roles/kube-vip/tasks/main.yaml b/ansible/Playbooks/RKE2/roles/kube-vip/tasks/main.yaml
new file mode 100644
index 0000000..aaa500b
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/kube-vip/tasks/main.yaml
@@ -0,0 +1,17 @@
+# Create directory to deploy kube-vip manifest
+- name: Create directory for Kube VIP Manifest
+ ansible.builtin.file:
+ path: "/var/lib/rancher/rke2/server/manifests"
+ state: directory
+ mode: '0644'
+ when: inventory_hostname in groups['servers']
+
+# Copy kube-vip to server 1 manifest folder for auto deployment at bootstrap
+- name: Deploy Kube VIP Configuration
+ ansible.builtin.template:
+ src: templates/kube-vip-config.j2
+ dest: /var/lib/rancher/rke2/server/manifests/kube-vip.yaml
+ owner: root
+ group: root
+ mode: '0644'
+ when: inventory_hostname == groups['servers'][0]
diff --git a/ansible/Playbooks/RKE2/roles/kube-vip/templates/kube-vip-config.j2 b/ansible/Playbooks/RKE2/roles/kube-vip/templates/kube-vip-config.j2
new file mode 100644
index 0000000..c0731fc
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/kube-vip/templates/kube-vip-config.j2
@@ -0,0 +1,88 @@
+apiVersion: apps/v1
+kind: DaemonSet
+metadata:
+ creationTimestamp: null
+ labels:
+ app.kubernetes.io/name: kube-vip-ds
+ app.kubernetes.io/version: {{ kube_vip_version }}
+ name: kube-vip-ds
+ namespace: kube-system
+spec:
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: kube-vip-ds
+ template:
+ metadata:
+ creationTimestamp: null
+ labels:
+ app.kubernetes.io/name: kube-vip-ds
+ app.kubernetes.io/version: {{ kube_vip_version }}
+ spec:
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: node-role.kubernetes.io/master
+ operator: Exists
+ - matchExpressions:
+ - key: node-role.kubernetes.io/control-plane
+ operator: Exists
+ containers:
+ - args:
+ - manager
+ env:
+ - name: vip_arp
+ value: "true"
+ - name: port
+ value: "6443"
+ - name: vip_interface
+ value: {{ vip_interface }}
+ - name: vip_cidr
+ value: "32"
+ - name: cp_enable
+ value: "true"
+ - name: cp_namespace
+ value: kube-system
+ - name: vip_ddns
+ value: "false"
+ - name: svc_enable
+ value: "false"
+ - name: svc_leasename
+ value: plndr-svcs-lock
+ - name: vip_leaderelection
+ value: "true"
+ - name: vip_leasename
+ value: plndr-cp-lock
+ - name: vip_leaseduration
+ value: "5"
+ - name: vip_renewdeadline
+ value: "3"
+ - name: vip_retryperiod
+ value: "1"
+ - name: address
+ value: {{ vip }}
+ - name: prometheus_server
+ value: :2112
+ image: ghcr.io/kube-vip/kube-vip:{{ kube_vip_version }}
+ imagePullPolicy: Always
+ name: kube-vip
+ resources: {}
+ securityContext:
+ capabilities:
+ add:
+ - NET_ADMIN
+ - NET_RAW
+ hostNetwork: true
+ serviceAccountName: kube-vip
+ tolerations:
+ - effect: NoSchedule
+ operator: Exists
+ - effect: NoExecute
+ operator: Exists
+ updateStrategy: {}
+status:
+ currentNumberScheduled: 0
+ desiredNumberScheduled: 0
+ numberMisscheduled: 0
+ numberReady: 0
diff --git a/ansible/Playbooks/RKE2/roles/prepare-nodes/tasks/main.yaml b/ansible/Playbooks/RKE2/roles/prepare-nodes/tasks/main.yaml
new file mode 100644
index 0000000..400f4b0
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/prepare-nodes/tasks/main.yaml
@@ -0,0 +1,15 @@
+- name: Enable IPv4 forwarding
+ ansible.posix.sysctl:
+ name: net.ipv4.ip_forward
+ value: "1"
+ state: present
+ reload: true
+ tags: sysctl
+
+- name: Enable IPv6 forwarding
+ ansible.posix.sysctl:
+ name: net.ipv6.conf.all.forwarding
+ value: "1"
+ state: present
+ reload: true
+ tags: sysctl
\ No newline at end of file
diff --git a/ansible/Playbooks/RKE2/roles/rke2-download/tasks/main.yaml b/ansible/Playbooks/RKE2/roles/rke2-download/tasks/main.yaml
new file mode 100644
index 0000000..c273e6e
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/rke2-download/tasks/main.yaml
@@ -0,0 +1,20 @@
+# Create a directory to download RKE2 binary to
+- name: Create directory for RKE2 binary
+ ansible.builtin.file:
+ path: "{{ rke2_install_dir }}"
+ state: directory
+ mode: '0755'
+
+# Download the RKE2 binary
+- name: Download RKE2 binary
+ ansible.builtin.get_url:
+ url: "{{ rke2_binary_url }}"
+ dest: "{{ rke2_install_dir }}/rke2"
+ mode: '0755'
+
+# Set permissions on the RKE2 binary
+- name: Set executable permissions on the RKE2 binary
+ ansible.builtin.file:
+ path: "{{ rke2_install_dir }}/rke2"
+ mode: '0755'
+ state: file
diff --git a/ansible/Playbooks/RKE2/roles/rke2-download/vars/main.yaml b/ansible/Playbooks/RKE2/roles/rke2-download/vars/main.yaml
new file mode 100644
index 0000000..e69de29
diff --git a/ansible/Playbooks/RKE2/roles/rke2-prepare/tasks/main.yaml b/ansible/Playbooks/RKE2/roles/rke2-prepare/tasks/main.yaml
new file mode 100644
index 0000000..f1fbccc
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/rke2-prepare/tasks/main.yaml
@@ -0,0 +1,134 @@
+- name: Create directory for RKE2 config
+ ansible.builtin.file:
+ path: "/etc/rancher/rke2"
+ state: directory
+ mode: '0644'
+
+- name: Create directory for RKE2 token
+ ansible.builtin.file:
+ path: "/var/lib/rancher/rke2/server"
+ state: directory
+ mode: '0644'
+
+# Copy server config to server 1 for bootstrap - we need to change server2 & 3 later with the token
+- name: Deploy RKE2 server Configuration
+ ansible.builtin.template:
+ src: templates/rke2-server-config.j2
+ dest: /etc/rancher/rke2/config.yaml
+ owner: root
+ group: root
+ mode: '0644'
+ when: inventory_hostname in groups['servers']
+
+- name: Create systemd service file for RKE2 server
+ ansible.builtin.template:
+ src: templates/rke2-server.service.j2
+ dest: /etc/systemd/system/rke2-server.service
+ owner: root
+ group: root
+ mode: '0644'
+ when: inventory_hostname in groups['servers']
+
+- name: Create systemd service file for RKE2 agent
+ ansible.builtin.template:
+ src: templates/rke2-agent.service.j2
+ dest: /etc/systemd/system/rke2-agent.service
+ owner: root
+ group: root
+ mode: '0644'
+ when: inventory_hostname in groups['agents']
+
+# we enable the first server to generate tokens etc, copy this afterwards to other servers
+- name: Ensure RKE2 server is enabled and running
+ ansible.builtin.systemd:
+ name: rke2-server
+ enabled: true
+ state: restarted
+ daemon_reload: true
+ when: inventory_hostname in groups['servers'][0]
+
+# wait for node token to be availale so that we can copy it, we need this to join other nodes
+- name: Wait for node-token
+ ansible.builtin.wait_for:
+ path: /var/lib/rancher/rke2/server/node-token
+ when: inventory_hostname == groups['servers'][0]
+
+# wait for kubectl to be downloaded, part of the rke2 installation
+- name: Wait for kubectl
+ ansible.builtin.wait_for:
+ path: /var/lib/rancher/rke2/bin/kubectl
+ when: inventory_hostname == groups['servers'][0]
+
+# copy kubectl to usr bin so that all users can run kubectl commands
+- name: Copy kubectl to user bin
+ ansible.builtin.copy:
+ src: /var/lib/rancher/rke2/bin/kubectl
+ dest: /usr/local/bin/kubectl
+ mode: '0755'
+ remote_src: true
+ become: true
+ when: inventory_hostname == groups['servers'][0]
+
+# wait for the kubectl copy to complete
+- name: Wait for kubectl
+ ansible.builtin.wait_for:
+ path: /usr/local/bin/kubectl
+ when: inventory_hostname == groups['servers'][0]
+
+# modify token access
+- name: Register node-token file access mode
+ ansible.builtin.stat:
+ path: /var/lib/rancher/rke2/server
+ register: p
+
+- name: Change file access for node-token
+ ansible.builtin.file:
+ path: /var/lib/rancher/rke2/server
+ mode: "g+rx,o+rx"
+ when: inventory_hostname == groups['servers'][0]
+
+# Save token as variable
+- name: Fetch the token from the first server node
+ ansible.builtin.slurp:
+ src: /var/lib/rancher/rke2/server/token
+ register: rke2_token
+ when: inventory_hostname == groups['servers'][0]
+ run_once: true
+
+# convert token to fact
+- name: Save Master node-token for later
+ ansible.builtin.set_fact:
+ token: "{{ rke2_token.content | b64decode | regex_replace('\n', '') }}"
+
+# revert token file access
+- name: Restore node-token file access
+ ansible.builtin.file:
+ path: /var/lib/rancher/rke2/server
+ mode: "{{ p.stat.mode }}"
+ when: inventory_hostname == groups['servers'][0]
+
+# check .kube folder exists so that we can use kubectl (config resides here)
+- name: Ensure .kube directory exists in user's home
+ ansible.builtin.file:
+ path: "/home/{{ ansible_user }}/.kube"
+ state: directory
+ mode: '0755'
+ become: true
+
+# copy kubectl config file to .kube folder
+- name: Copy config file to user home directory
+ ansible.builtin.copy:
+ src: /etc/rancher/rke2/rke2.yaml
+ dest: "/home/{{ ansible_user }}/.kube/config"
+ remote_src: true
+ owner: "{{ ansible_user }}"
+ mode: "u=rw,g=,o="
+ when: inventory_hostname == groups['servers'][0]
+
+# change IP from local to server 1 IP
+- name: Replace IP address with server1
+ ansible.builtin.replace:
+ path: /home/{{ ansible_user }}/.kube/config
+ regexp: '127.0.0.1'
+ replace: "{{ hostvars['server1']['ansible_host'] }}"
+ when: inventory_hostname == groups['servers'][0]
diff --git a/ansible/Playbooks/RKE2/roles/rke2-prepare/templates/rke2-agent.service.j2 b/ansible/Playbooks/RKE2/roles/rke2-prepare/templates/rke2-agent.service.j2
new file mode 100644
index 0000000..b032208
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/rke2-prepare/templates/rke2-agent.service.j2
@@ -0,0 +1,13 @@
+# rke2-agent.service.j2
+[Unit]
+Description=RKE2 Agent
+After=network.target
+
+[Service]
+ExecStart=/usr/local/bin/rke2 agent
+KillMode=process
+Restart=on-failure
+RestartSec=5s
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/Playbooks/RKE2/roles/rke2-prepare/templates/rke2-server-config.j2 b/ansible/Playbooks/RKE2/roles/rke2-prepare/templates/rke2-server-config.j2
new file mode 100644
index 0000000..a3131f1
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/rke2-prepare/templates/rke2-server-config.j2
@@ -0,0 +1,10 @@
+write-kubeconfig-mode: "0644"
+tls-san:
+ - {{ vip }}
+ - {{ hostvars['server1']['ansible_host'] }}
+ - {{ hostvars['server2']['ansible_host'] }}
+ - {{ hostvars['server3']['ansible_host'] }}
+node-label:
+ - server=true
+disable:
+ - rke2-ingress-nginx
\ No newline at end of file
diff --git a/ansible/Playbooks/RKE2/roles/rke2-prepare/templates/rke2-server.service.j2 b/ansible/Playbooks/RKE2/roles/rke2-prepare/templates/rke2-server.service.j2
new file mode 100644
index 0000000..a091ebd
--- /dev/null
+++ b/ansible/Playbooks/RKE2/roles/rke2-prepare/templates/rke2-server.service.j2
@@ -0,0 +1,13 @@
+# rke2-server.service.j2
+[Unit]
+Description=RKE2 server
+After=network.target
+
+[Service]
+ExecStart=/usr/local/bin/rke2 server
+KillMode=process
+Restart=on-failure
+RestartSec=5s
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/Playbooks/RKE2/roles/rke2-prepare/vars/main.yaml b/ansible/Playbooks/RKE2/roles/rke2-prepare/vars/main.yaml
new file mode 100644
index 0000000..e69de29
diff --git a/ansible/Playbooks/RKE2/site.yaml b/ansible/Playbooks/RKE2/site.yaml
new file mode 100644
index 0000000..d885cbb
--- /dev/null
+++ b/ansible/Playbooks/RKE2/site.yaml
@@ -0,0 +1,61 @@
+# Hello, thanks for using my playbook, hopefully you can help to improve it.
+# Things that need adding: (there are many more)
+# 1) Support different OS & architectures
+# 2) Support multiple CNIs
+# 3) Improve the wait logic
+# 4) Use kubernetes Ansible plugins more sensibly
+# 5) Optimise flow logic
+# 6) Clean up
+
+###############################################################
+# MAKE SURE YOU CHANGE group_vars/all.yaml VARIABLES!!!!!!!!!!!
+###############################################################
+
+# bootstraps first server and copies configs for others/agents
+- name: Prepare all nodes
+ hosts: servers,agents
+ gather_facts: true # enables us to gather lots of useful variables: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/setup_module.html
+ roles:
+ - prepare-nodes
+
+# creates directories for download and then downloads RKE2 and changes permissions
+- name: Download RKE2
+ hosts: servers,agents
+ gather_facts: true
+ roles:
+ - rke2-download
+
+# Creates RKE2 bootstrap manifests folder and copies kube-vip template over (configured with variables)
+- name: Deploy Kube VIP
+ hosts: servers
+ gather_facts: true
+ roles:
+ - kube-vip
+
+# bootstraps the first server, copies configs to nodes, saves token to use later
+- name: Prepare RKE2 on Servers and Agents
+ hosts: servers,agents
+ gather_facts: true
+ roles:
+ - rke2-prepare
+
+# Adds additional servers using the token from the previous task
+- name: Add additional RKE2 Servers
+ hosts: servers
+ gather_facts: true
+ roles:
+ - add-server
+
+# Adds agents to the cluster
+- name: Add additional RKE2 Agents
+ hosts: agents
+ gather_facts: true
+ roles:
+ - add-agent
+
+# Finish kube-vip, add metallb
+- name: Apply manifests after cluster is created
+ hosts: servers
+ gather_facts: true
+ roles:
+ - apply-manifests
diff --git a/ansible/Playbooks/Secrets-Variables/File-Copy-Playbook.yaml b/ansible/Playbooks/Secrets-Variables/File-Copy-Playbook.yaml
new file mode 100644
index 0000000..257ed87
--- /dev/null
+++ b/ansible/Playbooks/Secrets-Variables/File-Copy-Playbook.yaml
@@ -0,0 +1,67 @@
+---
+- name: Deploy Docker Container with Docker Compose
+ hosts: all
+ become: true
+ tasks:
+ - name: Include variables file
+ ansible.builtin.include_vars: myvars.yaml
+
+ - name: Ensure Docker is installed
+ ansible.builtin.package:
+ name: docker
+ state: present
+
+ - name: Ensure Docker service is running
+ ansible.builtin.service:
+ name: docker
+ state: started
+ enabled: true
+
+ - name: Create a directory for Docker Compose files
+ ansible.builtin.file:
+ path: /home/ubuntu/ansible-docker/docker-compose
+ state: directory
+ mode: '0755' # Optional file permissions
+ owner: ubuntu # Optional ownership
+ group: ubuntu # Optional group ownership
+
+ - name: Create a directory for Nginx website files
+ ansible.builtin.file:
+ path: /home/ubuntu/docker/nginx/web
+ state: directory
+ mode: '0755' # Optional file permissions
+ owner: ubuntu # Optional ownership
+ group: ubuntu # Optional group ownership
+
+ - name: Copy docker-compose to remote host
+ ansible.builtin.copy:
+ src: /home/ubuntu/nginx/docker-compose.yaml
+ dest: /home/ubuntu/ansible-docker/docker-compose/docker-compose.yaml
+ mode: '0755' # Optional file permissions
+ owner: ubuntu # Optional ownership
+ group: ubuntu # Optional group ownership
+
+ - name: Copy Nginx website folder to remote host # copies a folder - note no file extension
+ ansible.builtin.copy:
+ src: /home/ubuntu/nginx/website
+ dest: /home/ubuntu/docker/nginx/web
+ mode: '0755' # Optional file permissions
+ owner: ubuntu # Optional ownership
+ group: ubuntu # Optional group ownership
+
+ - name: Replace old name with new name (requires Ansible >= 2.4)
+ ansible.builtin.replace:
+ path: /home/ubuntu/docker/nginx/web/website/index.html
+ regexp: "Jim's Garage"
+ replace: "{{ website_name }}"
+
+ - name: Access and print secret
+ ansible.builtin.replace:
+ path: /home/ubuntu/docker/nginx/web/website/index.html
+ regexp: "Our Features"
+ replace: "{{ api_key }}"
+
+ - name: Start Docker Compose
+ community.docker.docker_compose:
+ project_src: /home/ubuntu/ansible-docker/docker-compose
+ state: present
diff --git a/ansible/Playbooks/Secrets-Variables/password b/ansible/Playbooks/Secrets-Variables/password
new file mode 100644
index 0000000..7aa311a
--- /dev/null
+++ b/ansible/Playbooks/Secrets-Variables/password
@@ -0,0 +1 @@
+password
\ No newline at end of file
diff --git a/ansible/Playbooks/Secrets-Variables/secrets_file.enc b/ansible/Playbooks/Secrets-Variables/secrets_file.enc
new file mode 100644
index 0000000..33ec709
--- /dev/null
+++ b/ansible/Playbooks/Secrets-Variables/secrets_file.enc
@@ -0,0 +1 @@
+api_key: SuperSecretPassword
\ No newline at end of file
diff --git a/ansible/Playbooks/talos/collections/requirements.yaml b/ansible/Playbooks/talos/collections/requirements.yaml
new file mode 100644
index 0000000..3ffb535
--- /dev/null
+++ b/ansible/Playbooks/talos/collections/requirements.yaml
@@ -0,0 +1,6 @@
+---
+collections:
+ - name: ansible.utils
+ - name: community.general
+ - name: ansible.posix
+ - name: kubernetes.core
\ No newline at end of file
diff --git a/ansible/Playbooks/talos/inventory/group_vars/all.yaml b/ansible/Playbooks/talos/inventory/group_vars/all.yaml
new file mode 100644
index 0000000..ed46479
--- /dev/null
+++ b/ansible/Playbooks/talos/inventory/group_vars/all.yaml
@@ -0,0 +1,27 @@
+os: "linux"
+arch: "amd64"
+
+talos_version: v1.7.0
+talosctl_version: v1.7.5
+control_plane_ip: 192.168.50.195
+
+control_plane_2: 192.168.50.196
+control_plane_3: 192.168.50.197
+
+worker_1: 192.168.50.198
+worker_2: 192.168.50.199
+
+config_directory: "/home/{{ ansible_user }}/.talos"
+config_file: "/home/{{ ansible_user }}/.talos/talosconfig"
+
+kube_vip_version: "v0.8.0"
+vip_interface: null
+vip: 192.168.50.220
+
+metallb_version: v0.13.12
+lb_range: 192.168.50.240-192.168.50.250
+lb_pool_name: first-pool
+
+ansible_user: ubuntu
+ansible_become: true
+ansible_become_method: sudo
diff --git a/ansible/Playbooks/talos/inventory/hosts.ini b/ansible/Playbooks/talos/inventory/hosts.ini
new file mode 100644
index 0000000..598dcf2
--- /dev/null
+++ b/ansible/Playbooks/talos/inventory/hosts.ini
@@ -0,0 +1,13 @@
+# Make sure Ansible host has access to these devices
+# Good idea to snapshot all machines and deploy uing cloud-template
+[ansible]
+127.0.0.1 ansible_connection=local
+
+[servers]
+server1 ansible_host=192.168.50.195
+server2 ansible_host=192.168.50.196
+server3 ansible_host=192.168.50.197
+
+[agents]
+agent1 ansible_host=192.168.50.198
+agent2 ansible_host=192.168.50.199
diff --git a/ansible/Playbooks/talos/roles/add-workers/tasks/main.yaml b/ansible/Playbooks/talos/roles/add-workers/tasks/main.yaml
new file mode 100644
index 0000000..96996b1
--- /dev/null
+++ b/ansible/Playbooks/talos/roles/add-workers/tasks/main.yaml
@@ -0,0 +1,11 @@
+---
+# Generate Machine Configurations. This is using the qemu agent as per: https://www.talos.dev/v1.7/talos-guides/install/virtualized-platforms/proxmox/
+- name: Apply config to first worker
+ ansible.builtin.command:
+ cmd: talosctl apply-config --insecure --nodes {{ worker_1 }} --file {{ config_directory }}/worker.yaml
+ changed_when: true
+
+- name: Apply config to second worker
+ ansible.builtin.command:
+ cmd: talosctl apply-config --insecure --nodes {{ worker_2 }} --file {{ config_directory }}/worker.yaml
+ changed_when: true
diff --git a/ansible/Playbooks/talos/roles/apply-config/tasks/main.yaml b/ansible/Playbooks/talos/roles/apply-config/tasks/main.yaml
new file mode 100644
index 0000000..55dede7
--- /dev/null
+++ b/ansible/Playbooks/talos/roles/apply-config/tasks/main.yaml
@@ -0,0 +1,16 @@
+---
+# Generate Machine Configurations. This is using the qemu agent as per: https://www.talos.dev/v1.7/talos-guides/install/virtualized-platforms/proxmox/
+- name: Apply config to first node
+ ansible.builtin.command:
+ cmd: talosctl apply-config --insecure --nodes {{ control_plane_ip }} --file {{ config_directory }}/controlplane.yaml
+ changed_when: true
+
+- name: Apply config to second node
+ ansible.builtin.command:
+ cmd: talosctl apply-config --insecure --nodes {{ control_plane_2 }} --file {{ config_directory }}/controlplane.yaml
+ changed_when: true
+
+- name: Apply config to first node
+ ansible.builtin.command:
+ cmd: talosctl apply-config --insecure --nodes {{ control_plane_3 }} --file {{ config_directory }}/controlplane.yaml
+ changed_when: true
diff --git a/ansible/Playbooks/talos/roles/configure-cluster/tasks/main.yaml b/ansible/Playbooks/talos/roles/configure-cluster/tasks/main.yaml
new file mode 100644
index 0000000..fb03399
--- /dev/null
+++ b/ansible/Playbooks/talos/roles/configure-cluster/tasks/main.yaml
@@ -0,0 +1,11 @@
+---
+- name: Check that the config file doesn't already exist
+ ansible.builtin.stat:
+ path: "{{ config_file }}"
+ register: stat_result
+
+# Generate Machine Configurations. This is using the qemu agent as per: https://www.talos.dev/v1.7/talos-guides/install/virtualized-platforms/proxmox/
+- name: Generate config for cluster
+ when: "not stat_result.stat.exists"
+ ansible.builtin.command: talosctl gen config talos-proxmox-cluster https://{{ control_plane_ip }}:6443 --output-dir {{ config_directory }} --install-image factory.talos.dev/installer/ce4c980550dd2ab1b17bbf2b08801c7eb59418eafe8f279833297925d67c7515:{{ talos_version }}
+ changed_when: true
diff --git a/ansible/Playbooks/talos/roles/configure-talosctl/tasks/main.yaml b/ansible/Playbooks/talos/roles/configure-talosctl/tasks/main.yaml
new file mode 100644
index 0000000..b14ec7d
--- /dev/null
+++ b/ansible/Playbooks/talos/roles/configure-talosctl/tasks/main.yaml
@@ -0,0 +1,26 @@
+---
+# Update TalosCTL
+- name: Update TalosCTL configs
+ ansible.builtin.command: talosctl config endpoint {{ control_plane_ip }} --talosconfig {{ config_file }}
+ changed_when: true
+
+- name: Update TalosCTL configs
+ ansible.builtin.command: talosctl config node {{ control_plane_ip }} --talosconfig {{ config_file }}
+ changed_when: true
+
+ #################################
+ # WAIT FOR REBOOT & BOOTSTRAP #
+ #################################
+- name: Keep trying to bootstrap
+ ansible.builtin.command:
+ cmd: "talosctl bootstrap --talosconfig {{ config_file }}"
+ register: bootstrap_result
+ retries: 10
+ delay: 30
+ until: bootstrap_result.rc == 0
+ changed_when: bootstrap_result.rc == 0
+
+# Grab Kubeconfig
+- name: Get Kubeconfig
+ ansible.builtin.command: talosctl kubeconfig . --talosconfig {{ config_file }}
+ changed_when: true
diff --git a/ansible/Playbooks/talos/roles/install-talosctl/tasks/main.yaml b/ansible/Playbooks/talos/roles/install-talosctl/tasks/main.yaml
new file mode 100644
index 0000000..d049a94
--- /dev/null
+++ b/ansible/Playbooks/talos/roles/install-talosctl/tasks/main.yaml
@@ -0,0 +1,12 @@
+---
+# Ansible Playbook to install Talos
+- name: Download talosctl for Linux (amd64)
+ ansible.builtin.get_url:
+ url: https://github.com/siderolabs/talos/releases/download/{{ talosctl_version }}/talosctl-linux-amd64
+ dest: /usr/local/bin/talosctl
+ mode: '0755' # Make the binary executable
+ register: download_result # Register the result for debugging or verification
+
+- name: Display download result
+ ansible.builtin.debug:
+ var: download_result # Display the result of the download task
diff --git a/ansible/Playbooks/talos/site.yaml b/ansible/Playbooks/talos/site.yaml
new file mode 100644
index 0000000..31e2477
--- /dev/null
+++ b/ansible/Playbooks/talos/site.yaml
@@ -0,0 +1,37 @@
+# Hello, thanks for using my playbook, hopefully you can help to improve it.
+
+# Install TalosCTL on Ansible node
+- name: Install TalosCTL
+ hosts: ansible
+ gather_facts: true # enables us to gather lots of useful variables: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/setup_module.html
+ become: true
+ roles:
+ - install-talosctl
+
+# Configure Cluster Configuration
+- name: Configure Cluster
+ hosts: ansible
+ gather_facts: true
+ roles:
+ - configure-cluster
+
+# Apply Cluster Configuration
+- name: Configure Cluster
+ hosts: ansible
+ gather_facts: true
+ roles:
+ - apply-config
+
+# Configure TalosCTL
+- name: Configure TalosCTL
+ hosts: ansible
+ gather_facts: true
+ roles:
+ - configure-talosctl
+
+# Add Workers
+- name: Add Workers
+ hosts: ansible
+ gather_facts: true
+ roles:
+ - add-workers
diff --git a/ansible/Playbooks/update/readme.md b/ansible/Playbooks/update/readme.md
new file mode 100644
index 0000000..73f9024
--- /dev/null
+++ b/ansible/Playbooks/update/readme.md
@@ -0,0 +1,7 @@
+# Add to Hosts File (change ansible_user if required)
+```
+[all:vars]
+ansible_user='ubuntu'
+ansible_become=yes
+ansible_become_method=sudo
+```
\ No newline at end of file
diff --git a/ansible/Playbooks/update/update-builtin.yml b/ansible/Playbooks/update/update-builtin.yml
new file mode 100644
index 0000000..0ae92d8
--- /dev/null
+++ b/ansible/Playbooks/update/update-builtin.yml
@@ -0,0 +1,24 @@
+---
+- hosts: all
+ gather_facts: yes
+ become: yes
+
+ tasks:
+ - name: Perform a distro upgrade
+ ansible.builtin.apt:
+ upgrade: dist
+ update_cache: yes
+
+ - name: Check if a reboot is required
+ ansible.builtin.stat:
+ path: /var/run/reboot-required
+ get_checksum: no
+ register: reboot_required_file
+
+ - name: Reboot the server (if necessary)
+ ansible.builtin.reboot:
+ when: reboot_required_file.stat.exists == true
+
+ - name: Remove dependencies that are no longer needed
+ ansible.builtin.apt:
+ autoremove: yes
\ No newline at end of file
diff --git a/ansible/Playbooks/update/update.yml b/ansible/Playbooks/update/update.yml
new file mode 100644
index 0000000..a87ace6
--- /dev/null
+++ b/ansible/Playbooks/update/update.yml
@@ -0,0 +1,23 @@
+---
+- hosts: all
+ become: true
+ tasks:
+ - name: Update apt repo and cache on all Debian/Ubuntu boxes
+ apt: update_cache=yes force_apt_get=yes cache_valid_time=3600
+
+ - name: Upgrade all packages on servers
+ apt: upgrade=dist force_apt_get=yes
+
+ - name: Check if a reboot is needed on all servers
+ register: reboot_required_file
+ stat: path=/var/run/reboot-required get_checksum=false
+
+ - name: Reboot the box if kernel updated
+ reboot:
+ msg: "Reboot initiated by Ansible for kernel updates"
+ connect_timeout: 5
+ reboot_timeout: 300
+ pre_reboot_delay: 0
+ post_reboot_delay: 30
+ test_command: uptime
+ when: reboot_required_file.stat.exists
diff --git a/kubernetes/service/metallb.yaml b/kubernetes/service/metallb.yaml
new file mode 100644
index 0000000..ae4d9c2
--- /dev/null
+++ b/kubernetes/service/metallb.yaml
@@ -0,0 +1,14 @@
+apiVersion: metallb.io/v1beta1
+kind: IPAddressPool
+metadata:
+ name: first-pool
+ namespace: metallb-system
+spec:
+ addresses:
+ - 192.168.50.230-192.168.50.240
+---
+apiVersion: metallb.io/v1beta1
+kind: L2Advertisement
+metadata:
+ name: metallb-l2adv
+ namespace: metallb-system