starting homelab RKE2 cluster
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
frr version 9.1
|
||||
frr defaults traditional
|
||||
hostname UniFi-Gateway
|
||||
log syslog informational
|
||||
service integrated-vtysh-config
|
||||
!
|
||||
router bgp 65100
|
||||
bgp router-id 192.168.1.1
|
||||
no bgp ebgp-requires-policy
|
||||
neighbor RKE2 peer-group
|
||||
neighbor RKE2 remote-as 65200
|
||||
neighbor 192.168.1.238 peer-group RKE2
|
||||
address-family ipv4 unicast
|
||||
neighbor RKE2 activate
|
||||
neighbor RKE2 next-hop-self
|
||||
redistribute connected
|
||||
exit-address-family
|
||||
!
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
direkt auf dem Server ausführen
|
||||
|
||||
# RKE2 installieren
|
||||
curl -sfL https://get.rke2.io | sudo INSTALL_RKE2_TYPE="server" sh
|
||||
|
||||
# Verzeichnis für die Konfiguration anlegen
|
||||
sudo mkdir -p /etc/rancher/rke2
|
||||
|
||||
# Konfigurationsdatei erstellen
|
||||
cat <<EOF | sudo tee /etc/rancher/rke2/config.yaml
|
||||
cni: none
|
||||
disable-kube-proxy: true
|
||||
disable:
|
||||
- rke2-canal
|
||||
- rke2-ingress-nginx # (Da wir Envoy nutzen wollen)
|
||||
EOF
|
||||
|
||||
# RKE2-Service enablen und starten
|
||||
sudo systemctl enable --now rke2-server.service
|
||||
|
||||
# K8S kube-config Datei auf Workstation kopieren
|
||||
sudo cat /etc/rancher/rke2/rke2.yaml
|
||||
@@ -0,0 +1,22 @@
|
||||
# notwendige Tools installieren
|
||||
brew install cilium-cli kubernetes-cli helm egctl switcher cmctl
|
||||
|
||||
# !!! zum richtigen cluster wechseln !!! Ich nutze dafür switcher
|
||||
|
||||
# cilium installieren
|
||||
cilium install \
|
||||
--version 1.18.5 \
|
||||
--set bgpControlPlane.enabled=true \
|
||||
--set bgpControlPlane.defaultInstance.type=cluster \
|
||||
--set kubeProxyReplacement=true \
|
||||
--set operator.replicas=1 \
|
||||
--set gatewayAPI.enabled=true
|
||||
|
||||
# Cilium überprüfen
|
||||
cilium status
|
||||
|
||||
# envoy installieren
|
||||
helm install eg oci://docker.io/envoyproxy/gateway-helm --version v1.6.1 -n envoy-gateway-system --create-namespace
|
||||
|
||||
# Envoy Gateway Dashboard
|
||||
egctl experimental dashboard envoy-gateway
|
||||
@@ -0,0 +1,92 @@
|
||||
# 1. Definiert, WAS angekündigt wird (LoadBalancer IPs)
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumBGPAdvertisement
|
||||
metadata:
|
||||
name: bgp-advertisement
|
||||
labels:
|
||||
bgp.cilium.io/advertise: loadbalancer-services
|
||||
spec:
|
||||
advertisements:
|
||||
- advertisementType: "Service"
|
||||
service:
|
||||
addresses:
|
||||
- LoadBalancerIP
|
||||
selector:
|
||||
matchLabels: {}
|
||||
---
|
||||
|
||||
# 2. Definiert, an WEN wir senden (Dein UniFi Router)
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumBGPPeerConfig
|
||||
metadata:
|
||||
name: unifi-peer-config
|
||||
spec:
|
||||
families:
|
||||
- afi: ipv4
|
||||
safi: unicast
|
||||
advertisements:
|
||||
matchLabels:
|
||||
bgp.cilium.io/advertise: loadbalancer-services
|
||||
gracefulRestart:
|
||||
enabled: true
|
||||
---
|
||||
|
||||
# 3. Verknüpft alles mit deinem Node
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumBGPClusterConfig
|
||||
metadata:
|
||||
name: bpg-cluster-config
|
||||
spec:
|
||||
nodeSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/os: linux
|
||||
bgpInstances:
|
||||
- name: "asus-pn51-e1"
|
||||
localASN: 65200
|
||||
peers:
|
||||
- name: "unifi-router"
|
||||
peerAddress: 192.168.1.1
|
||||
peerASN: 65100 # Hier gehört die Remote-ASN jetzt hin!
|
||||
peerConfigRef:
|
||||
name: unifi-peer-config
|
||||
|
||||
---
|
||||
apiVersion: "cilium.io/v2alpha1"
|
||||
kind: CiliumLoadBalancerIPPool
|
||||
metadata:
|
||||
name: "envoy-gateway-pool"
|
||||
spec:
|
||||
blocks:
|
||||
- cidr: "192.168.200.240/28"
|
||||
serviceSelector:
|
||||
matchLabels: {}
|
||||
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: GatewayClass
|
||||
metadata:
|
||||
name: envoy-gateway-class
|
||||
spec:
|
||||
controllerName: gateway.envoyproxy.io/gatewayclass-controller
|
||||
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: external-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: envoy-gateway-class
|
||||
listeners:
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: All
|
||||
- name: https
|
||||
protocol: HTTPS
|
||||
port: 443
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: All
|
||||
@@ -0,0 +1,40 @@
|
||||
fullnameOverride: external-dns-unifi
|
||||
|
||||
# Konfiguration des Webhook-Providers (der "Übersetzer" für UniFi)
|
||||
provider:
|
||||
name: webhook
|
||||
webhook:
|
||||
image:
|
||||
repository: ghcr.io/kashalls/external-dns-unifi-webhook
|
||||
tag: main
|
||||
env:
|
||||
- name: UNIFI_HOST
|
||||
value: https://192.168.1.1 # Deine Gateway IP
|
||||
- name: UNIFI_API_KEY
|
||||
value: "J5VRZY-rGrtdGTf-fj1mTdZeUpLGzDBH"
|
||||
- name: UNIFI_EXTERNAL_CONTROLLER
|
||||
value: "false" # false, da der Controller auf dem Gateway selbst läuft
|
||||
- name: LOG_LEVEL
|
||||
value: info
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http-webhook
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: http-webhook
|
||||
|
||||
# Allgemeine External-DNS Einstellungen
|
||||
policy: sync # "sync" löscht auch Einträge, die nicht mehr in K8s sind. "upsert-only" ist sicherer.
|
||||
sources:
|
||||
- service
|
||||
- ingress
|
||||
- gateway-httproute
|
||||
|
||||
# WICHTIG: Nur diese Domain verwalten
|
||||
domainFilters:
|
||||
- "k8s.hnrx.net" # <--- ÄNDERE DIES auf deine Domain (muss im UniFi als Domain konfiguriert sein?)
|
||||
- "hnrx.net"
|
||||
# Registry (verhindert, dass external-dns fremde Einträge überschreibt)
|
||||
txtOwnerId: "k8s-cluster"
|
||||
@@ -0,0 +1,31 @@
|
||||
# Basic requirements
|
||||
|
||||
In diesem Schritt installieren wir
|
||||
- phase-secrets-operator
|
||||
- cert-manager
|
||||
- external-DNS mit Webhook Provider für Unifi
|
||||
|
||||
## Phase-Secrets-Operator
|
||||
|
||||
helm repo add phase https://helm.phase.dev && helm repo update
|
||||
|
||||
helm install phase-secrets-operator phase/phase-kubernetes-operator --set image.tag=v1.3.0
|
||||
|
||||
kubectl create secret generic phase-service-token \
|
||||
--from-literal=token=pss_service:v2:XXXXXXXXXXXXXXXXXXXXX \
|
||||
--type=Opaque \
|
||||
--namespace=default
|
||||
|
||||
## Cert-Manager und Cluster-Issuer
|
||||
|
||||
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.19.2/cert-manager.yaml
|
||||
|
||||
k apply -f manifests
|
||||
|
||||
## External-DNS
|
||||
|
||||
helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
|
||||
|
||||
kubectl create ns external-dns
|
||||
|
||||
helm upgrade --install external-dns external-dns/external-dns --namespace external-dns --version 1.19.0 -f external-dns-values.yaml
|
||||
@@ -0,0 +1,19 @@
|
||||
apiVersion: secrets.phase.dev/v1alpha1
|
||||
kind: PhaseSecret
|
||||
metadata:
|
||||
name: cloudflare-api-key-phase-secret
|
||||
namespace: cert-manager
|
||||
spec:
|
||||
phaseApp: 'cert-manager' # The name of your Phase application
|
||||
phaseAppEnv: 'production' # OPTIONAL - The Phase App Environment to fetch secrets from
|
||||
phaseAppEnvPath: '/' # OPTIONAL Path within the Phase application environment to fetch secrets from
|
||||
phaseHost: 'https://phase.hnrx.net' # OPTIONAL - URL of a Phase Console instance
|
||||
authentication:
|
||||
serviceToken:
|
||||
serviceTokenSecretReference:
|
||||
secretName: 'phase-service-token' # Name of the Phase Service Token with access to your application
|
||||
secretNamespace: 'default'
|
||||
managedSecretReferences:
|
||||
- secretName: 'cloudflare-api-key' # Name of the Kubernetes managed secret that Phase will sync
|
||||
secretNamespace: 'cert-manager'
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: cloudflare-cluster-issuer
|
||||
spec:
|
||||
acme:
|
||||
email: matthias.hinrichs@me.com
|
||||
server: https://acme-v02.api.letsencrypt.org/directory
|
||||
privateKeySecretRef:
|
||||
name: cluster-issuer-account-key
|
||||
solvers:
|
||||
- dns01:
|
||||
cloudflare:
|
||||
apiTokenSecretRef:
|
||||
name: cloudflare-api-key
|
||||
key: CLOUDFLARE_API_KEY
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: argocd
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: argocd-gateway
|
||||
namespace: argocd
|
||||
labels:
|
||||
bgp.cilium.io/ip-pool: default # Damit bekommt das Gateway eine IP aus deinem Pool
|
||||
annotations:
|
||||
# Damit external-dns diesen Gateway findet und einen DNS-Eintrag erstellt
|
||||
# (falls external-dns Gateway API unterstützt, was es tut)
|
||||
cert-manager.io/cluster-issuer: cloudflare-cluster-issuer
|
||||
spec:
|
||||
gatewayClassName: envoy-gateway-class
|
||||
listeners:
|
||||
- name: https
|
||||
hostname: "argocd.k8s.hnrx.net"
|
||||
protocol: HTTPS
|
||||
port: 443
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: All
|
||||
tls:
|
||||
mode: Terminate
|
||||
certificateRefs:
|
||||
- name: argocd-gateway-tls
|
||||
- name: http
|
||||
hostname: "argocd.k8s.hnrx.net"
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
kinds:
|
||||
- kind: HTTPRoute
|
||||
- kind: GRPCRoute
|
||||
namespaces:
|
||||
from: All
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: argocd-gateway-tls
|
||||
namespace: argocd
|
||||
spec:
|
||||
secretName: argocd-gateway-tls
|
||||
dnsNames:
|
||||
- argocd.k8s.hnrx.net
|
||||
issuerRef:
|
||||
name: cloudflare-cluster-issuer
|
||||
kind: ClusterIssuer
|
||||
@@ -0,0 +1,100 @@
|
||||
global:
|
||||
domain: "argocd.k8s.hnrx.net"
|
||||
|
||||
extraObjects:
|
||||
- apiVersion: secrets.phase.dev/v1alpha1
|
||||
kind: PhaseSecret
|
||||
metadata:
|
||||
name: argocd-phase-secret
|
||||
namespace: argocd
|
||||
labels:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
spec:
|
||||
phaseApp: 'argocd' # The name of your Phase application
|
||||
phaseAppEnv: 'production' # OPTIONAL - The Phase App Environment to fetch secrets from
|
||||
phaseAppEnvPath: '/' # OPTIONAL Path within the Phase application environment to fetch secrets from
|
||||
phaseHost: 'https://phase.hnrx.net' # OPTIONAL - URL of a Phase Console instance
|
||||
authentication:
|
||||
serviceToken:
|
||||
serviceTokenSecretReference:
|
||||
secretName: 'phase-service-token' # Name of the Phase Service Token with access to your application
|
||||
secretNamespace: 'default'
|
||||
managedSecretReferences:
|
||||
- secretName: 'argocd-authentik-client-secret' # Name of the Kubernetes managed secret that Phase will sync
|
||||
secretNamespace: 'argocd'
|
||||
|
||||
configs:
|
||||
cm:
|
||||
url: https://argocd.k8s.hnrx.net
|
||||
dex.config: |
|
||||
connectors:
|
||||
- config:
|
||||
issuer: ${AUTHENTIK_ISSUER_URL}
|
||||
clientID: ${AUTHENTIK_CLIENT_ID}
|
||||
clientSecret: ${AUTHENTIK_CLIENT_SECRET}
|
||||
insecureEnableGroups: true
|
||||
scopes:
|
||||
- openid
|
||||
- profile
|
||||
- email
|
||||
name: authentik
|
||||
type: oidc
|
||||
id: authentik
|
||||
|
||||
params:
|
||||
server.insecure: true
|
||||
rbac:
|
||||
policy.csv: |
|
||||
g, ArgoCD Admins, role:admin
|
||||
g, ArgoCD Viewers, role:readonly
|
||||
secret:
|
||||
extra:
|
||||
dex.authentik.clientSecret: "${AUTHENTIK_CLIENT_SECRET}"
|
||||
cmp:
|
||||
credentialTemplates:
|
||||
https-creds:
|
||||
url: https://git.hnrx.net
|
||||
username: ${GIT_USER}
|
||||
password: ${GIT_PASSWORD}
|
||||
|
||||
|
||||
dex:
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: argocd-authentik-client-secret
|
||||
|
||||
server:
|
||||
httproute:
|
||||
enabled: true
|
||||
parentRefs:
|
||||
- name: argocd-gateway
|
||||
namespace: argocd
|
||||
sectionName: https
|
||||
hostnames:
|
||||
- "argocd.k8s.hnrx.net"
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: argocd-server
|
||||
port: 80
|
||||
|
||||
grpcroute:
|
||||
enabled: true
|
||||
parentRefs:
|
||||
- name: argocd-gateway
|
||||
namespace: argocd
|
||||
sectionName: http
|
||||
hostnames:
|
||||
- "argocd.k8s.hnrx.net"
|
||||
rules:
|
||||
- matches:
|
||||
- method:
|
||||
type: Exact
|
||||
service: "cluster.argoproj.v1alpha1.repositorieservice"
|
||||
method: "List"
|
||||
backendRefs:
|
||||
- name: argocd-server
|
||||
port: 443
|
||||
@@ -0,0 +1,5 @@
|
||||
# Argo-CD Installation mit SSO über Authentik
|
||||
|
||||
helm repo add argo https://argoproj.github.io/argo-helm
|
||||
|
||||
helm upgrade --install argocd argo/argo-cd --namespace argocd -f argo-values.yaml
|
||||
@@ -0,0 +1,10 @@
|
||||
# Zwischenstand
|
||||
Der Cluster hat bereits folgendes installiert:
|
||||
- Cilium Netzwerk mit BGP
|
||||
- Envoy Gateway API
|
||||
- Cert-Manager
|
||||
- External DNS für Einträge im Unifi-DNS-Server
|
||||
|
||||
## Weitere Infrastuktur-Bestandteile installieren
|
||||
|
||||
Diese werden mit ArgoCD gemanagt.
|
||||
@@ -0,0 +1,27 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ApplicationSet
|
||||
metadata:
|
||||
name: cluster-infra
|
||||
namespace: argocd
|
||||
spec:
|
||||
generators:
|
||||
- git:
|
||||
repoURL: https://github.com/dein-user/git-repo.git
|
||||
revision: HEAD
|
||||
directories:
|
||||
- path: 08_cluster_infrastructure/*
|
||||
template:
|
||||
metadata:
|
||||
name: '{{path.basename}}'
|
||||
spec:
|
||||
project: cluster-infra
|
||||
source:
|
||||
repoURL: https://github.com/dein-user/git-repo.git
|
||||
path: '{{path}}'
|
||||
helm:
|
||||
values: values-{{cluster.name}}.yaml # Env-spezifisch
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: '{{path.basename}}'
|
||||
syncPolicy:
|
||||
automated: {prune: true, selfHeal: true}
|
||||
Reference in New Issue
Block a user