Domowy Homelab krążył za mną od jakiegoś czasu. Przerażała mnie jednak myśl tego, że mam zmienne IP i inne wydatki. Jednak po odkryciu usług Cloudflare Tunnel, sprawa sporo się ułatwiła.
Setup
Czym jest DDNS ?
DDNS (Dynamic Domain Name System) to usługa, która automatycznie aktualizuje rekordy DNS, gdy zmienia się adres IP urządzenia.
DDNS mam w domu, dzięki użyciu usługi w NAS Synology, ale mimo to jest to usługa dość ograniczona, podobnie jak routing w web platform od Synology. Można było zainstalować Nginx w Dockerze i kierować porty 80 i 443 tam, aby rozwiązywać routing, ale było to uciążliwe. Zakupiłem więc Mini PC Dell Optiflex 7050 z konfiguracją: i5 6gen, 16 GB RAM i 512 SSD, aby zainstalować na nim Proxmox i Kubernetes.
W przyszłości planuję dokupić więcej RAM, aby ten master PC mógł obsługiwać dodatkowe usługi, jak baza danych czy Home Assistant z dodatkami.
Przy okazji, to także sposób na szybszy hosting dedykowanego serwera do gry Satisfactory, który na procesorze z Synology… zaczynał zawodzić.
Proxmox
Tutaj, miałem wiele opcji, bo mogłem zainstalować bezpośrednio Ubuntu i na nim postawić k3s, ale.. Zachęciła mnie myśl o separacji usług na osobne maszyny (kontenery), z myślą np. o Home Assistant w przyszłości. Proxmox, dzięki swoim skryptom, sporo to ułatwia, a hyper-v od MS mam wrażenie, że jest jednak trochę ociężałe i nie ma web panelu.
Proxmox to dystrybucja oparta na Debianie, która oferuje wirtualizację. Dodatkowym atutem jest obsługa przez web panel. Społeczność wokół Proxmox jest bogata, więc jest pełno gotowych skryptów z obrazami i konfiguracjami, np. do szybkiego postawienia Home Assistant z usługami.
Proxmox można pobrać za darmo ze strony: https://www.proxmox.com/en/downloads
Strona ze skryptami: https://tteck.github.io/Proxmox/
ISO na pendrive wrzuciłem za pomocą Rufus, a następnie w BIOS ustawiłem bootowanie z pendrive i zainstalowałem Proxmox zgodnie z prostym przewodnikiem. Ustawiłem też stałe IP na routerze.
Warto zainstalować skrypt „Proxmox VE Post Install” z powyższej strony.
Warto też dodać, że Jeśli w sytuacjach, gdy posiadacie nas, to śmiało możecie podłączyć do każdej instancji dysk sieciowy po SMB czy NFS. Warto tylko dodać, że do LXC, musicie odznaczyć Typ instalacji, jako unprivileged, przy tworzeniu, bo inaczej nie będziecie nawet mieli opcji ustawienia tego potem. Więcej o tym napiszę w późniejszych wpisach.
Kubernetes
Ostatnio coraz częściej pracuję z Kubernetesem w firmie. Na początku wydawał się, bardziej skomplikowany niż trzeba, głównie przez pliki konfiguracyjne, które są trudniejsze niż np. Docker Compose.
Swojego master node stworzyłem na podstawie Debian LXC, który jest lżejszy i bardziej wydajny niż VM. Kontener ma 14 GB RAM i 4 vCPU, ponieważ obsługuje także dedykowany serwer do gry Satisfactory. W przyszłości będzie można dodać kolejne węzły, np. Raspberry Pi 4+.
Zainstalowałem K3s na Debian LXC: [https://k3s.io/](https://k3s.io/), co było bardzo proste. Aktualne dokumenty instalacyjne można znaleźć tutaj: https://docs.k3s.io/quick-start
Dla łatwiejszego dostępu do konfiguracji klastra:
cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
lub
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
Polecam także narzędzie K9s, które znacznie ułatwia zarządzanie Kubernetes. Instrukcje instalacji znajdziesz tutaj: https://k9scli.io
Certyfikat
Kupiłem domenę lifelike.cloud, aby podpiąć certyfikat. Na potrzeby tego artykułu tworzę self-signed certificate, ponieważ ostateczny certyfikat będzie dostarczony przez Cloudflare Tunnel.
Tworzenie klucza prywatnego:
openssl genrsa -out wildcard.key 2048
Tworzenie CSR:
openssl req -new -key wildcard.key -subj "/CN=*.lifelike.cloud" -out wildcard.csr
Tworzenie certyfikatu ważnego rok:
openssl x509 -req -in wildcard.csr -signkey wildcard.key -out wildcard.crt -days 365
Podpinanie certyfikatu jako sekret w Kubernetes:
kubectl create secret tls tls-cert --cert=wildcard.crt --key=wildcard.key
Serwisy
Stawiam API dostępne w open source na moim GitHubie: https://github.com/aluspl/CoffeeRecipesApi/tree/develop.
Obraz aplikacji jest hostowany w Docker Hub jako:
aluspl/coffeerecipesapi:develop
Najpierw łączymy się z master node i tworzymy plik `api.yml`:
apiVersion: apps/v1
kind: Deployment
metadata:
name: coffeerecipes-api
labels:
app: coffeerecipes-api
spec:
replicas: 1
selector:
matchLabels:
app: coffeerecipes-api
template:
metadata:
labels:
app: coffeerecipes-api
spec:
containers:
- name: coffeerecipes-api
image: aluspl/coffeerecipesapi:develop
imagePullPolicy: Always
ports:
- containerPort: 80
env:
- name: ConnectionStrings__Marten
value: "Host=ip;Port=6432;Database=coffeerecipes;Username=postgres;Password=password#;"
- name: Media__ConnectionStrings
value: "blobStorageConnectionString"
- name: ASPNETCORE_URLS
value: "http://*:80"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
resources:
limits:
memory: "2024Mi"
cpu: "500m"
requests:
memory: "1024Mi"
cpu: "500m"
---
# Service dla aplikacji .NET
apiVersion: v1
kind: Service
metadata:
name: coffeerecipes-api-service
spec:
selector:
app: coffeerecipes-api
ports:
- protocol: TCP
port: 80
targetPort: 80
name: "http"
---
# Ingress dla aplikacji z użyciem Traefik
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: coffeerecipes-api-ingress
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
spec:
tls:
- hosts:
- dev-api-recipes.lifelike.cloud
secretName: lifelike-cloud-tls
rules:
- host: dev-api-recipes.lifelike.cloud
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: coffeerecipes-api-service
port:
number: 80
Następnie aplikujemy konfigurację:
kubectl apply -f api.yaml
Cloudflare Tunnel
Cloudflare Tunnel pozwala na udostępnienie serwisów na zewnątrz bez otwierania portów na routerze. Chroni także przed atakami DDoS. Ustawiłem domenę na Cloudflare, aby zarządzać rekordami DNS.
Link do dokumentacji Cloudflare Tunnel: https://developers.cloudflare.com/cloudflare-one/tutorials/many-cfd-one-tunnel.
Przykład konfiguracji:
apiVersion: v1
kind: ConfigMap
metadata:
name: cloudflared
data:
config.yaml: |
tunnel: lifelikecloudtunnel
credentials-file: /etc/cloudflared/creds/credentials.json
ingress:
- hostname: dev-api-recipes.lifelike.cloud
service: http://coffeerecipes-api-service:80
Teraz aplikujemy konfigurację:
kubectl apply -f cloudflare.yaml
Podsumowanie
Temat Homelab może wydawać się skomplikowany, ale po zrozumieniu podstaw, wszystko staje się łatwiejsze. Zachęcam do eksperymentowania i dalszej zabawy z technologiami!
Przy okazji, w kolejnej części, opowiem więcej o przejściu z ręcznie tworzonego certyfikatu, do automatycznie odnawianego let’s encrypt oraz przeniesieniu zmiennych typu connection stringi (do bazy czy blob storage) do kubernetesowych secretów.
p.s Dzięki Łukasz i Teodor za merytoryczne sprawdzenie artykułu.