infra/ansible/k8s-cluster.yml
2025-07-24 09:55:24 -05:00

300 lines
No EOL
8.2 KiB
YAML

---
# Playbook to deploy a 3-node Kubernetes cluster on Proxmox
# This creates VMs on Proxmox and then installs K8s
- name: Create VMs on Proxmox
hosts: proxmox
gather_facts: yes
vars:
k8s_nodes:
- name: k8s-master
vmid: 200
cores: 2
memory: 4096
disk: 40
ip: 10.0.19.200/24
- name: k8s-worker1
vmid: 201
cores: 2
memory: 4096
disk: 40
ip: 10.0.19.201/24
- name: k8s-worker2
vmid: 202
cores: 2
memory: 4096
disk: 40
ip: 10.0.19.202/24
template_vmid: 9000 # Your cloud-init template
gateway: 10.0.19.254
nameserver: 10.0.19.254
storage: local-lvm
network_bridge: vmbr0
tasks:
- name: Clone VMs from template
community.general.proxmox_kvm:
api_user: root@pam
api_password: "{{ proxmox_password }}"
api_host: "{{ ansible_host | default(ansible_default_ipv4.address) }}"
clone: "{{ template_vmid }}"
name: "{{ item.name }}"
vmid: "{{ item.vmid }}"
node: "{{ ansible_hostname }}"
storage: "{{ storage }}"
timeout: 300
loop: "{{ k8s_nodes }}"
when: ansible_hostname == "lab01" # Create all VMs on first host
- name: Configure VM resources
community.general.proxmox_kvm:
api_user: root@pam
api_password: "{{ proxmox_password }}"
api_host: "{{ ansible_host | default(ansible_default_ipv4.address) }}"
name: "{{ item.name }}"
cores: "{{ item.cores }}"
memory: "{{ item.memory }}"
update: yes
loop: "{{ k8s_nodes }}"
when: ansible_hostname == "lab01"
- name: Configure cloud-init
community.general.proxmox_kvm:
api_user: root@pam
api_password: "{{ proxmox_password }}"
api_host: "{{ ansible_host | default(ansible_default_ipv4.address) }}"
name: "{{ item.name }}"
ciuser: debian
cipassword: "{{ vm_password | default('changeme') }}"
ipconfig:
ipconfig0: "ip={{ item.ip }},gw={{ gateway }}"
nameservers: "{{ nameserver }}"
sshkeys: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
update: yes
loop: "{{ k8s_nodes }}"
when: ansible_hostname == "lab01"
- name: Start VMs
community.general.proxmox_kvm:
api_user: root@pam
api_password: "{{ proxmox_password }}"
api_host: "{{ ansible_host | default(ansible_default_ipv4.address) }}"
name: "{{ item.name }}"
state: started
loop: "{{ k8s_nodes }}"
when: ansible_hostname == "lab01"
- name: Wait for VMs to be reachable
wait_for:
host: "{{ item.ip.split('/')[0] }}"
port: 22
delay: 30
timeout: 300
loop: "{{ k8s_nodes }}"
delegate_to: localhost
- name: Prepare K8s nodes
hosts: k8s_cluster
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
cache_valid_time: 3600
- name: Install required packages
apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg
- lsb-release
- software-properties-common
state: present
- name: Disable swap
command: swapoff -a
- name: Remove swap from fstab
lineinfile:
path: /etc/fstab
regexp: '\sswap\s'
state: absent
- name: Load required kernel modules
modprobe:
name: "{{ item }}"
state: present
loop:
- overlay
- br_netfilter
- name: Setup required sysctl params
sysctl:
name: "{{ item.key }}"
value: "{{ item.value }}"
sysctl_set: yes
state: present
reload: yes
loop:
- { key: net.bridge.bridge-nf-call-iptables, value: 1 }
- { key: net.bridge.bridge-nf-call-ip6tables, value: 1 }
- { key: net.ipv4.ip_forward, value: 1 }
- name: Install containerd
hosts: k8s_cluster
become: yes
tasks:
- name: Add Docker GPG key
apt_key:
url: https://download.docker.com/linux/debian/gpg
state: present
- name: Add Docker repository
apt_repository:
repo: "deb [arch=amd64] https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable"
state: present
- name: Install containerd
apt:
name: containerd.io
state: present
- name: Create containerd config directory
file:
path: /etc/containerd
state: directory
- name: Generate default containerd config
shell: containerd config default > /etc/containerd/config.toml
args:
creates: /etc/containerd/config.toml
- name: Configure containerd to use systemd cgroup
lineinfile:
path: /etc/containerd/config.toml
regexp: ' SystemdCgroup = false'
line: ' SystemdCgroup = true'
- name: Restart containerd
systemd:
name: containerd
state: restarted
enabled: yes
- name: Install Kubernetes
hosts: k8s_cluster
become: yes
vars:
kubernetes_version: "1.33"
kubernetes_patch_version: "1.33.3"
tasks:
- name: Add Kubernetes GPG key
apt_key:
url: https://pkgs.k8s.io/core:/stable:/v{{ kubernetes_version }}/deb/Release.key
state: present
- name: Add Kubernetes repository
apt_repository:
repo: "deb https://pkgs.k8s.io/core:/stable:/v{{ kubernetes_version }}/deb/ /"
state: present
- name: Install Kubernetes packages
apt:
name:
- kubelet={{ kubernetes_patch_version }}-*
- kubeadm={{ kubernetes_patch_version }}-*
- kubectl={{ kubernetes_patch_version }}-*
state: present
- name: Hold Kubernetes packages
dpkg_selections:
name: "{{ item }}"
selection: hold
loop:
- kubelet
- kubeadm
- kubectl
- name: Initialize Kubernetes master
hosts: k8s_master
become: yes
vars:
pod_network_cidr: "10.244.0.0/16"
tasks:
- name: Check if kubeadm has already run
stat:
path: /etc/kubernetes/admin.conf
register: kubeadm_init
- name: Initialize master node
command: |
kubeadm init --pod-network-cidr={{ pod_network_cidr }} \
--apiserver-advertise-address={{ ansible_default_ipv4.address }}
when: not kubeadm_init.stat.exists
register: kubeadm_output
- name: Create .kube directory for debian user
file:
path: /home/debian/.kube
state: directory
owner: debian
group: debian
mode: '0755'
- name: Copy admin.conf to debian user
copy:
src: /etc/kubernetes/admin.conf
dest: /home/debian/.kube/config
remote_src: yes
owner: debian
group: debian
mode: '0644'
- name: Install Flannel CNI
become: no
command: kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
- name: Generate join command
command: kubeadm token create --print-join-command
register: join_command
- name: Save join command
set_fact:
kubeadm_join_command: "{{ join_command.stdout }}"
- name: Join worker nodes
hosts: k8s_workers
become: yes
tasks:
- name: Check if node has already joined
stat:
path: /etc/kubernetes/kubelet.conf
register: kubelet_conf
- name: Join cluster
command: "{{ hostvars[groups['k8s_master'][0]]['kubeadm_join_command'] }}"
when: not kubelet_conf.stat.exists
- name: Configure kubectl for management
hosts: k8s_master
become: no
tasks:
- name: Check nodes
command: kubectl get nodes
register: nodes_output
- name: Display nodes
debug:
var: nodes_output.stdout_lines
- name: Install metrics server
command: kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
- name: Create dashboard namespace
command: kubectl create namespace kubernetes-dashboard
ignore_errors: yes
- name: Install Kubernetes dashboard
command: kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml