mirror of
https://github.com/lukaszraczylo/rpi-home-cluster-setup.git
synced 2026-10-12 00:45:39 +00:00
Home K8S setup
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
step1/static/alpine-aarch64.tar.gz
|
||||
step2/static/token_file
|
||||
step2/static/kubectl.conf
|
||||
#
|
||||
|
||||
*/traefik-static-config.yaml
|
||||
*terraform.tfstate*
|
||||
*.log
|
||||
*/.terraform/
|
||||
@@ -0,0 +1,71 @@
|
||||
# Raspberry Pi kubernetes cluster on Alpine linux setup
|
||||
|
||||
This repository is supposed to help if I'd EVER AGAIN destroy the whole cluster by accident.
|
||||
Code is a result of 6 hours coding marathon, but will be improved and patched in future.
|
||||
|
||||
## Usage
|
||||
|
||||
### Memory card preparations [step1]
|
||||
|
||||
To prepare memory cards check the **step1** directory.
|
||||
If your Pi memory card is present under /dev/disk5 - you don't need to change anything, otherwise change it to the device of your choice.
|
||||
|
||||
```bash
|
||||
PI_CARD="/dev/disk5"
|
||||
```
|
||||
|
||||
Run the following script which will:
|
||||
* Format memory card
|
||||
* Split it into two partitions (1G + remaining)
|
||||
* Copy basic Alpine system onto 1G partition
|
||||
* Add an overlay allowing ethernet interface get up and SSH root access without the password
|
||||
|
||||
```bash
|
||||
001-prepare-card.sh
|
||||
```
|
||||
|
||||
### Cluster preparations [step2]
|
||||
|
||||
#### Before
|
||||
|
||||
* Modify pi-hosts.txt file and adjust it to your setup.
|
||||
* Modify address class in step2/static/k8s-metallb-dashboard-config.yaml to suit your network
|
||||
|
||||
Add following to your ~/.ssh/config file
|
||||
|
||||
```bash
|
||||
Host pi?
|
||||
User root
|
||||
Hostname %h.local
|
||||
```
|
||||
|
||||
#### Prepare your nodes for Ansible
|
||||
|
||||
```bash
|
||||
001-prepare-ansible.sh
|
||||
```
|
||||
|
||||
#### Run the playbook
|
||||
|
||||
```bash
|
||||
ansible-playbook rpi.yaml -f 10
|
||||
```
|
||||
|
||||
### K8S definitions [step3]
|
||||
|
||||
Use makefile from step3 to apply / destroy resources
|
||||
|
||||
#### Required environment variables:
|
||||
|
||||
```bash
|
||||
TRAEFIK_API_KEY // Traefik API key
|
||||
GH_USER // GitHub user
|
||||
GH_PAT // GitHub Personal Access Token
|
||||
```
|
||||
|
||||
## Outcome
|
||||
|
||||
* Raspberry Pi cluster running Alpine linux as a base
|
||||
* MetalLB for load balancing in your LAN
|
||||
* Kubernetes dashboard installed and exposed via MetalLB
|
||||
* Traefik managing the.. traffic
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script
|
||||
# - prepares raspberry pi memory card ( /dev/disk5 )
|
||||
# - partitions the memory card
|
||||
# - unpacks RPI rpi base system
|
||||
# - applies headless boot configuration with network interface and ssh agent accepting connections without password
|
||||
|
||||
PI_CARD="/dev/disk5"
|
||||
ALPINE_BASE_IMAGE="https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/aarch64/alpine-rpi-3.13.2-aarch64.tar.gz"
|
||||
# [[ -f /Volumes/RPI0 ]] && echo "Deleting leftover directory"; rm -fr /Volumes/RPI0 || echo "Clean and dandy on the Volumes front"
|
||||
[[ ! -f static/alpine-aarch64.tar.gz ]] && wget $ALPINE_BASE_IMAGE -O static/alpine-aarch64.tar.gz || echo "Alpine baseimg already exists"
|
||||
sudo diskutil eraseDisk FAT32 RPI MBRFormat $PI_CARD
|
||||
sudo diskutil partitionDisk /dev/$PI_CARD MBRFormat FAT32 RPI0 1g FREE RPISYS 0b
|
||||
sudo tar xf static/alpine-aarch64.tar.gz -C /Volumes/RPI0
|
||||
sudo cp static/headless.tar.gz /Volumes/RPI0/headless.apkovl.tar.gz
|
||||
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
KEYMAPOPTS="us us-intl"
|
||||
HOSTNAMEOPTS="-n alpine-test"
|
||||
|
||||
INTERFACESOPTS="auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
auto eth0
|
||||
iface eth0 inet dhcp
|
||||
hostname alpine-test
|
||||
"
|
||||
|
||||
DNSOPTS="-d local"
|
||||
TIMEZONEOPTS="-z UTC"
|
||||
APKREPOSOPTS="-f"
|
||||
SSHDOPTS="-c openssh"
|
||||
NTPOPTS="-c openntpd"
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
AVAILABLE_HOSTS=$(grep "\." pi-hosts.txt | awk '{print $2}' | cut -d "=" -f2)
|
||||
for HOST in $AVAILABLE_HOSTS; do
|
||||
echo "Working on host $HOST"
|
||||
ssh -t root@$HOST 'setup-ntp -c chrony; setup-apkrepos -f; apk update; apk add python3'
|
||||
done
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
all:
|
||||
./001-prepare-ansible.sh
|
||||
ansible-playbook rpi.yaml -f 10
|
||||
@@ -0,0 +1,8 @@
|
||||
[defaults]
|
||||
host_key_checking = False
|
||||
remote_user = root
|
||||
inventory = ./pi-hosts.txt
|
||||
interpreter_python = auto_silent
|
||||
|
||||
[ssh_connection]
|
||||
pipelining = True
|
||||
@@ -0,0 +1,9 @@
|
||||
[masters]
|
||||
pi0 ansible_host=192.168.50.132 # Pi0
|
||||
|
||||
[workers]
|
||||
pi1 ansible_host=192.168.50.135 # Pi1
|
||||
pi3 ansible_host=192.168.50.60 # Pi3
|
||||
pi4 ansible_host=192.168.50.36 # Pi4
|
||||
pi2 ansible_host=192.168.50.85 # Pi2
|
||||
pi5 ansible_host=192.168.50.230 # Pi5
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- name: Taint nodes
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
kubectl taint nodes --all node-role.kubernetes.io/master:NoSchedule- || true
|
||||
|
||||
- name: Install py3-pip
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- py3-pip
|
||||
- helm
|
||||
state: present
|
||||
|
||||
- name: Install yaml package
|
||||
pip:
|
||||
name: PyYAML
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
# - name: Github authentication
|
||||
# ansible.builtin.shell:
|
||||
# cmd: |
|
||||
# kubectl create secret docker-registry docker-ghcr --docker-server=https://ghcr.io --docker-username=lukaszraczylo --docker-password=$GITHUB_TOKEN [email protected]
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
# - include: k8s-general-setup.yml
|
||||
- include: k8s-github.yml
|
||||
@@ -0,0 +1,94 @@
|
||||
---
|
||||
- name: Install packages - filesystem
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- e2fsprogs
|
||||
- parted
|
||||
state: present
|
||||
|
||||
- name: Create partition for perm data
|
||||
community.general.parted:
|
||||
device: /dev/mmcblk0
|
||||
number: 2
|
||||
fs_type: ext4
|
||||
part_start: 1GiB
|
||||
part_end: 100%
|
||||
flags: [ boot ]
|
||||
state: present
|
||||
|
||||
- name: Fomat perm data partition
|
||||
community.general.filesystem:
|
||||
dev: /dev/mmcblk0p2
|
||||
fstype: ext4
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Re-mount old data partition
|
||||
ansible.posix.mount:
|
||||
path: /media/mmcblk0p1
|
||||
src: /dev/mmcblk0p1
|
||||
opts: rw
|
||||
state: remounted
|
||||
|
||||
- name: Mount perm data partition
|
||||
ansible.posix.mount:
|
||||
path: /mnt
|
||||
src: /dev/mmcblk0p2
|
||||
opts: rw
|
||||
fstype: ext4
|
||||
state: mounted
|
||||
|
||||
- name: Overwrite setup-disk
|
||||
ansible.builtin.copy:
|
||||
src: static/setup-disk
|
||||
dest: /sbin/setup-disk
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0744'
|
||||
backup: yes
|
||||
|
||||
- name: Setup new disk as system
|
||||
ansible.builtin.command:
|
||||
cmd: setup-disk -m sys /mnt
|
||||
creates: /mnt/bin/date
|
||||
|
||||
- name: Housekeeping
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
rm -f /media/mmcblk0p1/boot/*
|
||||
cd /mnt
|
||||
rm boot/boot
|
||||
mv boot/* /media/mmcblk0p1/boot/
|
||||
rm -Rf boot
|
||||
mkdir media/mmcblk0p1
|
||||
ln -s media/mmcblk0p1/boot boot
|
||||
removes: /mnt/boot/boot
|
||||
|
||||
- name: Add mountpoints to fstab
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
echo "/dev/mmcblk0p1 /media/mmcblk0p1 vfat defaults 0 0" >> etc/fstab
|
||||
echo "/dev/mmcblk0p1 /media/mmcblk0p1 vfat defaults 0 0" >> /etc/fstab
|
||||
sed -i '/cdrom/d' etc/fstab
|
||||
sed -i '/floppy/d' etc/fstab
|
||||
sed -i '/usbdisk/d' etc/fstab
|
||||
touch /mnt/.nvm_mountpoints
|
||||
chdir: /mnt
|
||||
creates: /mnt/.nvm_mountpoints
|
||||
|
||||
- name: Enable repositories and cgroups
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
sed -i '/edge/s/^#//' /mnt/etc/apk/repositories
|
||||
sed -i 's/^/root=\/dev\/mmcblk0p2 /' /media/mmcblk0p1/cmdline.txt
|
||||
echo "cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1" >> /media/mmcblk0p1/cmdline.txt
|
||||
sed -i ':a;N;$!ba;s/\n/ /g' /media/mmcblk0p1/cmdline.txt
|
||||
touch /mnt/.nvm_cgroups
|
||||
creates: /mnt/.nvm_cgroups
|
||||
|
||||
- name: Commit changes
|
||||
ansible.builtin.shell:
|
||||
chdir: /media/mmcblk0p1
|
||||
cmd: lbu_commit -d || true
|
||||
|
||||
- name: Reboot
|
||||
reboot:
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Pull basic images
|
||||
ansible.builtin.shell:
|
||||
cmd: kubeadm config images pull
|
||||
|
||||
- name: Install helm
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
|
||||
creates: /etc/kubernetes/kubelet.conf
|
||||
register: k8sinit_output
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
- name: Check for base system config lockfile
|
||||
stat: path="/mnt/.nvm_mountpoints"
|
||||
register: basic_config_lock
|
||||
- include: filesystem.yml
|
||||
when: basic_config_lock.stat.exists == False
|
||||
- include: networking.yml
|
||||
- include: kubernetes.yml
|
||||
- include: nfs.yml
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
- name: Set hostname
|
||||
ansible.builtin.hostname:
|
||||
name: '{{ inventory_hostname }}'
|
||||
|
||||
- name: "Build hosts file"
|
||||
lineinfile:
|
||||
dest: /etc/hosts
|
||||
regexp: '.*{{ item }}$'
|
||||
line: "{{hostvars[item]['ansible_default_ipv4']['address']}} {{item}} {{item}}.local"
|
||||
state: present
|
||||
register: etchostsupdate
|
||||
when: hostvars[item]['ansible_facts']['default_ipv4'] is defined
|
||||
with_items:
|
||||
- "{{ groups['all'] }}"
|
||||
|
||||
- name: Install packages for networking
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- dbus
|
||||
- avahi
|
||||
- kubernetes
|
||||
- kubectl
|
||||
- docker
|
||||
- cni-plugins
|
||||
- kubelet
|
||||
- kubeadm
|
||||
- sudo
|
||||
- curl
|
||||
state: present
|
||||
|
||||
- name: Enable service dbus
|
||||
ansible.builtin.service:
|
||||
name: dbus
|
||||
state: started
|
||||
enabled: yes
|
||||
|
||||
- name: Overwrite avahi config
|
||||
ansible.builtin.copy:
|
||||
src: static/avahi-config
|
||||
dest: /etc/avahi/avahi-daemon.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
backup: yes
|
||||
|
||||
- name: Enable service avahi
|
||||
ansible.builtin.service:
|
||||
name: avahi-daemon
|
||||
state: restarted
|
||||
enabled: yes
|
||||
|
||||
- name: Enable service docker
|
||||
ansible.builtin.service:
|
||||
name: docker
|
||||
state: started
|
||||
enabled: yes
|
||||
|
||||
- name: Enable service kubelet
|
||||
ansible.builtin.service:
|
||||
name: kubelet
|
||||
state: started
|
||||
enabled: yes
|
||||
|
||||
- name: Enable promisc mode for ARP requests
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
ip link set eth0 promisc on
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
- name: Install nfsprogs
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- nfs-utils
|
||||
|
||||
- name: Prepare nfs mountpoint
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
mkdir -p /media/nfs
|
||||
|
||||
- name: Mount NFS resources
|
||||
ansible.posix.mount:
|
||||
src: "{{settings.nfs_host}}:{{settings.nfs_multi_share_path}}"
|
||||
path: /media/nfs
|
||||
fstype: nfs
|
||||
opts: nofail,noatime,nolock,tcp,actimeo=1800
|
||||
state: mounted
|
||||
|
||||
- name: Mount NFS torrent
|
||||
ansible.posix.mount:
|
||||
src: "{{settings.nfs_host}}:{{settings.nfs_torrent_path}}"
|
||||
path: /mnt/drobo-storage/docker-volumes/torrent
|
||||
fstype: nfs
|
||||
opts: nofail,noatime,nolock,tcp,actimeo=1800
|
||||
state: mounted
|
||||
|
||||
- name: Mount NFS adguard
|
||||
ansible.posix.mount:
|
||||
src: "{{settings.nfs_host}}:{{settings.nfs_adguard_path}}"
|
||||
path: /mnt/drobo-storage/docker-volumes/adguard
|
||||
fstype: nfs
|
||||
opts: nofail,noatime,nolock,tcp,actimeo=1800
|
||||
state: mounted
|
||||
@@ -0,0 +1,2 @@
|
||||
---
|
||||
- include: master-setup.yml
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
- name: Initialize cluster
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
kubeadm reset -f
|
||||
kubeadm init --pod-network-cidr=10.244.0.0/16
|
||||
creates: /etc/kubernetes/kubelet.conf
|
||||
register: k8sinit_output
|
||||
|
||||
- name: Storing Logs and Generated token for nodes config
|
||||
ansible.builtin.copy:
|
||||
content: '{{ k8sinit_output.stdout }}'
|
||||
dest: cluster_join_file
|
||||
when: '"token" in k8sinit_output.stdout'
|
||||
|
||||
- name: Pulling the token file for setup purposes
|
||||
ansible.builtin.fetch:
|
||||
flat: yes
|
||||
src: cluster_join_file
|
||||
dest: static/token_file
|
||||
when: '"token" in k8sinit_output.stdout'
|
||||
|
||||
- name: Copying kubeconfig file
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
mkdir -p $HOME/.kube
|
||||
cp -f /etc/kubernetes/admin.conf $HOME/.kube/config
|
||||
chown $(id -u):$(id -g) $HOME/.kube/config
|
||||
|
||||
- name: Save kubeconfig locally
|
||||
ansible.builtin.fetch:
|
||||
flat: yes
|
||||
src: /etc/kubernetes/admin.conf
|
||||
dest: static/kubectl.conf
|
||||
fail_on_missing: yes
|
||||
@@ -0,0 +1,2 @@
|
||||
---
|
||||
- include: worker-setup.yml
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
- name: Copy token file to workers
|
||||
ansible.builtin.copy:
|
||||
src: static/token_file
|
||||
dest: /root/cluster_token_file
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Joining worker nodes with kubernetes master
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
kubeadm reset -f
|
||||
cat /root/cluster_token_file | tail -2 > out.sh
|
||||
sh out.sh
|
||||
creates: out.sh
|
||||
|
||||
- name: Copy kubectl config to workers
|
||||
ansible.builtin.copy:
|
||||
src: static/kubectl.conf
|
||||
dest: /root/kubectl-config
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Copying kubeconfig file
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
mkdir -p $HOME/.kube
|
||||
cp -f /root/kubectl-config $HOME/.kube/config
|
||||
chown $(id -u):$(id -g) $HOME/.kube/config
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
settings:
|
||||
nfs_host: 192.168.50.5
|
||||
nfs_torrent_path: "/mnt/drobo-storage/docker-volumes/torrent"
|
||||
nfs_adguard_path: "/mnt/drobo-storage/docker-volumes/adguard"
|
||||
nfs_multi_share_path: "/mnt/drobo-storage/docker-volumes/nfs-share"
|
||||
roles:
|
||||
- common
|
||||
|
||||
- hosts: masters
|
||||
roles:
|
||||
- kubemaster
|
||||
|
||||
- hosts: workers
|
||||
roles:
|
||||
- kubeworkers
|
||||
|
||||
- hosts: masters
|
||||
roles:
|
||||
- basics
|
||||
@@ -0,0 +1,49 @@
|
||||
[server]
|
||||
#host-name=foo
|
||||
domain-name=local
|
||||
#browse-domains=0pointer.de, zeroconf.org
|
||||
use-ipv4=yes
|
||||
use-ipv6=yes
|
||||
#allow-interfaces=eth0
|
||||
#deny-interfaces=eth1
|
||||
#check-response-ttl=no
|
||||
#use-iff-running=no
|
||||
#enable-dbus=yes
|
||||
#disallow-other-stacks=no
|
||||
#allow-point-to-point=no
|
||||
#cache-entries-max=4096
|
||||
#clients-max=4096
|
||||
#objects-per-client-max=1024
|
||||
#entries-per-entry-group-max=32
|
||||
ratelimit-interval-usec=1000000
|
||||
ratelimit-burst=1000
|
||||
|
||||
[wide-area]
|
||||
enable-wide-area=yes
|
||||
|
||||
[publish]
|
||||
#disable-publishing=no
|
||||
#disable-user-service-publishing=no
|
||||
#add-service-cookie=no
|
||||
#publish-addresses=yes
|
||||
publish-hinfo=no
|
||||
publish-workstation=no
|
||||
#publish-domain=yes
|
||||
#publish-dns-servers=192.168.50.1, 192.168.50.2
|
||||
#publish-resolv-conf-dns-servers=yes
|
||||
#publish-aaaa-on-ipv4=yes
|
||||
#publish-a-on-ipv6=no
|
||||
|
||||
[reflector]
|
||||
#enable-reflector=no
|
||||
#reflect-ipv=no
|
||||
#reflect-filters=_airplay._tcp.local,_raop._tcp.local
|
||||
|
||||
[rlimits]
|
||||
#rlimit-as=
|
||||
#rlimit-core=0
|
||||
#rlimit-data=8388608
|
||||
#rlimit-fsize=0
|
||||
#rlimit-nofile=768
|
||||
#rlimit-stack=8388608
|
||||
#rlimit-nproc=3
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
**.terraform
|
||||
@@ -0,0 +1,22 @@
|
||||
ADDITIONAL_ARGS=-var 'traefik_api_key=$(TRAEFIK_API_KEY)' -var "github_user=$(GH_USER)" -var "github_pat=$(GH_TOKEN)"
|
||||
|
||||
apply:
|
||||
cd infrastructure; terraform apply $(ADDITIONAL_ARGS) -auto-approve -var-file ../variables.tfvars
|
||||
|
||||
plan:
|
||||
cd infrastructure; terraform plan $(ADDITIONAL_ARGS) -var-file ../variables.tfvars
|
||||
|
||||
destroy:
|
||||
cd infrastructure; terraform destroy $(ADDITIONAL_ARGS) -var-file ../variables.tfvars
|
||||
|
||||
refresh:
|
||||
cd infrastructure; terraform refresh $(ADDITIONAL_ARGS) -var-file ../variables.tfvars
|
||||
|
||||
init:
|
||||
cd infrastructure; rm -fr .terraform; terraform init
|
||||
|
||||
import:
|
||||
cd infrastructure; terraform import $(ADDITIONAL_ARGS) -var-file ../variables.tfvars $(ARGS)
|
||||
|
||||
lint:
|
||||
terraform fmt -recursive infrastructure/
|
||||
@@ -0,0 +1,231 @@
|
||||
resource "kubernetes_storage_class" "adguard_nfs" {
|
||||
metadata {
|
||||
name = "nfs-adguard"
|
||||
}
|
||||
storage_provisioner = "local"
|
||||
reclaim_policy = "Retain"
|
||||
allow_volume_expansion = true
|
||||
volume_binding_mode = "Immediate"
|
||||
}
|
||||
|
||||
resource "kubernetes_namespace" "adguard_ns" {
|
||||
metadata {
|
||||
name = "adguard"
|
||||
labels = {
|
||||
app = "adguard"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_ingress" "adguard_ingress" {
|
||||
metadata {
|
||||
name = "traefik-adguard"
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" : "traefik"
|
||||
}
|
||||
namespace = kubernetes_namespace.adguard_ns.metadata.0.name
|
||||
}
|
||||
|
||||
spec {
|
||||
rule {
|
||||
host = "adguard.local"
|
||||
http {
|
||||
path {
|
||||
path = "/"
|
||||
backend {
|
||||
service_name = kubernetes_service.adguard_svc.metadata.0.name
|
||||
service_port = "adguard-http"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_service" "adguard_svc" {
|
||||
depends_on = [kubernetes_config_map.metallb_cfg_map]
|
||||
metadata {
|
||||
namespace = kubernetes_namespace.adguard_ns.metadata.0.name
|
||||
name = "adguard-fwd"
|
||||
annotations = {
|
||||
"metallb.universe.tf/address-pool" : "default"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
port {
|
||||
name = "adguard-dns-tcp"
|
||||
port = 53
|
||||
target_port = 53
|
||||
}
|
||||
port {
|
||||
name = "adguard-dns-tls"
|
||||
port = 853
|
||||
target_port = 853
|
||||
}
|
||||
port {
|
||||
name = "adguard-http"
|
||||
port = 8080
|
||||
target_port = 8080
|
||||
}
|
||||
port {
|
||||
name = "adguard-init"
|
||||
port = 3000
|
||||
target_port = 3000
|
||||
}
|
||||
load_balancer_ip = "${var.network_subnet}.${var.adguard_catchall_host}"
|
||||
selector = {
|
||||
"app" : "adguard"
|
||||
}
|
||||
session_affinity = "ClientIP"
|
||||
type = "LoadBalancer"
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_service" "adguard_udp_svc" {
|
||||
depends_on = [kubernetes_config_map.metallb_cfg_map]
|
||||
metadata {
|
||||
namespace = kubernetes_namespace.adguard_ns.metadata.0.name
|
||||
name = "adguard-fwd-udp"
|
||||
annotations = {
|
||||
"metallb.universe.tf/address-pool" : "default"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
port {
|
||||
name = "adguard-dns-udp"
|
||||
port = 53
|
||||
target_port = 53
|
||||
protocol = "UDP"
|
||||
}
|
||||
load_balancer_ip = "${var.network_subnet}.${var.adguard_host}"
|
||||
selector = {
|
||||
"app" : "adguard"
|
||||
}
|
||||
type = "LoadBalancer"
|
||||
session_affinity = "ClientIP"
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_persistent_volume" "adguard_shared_nfs" {
|
||||
metadata {
|
||||
name = "adguard-pv"
|
||||
labels = {
|
||||
name = "type"
|
||||
value = "local"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
capacity = {
|
||||
storage = "2Gi"
|
||||
}
|
||||
storage_class_name = kubernetes_storage_class.adguard_nfs.metadata.0.name
|
||||
access_modes = ["ReadWriteMany"]
|
||||
persistent_volume_source {
|
||||
host_path {
|
||||
path = var.nfs_adguard_path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_persistent_volume_claim" "adguard_shared_nfs_claim" {
|
||||
metadata {
|
||||
name = "adguard-pvc"
|
||||
namespace = kubernetes_namespace.adguard_ns.metadata.0.name
|
||||
}
|
||||
spec {
|
||||
storage_class_name = kubernetes_storage_class.adguard_nfs.metadata.0.name
|
||||
access_modes = ["ReadWriteMany"]
|
||||
resources {
|
||||
requests = {
|
||||
storage = "2Gi"
|
||||
}
|
||||
}
|
||||
volume_name = kubernetes_persistent_volume.adguard_shared_nfs.metadata.0.name
|
||||
}
|
||||
}
|
||||
|
||||
## adguard deployment
|
||||
|
||||
resource "kubernetes_deployment" "adguard" {
|
||||
depends_on = [kubernetes_persistent_volume_claim.adguard_shared_nfs_claim]
|
||||
metadata {
|
||||
name = "adguard"
|
||||
labels = {
|
||||
app = "adguard"
|
||||
}
|
||||
namespace = kubernetes_namespace.adguard_ns.metadata.0.name
|
||||
}
|
||||
|
||||
spec {
|
||||
replicas = 1
|
||||
selector {
|
||||
match_labels = {
|
||||
app = "adguard"
|
||||
}
|
||||
}
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "adguard"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
volume {
|
||||
name = "adguard-v-nfs"
|
||||
persistent_volume_claim {
|
||||
claim_name = kubernetes_persistent_volume_claim.adguard_shared_nfs_claim.metadata.0.name
|
||||
}
|
||||
}
|
||||
container {
|
||||
name = "adguard"
|
||||
image = "adguard/adguardhome:arm64-edge"
|
||||
port {
|
||||
container_port = 53
|
||||
protocol = "TCP"
|
||||
}
|
||||
port {
|
||||
container_port = 53
|
||||
protocol = "UDP"
|
||||
}
|
||||
port {
|
||||
container_port = 853
|
||||
protocol = "TCP"
|
||||
}
|
||||
port {
|
||||
container_port = 3000
|
||||
protocol = "TCP"
|
||||
}
|
||||
port {
|
||||
container_port = 8080
|
||||
protocol = "TCP"
|
||||
}
|
||||
volume_mount {
|
||||
mount_path = "/opt/adguardhome/work"
|
||||
sub_path = "work-k8s"
|
||||
name = "adguard-v-nfs"
|
||||
}
|
||||
volume_mount {
|
||||
mount_path = "/opt/adguardhome/conf"
|
||||
sub_path = "conf-k8s"
|
||||
name = "adguard-v-nfs"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "null_resource" "adguard_crd" {
|
||||
|
||||
provisioner "local-exec" {
|
||||
when = create
|
||||
command = "kubectl apply -f ./static/crd-adguard-traefik-udp-53.yaml"
|
||||
}
|
||||
|
||||
provisioner "local-exec" {
|
||||
when = destroy
|
||||
command = "kubectl delete -f ./static/crd-adguard-traefik-udp-53.yaml"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
## Install metrics server
|
||||
module "dashboard_metrics" {
|
||||
depends_on = [kubernetes_service.traefik_svc]
|
||||
source = "./modules/dashboard-metrics"
|
||||
}
|
||||
|
||||
## Install dashboard
|
||||
resource "helm_release" "k8s_dashboard" {
|
||||
name = "k8s-dashboard"
|
||||
namespace = "default"
|
||||
repository = "https://kubernetes.github.io/dashboard/"
|
||||
chart = "kubernetes-dashboard"
|
||||
|
||||
set {
|
||||
name = "protocolHttp"
|
||||
value = "true"
|
||||
}
|
||||
set {
|
||||
name = "ingress.enabled"
|
||||
value = "false"
|
||||
}
|
||||
set {
|
||||
name = "rbac.create"
|
||||
value = "true"
|
||||
}
|
||||
set {
|
||||
name = "serviceAccount.create"
|
||||
value = "true"
|
||||
}
|
||||
set {
|
||||
name = "service.externalPort"
|
||||
value = "1337"
|
||||
}
|
||||
set {
|
||||
name = "networkPolicy.enabled"
|
||||
value = "true"
|
||||
}
|
||||
set {
|
||||
name = "podLabels.app"
|
||||
value = "k8s-dashboard"
|
||||
}
|
||||
set {
|
||||
name = "metrics-server.enabled"
|
||||
value = "false"
|
||||
}
|
||||
set {
|
||||
name = "metricsScraper.enabled"
|
||||
value = "true"
|
||||
}
|
||||
set {
|
||||
name = "metricsScraper.image.repository"
|
||||
value = "kubernetesui/metrics-scraper-arm"
|
||||
}
|
||||
set {
|
||||
name = "metricsScraper.image.tag"
|
||||
value = "latest"
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_cluster_role_binding" "k8s_dashboard_role" {
|
||||
metadata {
|
||||
name = "kubernetes-dashboard"
|
||||
}
|
||||
role_ref {
|
||||
api_group = "rbac.authorization.k8s.io"
|
||||
kind = "ClusterRole"
|
||||
name = "cluster-admin"
|
||||
}
|
||||
subject {
|
||||
kind = "ServiceAccount"
|
||||
name = "k8s-dashboard-kubernetes-dashboard"
|
||||
namespace = "default"
|
||||
}
|
||||
}
|
||||
|
||||
# Commented out as traffic runs via traefik anyway.
|
||||
|
||||
# resource "kubernetes_service" "k8s_dashboard_svc" {
|
||||
# depends_on = [ kubernetes_config_map.metallb_cfg_map ]
|
||||
# metadata {
|
||||
# namespace = "default"
|
||||
# name = "dashboard"
|
||||
# annotations = {
|
||||
# "metallb.universe.tf/address-pool": "default"
|
||||
# }
|
||||
# }
|
||||
# spec {
|
||||
# port {
|
||||
# port = 80
|
||||
# target_port = 9090
|
||||
# }
|
||||
# load_balancer_ip = "192.168.50.200"
|
||||
# selector = {
|
||||
# "app.kubernetes.io/instance": "k8s-dashboard"
|
||||
# }
|
||||
# type = "LoadBalancer"
|
||||
# }
|
||||
# }
|
||||
|
||||
resource "kubernetes_ingress" "traefik_dashboard_routing" {
|
||||
metadata {
|
||||
name = "traefik-k8s-dashboard"
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" : "traefik"
|
||||
}
|
||||
namespace = "default"
|
||||
}
|
||||
|
||||
spec {
|
||||
rule {
|
||||
host = "k8s.local"
|
||||
http {
|
||||
path {
|
||||
path = "/"
|
||||
backend {
|
||||
service_name = "k8s-dashboard-kubernetes-dashboard"
|
||||
service_port = 1337
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
provider "kubernetes" {
|
||||
config_path = "~/.kube/config"
|
||||
config_context = "home-k8s"
|
||||
}
|
||||
|
||||
provider "helm" {
|
||||
kubernetes {
|
||||
config_path = "~/.kube/config"
|
||||
config_context = "home-k8s"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
|
||||
|
||||
resource "null_resource" "metrics_server" {
|
||||
|
||||
provisioner "local-exec" {
|
||||
when = create
|
||||
command = "kubectl apply -f ./static/metrics-server.yaml"
|
||||
}
|
||||
|
||||
provisioner "local-exec" {
|
||||
when = destroy
|
||||
command = "kubectl delete -f ./static/metrics-server.yaml"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
|
||||
|
||||
resource "null_resource" "flannel_networking" {
|
||||
|
||||
provisioner "local-exec" {
|
||||
when = create
|
||||
command = "kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml"
|
||||
}
|
||||
|
||||
provisioner "local-exec" {
|
||||
when = destroy
|
||||
command = "kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
resource "null_resource" "metallb_networking" {
|
||||
|
||||
provisioner "local-exec" {
|
||||
when = create
|
||||
command = "kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/main/manifests/metallb.yaml; kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e \"s/strictARP: false/strictARP: true/\" | kubectl apply -f - -n kube-system"
|
||||
}
|
||||
|
||||
provisioner "local-exec" {
|
||||
when = destroy
|
||||
command = "kubectl delete -f https://raw.githubusercontent.com/metallb/metallb/main/manifests/metallb.yaml"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
# Basic networking
|
||||
|
||||
module "networking_flannel" {
|
||||
source = "./modules/networking-flannel"
|
||||
}
|
||||
|
||||
resource "kubernetes_namespace" "metallb_system" {
|
||||
metadata {
|
||||
name = "metallb-system"
|
||||
labels = {
|
||||
app = "metallb"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module "networking_metallb" {
|
||||
depends_on = [kubernetes_namespace.metallb_system]
|
||||
source = "./modules/networking-metallb"
|
||||
}
|
||||
|
||||
resource "random_string" "metallb_secret_string" {
|
||||
length = 128
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "kubernetes_secret" "metallb_secret" {
|
||||
type = "generic"
|
||||
metadata {
|
||||
name = "memberlist"
|
||||
namespace = "metallb-system"
|
||||
}
|
||||
data = {
|
||||
secretkey = base64encode(random_string.metallb_secret_string.result)
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_config_map" "metallb_cfg_map" {
|
||||
metadata {
|
||||
name = "config"
|
||||
namespace = "metallb-system"
|
||||
}
|
||||
|
||||
data = {
|
||||
config = <<CFGMAP
|
||||
address-pools:
|
||||
- name: default
|
||||
protocol: layer2
|
||||
addresses:
|
||||
- ${var.network_subnet}.200-${var.network_subnet}.250
|
||||
CFGMAP
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
# resource "null_resource" "prometheus_pv" {
|
||||
|
||||
# provisioner "local-exec" {
|
||||
# when = create
|
||||
# command = "kubectl apply -f static/prometheus-pv.yaml"
|
||||
# }
|
||||
|
||||
# provisioner "local-exec" {
|
||||
# when = destroy
|
||||
# command = "kubectl delete -f static/prometheus-pv.yaml"
|
||||
# }
|
||||
# }
|
||||
|
||||
resource "helm_release" "prometheus" {
|
||||
# depends_on = [ null_resource.prometheus_pv ]
|
||||
name = "prometheus"
|
||||
namespace = "default"
|
||||
chart = "kube-prometheus-stack"
|
||||
repository = "https://prometheus-community.github.io/helm-charts"
|
||||
wait = false
|
||||
# set {
|
||||
# name = "kube-state-metrics.image.repository"
|
||||
# value = "carlosedp/kube-state-metrics"
|
||||
# }
|
||||
|
||||
# set {
|
||||
# name = "kube-state-metrics.image.tag"
|
||||
# value = "v1.9.6"
|
||||
# }
|
||||
}
|
||||
|
||||
resource "null_resource" "prometheus_patch" {
|
||||
depends_on = [helm_release.prometheus]
|
||||
provisioner "local-exec" {
|
||||
when = create
|
||||
command = <<EOF
|
||||
kubectl patch ds prometheus-prometheus-node-exporter --type json -p '[{"op": "remove", "path" : "/spec/template/spec/containers/0/volumeMounts/2/mountPropagation"}]' || true
|
||||
EOF
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_ingress" "traefik_grafana_routing" {
|
||||
metadata {
|
||||
name = "traefik-k8s-grafana"
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" : "traefik"
|
||||
}
|
||||
namespace = "default"
|
||||
}
|
||||
|
||||
spec {
|
||||
rule {
|
||||
host = "grafana.local"
|
||||
http {
|
||||
path {
|
||||
path = "/"
|
||||
backend {
|
||||
service_name = "prometheus-grafana"
|
||||
service_port = 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRouteUDP
|
||||
metadata:
|
||||
name: adguard-traefik-udp
|
||||
namespace: adguard
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- dnsentry
|
||||
routes:
|
||||
- match: HostSNI(`*`)
|
||||
services:
|
||||
- name: adguard-fwd-udp
|
||||
port: 53
|
||||
protocol: "UDP"
|
||||
@@ -0,0 +1,188 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: metrics-server
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: metrics-server
|
||||
rbac.authorization.k8s.io/aggregate-to-admin: "true"
|
||||
rbac.authorization.k8s.io/aggregate-to-edit: "true"
|
||||
rbac.authorization.k8s.io/aggregate-to-view: "true"
|
||||
name: system:aggregated-metrics-reader
|
||||
rules:
|
||||
- apiGroups:
|
||||
- metrics.k8s.io
|
||||
resources:
|
||||
- pods
|
||||
- nodes
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: metrics-server
|
||||
name: system:metrics-server
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
- nodes
|
||||
- nodes/stats
|
||||
- namespaces
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: metrics-server
|
||||
name: metrics-server-auth-reader
|
||||
namespace: kube-system
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: extension-apiserver-authentication-reader
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: metrics-server
|
||||
name: metrics-server:system:auth-delegator
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: system:auth-delegator
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: metrics-server
|
||||
name: system:metrics-server
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: system:metrics-server
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: metrics-server
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
port: 443
|
||||
protocol: TCP
|
||||
targetPort: https
|
||||
selector:
|
||||
k8s-app: metrics-server
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: metrics-server
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
k8s-app: metrics-server
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxUnavailable: 0
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: metrics-server
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --cert-dir=/tmp
|
||||
- --secure-port=4443
|
||||
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
|
||||
- --kubelet-use-node-status-port
|
||||
- --kubelet-insecure-tls
|
||||
- --authorization-always-allow-paths=/livez,/readyz
|
||||
image: k8s.gcr.io/metrics-server/metrics-server:v0.4.2
|
||||
imagePullPolicy: IfNotPresent
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
httpGet:
|
||||
path: /livez
|
||||
port: https
|
||||
scheme: HTTPS
|
||||
periodSeconds: 10
|
||||
name: metrics-server
|
||||
ports:
|
||||
- containerPort: 4443
|
||||
name: https
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
failureThreshold: 3
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: https
|
||||
scheme: HTTPS
|
||||
periodSeconds: 10
|
||||
securityContext:
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
volumeMounts:
|
||||
- mountPath: /tmp
|
||||
name: tmp-dir
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
priorityClassName: system-cluster-critical
|
||||
serviceAccountName: metrics-server
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: tmp-dir
|
||||
---
|
||||
apiVersion: apiregistration.k8s.io/v1
|
||||
kind: APIService
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: metrics-server
|
||||
name: v1beta1.metrics.k8s.io
|
||||
spec:
|
||||
group: metrics.k8s.io
|
||||
groupPriorityMinimum: 100
|
||||
insecureSkipTLSVerify: true
|
||||
service:
|
||||
name: metrics-server
|
||||
namespace: kube-system
|
||||
version: v1beta1
|
||||
versionPriority: 100
|
||||
@@ -0,0 +1,63 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
annotations:
|
||||
finalizers:
|
||||
- kubernetes.io/pv-protection
|
||||
name: prometheus-server
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
capacity:
|
||||
storage: 8Gi
|
||||
claimRef:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
name: prometheus-server
|
||||
namespace: monitoring
|
||||
local:
|
||||
path: /data/localstorage/prometheus-server
|
||||
nodeAffinity:
|
||||
required:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: kubernetes.io/hostname
|
||||
operator: In
|
||||
values:
|
||||
- pi-worker
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
storageClassName: local-storage
|
||||
volumeMode: Filesystem
|
||||
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
annotations:
|
||||
finalizers:
|
||||
- kubernetes.io/pv-protection
|
||||
name: prometheus-alertmanager
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
capacity:
|
||||
storage: 2Gi
|
||||
claimRef:
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
name: prometheus-alertmanager
|
||||
namespace: monitoring
|
||||
local:
|
||||
path: /data/localstorage/prometheus-alertmanager
|
||||
nodeAffinity:
|
||||
required:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: kubernetes.io/hostname
|
||||
operator: In
|
||||
values:
|
||||
- pi-worker
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
storageClassName: local-storage
|
||||
volumeMode: Filesystem
|
||||
@@ -0,0 +1,4 @@
|
||||
providers:
|
||||
file:
|
||||
filename: /custom-data/traefik-config.yaml
|
||||
kubernetesIngress: {}
|
||||
@@ -0,0 +1,22 @@
|
||||
# Activate Pilot integration
|
||||
pilot:
|
||||
enabled: true
|
||||
token: "${traefik_api_key_value}"
|
||||
|
||||
additionalArguments:
|
||||
# - --entryPoints.tcpentry.address=:3333/tcp
|
||||
# - --entryPoints.udpentry.address=:3333/udp
|
||||
- --entryPoints.dnsentry.address=:53/udp
|
||||
- --providers.file.filename=/custom-data/traefik-config.yaml
|
||||
- --providers.file.watch=true
|
||||
- --providers.kubernetesingress=true
|
||||
- --metrics.prometheus=true
|
||||
- --metrics.prometheus.entryPoint=metrics
|
||||
- --metrics.prometheus.addServicesLabels=true
|
||||
- --metrics.prometheus.addEntryPointsLabels=true
|
||||
- --entryPoints.metrics.address=:8082
|
||||
|
||||
volumes:
|
||||
- mountPath: /custom-data
|
||||
name: traefik-config
|
||||
type: configMap
|
||||
@@ -0,0 +1,196 @@
|
||||
resource "kubernetes_storage_class" "torrent_nfs" {
|
||||
metadata {
|
||||
name = "nfs-torrent"
|
||||
}
|
||||
storage_provisioner = "local"
|
||||
reclaim_policy = "Retain"
|
||||
allow_volume_expansion = true
|
||||
volume_binding_mode = "Immediate"
|
||||
}
|
||||
|
||||
resource "kubernetes_namespace" "torrent_ns" {
|
||||
metadata {
|
||||
name = "torrent"
|
||||
labels = {
|
||||
app = "torrent"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_ingress" "torrent_ingress" {
|
||||
metadata {
|
||||
name = "traefik-k8s"
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" : "traefik"
|
||||
}
|
||||
namespace = kubernetes_namespace.torrent_ns.metadata.0.name
|
||||
}
|
||||
|
||||
spec {
|
||||
rule {
|
||||
host = "torrent.local"
|
||||
http {
|
||||
path {
|
||||
path = "/"
|
||||
backend {
|
||||
service_name = kubernetes_service.torrent_svc.metadata.0.name
|
||||
service_port = 3000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_service" "torrent_svc" {
|
||||
depends_on = [kubernetes_config_map.metallb_cfg_map]
|
||||
metadata {
|
||||
namespace = kubernetes_namespace.torrent_ns.metadata.0.name
|
||||
name = "torrent-fwd"
|
||||
annotations = {
|
||||
"metallb.universe.tf/address-pool" : "default"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
port {
|
||||
name = "torrent-rpc"
|
||||
port = 5000
|
||||
target_port = 5000
|
||||
}
|
||||
port {
|
||||
name = "torrent-tcp"
|
||||
port = 23340
|
||||
target_port = 23340
|
||||
}
|
||||
port {
|
||||
name = "torrent-http"
|
||||
port = 3000
|
||||
target_port = 3000
|
||||
}
|
||||
load_balancer_ip = "${var.network_subnet}.${var.rtorrent_rpc_host}"
|
||||
selector = {
|
||||
"app" : "torrent"
|
||||
}
|
||||
type = "LoadBalancer"
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_persistent_volume" "torrent_shared_nfs" {
|
||||
metadata {
|
||||
name = "torrent-pv"
|
||||
labels = {
|
||||
name = "type"
|
||||
value = "local"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
capacity = {
|
||||
storage = "8Ti"
|
||||
}
|
||||
storage_class_name = kubernetes_storage_class.torrent_nfs.metadata.0.name
|
||||
access_modes = ["ReadWriteMany"]
|
||||
persistent_volume_source {
|
||||
host_path {
|
||||
path = var.nfs_torrent_path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_persistent_volume_claim" "torrent_shared_nfs_claim" {
|
||||
metadata {
|
||||
name = "torrent-pvc"
|
||||
namespace = kubernetes_namespace.torrent_ns.metadata.0.name
|
||||
}
|
||||
spec {
|
||||
storage_class_name = kubernetes_storage_class.torrent_nfs.metadata.0.name
|
||||
access_modes = ["ReadWriteMany"]
|
||||
resources {
|
||||
requests = {
|
||||
storage = "8Ti"
|
||||
}
|
||||
}
|
||||
volume_name = kubernetes_persistent_volume.torrent_shared_nfs.metadata.0.name
|
||||
}
|
||||
}
|
||||
|
||||
## rTorrent deployment
|
||||
|
||||
resource "kubernetes_deployment" "flood-torrent" {
|
||||
depends_on = [kubernetes_persistent_volume_claim.torrent_shared_nfs_claim]
|
||||
metadata {
|
||||
name = "flood-torrent"
|
||||
labels = {
|
||||
app = "torrent"
|
||||
}
|
||||
namespace = kubernetes_namespace.torrent_ns.metadata.0.name
|
||||
}
|
||||
|
||||
spec {
|
||||
replicas = 1
|
||||
selector {
|
||||
match_labels = {
|
||||
app = "torrent"
|
||||
}
|
||||
}
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "torrent"
|
||||
}
|
||||
}
|
||||
|
||||
spec {
|
||||
volume {
|
||||
name = "torrent-v-nfs"
|
||||
persistent_volume_claim {
|
||||
claim_name = kubernetes_persistent_volume_claim.torrent_shared_nfs_claim.metadata.0.name
|
||||
}
|
||||
}
|
||||
container {
|
||||
name = "flood-torrent"
|
||||
image = "ghcr.io/lukaszraczylo/flood:1.2292.7"
|
||||
env {
|
||||
name = "FLOOD_DISABLE_AUTH"
|
||||
value = "true"
|
||||
}
|
||||
args = ["--rthost", "${var.network_subnet}.${var.rtorrent_rpc_host}",
|
||||
"--rtport", "5000", "-e", "HOME=/config", "--auth", "none", "-d", "/config/flood",
|
||||
"--allowedpath", "/config",
|
||||
"--allowedpath", "/data",
|
||||
"--rtorrent", "--rtconfig", "/data/rtorrent/.rtorrent.rc"]
|
||||
port {
|
||||
container_port = 3000
|
||||
protocol = "TCP"
|
||||
}
|
||||
port {
|
||||
container_port = 5000
|
||||
protocol = "TCP"
|
||||
}
|
||||
port {
|
||||
container_port = 23340
|
||||
protocol = "TCP"
|
||||
}
|
||||
port {
|
||||
container_port = 23340
|
||||
protocol = "UDP"
|
||||
}
|
||||
volume_mount {
|
||||
mount_path = "/data"
|
||||
name = "torrent-v-nfs"
|
||||
}
|
||||
volume_mount {
|
||||
mount_path = "/mnt/storage/torrent/downloaded"
|
||||
sub_path = "downloaded"
|
||||
name = "torrent-v-nfs"
|
||||
}
|
||||
volume_mount {
|
||||
mount_path = "/config"
|
||||
sub_path = "flood"
|
||||
name = "torrent-v-nfs"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
resource "helm_release" "traefik" {
|
||||
# depends_on = [ helm_release.prometheus ]
|
||||
name = "traefik"
|
||||
namespace = "default"
|
||||
chart = "traefik/traefik"
|
||||
|
||||
set {
|
||||
name = "deployment.replicas"
|
||||
value = "2"
|
||||
}
|
||||
|
||||
set {
|
||||
name = "service.spec.loadBalancerIP"
|
||||
value = "${var.network_subnet}.234"
|
||||
}
|
||||
|
||||
values = [
|
||||
templatefile("static/traefik-static-config.tmpl", { traefik_api_key_value = var.traefik_api_key })
|
||||
]
|
||||
}
|
||||
|
||||
resource "kubernetes_config_map" "traefic_cfg_map" {
|
||||
metadata {
|
||||
name = "traefik-config"
|
||||
namespace = "default"
|
||||
}
|
||||
data = {
|
||||
"traefik-config.yaml" = file("static/traefik-cfg.yaml")
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_service" "traefik_svc" {
|
||||
depends_on = [kubernetes_config_map.metallb_cfg_map, helm_release.traefik]
|
||||
metadata {
|
||||
namespace = "default"
|
||||
name = "traefik-dashboard"
|
||||
annotations = {
|
||||
"metallb.universe.tf/address-pool" : "default"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
port {
|
||||
port = 80
|
||||
target_port = 9000
|
||||
}
|
||||
selector = {
|
||||
"app.kubernetes.io/instance" : "traefik"
|
||||
}
|
||||
type = "LoadBalancer"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
variable "network_subnet" {}
|
||||
variable "rtorrent_rpc_host" {}
|
||||
variable "nfs_torrent_path" {}
|
||||
variable "nfs_adguard_path" {}
|
||||
variable "adguard_host" {}
|
||||
variable "adguard_catchall_host" {}
|
||||
variable "traefik_api_key" {}
|
||||
variable "github_user" {}
|
||||
variable "github_pat" {}
|
||||
@@ -0,0 +1,30 @@
|
||||
terraform {
|
||||
required_version = ">= 0.13"
|
||||
|
||||
required_providers {
|
||||
kubernetes = {
|
||||
source = "hashicorp/kubernetes"
|
||||
version = "~> 2.0.2"
|
||||
}
|
||||
|
||||
http = {
|
||||
source = "hashicorp/http"
|
||||
version = "~> 2.1.0"
|
||||
}
|
||||
|
||||
helm = {
|
||||
source = "hashicorp/helm"
|
||||
version = "~> 2.0.3"
|
||||
}
|
||||
|
||||
null = {
|
||||
source = "hashicorp/null"
|
||||
version = "~> 3.1.0"
|
||||
}
|
||||
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = "~> 3.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
# Variables used for barebone kubernetes setup
|
||||
network_subnet = "192.168.50"
|
||||
rtorrent_rpc_host = "245"
|
||||
adguard_host = "240"
|
||||
adguard_catchall_host = "249"
|
||||
|
||||
nfs_torrent_path = "/mnt/drobo-storage/docker-volumes/torrent"
|
||||
nfs_adguard_path = "/mnt/drobo-storage/docker-volumes/adguard"
|
||||
|
||||
# ENV variable: TRAEFIK_API_KEY sets traefik_api_key
|
||||
# ENV variable: GH_USER, GH_PAT for authentication with private containers
|
||||
Reference in New Issue
Block a user