k8s start

This commit is contained in:
Graham McIntire 2025-07-24 09:55:24 -05:00
parent d5bddcbbaa
commit 718f1d2f90
No known key found for this signature in database
11 changed files with 851 additions and 4 deletions

169
ansible/K8S-DEPLOYMENT.md Normal file
View file

@ -0,0 +1,169 @@
# Kubernetes Cluster Deployment on Proxmox
This guide helps you deploy a 3-node Kubernetes cluster on Proxmox using Debian 12.
## Prerequisites
1. Three Proxmox hosts (lab01, lab02, lab03)
2. Proxmox API access with root credentials
3. Network configured with:
- Gateway: 10.0.19.254
- Available IPs: 10.0.19.200-202
4. Ansible collections installed:
```bash
ansible-galaxy collection install -r requirements.yml
```
## Architecture
- **k8s-master** (10.0.19.200): Control plane node
- **k8s-worker1** (10.0.19.201): Worker node
- **k8s-worker2** (10.0.19.202): Worker node
All nodes run Debian 12 with:
- 2 CPU cores
- 4GB RAM
- 40GB disk
- Containerd runtime
- Kubernetes 1.33.3
## Deployment Methods
### Method 1: Full Automated Deployment
Use this to create VMs and install Kubernetes:
```bash
export PROXMOX_PASSWORD='your-proxmox-password'
export K8S_VM_PASSWORD='secure-password' # Optional, defaults to 'changeme'
./deploy-k8s-cluster.sh
```
### Method 2: Step-by-Step Deployment
1. **Create VM Template**:
```bash
ansible-playbook create-vm-template.yml -e proxmox_password='your-password'
```
2. **Deploy Cluster**:
```bash
ansible-playbook -i inventories/k8s-cluster/hosts k8s-cluster.yml \
-e proxmox_password='your-password' \
-e vm_password='secure-password'
```
### Method 3: Install on Existing VMs
If you already have Debian 12 VMs:
```bash
ansible-playbook -i inventories/k8s-cluster/hosts k8s-install-only.yml
```
## Post-Deployment
### Access the Cluster
1. **SSH to master**:
```bash
ssh debian@10.0.19.200
kubectl get nodes
```
2. **Copy kubeconfig locally**:
```bash
scp debian@10.0.19.200:~/.kube/config ~/.kube/config-k8s
export KUBECONFIG=~/.kube/config-k8s
kubectl get nodes
```
### Verify Installation
```bash
# Check nodes
kubectl get nodes
# Check system pods
kubectl get pods -n kube-system
# Check cluster info
kubectl cluster-info
```
### Access Dashboard
The Kubernetes dashboard is installed by default:
```bash
# Create admin user
kubectl create serviceaccount dashboard-admin -n kubernetes-dashboard
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:dashboard-admin
# Get token
kubectl -n kubernetes-dashboard create token dashboard-admin
# Start proxy
kubectl proxy
# Access at: http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
```
## Customization
### Change Network Settings
Edit `k8s-cluster.yml`:
```yaml
vars:
k8s_nodes:
- name: k8s-master
ip: 10.0.19.200/24 # Change IP here
gateway: 10.0.19.254 # Change gateway
nameserver: 10.0.19.254 # Change DNS
```
### Change VM Resources
Edit `k8s-cluster.yml`:
```yaml
k8s_nodes:
- name: k8s-master
cores: 4 # Increase CPU
memory: 8192 # Increase RAM
disk: 100 # Increase disk
```
### Use Different CNI
Replace Flannel with Calico:
```yaml
- name: Install Calico CNI
command: kubectl apply -f https://docs.projectcalico.org/manifests/tigera-operator.yaml
```
## Troubleshooting
### VMs Won't Start
- Check Proxmox storage space
- Verify template was created successfully
- Check VM IDs aren't already in use
### Nodes Not Joining
- Verify network connectivity between nodes
- Check firewall rules
- Ensure time is synchronized
### Pods Stuck in Pending
- Check node resources: `kubectl describe nodes`
- Verify CNI is working: `kubectl get pods -n kube-system`
## Cleanup
To remove the cluster:
```bash
# Delete VMs from Proxmox
for vmid in 200 201 202; do
ssh root@lab01.w5isp.com "qm stop $vmid && qm destroy $vmid"
done
```

View file

@ -0,0 +1,74 @@
---
# Create a cloud-init template on Proxmox for K8s nodes
# This playbook runs commands directly on the Proxmox host
- name: Create cloud-init template on Proxmox
hosts: proxmox[0]
become: yes
vars:
template_vmid: 9000
template_name: debian12-cloud-init
debian_image_url: https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2
storage: local-lvm
tasks:
- name: Install required packages
apt:
name:
- wget
- libguestfs-tools
state: present
update_cache: yes
- name: Download Debian cloud image
get_url:
url: "{{ debian_image_url }}"
dest: /var/lib/vz/template/iso/debian-12-genericcloud-amd64.qcow2
mode: '0644'
- name: Create VM for template
shell: |
qm create {{ template_vmid }} --name {{ template_name }} --memory 2048 --cores 2 --net0 virtio,bridge=vmbr0
args:
creates: /etc/pve/qemu-server/{{ template_vmid }}.conf
- name: Import disk image to VM
shell: |
qm importdisk {{ template_vmid }} /var/lib/vz/template/iso/debian-12-genericcloud-amd64.qcow2 {{ storage }}
register: import_result
changed_when: "'successfully imported' in import_result.stdout"
- name: Get imported disk name
shell: |
pvesm list {{ storage }} | grep "vm-{{ template_vmid }}-disk-" | awk '{print $1}' | head -1
register: disk_name
- name: Attach imported disk to VM
shell: |
qm set {{ template_vmid }} --scsihw virtio-scsi-pci --scsi0 {{ disk_name.stdout }}
when: disk_name.stdout != ""
- name: Add cloud-init drive
shell: |
qm set {{ template_vmid }} --ide2 {{ storage }}:cloudinit
- name: Set boot disk
shell: |
qm set {{ template_vmid }} --boot c --bootdisk scsi0
- name: Add serial console
shell: |
qm set {{ template_vmid }} --serial0 socket --vga serial0
- name: Enable QEMU guest agent
shell: |
qm set {{ template_vmid }} --agent enabled=1
- name: Convert VM to template
shell: |
qm template {{ template_vmid }}
- name: Clean up downloaded image
file:
path: /var/lib/vz/template/iso/debian-12-genericcloud-amd64.qcow2
state: absent

55
ansible/deploy-k8s-cluster.sh Executable file
View file

@ -0,0 +1,55 @@
#!/bin/bash
# Deploy a 3-node Kubernetes cluster on Proxmox using Debian 12
set -e
echo "=== Kubernetes Cluster Deployment Script ==="
echo "This will create a 3-node K8s cluster on your Proxmox servers"
echo
# Check if proxmox password is set
if [ -z "$PROXMOX_PASSWORD" ]; then
echo "Please set PROXMOX_PASSWORD environment variable"
echo "export PROXMOX_PASSWORD='your-proxmox-password'"
exit 1
fi
# Install required collections
echo "Installing Ansible collections..."
ansible-galaxy collection install -r requirements.yml
# Step 1: Create VM template
echo "Step 1: Creating Debian 12 cloud-init template on Proxmox..."
read -p "Do you want to create the VM template? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
ansible-playbook create-vm-template.yml -e proxmox_password="$PROXMOX_PASSWORD"
fi
# Step 2: Deploy K8s cluster
echo "Step 2: Deploying Kubernetes cluster..."
echo "This will:"
echo " - Create 3 VMs from the template"
echo " - Install containerd and Kubernetes"
echo " - Initialize the master node"
echo " - Join worker nodes to the cluster"
echo " - Install Flannel CNI and dashboard"
echo
read -p "Continue with deployment? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
ansible-playbook -i inventories/k8s-cluster/hosts k8s-cluster.yml \
-e proxmox_password="$PROXMOX_PASSWORD" \
-e vm_password="${K8S_VM_PASSWORD:-changeme}"
fi
echo
echo "=== Deployment Complete ==="
echo "To access your cluster from the master node:"
echo " ssh debian@10.0.19.200"
echo " kubectl get nodes"
echo
echo "To copy kubeconfig to your local machine:"
echo " scp debian@10.0.19.200:~/.kube/config ~/.kube/config-k8s"
echo " export KUBECONFIG=~/.kube/config-k8s"

View file

@ -0,0 +1,26 @@
---
# Kubernetes cluster variables
# Kubernetes version
kubernetes_version: "1.33"
kubernetes_patch_version: "1.33.3"
# Network configuration
pod_network_cidr: "10.244.0.0/16"
service_cidr: "10.96.0.0/12"
# Container runtime
container_runtime: containerd
# Cluster DNS
cluster_dns_domain: cluster.local
cluster_dns_server: 10.96.0.10
# Feature gates and extra args
kubelet_extra_args: "--cgroup-driver=systemd"
# Resource limits for system pods
kube_reserved_cpu: "100m"
kube_reserved_memory: "256Mi"
system_reserved_cpu: "100m"
system_reserved_memory: "256Mi"

View file

@ -0,0 +1,6 @@
---
# Proxmox hosts configuration
ansible_user: ansible
ansible_become: yes
ansible_become_method: sudo
# Use sudo without password (assuming ansible user has NOPASSWD sudo)

View file

@ -19,10 +19,10 @@ apps.w5isp.com
skippy.w5isp.com
g.w5isp.com
#[proxmox]
#lab01.w5isp.com
#lab02.w5isp.com
#lab03.w5isp.com
[proxmox]
lab01.w5isp.com
lab02.w5isp.com
lab03.w5isp.com
[tailscale_home]
lab01.w5isp.com

View file

@ -0,0 +1,20 @@
# Kubernetes cluster inventory
[proxmox]
lab01.w5isp.com
lab02.w5isp.com
lab03.w5isp.com
[k8s_master]
k8s-master ansible_host=10.0.19.200 ansible_user=debian
[k8s_workers]
k8s-worker1 ansible_host=10.0.19.201 ansible_user=debian
k8s-worker2 ansible_host=10.0.19.202 ansible_user=debian
[k8s_cluster:children]
k8s_master
k8s_workers
[k8s_cluster:vars]
ansible_python_interpreter=/usr/bin/python3

300
ansible/k8s-cluster.yml Normal file
View file

@ -0,0 +1,300 @@
---
# 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

View file

@ -0,0 +1,138 @@
---
# Install Kubernetes on existing Debian 12 VMs
# Usage: ansible-playbook -i inventories/k8s-cluster/hosts k8s-install-only.yml
- name: Prepare nodes for Kubernetes
hosts: k8s_cluster
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
- name: Install required packages
apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg
- lsb-release
state: present
- name: Disable swap
shell: |
swapoff -a
sed -i '/swap/d' /etc/fstab
- name: Load kernel modules
modprobe:
name: "{{ item }}"
loop: [overlay, br_netfilter]
- name: Persist kernel modules
copy:
content: |
overlay
br_netfilter
dest: /etc/modules-load.d/k8s.conf
- name: Configure sysctl
sysctl:
name: "{{ item.key }}"
value: "{{ item.value }}"
sysctl_set: yes
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: Add Docker GPG key
apt_key:
url: https://download.docker.com/linux/debian/gpg
- name: Add Docker repo
apt_repository:
repo: "deb [arch=amd64] https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable"
- name: Install containerd
apt:
name: containerd.io
state: present
- name: Configure containerd
shell: |
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
- name: Restart containerd
systemd:
name: containerd
state: restarted
enabled: yes
- name: Add Kubernetes GPG key
apt_key:
url: https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key
- name: Add Kubernetes repo
apt_repository:
repo: "deb https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /"
- name: Install Kubernetes
apt:
name:
- kubelet=1.33.3-*
- kubeadm=1.33.3-*
- kubectl=1.33.3-*
state: present
- name: Hold Kubernetes packages
dpkg_selections:
name: "{{ item }}"
selection: hold
loop: [kubelet, kubeadm, kubectl]
- name: Initialize master
hosts: k8s_master
become: yes
tasks:
- name: Initialize cluster
command: kubeadm init --pod-network-cidr=10.244.0.0/16
args:
creates: /etc/kubernetes/admin.conf
register: kubeadm_init
- name: Create .kube directory
file:
path: "/home/{{ ansible_user }}/.kube"
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
- name: Copy admin.conf
copy:
src: /etc/kubernetes/admin.conf
dest: "/home/{{ ansible_user }}/.kube/config"
remote_src: yes
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
- name: Install Flannel
become_user: "{{ ansible_user }}"
command: kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
- name: Get join command
command: kubeadm token create --print-join-command
register: join_command
- name: Join workers
hosts: k8s_workers
become: yes
tasks:
- name: Join cluster
command: "{{ hostvars[groups['k8s_master'][0]]['join_command']['stdout'] }}"
args:
creates: /etc/kubernetes/kubelet.conf

13
ansible/requirements.yml Normal file
View file

@ -0,0 +1,13 @@
---
collections:
- name: community.general
version: ">=8.0.0"
- name: ansible.posix
- name: kubernetes.core
version: ">=2.4.0"
roles:
- name: geerlingguy.docker
version: "6.1.0"
- name: geerlingguy.kubernetes
version: "8.0.0" # This role supports K8s 1.30+

View file

@ -0,0 +1,46 @@
---
# Setup passwordless sudo for ansible user on Proxmox hosts
# Run this with: ansible-playbook setup-proxmox-sudo.yml -e ansible_user=root
- name: Setup sudo for ansible user on Proxmox
hosts: proxmox
tasks:
- name: Ensure sudo is installed
apt:
name: sudo
state: present
update_cache: yes
- name: Ensure ansible user exists
user:
name: ansible
state: present
shell: /bin/bash
- name: Add ansible user to sudo group
user:
name: ansible
groups: sudo
append: yes
- name: Configure passwordless sudo for ansible user
lineinfile:
path: /etc/sudoers.d/ansible
line: 'ansible ALL=(ALL) NOPASSWD: ALL'
create: yes
mode: '0440'
validate: 'visudo -cf %s'
- name: Ensure .ssh directory exists for ansible user
file:
path: /home/ansible/.ssh
state: directory
owner: ansible
group: ansible
mode: '0700'
- name: Copy SSH key for ansible user
authorized_key:
user: ansible
key: "{{ lookup('file', '~/.ssh/ansible.pub') }}"
state: present