├── .gitignore ├── Makefile ├── README.md ├── ansible.cfg ├── image.jpg ├── inventory.example ├── playbooks ├── configuration.yaml ├── control_plane.yaml ├── k8s_flush.yaml ├── k8s_post.yaml ├── master.yaml └── nodes.yaml └── roles ├── argocd └── tasks │ └── main.yaml ├── cilium └── tasks │ └── main.yaml ├── cli └── tasks │ └── main.yaml ├── containerd └── tasks │ └── main.yaml ├── helm └── tasks │ └── main.yaml ├── k8s └── tasks │ └── main.yaml ├── k8s_flush └── tasks │ └── main.yaml ├── k8s_post └── tasks │ └── main.yaml ├── master ├── defaults │ └── main.yaml └── tasks │ └── main.yaml ├── nodes └── tasks │ └── main.yaml └── timezone ├── defaults └── main.yaml └── tasks └── main.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | inventory 2 | 3 | # Logs 4 | logs 5 | *.log 6 | 7 | # OS 8 | .DS_Store 9 | 10 | # Tests 11 | /coverage 12 | /.nyc_output 13 | 14 | # IDEs and editors 15 | /.idea 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # IDE - VSCode 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | 30 | ./playbooks/temp/* -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | 3 | default: config master nodes post_install control_plane 4 | 5 | config: 6 | ansible-playbook playbooks/configuration.yaml 7 | 8 | master: 9 | ansible-playbook playbooks/master.yaml 10 | 11 | nodes: 12 | ansible-playbook playbooks/nodes.yaml 13 | 14 | post_install: 15 | ansible-playbook playbooks/k8s_post.yaml 16 | 17 | control_plane: 18 | ansible-playbook playbooks/control_plane.yaml 19 | 20 | k8s_flush: 21 | ansible-playbook playbooks/k8s_flush.yaml 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Homelab 2 | 3 | Metin Seylan's personal bare-metal Kubernetes cluster. 4 | 5 | - Network 6 | - [PFsense](https://www.pfsense.org/) 7 | 8 | - Apps 9 | - [ArgoCD](https://argoproj.github.io/argo-cd/) 10 | - [Grafana](https://grafana.com/) 11 | - [Kubernetes](https://kubernetes.io/) 12 | - [Metallb](https://metallb.universe.tf/) 13 | - [Nginx Ingress](https://kubernetes.github.io/ingress-nginx/) 14 | - [Prometheus](https://prometheus.io/) 15 | 16 | 17 | - Hardware 18 | - Lenovo ThinkCentre Tiny 3x 19 | - Intel Core i7-7700T 20 | - Crucial 64GB DDR4 2666MHz 21 | - 1TB SSD 22 | - 1TB NVME 23 | 24 |

25 | Homelab 26 |

27 | 28 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory = ./inventory 3 | stdout_callback = yaml 4 | 5 | roles_path = ./roles 6 | collections_paths = ./collections -------------------------------------------------------------------------------- /image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetinSeylan/homelab/e60735de411aee0f51715cb8a88b3db2874f0824/image.jpg -------------------------------------------------------------------------------- /inventory.example: -------------------------------------------------------------------------------- 1 | [master] 2 | 192.168.2.72 3 | 4 | [master:vars] 5 | ansible_user= 6 | ansible_password= 7 | ansible_sudo_user= 8 | ansible_sudo_pass= 9 | 10 | [node1] 11 | 192.168.2.77 12 | 192.168.2.78 13 | 14 | [node1:vars] 15 | ansible_user= 16 | ansible_password= 17 | ansible_sudo_user= 18 | ansible_sudo_pass= 19 | 20 | [node2] 21 | 192.168.2.78 22 | 23 | [node2:vars] 24 | ansible_user= 25 | ansible_password= 26 | ansible_sudo_user= 27 | ansible_sudo_pass= -------------------------------------------------------------------------------- /playbooks/configuration.yaml: -------------------------------------------------------------------------------- 1 | - name: Basic Linux Configuration 2 | hosts: "*" 3 | become: true 4 | gather_facts: yes 5 | roles: 6 | - timezone 7 | - cli 8 | - containerd 9 | - k8s -------------------------------------------------------------------------------- /playbooks/control_plane.yaml: -------------------------------------------------------------------------------- 1 | - name: Install Helm and Cilium 2 | hosts: "master" 3 | become: yes 4 | roles: 5 | - helm 6 | - cilium 7 | - argocd 8 | -------------------------------------------------------------------------------- /playbooks/k8s_flush.yaml: -------------------------------------------------------------------------------- 1 | - name: Post K8s Setup 2 | hosts: "master,node1,node2,node3,node4" 3 | become: true 4 | roles: 5 | - k8s_flush 6 | -------------------------------------------------------------------------------- /playbooks/k8s_post.yaml: -------------------------------------------------------------------------------- 1 | - name: Post K8s Setup 2 | hosts: "master" 3 | become: true 4 | roles: 5 | - k8s_post 6 | -------------------------------------------------------------------------------- /playbooks/master.yaml: -------------------------------------------------------------------------------- 1 | - name: Install K8s Master 2 | hosts: "master" 3 | become: true 4 | roles: 5 | - master 6 | -------------------------------------------------------------------------------- /playbooks/nodes.yaml: -------------------------------------------------------------------------------- 1 | - name: Setup K8s Nodes 2 | hosts: "node1,node2,node3,node4" 3 | become: true 4 | roles: 5 | - nodes 6 | -------------------------------------------------------------------------------- /roles/argocd/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | - name: Argocd Helm Repo 2 | shell: helm repo add argo https://argoproj.github.io/argo-helm 3 | 4 | - name: Install Argocd 5 | shell: | 6 | echo " 7 | global: 8 | nodeSelector: 9 | role: master 10 | configs: 11 | rbac: 12 | policy.default: role:admin 13 | cm: 14 | users.anonymous.enabled: true 15 | dex: 16 | enabled: false 17 | server: 18 | extraArgs: 19 | - --insecure 20 | " | helm install argocd argo/argo-cd --version 5.43.7 --namespace argocd --create-namespace -f - 21 | environment: 22 | KUBECONFIG: /etc/kubernetes/admin.conf -------------------------------------------------------------------------------- /roles/cilium/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | - name: Cilium Helm Repo 2 | shell: helm repo add cilium https://helm.cilium.io/ 3 | 4 | - name: Install Cilium 5 | shell: helm install cilium cilium/cilium --version 1.14.1 \ 6 | --namespace kube-system \ 7 | --set hubble.relay.enabled=true \ 8 | --set hubble.ui.enabled=true \ 9 | --set k8sServiceHost=192.168.1.10 \ 10 | --set k8sServicePort=6443 11 | environment: 12 | KUBECONFIG: /etc/kubernetes/admin.conf -------------------------------------------------------------------------------- /roles/cli/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | - name: Remove the first line 2 | ansible.builtin.shell: "sed -i '1d' /etc/apt/sources.list" 3 | become: yes 4 | 5 | - name: Install CLI Tools 6 | ansible.builtin.apt: 7 | update_cache: yes 8 | pkg: 9 | - ca-certificates 10 | - curl 11 | 12 | - name: Install Kubectl 13 | shell: | 14 | curl -Lo /usr/local/bin/kubectl "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" 15 | chmod +x /usr/local/bin/kubectl 16 | args: 17 | creates: "/usr/local/bin/kubectl" 18 | -------------------------------------------------------------------------------- /roles/containerd/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Containerd Dependencies 3 | ansible.builtin.apt: 4 | pkg: 5 | - ca-certificates 6 | - curl 7 | - gnupg 8 | - lsb-release 9 | 10 | - name: Add Containerd GPG Key 11 | apt_key: 12 | url: https://download.docker.com/linux/ubuntu/gpg 13 | state: present 14 | 15 | - name: Add Containerd Repo 16 | apt_repository: 17 | repo: deb [arch=amd64] https://download.docker.com/{{ ansible_system | lower }}/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable 18 | 19 | - name: Run the equivalent of "apt-get update" as a separate step 20 | ansible.builtin.apt: 21 | update_cache: yes 22 | 23 | - name: Install Containerd 24 | ansible.builtin.apt: 25 | update_cache: yes 26 | state: latest 27 | pkg: 28 | - docker-ce 29 | - docker-ce-cli 30 | - containerd.io 31 | - docker-buildx-plugin 32 | - docker-compose-plugin 33 | 34 | - name: Remove Containerd Config 35 | ansible.builtin.file: 36 | path: /etc/containerd/config.toml 37 | state: absent 38 | 39 | - name: Generate Containerd Config 40 | shell: | 41 | containerd config default | sudo tee /etc/containerd/config.toml 42 | sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml 43 | args: 44 | creates: "/etc/containerd/config.toml" 45 | 46 | - name: Enable Container.d Service 47 | ansible.builtin.systemd: 48 | name: containerd.service 49 | state: restarted 50 | daemon_reload: true 51 | enabled: true 52 | 53 | - name: Enable Docker.d Service 54 | ansible.builtin.systemd: 55 | name: docker.service 56 | state: restarted 57 | daemon_reload: true 58 | enabled: true 59 | -------------------------------------------------------------------------------- /roles/helm/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | - name: Helm gpg key 2 | shell: curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg 3 | args: 4 | creates: "/usr/share/keyrings/helm.gpg" 5 | 6 | - name: Install apt-transport-https 7 | ansible.builtin.apt: 8 | update_cache: yes 9 | pkg: 10 | - apt-transport-https 11 | 12 | - name: Helm gpg key sign 13 | shell: echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list 14 | args: 15 | creates: "/etc/apt/sources.list.d/helm-stable-debian.list" 16 | 17 | - name: Install Helm 18 | ansible.builtin.apt: 19 | update_cache: yes 20 | pkg: 21 | - helm 22 | -------------------------------------------------------------------------------- /roles/k8s/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Disable Swap 3 | command: swapoff -a 4 | when: ansible_swaptotal_mb > 0 5 | 6 | - name: Remove SWAP from fstab 7 | mount: 8 | name: "{{ item }}" 9 | fstype: swap 10 | state: absent 11 | with_items: 12 | - swap 13 | - none 14 | 15 | - name: Reduce Swappiness 16 | ansible.posix.sysctl: 17 | name: vm.swappiness 18 | value: '0' 19 | state: present 20 | 21 | - name: Add K8s GPG Key 22 | apt_key: 23 | url: https://packages.cloud.google.com/apt/doc/apt-key.gpg 24 | state: present 25 | register: add_repository_key 26 | 27 | - name: Add K8s Repo 28 | apt_repository: 29 | repo: deb https://apt.kubernetes.io/ kubernetes-xenial main 30 | state: present 31 | update_cache: true 32 | 33 | - name: Install Kubeadm, Kubelet and Kubernetes-cni 34 | ansible.builtin.apt: 35 | update_cache: yes 36 | pkg: 37 | - kubelet 38 | - kubeadm 39 | - kubernetes-cni 40 | 41 | 42 | -------------------------------------------------------------------------------- /roles/k8s_flush/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | - name: kubeadm reset 2 | shell: kubeadm reset -f 3 | 4 | - name: docker prune 5 | shell: docker image prune -a -f 6 | 7 | - name: restart docker 8 | shell: systemctl restart docker 9 | 10 | - name: remove docker 11 | shell: | 12 | rm -rf ~/.kube 13 | 14 | - name: clear iptables 15 | shell: | 16 | iptables -F && iptables -X && 17 | iptables -t nat -F && iptables -t nat -X && 18 | iptables -t raw -F && iptables -t raw -X && 19 | iptables -t mangle -F && iptables -t mangle -X 20 | 21 | - name: reboot 22 | shell: reboot 23 | 24 | 25 | -------------------------------------------------------------------------------- /roles/k8s_post/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | - name: add label to master 2 | shell: kubectl label node master role=master 3 | environment: 4 | KUBECONFIG: /etc/kubernetes/admin.conf 5 | 6 | - name: add label to node1 7 | shell: kubectl label node node1 role=node1 8 | environment: 9 | KUBECONFIG: /etc/kubernetes/admin.conf 10 | 11 | - name: add label to node2 12 | shell: kubectl label node node2 role=node2 13 | environment: 14 | KUBECONFIG: /etc/kubernetes/admin.conf 15 | 16 | - name: add label to node3 17 | shell: kubectl label node node3 role=node3 18 | environment: 19 | KUBECONFIG: /etc/kubernetes/admin.conf 20 | 21 | - name: add label to node4 22 | shell: kubectl label node node4 role=node4 23 | environment: 24 | KUBECONFIG: /etc/kubernetes/admin.conf 25 | 26 | - name: allow master node to schedule pods 27 | shell: kubectl taint nodes master node-role.kubernetes.io/control-plane:NoSchedule- 28 | environment: 29 | KUBECONFIG: /etc/kubernetes/admin.conf 30 | 31 | - name: add label to workers 32 | shell: kubectl label node node1 type=worker && kubectl label node node2 type=worker && kubectl label node node3 type=worker && kubectl label node node4 type=worker 33 | environment: 34 | KUBECONFIG: /etc/kubernetes/admin.conf 35 | -------------------------------------------------------------------------------- /roles/master/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | k8s_user: "metin" 2 | k8s_user_home: "/home/{{ k8s_user }}" -------------------------------------------------------------------------------- /roles/master/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | - name: Init Kubernetes Cluster 2 | shell: kubeadm init --cri-socket unix:///run/containerd/containerd.sock 3 | args: 4 | creates: "/etc/kubernetes/admin.conf" 5 | 6 | - name: Setup Kubeconfig for {{ k8s_user }} User 7 | file: 8 | path: "/home/{{ k8s_user }}/.kube" 9 | state: directory 10 | owner: "{{ k8s_user }}" 11 | group: "{{ k8s_user }}" 12 | mode: 0750 13 | 14 | - name: Copy /etc/kubernetes/admin.conf 15 | become: yes 16 | copy: 17 | src: "/etc/kubernetes/admin.conf" 18 | dest: "/home/{{ k8s_user }}/.kube/config" 19 | owner: "{{ k8s_user }}" 20 | group: "{{ k8s_user }}" 21 | mode: 0640 22 | remote_src: yes 23 | 24 | 25 | - name: Get join token 26 | shell: sudo kubeadm token create --print-join-command 27 | register: kubernetes_join_command 28 | 29 | - name: Copy join command to local file. 30 | become: false 31 | local_action: copy content="{{ kubernetes_join_command.stdout_lines[0] }}" dest="./temp/kubernetes_join_command" mode=0777 -------------------------------------------------------------------------------- /roles/nodes/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | - name: Copy join command from Ansiblehost to the worker nodes. 2 | become: yes 3 | copy: 4 | src: ./temp/kubernetes_join_command 5 | dest: /tmp/kubernetes_join_command 6 | mode: 0777 7 | 8 | - name: Join the Worker nodes to the cluster. 9 | become: yes 10 | command: sh /tmp/kubernetes_join_command 11 | register: joined_or_not -------------------------------------------------------------------------------- /roles/timezone/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | timezone_value: "UTC" 3 | -------------------------------------------------------------------------------- /roles/timezone/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Linux | Set Timezone to {{ timezone_value }} 3 | timezone: 4 | name: "{{ timezone_value }}" 5 | --------------------------------------------------------------------------------