├── .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 |
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 |
--------------------------------------------------------------------------------