Compare commits
10 Commits
e86b9d5e49
...
45dfbfcfbb
| Author | SHA1 | Date | |
|---|---|---|---|
| 45dfbfcfbb | |||
| 99e9371969 | |||
| ff3e6f723c | |||
| 620d757f8b | |||
| 0f61ffae27 | |||
| 3970af8ce2 | |||
| 0e08d89e01 | |||
| 62f0e703de | |||
| 447231f6b0 | |||
| 7e0a5ee800 |
@@ -0,0 +1,112 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Repository Overview
|
||||
|
||||
This repository contains Kubernetes configuration files for a K3s homelab cluster running on TuringPi hardware. It includes Helm charts, values files, and manifests for deploying various self-hosted applications.
|
||||
|
||||
## Cluster Architecture
|
||||
|
||||
### Hardware Setup
|
||||
- **turing1**: Control plane + worker (master node, IP: 192.168.222.237)
|
||||
- **turing2**: Worker node (currently SchedulingDisabled)
|
||||
- **turing3**: Worker node (also serves as NFS server at turing3.lan)
|
||||
- **turing4**: Worker node
|
||||
- **beelink**: Additional worker node
|
||||
|
||||
### Core Infrastructure
|
||||
- **K3s version**: v1.31.6+k3s1
|
||||
- **Storage**: NFS-backed persistent volumes from turing3.lan:/mnt/ssd
|
||||
- **Load Balancer**: MetalLB for bare metal LoadBalancer services
|
||||
- **SSL**: cert-manager with Let's Encrypt (staging/production cluster issuers)
|
||||
- **Ingress**: Nginx with LAN-only restrictions
|
||||
|
||||
## Application Stack
|
||||
|
||||
### Media Services
|
||||
- **Plex**: kube-plex (Kubernetes-native with dynamic transcoding pods)
|
||||
- **Jellyfin**: Alternative media server
|
||||
- **Sonarr/Radarr**: TV/Movie management (Bananaspliff charts)
|
||||
- **Prowlarr**: Indexer management (custom chart)
|
||||
- **Transmission**: BitTorrent client with OpenVPN
|
||||
- **FlareSolverr**: Captcha solver service
|
||||
|
||||
### Other Applications
|
||||
- **Actual Budget**: Personal finance (custom chart: my-actual-server/)
|
||||
- **Home Assistant Voice LLMs**: AI voice integration (custom chart)
|
||||
- **Ollama**: Local LLM inference
|
||||
- **Prometheus**: Monitoring stack
|
||||
- **PostgreSQL**: Database backend
|
||||
|
||||
## Common Helm Operations
|
||||
|
||||
### Repository Management
|
||||
```bash
|
||||
# Key repositories used
|
||||
helm repo add metallb https://metallb.github.io/metallb
|
||||
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner
|
||||
helm repo add jetstack https://charts.jetstack.io
|
||||
helm repo add bitnami https://charts.bitnami.com/bitnami
|
||||
helm repo add bananaspliff https://bananaspliff.github.io/geek-charts
|
||||
helm repo add k8s-at-home https://k8s-at-home.com/charts/
|
||||
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
|
||||
helm repo add jellyfin https://jellyfin.github.io/jellyfin-helm
|
||||
helm repo add ollama-helm https://otwld.github.io/ollama-helm/
|
||||
helm repo update
|
||||
```
|
||||
|
||||
### Application Deployment Pattern
|
||||
```bash
|
||||
# Standard deployment with values file
|
||||
helm upgrade <release-name> <chart> -f <app>_values.yaml -i
|
||||
|
||||
# Examples from history:
|
||||
helm upgrade actual my-actual-server -f actual_values.yaml -i
|
||||
helm upgrade plex kube-plex/charts/kube-plex --values plex_values.yml
|
||||
helm upgrade radarr bananaspliff/radarr -f radarr_values.yaml
|
||||
helm upgrade sonarr bananaspliff/sonarr -f sonarr_values.yaml
|
||||
helm upgrade prowlarr prowlarr -f prowlarr_values.yml
|
||||
```
|
||||
|
||||
### Development Workflow
|
||||
```bash
|
||||
# Chart development
|
||||
helm create <chart-name>
|
||||
helm lint <chart-path>
|
||||
helm template <chart> -f <values> | vim -
|
||||
|
||||
# Values inspection
|
||||
helm show values <chart> > <app>_values.yaml
|
||||
helm get values <release-name>
|
||||
helm get manifest <release-name>
|
||||
```
|
||||
|
||||
## File Structure Patterns
|
||||
|
||||
- `<app>_values.yaml` - Helm values overrides for each application
|
||||
- Custom charts in subdirectories (my-actual-server/, home-assistant-voice-llms/, prowlarr/)
|
||||
- `*_persistent_volume.yml` - PV definitions for applications requiring storage
|
||||
- Infrastructure manifests: metallb.yml, ingress.yaml, cluster-issuer-*.yaml
|
||||
|
||||
## Storage Configuration
|
||||
|
||||
- **NFS Server**: turing3.lan serving /mnt/ssd
|
||||
- **StorageClass**: nfs-client (via nfs-subdir-external-provisioner)
|
||||
- **Access Mode**: ReadWriteMany for shared media access
|
||||
- **PVC Pattern**: Applications create their own PVCs or reference pre-existing ones
|
||||
|
||||
## Network Setup
|
||||
|
||||
- **Pod Network**: Cluster subnet requires allowlisting in Plex for transcoding
|
||||
- **Ingress**: LAN-only access enforced via limit_ingress_to_lan.yaml
|
||||
- **Load Balancer**: MetalLB provides external IPs for services
|
||||
- **DNS**: .lan domain for internal services
|
||||
|
||||
## Kube-Plex Specifics
|
||||
|
||||
The kube-plex/ directory contains a Go application that replaces the standard Plex transcoder:
|
||||
- Creates Kubernetes pods for each transcode job
|
||||
- Requires AMD64 nodes (configured via nodeSelector)
|
||||
- Mounts shared NFS volumes for media access
|
||||
- Environment variables: DATA_PVC, CONFIG_PVC, TRANSCODE_PVC, PMS_IMAGE, PMS_INTERNAL_ADDRESS
|
||||
@@ -0,0 +1,144 @@
|
||||
# TuringPi K3s Homelab
|
||||
|
||||
This repository contains Kubernetes configuration files for a K3s cluster running on TuringPi hardware. It includes Helm charts, values files, and manifests for deploying various self-hosted applications in a homelab environment.
|
||||
|
||||
## 🏗️ Cluster Architecture
|
||||
|
||||
### Hardware Setup
|
||||
- **turing1**: Control plane + worker (192.168.222.237)
|
||||
- **turing2**: Worker node
|
||||
- **turing3**: Worker node (NFS server at turing3.lan)
|
||||
- **turing4**: Worker node
|
||||
- **beelink**: Additional x86_64 worker node
|
||||
|
||||
### Infrastructure Stack
|
||||
- **Kubernetes**: K3s lightweight distribution
|
||||
- **Storage**: NFS-backed persistent volumes from turing3.lan:/mnt/ssd
|
||||
- **Load Balancer**: MetalLB for bare metal LoadBalancer services
|
||||
- **SSL**: cert-manager with Let's Encrypt certificates
|
||||
- **Ingress**: Nginx with LAN-only access restrictions
|
||||
|
||||
## 🚀 Applications
|
||||
|
||||
### Media Services
|
||||
- **Plex**: Via kube-plex (Kubernetes-native with dynamic transcoding)
|
||||
- **Jellyfin**: Alternative media server
|
||||
- **Sonarr/Radarr**: TV/Movie management
|
||||
- **Prowlarr**: Indexer management
|
||||
- **Transmission**: BitTorrent client with OpenVPN
|
||||
- **FlareSolverr**: Captcha solver service
|
||||
|
||||
### Other Applications
|
||||
- **Actual Budget**: Personal finance management
|
||||
- **Home Assistant Voice LLMs**: AI voice integration
|
||||
- **Ollama**: Local LLM inference
|
||||
- **Prometheus**: Monitoring and metrics
|
||||
- **PostgreSQL**: Database backend
|
||||
|
||||
## 📁 Repository Structure
|
||||
|
||||
```
|
||||
├── *_values.yaml # Helm values overrides for applications
|
||||
├── my-actual-server/ # Custom Helm chart for Actual Budget
|
||||
├── home-assistant-voice-llms/ # Custom Helm chart for Voice AI
|
||||
├── prowlarr/ # Custom Helm chart for Prowlarr
|
||||
├── kube-plex/ # Kubernetes-native Plex implementation
|
||||
├── *.yml # Infrastructure manifests (MetalLB, ingress, etc.)
|
||||
└── persistent_volume*.yml # Storage definitions
|
||||
```
|
||||
|
||||
## 🔧 Common Operations
|
||||
|
||||
### Application Deployment
|
||||
```bash
|
||||
# Deploy with Helm using values files
|
||||
helm upgrade <release-name> <chart> -f <app>_values.yaml -i
|
||||
|
||||
# Examples:
|
||||
helm upgrade actual my-actual-server -f actual_values.yaml -i
|
||||
helm upgrade plex kube-plex/charts/kube-plex --values plex_values.yml
|
||||
helm upgrade radarr bananaspliff/radarr -f radarr_values.yaml
|
||||
```
|
||||
|
||||
### Infrastructure Management
|
||||
```bash
|
||||
# Apply Kubernetes manifests
|
||||
kubectl apply -f metallb.yml
|
||||
kubectl apply -f ingress.yaml
|
||||
|
||||
# Check cluster status
|
||||
kubectl get nodes
|
||||
kubectl get pods --all-namespaces
|
||||
```
|
||||
|
||||
## 🔄 K3s Cluster Updates
|
||||
|
||||
### Automated Update
|
||||
Run the provided script to update all nodes:
|
||||
```bash
|
||||
./update.sh
|
||||
```
|
||||
|
||||
### Manual Update Process
|
||||
|
||||
#### 1. Update Master Node (turing1)
|
||||
```bash
|
||||
ssh root@turing1 # password: turing
|
||||
curl -sfL https://get.k3s.io | INSTALL_K3S_SKIP_DOWNLOAD=false sh -s - \
|
||||
--write-kubeconfig-mode 644 \
|
||||
--disable servicelb \
|
||||
--token torino \
|
||||
--node-ip 192.168.222.237 \
|
||||
--disable-cloud-controller \
|
||||
--disable local-storage
|
||||
```
|
||||
|
||||
#### 2. Update Worker Nodes (turing2, turing3, turing4)
|
||||
```bash
|
||||
ssh root@<node> # password: turing
|
||||
curl -sfL https://get.k3s.io | INSTALL_K3S_SKIP_DOWNLOAD=false \
|
||||
K3S_URL=https://192.168.222.237:6443 \
|
||||
K3S_TOKEN=torino sh -
|
||||
```
|
||||
|
||||
#### 3. Update Beelink Node
|
||||
```bash
|
||||
ssh gilgamezh@beelink.lan # no password (SSH keys)
|
||||
sudo curl -sfL https://get.k3s.io | INSTALL_K3S_SKIP_DOWNLOAD=false \
|
||||
K3S_URL=https://192.168.222.237:6443 \
|
||||
K3S_TOKEN=torino sh -
|
||||
```
|
||||
|
||||
#### 4. Verify Update
|
||||
```bash
|
||||
kubectl get nodes # Check all nodes show new version
|
||||
kubectl get pods --all-namespaces | grep -v Running # Check for issues
|
||||
```
|
||||
|
||||
## 🔑 Access Information
|
||||
|
||||
- **Cluster Token**: `torino`
|
||||
- **Master Node**: `192.168.222.237:6443`
|
||||
- **SSH Access**:
|
||||
- TuringPi nodes: `root@<hostname>` (password: `turing`)
|
||||
- Beelink: `gilgamezh@beelink.lan` (SSH keys)
|
||||
|
||||
## 📚 Additional Documentation
|
||||
|
||||
- See `CLAUDE.md` for detailed Claude Code integration guide
|
||||
- Custom Helm charts include their own README files
|
||||
- Check application-specific `*_values.yaml` files for configuration options
|
||||
|
||||
## 🛠️ Development
|
||||
|
||||
### Helm Chart Development
|
||||
```bash
|
||||
helm create <chart-name>
|
||||
helm lint <chart-path>
|
||||
helm template <chart> -f <values> | kubectl apply --dry-run=client -f -
|
||||
```
|
||||
|
||||
### Storage Requirements
|
||||
- NFS server must be running on turing3.lan
|
||||
- Applications require ReadWriteMany access for shared media
|
||||
- Persistent volumes are dynamically provisioned via nfs-subdir-external-provisioner
|
||||
+4
-20
@@ -1,14 +1,11 @@
|
||||
# Default values for my-actual-server.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
---
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: docker.io/actualbudget/actual-server
|
||||
pullPolicy: IfNotPresent
|
||||
pullPolicy: Always
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: "latest"
|
||||
tag: "25.3.1"
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
@@ -16,24 +13,11 @@ service:
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
className: ""
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-production
|
||||
kubernetes.io/ingress.class: traefik
|
||||
hosts:
|
||||
- host: actual.gilgamezh.me
|
||||
paths:
|
||||
- path: /
|
||||
pathType: ImplementationSpecific
|
||||
tls:
|
||||
- hosts:
|
||||
- actual.gilgamezh.me
|
||||
secretName: actual-gilgamezh-me
|
||||
|
||||
volumes:
|
||||
- name: "actual-data"
|
||||
persistentVolumeClaim:
|
||||
claimName: "actual-data" # PersistentVolumeClaim created earlier
|
||||
claimName: "actual-data" # PersistentVolumeClaim created earlier
|
||||
|
||||
volumeMounts:
|
||||
- name: "actual-data"
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# Example ArgoCD Application with Image Auto-Update
|
||||
# This demonstrates how to set up your existing Helm applications in ArgoCD
|
||||
# with automatic "latest" tag updates
|
||||
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: plex-example
|
||||
namespace: argocd
|
||||
annotations:
|
||||
# Enable automatic image updates for Plex
|
||||
argocd-image-updater.argoproj.io/image-list: plex=ghcr.io/k8s-at-home/plex:latest
|
||||
# Use 'newest-build' strategy for latest images
|
||||
argocd-image-updater.argoproj.io/plex.update-strategy: newest-build
|
||||
# Write back to ArgoCD (for testing - production should use git method)
|
||||
argocd-image-updater.argoproj.io/write-back-method: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
# Point to your repository (replace with your actual Git repo)
|
||||
repoURL: https://github.com/munnerz/kube-plex
|
||||
path: charts/kube-plex
|
||||
targetRevision: HEAD
|
||||
helm:
|
||||
valueFiles:
|
||||
# This would reference your existing plex_values.yml
|
||||
# For now, this is just an example structure
|
||||
- values.yaml
|
||||
parameters:
|
||||
- name: image.tag
|
||||
value: latest
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: plex
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
@@ -0,0 +1,114 @@
|
||||
# ArgoCD Migration Guide for TuringPi Cluster
|
||||
|
||||
## ArgoCD Access Information
|
||||
|
||||
**Web UI Access:**
|
||||
- URL: http://192.168.222.25 (LoadBalancer IP)
|
||||
- Alternative: http://argocd.turing.lan (if you add to your hosts file)
|
||||
- Username: `admin`
|
||||
- Password: `fJ3diddVd2yson3W`
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
Your existing Helm-based applications can be migrated to ArgoCD gradually. Here's how:
|
||||
|
||||
### Option 1: Keep Existing Helm + Add GitOps Overlay
|
||||
1. Keep your current `*_values.yaml` files
|
||||
2. Create ArgoCD Applications that reference the same charts
|
||||
3. ArgoCD manages the lifecycle, you keep the familiar structure
|
||||
|
||||
### Option 2: Git-First Approach (Recommended for Production)
|
||||
1. Commit your values files to a Git repository
|
||||
2. Use ArgoCD's Git source with `argocd-image-updater` writing back to Git
|
||||
3. Full GitOps workflow with audit trail
|
||||
|
||||
## Adding Image Auto-Updates to Your Applications
|
||||
|
||||
For any application, add these annotations to the ArgoCD Application manifest:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
annotations:
|
||||
# Define which images to track
|
||||
argocd-image-updater.argoproj.io/image-list: myapp=myregistry/myapp:latest
|
||||
|
||||
# Use newest-build strategy for "latest" tags
|
||||
argocd-image-updater.argoproj.io/myapp.update-strategy: newest-build
|
||||
|
||||
# Write method: 'argocd' for testing, 'git' for production
|
||||
argocd-image-updater.argoproj.io/write-back-method: argocd
|
||||
```
|
||||
|
||||
## Example: Converting Your Plex Deployment
|
||||
|
||||
Your current command:
|
||||
```bash
|
||||
helm upgrade plex kube-plex/charts/kube-plex --values plex_values.yml
|
||||
```
|
||||
|
||||
Becomes this ArgoCD Application:
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: plex
|
||||
namespace: argocd
|
||||
annotations:
|
||||
argocd-image-updater.argoproj.io/image-list: plex=ghcr.io/k8s-at-home/plex:latest
|
||||
argocd-image-updater.argoproj.io/plex.update-strategy: newest-build
|
||||
argocd-image-updater.argoproj.io/write-back-method: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/munnerz/kube-plex # or your fork
|
||||
path: charts/kube-plex
|
||||
targetRevision: HEAD
|
||||
helm:
|
||||
valueFiles:
|
||||
- ../../plex_values.yml # Reference your existing values
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: plex
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
```
|
||||
|
||||
## Quick Start Commands
|
||||
|
||||
1. **Access ArgoCD UI**: Visit http://192.168.222.25 with admin/fJ3diddVd2yson3W
|
||||
|
||||
2. **Create your first application via CLI**:
|
||||
```bash
|
||||
# Install ArgoCD CLI (optional)
|
||||
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
|
||||
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
|
||||
|
||||
# Login (using the LoadBalancer IP)
|
||||
argocd login 192.168.222.25 --insecure --username admin --password fJ3diddVd2yson3W
|
||||
```
|
||||
|
||||
3. **Apply the example application**:
|
||||
```bash
|
||||
kubectl apply -f argocd-example-app.yaml
|
||||
```
|
||||
|
||||
## Benefits You Get Immediately
|
||||
|
||||
✅ **Keep using Helm** - ArgoCD manages Helm releases
|
||||
✅ **Auto image updates** - Latest tags update automatically
|
||||
✅ **Visual UI** - See deployment status, sync state, rollback easily
|
||||
✅ **GitOps ready** - When you want to commit values to Git
|
||||
✅ **Rollback capability** - Easy rollback to previous versions
|
||||
✅ **Multi-environment** - Can manage dev/staging/prod from one place
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Access the ArgoCD UI and familiarize yourself with it
|
||||
2. Create ArgoCD Applications for 1-2 of your existing services
|
||||
3. Test the image auto-update functionality
|
||||
4. Once comfortable, migrate more applications
|
||||
5. Consider setting up a Git repository for full GitOps workflow
|
||||
|
||||
Your existing Helm workflow continues to work while you gain GitOps benefits!
|
||||
@@ -0,0 +1,66 @@
|
||||
# ArgoCD configuration for TuringPi K3s cluster
|
||||
# Simplified setup - no RBAC restrictions for single-user environment
|
||||
|
||||
global:
|
||||
# Set domain for your LAN access
|
||||
domain: argocd.turing.lan
|
||||
|
||||
# Server configuration
|
||||
server:
|
||||
# Enable ingress for web UI access
|
||||
ingress:
|
||||
enabled: true
|
||||
controller: generic
|
||||
ingressClassName: nginx
|
||||
hostname: argocd.turing.lan
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
|
||||
# Restrict to LAN access (matching your existing pattern)
|
||||
nginx.ingress.kubernetes.io/whitelist-source-range: "192.168.0.0/16,10.0.0.0/8,172.16.0.0/12"
|
||||
|
||||
# Use LoadBalancer service for direct access via MetalLB
|
||||
service:
|
||||
type: LoadBalancer
|
||||
servicePortHttp: 80
|
||||
servicePortHttps: 443
|
||||
|
||||
# Enable insecure mode since this is a homelab (simpler setup)
|
||||
extraArgs:
|
||||
- --insecure
|
||||
|
||||
# ApplicationSet controller (for managing multiple apps)
|
||||
applicationSet:
|
||||
enabled: true
|
||||
|
||||
# Image updater will be installed separately
|
||||
# This is just the base ArgoCD installation
|
||||
|
||||
# Disable HA components for single-node simplicity
|
||||
redis-ha:
|
||||
enabled: false
|
||||
|
||||
# Use single Redis instance
|
||||
redis:
|
||||
enabled: true
|
||||
|
||||
# Disable RBAC since you're the only user
|
||||
rbac:
|
||||
create: true
|
||||
# Allow admin access without restrictions
|
||||
policy.default: role:admin
|
||||
|
||||
# No authentication complexity needed for homelab
|
||||
configs:
|
||||
secret:
|
||||
createSecret: true
|
||||
|
||||
# Storage for repo data (using your NFS setup)
|
||||
repoServer:
|
||||
volumes:
|
||||
- name: custom-tools
|
||||
emptyDir: {}
|
||||
|
||||
# Monitoring (since you have Prometheus)
|
||||
prometheus:
|
||||
enabled: false # Set to true if you want ArgoCD metrics in Prometheus
|
||||
@@ -0,0 +1,159 @@
|
||||
# Gitea + ArgoCD Setup Guide
|
||||
|
||||
## Gitea Access Information
|
||||
|
||||
**Web UI Access:**
|
||||
- **LoadBalancer URL**: http://192.168.222.27:3000
|
||||
- **Ingress URL**: http://gitea.turing.lan (add to your hosts file: `192.168.222.27 gitea.turing.lan`)
|
||||
- **SSH Clone URL**: `git@192.168.222.26:username/repo.git`
|
||||
|
||||
**Admin Credentials:**
|
||||
- **Username**: `admin`
|
||||
- **Password**: `gitea-admin-pass`
|
||||
- **Email**: `admin@turing.lan`
|
||||
|
||||
## Initial Gitea Setup
|
||||
|
||||
1. **Access Gitea**: Visit http://192.168.222.27:3000
|
||||
2. **Login**: Use admin credentials above
|
||||
3. **Create Organization**: Create an org for your homelab projects (e.g., "turingpi")
|
||||
4. **Create Repository**: Create your first repo for ArgoCD manifests
|
||||
|
||||
## Setting Up Your First Repository
|
||||
|
||||
### Create a Repository for ArgoCD Applications
|
||||
|
||||
1. **Create new repo**: `turingpi-argocd-apps`
|
||||
2. **Clone locally**:
|
||||
```bash
|
||||
git clone http://192.168.222.27:3000/admin/turingpi-argocd-apps.git
|
||||
cd turingpi-argocd-apps
|
||||
```
|
||||
|
||||
3. **Copy your existing values files**:
|
||||
```bash
|
||||
# Copy your existing values files to the repo
|
||||
cp /home/gilgamezh/code/turingpi/*_values.yaml ./helm-values/
|
||||
mkdir -p apps/
|
||||
```
|
||||
|
||||
4. **Create directory structure**:
|
||||
```
|
||||
turingpi-argocd-apps/
|
||||
├── apps/ # ArgoCD Application manifests
|
||||
├── helm-values/ # Your existing *_values.yaml files
|
||||
├── manifests/ # Raw Kubernetes manifests
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## Migrating Plex to GitOps
|
||||
|
||||
### Step 1: Create ArgoCD Application
|
||||
|
||||
Create `apps/plex.yaml`:
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: plex
|
||||
namespace: argocd
|
||||
annotations:
|
||||
# Enable automatic image updates
|
||||
argocd-image-updater.argoproj.io/image-list: plex=ghcr.io/k8s-at-home/plex:latest
|
||||
argocd-image-updater.argoproj.io/plex.update-strategy: newest-build
|
||||
argocd-image-updater.argoproj.io/write-back-method: git
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: http://gitea-http.gitea.svc.cluster.local:3000/admin/turingpi-argocd-apps.git
|
||||
path: helm-values
|
||||
targetRevision: HEAD
|
||||
helm:
|
||||
valueFiles:
|
||||
- plex_values.yml
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: plex
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
```
|
||||
|
||||
### Step 2: Configure ArgoCD to Access Gitea
|
||||
|
||||
Add Gitea as a repository in ArgoCD:
|
||||
|
||||
1. **Via ArgoCD UI**:
|
||||
- Go to Settings → Repositories → Connect Repo
|
||||
- URL: `http://gitea-http.gitea.svc.cluster.local:3000/admin/turingpi-argocd-apps.git`
|
||||
- Username: `admin`
|
||||
- Password: `gitea-admin-pass`
|
||||
|
||||
2. **Via CLI**:
|
||||
```bash
|
||||
argocd repo add http://gitea-http.gitea.svc.cluster.local:3000/admin/turingpi-argocd-apps.git \
|
||||
--username admin --password gitea-admin-pass
|
||||
```
|
||||
|
||||
## Benefits of This Setup
|
||||
|
||||
✅ **Version Control**: All your configurations are in Git
|
||||
✅ **Automatic Updates**: Images update when "latest" tags change
|
||||
✅ **Audit Trail**: See what changed and when
|
||||
✅ **Easy Rollbacks**: Git history = deployment history
|
||||
✅ **Local Control**: No external dependencies
|
||||
✅ **Team Collaboration**: Others can contribute via Git
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
1. **Start Small**: Migrate 1-2 applications first
|
||||
2. **Test Process**: Verify auto-updates work as expected
|
||||
3. **Bulk Migration**: Move remaining applications
|
||||
4. **Cleanup**: Remove manual Helm commands once confident
|
||||
|
||||
## Git Workflow Examples
|
||||
|
||||
### Adding a New Application
|
||||
```bash
|
||||
# Create new app manifest
|
||||
cat > apps/new-app.yaml << EOF
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: new-app
|
||||
namespace: argocd
|
||||
spec:
|
||||
# ... configuration
|
||||
EOF
|
||||
|
||||
# Commit and push
|
||||
git add apps/new-app.yaml
|
||||
git commit -m "Add new application: new-app"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### Updating Values
|
||||
```bash
|
||||
# Edit your values file
|
||||
vim helm-values/plex_values.yml
|
||||
|
||||
# Commit changes
|
||||
git add helm-values/plex_values.yml
|
||||
git commit -m "Update Plex CPU limits"
|
||||
git push origin main
|
||||
|
||||
# ArgoCD will auto-sync the changes
|
||||
```
|
||||
|
||||
Your homelab now has enterprise-grade GitOps capabilities while staying completely self-hosted! 🏠✨
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Access Gitea** and create your first repository
|
||||
2. **Copy your values files** to the new repo
|
||||
3. **Create your first ArgoCD application** pointing to Gitea
|
||||
4. **Test the workflow** with a simple change
|
||||
5. **Migrate more applications** gradually
|
||||
@@ -0,0 +1,117 @@
|
||||
# Gitea configuration for TuringPi K3s cluster
|
||||
# Self-hosted Git server for ArgoCD integration
|
||||
|
||||
# Single replica for homelab
|
||||
replicaCount: 1
|
||||
|
||||
# Service configuration - LoadBalancer for direct access
|
||||
service:
|
||||
http:
|
||||
type: LoadBalancer
|
||||
port: 3000
|
||||
# MetalLB will assign an IP
|
||||
ssh:
|
||||
type: LoadBalancer
|
||||
port: 22
|
||||
# For git SSH access
|
||||
|
||||
# Ingress for web access
|
||||
ingress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
pathType: Prefix
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
||||
# Restrict to LAN access (matching your existing pattern)
|
||||
nginx.ingress.kubernetes.io/whitelist-source-range: "192.168.0.0/16,10.0.0.0/8,172.16.0.0/12"
|
||||
hosts:
|
||||
- host: gitea.turing.lan
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
|
||||
# Storage using your NFS setup
|
||||
persistence:
|
||||
enabled: true
|
||||
create: true
|
||||
storageClass: "nfs-client" # Your existing NFS storage class
|
||||
size: 20Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
|
||||
# Database - use PostgreSQL for production-ready setup
|
||||
postgresql:
|
||||
enabled: true
|
||||
auth:
|
||||
username: gitea
|
||||
database: gitea
|
||||
# Password will be auto-generated
|
||||
primary:
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: "nfs-client"
|
||||
size: 10Gi
|
||||
|
||||
# Disable PostgreSQL HA (since we're enabling regular postgresql)
|
||||
postgresql-ha:
|
||||
enabled: false
|
||||
|
||||
# Disable Valkey cluster (Redis alternative) - not needed for homelab
|
||||
valkey-cluster:
|
||||
enabled: false
|
||||
|
||||
# Gitea configuration
|
||||
gitea:
|
||||
cache:
|
||||
enabled: false
|
||||
admin:
|
||||
username: admin
|
||||
password: "gitea-admin-pass" # Change this!
|
||||
email: "admin@turing.lan"
|
||||
|
||||
config:
|
||||
APP_NAME: "TuringPi Gitea"
|
||||
RUN_MODE: prod
|
||||
|
||||
server:
|
||||
DOMAIN: gitea.turing.lan
|
||||
SSH_DOMAIN: gitea.turing.lan
|
||||
ROOT_URL: http://gitea.turing.lan
|
||||
DISABLE_SSH: false
|
||||
SSH_PORT: 22
|
||||
LFS_START_SERVER: true
|
||||
|
||||
database:
|
||||
DB_TYPE: postgres
|
||||
|
||||
security:
|
||||
INSTALL_LOCK: true
|
||||
|
||||
service:
|
||||
DISABLE_REGISTRATION: false # Allow user registration
|
||||
REQUIRE_SIGNIN_VIEW: false # Allow anonymous viewing of public repos
|
||||
|
||||
ui:
|
||||
DEFAULT_THEME: auto
|
||||
|
||||
repository:
|
||||
DEFAULT_PRIVATE: false # Public repos by default for easier ArgoCD access
|
||||
|
||||
# Resource limits (adjust based on your node capacity)
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
|
||||
# Node affinity (prefer worker nodes, avoid control plane)
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
preference:
|
||||
matchExpressions:
|
||||
- key: node-role.kubernetes.io/control-plane
|
||||
operator: DoesNotExist
|
||||
@@ -0,0 +1,23 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
@@ -0,0 +1,24 @@
|
||||
apiVersion: v2
|
||||
name: home-assistant-voice-llms
|
||||
description: A Helm chart for Kubernetes
|
||||
|
||||
# A chart can be either an 'application' or a 'library' chart.
|
||||
#
|
||||
# Application charts are a collection of templates that can be packaged into versioned archives
|
||||
# to be deployed.
|
||||
#
|
||||
# Library charts provide useful utilities or functions for the chart developer. They're included as
|
||||
# a dependency of application charts to inject those utilities and functions into the rendering
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.1.0
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
# It is recommended to use it with quotes.
|
||||
appVersion: "1.16.0"
|
||||
@@ -0,0 +1,62 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "home-assistant-voice-llms.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "home-assistant-voice-llms.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "home-assistant-voice-llms.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "home-assistant-voice-llms.labels" -}}
|
||||
helm.sh/chart: {{ include "home-assistant-voice-llms.chart" . }}
|
||||
{{ include "home-assistant-voice-llms.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "home-assistant-voice-llms.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "home-assistant-voice-llms.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "home-assistant-voice-llms.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "home-assistant-voice-llms.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,97 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-faster-whisper
|
||||
spec:
|
||||
replicas: {{ .Values.defaults.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: faster-whisper
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: faster-whisper
|
||||
spec:
|
||||
containers:
|
||||
- name: faster-whisper
|
||||
image: {{ .Values.defaults.fasterWhisper.image.repository }}:{{ .Values.defaults.fasterWhisper.image.tag }}
|
||||
imagePullPolicy: {{ .Values.defaults.fasterWhisper.image.pullPolicy }}
|
||||
env:
|
||||
- name: PUID
|
||||
value: "{{ .Values.defaults.fasterWhisper.env.PUID }}"
|
||||
- name: PGID
|
||||
value: "{{ .Values.defaults.fasterWhisper.env.PGID }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.defaults.fasterWhisper.env.TZ }}"
|
||||
- name: WHISPER_MODEL
|
||||
value: "{{ .Values.defaults.fasterWhisper.env.WHISPER_MODEL }}"
|
||||
- name: WHISPER_BEAM
|
||||
value: "{{ .Values.defaults.fasterWhisper.env.WHISPER_BEAM }}"
|
||||
- name: WHISPER_LANG
|
||||
value: "{{ .Values.defaults.fasterWhisper.env.WHISPER_LANG }}"
|
||||
ports:
|
||||
- containerPort: 10300
|
||||
volumeMounts:
|
||||
- mountPath: {{ .Values.defaults.fasterWhisper.volume.mountPath }}
|
||||
name: config
|
||||
{{- if .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml .Values.nodeSelector | indent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: config
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Values.defaults.fasterWhisper.volume.claimName }}
|
||||
|
||||
---
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-piper
|
||||
spec:
|
||||
replicas: {{ .Values.defaults.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: piper
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: piper
|
||||
spec:
|
||||
containers:
|
||||
- name: piper
|
||||
image: {{ .Values.defaults.piper.image.repository }}:{{ .Values.defaults.piper.image.tag }}
|
||||
imagePullPolicy: {{ .Values.defaults.piper.image.pullPolicy }}
|
||||
env:
|
||||
- name: PUID
|
||||
value: "{{ .Values.defaults.piper.env.PUID }}"
|
||||
- name: PGID
|
||||
value: "{{ .Values.defaults.piper.env.PGID }}"
|
||||
- name: TZ
|
||||
value: "{{ .Values.defaults.piper.env.TZ }}"
|
||||
- name: PIPER_VOICE
|
||||
value: "{{ .Values.defaults.piper.env.PIPER_VOICE }}"
|
||||
- name: PIPER_LENGTH
|
||||
value: "{{ .Values.defaults.piper.env.PIPER_LENGTH }}"
|
||||
- name: PIPER_NOISE
|
||||
value: "{{ .Values.defaults.piper.env.PIPER_NOISE }}"
|
||||
- name: PIPER_NOISEW
|
||||
value: "{{ .Values.defaults.piper.env.PIPER_NOISEW }}"
|
||||
- name: PIPER_SPEAKER
|
||||
value: "{{ .Values.defaults.piper.env.PIPER_SPEAKER }}"
|
||||
- name: PIPER_PROCS
|
||||
value: "{{ .Values.defaults.piper.env.PIPER_PROCS }}"
|
||||
ports:
|
||||
- containerPort: 10200
|
||||
volumeMounts:
|
||||
- mountPath: {{ .Values.defaults.piper.volume.mountPath }}
|
||||
name: config
|
||||
volumes:
|
||||
- name: config
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Values.defaults.piper.volume.claimName }}
|
||||
{{- if .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml .Values.nodeSelector | indent 8 }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,25 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ .Values.defaults.fasterWhisper.volume.claimName }}
|
||||
spec:
|
||||
storageClassName: nfs-client
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.defaults.fasterWhisper.volume.storage }}
|
||||
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ .Values.defaults.piper.volume.claimName }}
|
||||
spec:
|
||||
storageClassName: nfs-client
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.defaults.piper.volume.storage }}
|
||||
@@ -0,0 +1,25 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-faster-whisper
|
||||
spec:
|
||||
type: {{ .Values.defaults.fasterWhisper.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.defaults.fasterWhisper.service.port }}
|
||||
targetPort: 10300
|
||||
selector:
|
||||
app: faster-whisper
|
||||
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-piper
|
||||
spec:
|
||||
type: {{ .Values.defaults.piper.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.defaults.piper.service.port }}
|
||||
targetPort: 10200
|
||||
selector:
|
||||
app: piper
|
||||
@@ -0,0 +1,57 @@
|
||||
defaults:
|
||||
replicaCount: 1
|
||||
fasterWhisper:
|
||||
image:
|
||||
repository: lscr.io/linuxserver/faster-whisper
|
||||
tag: "2.4.0"
|
||||
pullPolicy: IfNotPresent
|
||||
service:
|
||||
type: LoadBalancer
|
||||
port: 10300
|
||||
resources:
|
||||
limits:
|
||||
cpu: "3"
|
||||
memory: "5000Mi"
|
||||
requests:
|
||||
cpu: "3"
|
||||
memory: "2000Mi"
|
||||
env:
|
||||
PUID: 1000
|
||||
PGID: 1000
|
||||
TZ: Europe/Amsterdam
|
||||
WHISPER_MODEL: small-int8
|
||||
WHISPER_BEAM: 1
|
||||
WHISPER_LANG: en
|
||||
volume:
|
||||
mountPath: /config
|
||||
claimName: faster-whisper-pvc
|
||||
storage: 1Gi
|
||||
piper:
|
||||
image:
|
||||
repository: lscr.io/linuxserver/piper
|
||||
tag: "latest"
|
||||
pullPolicy: IfNotPresent
|
||||
service:
|
||||
type: LoadBalancer
|
||||
port: 10200
|
||||
resources:
|
||||
limits:
|
||||
cpu: "2"
|
||||
memory: "4000Mi"
|
||||
requests:
|
||||
cpu: "1"
|
||||
memory: "2000Mi"
|
||||
env:
|
||||
PUID: 1000
|
||||
PGID: 1000
|
||||
TZ: Europe/Amsterdam
|
||||
PIPER_VOICE: en_US-lessac-medium
|
||||
PIPER_LENGTH: 1.0
|
||||
PIPER_NOISE: 0.667
|
||||
PIPER_NOISEW: 0.333
|
||||
PIPER_SPEAKER: 0
|
||||
PIPER_PROCS: 2
|
||||
volume:
|
||||
mountPath: /config
|
||||
claimName: piper-pvc
|
||||
storage: 1Gi
|
||||
@@ -0,0 +1,61 @@
|
||||
defaults:
|
||||
replicaCount: 1
|
||||
fasterWhisper:
|
||||
image:
|
||||
repository: lscr.io/linuxserver/faster-whisper
|
||||
tag: "2.5.0"
|
||||
pullPolicy: Always
|
||||
service:
|
||||
type: LoadBalancer
|
||||
port: 10300
|
||||
resources:
|
||||
limits:
|
||||
cpu: "3"
|
||||
memory: "4Gi"
|
||||
requests:
|
||||
cpu: "3"
|
||||
memory: "2Gi"
|
||||
env:
|
||||
PUID: 1000
|
||||
PGID: 1000
|
||||
TZ: Europe/Amsterdam
|
||||
WHISPER_MODEL: Zoont/faster-whisper-large-v3-turbo-int8-ct2
|
||||
WHISPER_BEAM: 1
|
||||
WHISPER_LANG: en
|
||||
WHISPER_THREADS value: 4
|
||||
volume:
|
||||
mountPath: /config
|
||||
claimName: faster-whisper-pvc
|
||||
storage: 1Gi
|
||||
piper:
|
||||
image:
|
||||
repository: lscr.io/linuxserver/piper
|
||||
tag: "1.5.3"
|
||||
pullPolicy: Always
|
||||
service:
|
||||
type: LoadBalancer
|
||||
port: 10200
|
||||
resources:
|
||||
limits:
|
||||
cpu: "2"
|
||||
memory: "4000Mi"
|
||||
requests:
|
||||
cpu: "1"
|
||||
memory: "2000Mi"
|
||||
env:
|
||||
PUID: 1000
|
||||
PGID: 1000
|
||||
TZ: Europe/Amsterdam
|
||||
PIPER_VOICE: en_US-lessac-medium
|
||||
PIPER_LENGTH: 1.0
|
||||
PIPER_NOISE: 0.667
|
||||
PIPER_NOISEW: 0.333
|
||||
PIPER_SPEAKER: 0
|
||||
PIPER_PROCS: 2
|
||||
volume:
|
||||
mountPath: /config
|
||||
claimName: piper-pvc
|
||||
storage: 1Gi
|
||||
|
||||
nodeSelector:
|
||||
kubernetes.io/arch: amd64
|
||||
@@ -0,0 +1,3 @@
|
||||
master: curl -sfL https://get.k3s.io | INSTALL_K3S_SKIP_DOWNLOAD=false sh -s - --write-kubeconfig-mode 644 --disable servicelb --token torino --node-ip 192.168.222.237 --disable-cloud-controller --disable local-storage
|
||||
|
||||
nodes: curl -sfL https://get.k3s.io | INSTALL_K3S_SKIP_DOWNLOAD=false K3S_URL=https://192.168.222.237:6443 K3S_TOKEN=torino sh -
|
||||
@@ -79,30 +79,3 @@ spec:
|
||||
- hosts:
|
||||
- sonarr.gilgamezh.me
|
||||
secretName: sonarr-gilgamezh-me
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-production
|
||||
kubernetes.io/ingress.class: traefik
|
||||
labels:
|
||||
app: transmission-transmission-openvpn
|
||||
name: transmission-transmission-openvpn
|
||||
namespace: default
|
||||
spec:
|
||||
rules:
|
||||
- host: torrent.gilgamezh.me
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: transmission-transmission-openvpn
|
||||
port:
|
||||
number: 9091
|
||||
tls:
|
||||
- hosts:
|
||||
- torrent.gilgamezh.me
|
||||
secretName: torrent-gilgamezh-me
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
image:
|
||||
repository: docker.io/jellyfin/jellyfin
|
||||
tag: ""
|
||||
pullPolicy: Always
|
||||
|
||||
service:
|
||||
type: LoadBalancer
|
||||
port: 8096
|
||||
|
||||
persistence:
|
||||
config:
|
||||
existingClaim: "plex-config"
|
||||
media:
|
||||
existingClaim: "plex-data"
|
||||
|
||||
resources:
|
||||
requests:
|
||||
memory: "2Gi"
|
||||
cpu: "3"
|
||||
ephemeral-storage: "50Mi"
|
||||
limits:
|
||||
memory: "6Gi"
|
||||
cpu: "4"
|
||||
ephemeral-storage: "1Gi"
|
||||
@@ -0,0 +1,22 @@
|
||||
replicaCount: 1
|
||||
image:
|
||||
repository: ollama/ollama
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "latest"
|
||||
|
||||
|
||||
# Ollama parameters
|
||||
ollama:
|
||||
models:
|
||||
pull:
|
||||
- TinyLlama
|
||||
- llama3.1:8b
|
||||
# Configure Service
|
||||
service:
|
||||
# -- Service type
|
||||
type: LoadBalancer
|
||||
# -- Service port
|
||||
port: 11434
|
||||
|
||||
nodeSelector:
|
||||
kubernetes.io/arch: amd64
|
||||
+11
-6
@@ -2,7 +2,7 @@ claimToken: "claim-Ku2YYmJzDB1mpyG6YD7x"
|
||||
|
||||
image:
|
||||
repository: linuxserver/plex
|
||||
tag: 1.41.3
|
||||
tag: 1.41.8
|
||||
pullPolicy: Always
|
||||
|
||||
|
||||
@@ -19,8 +19,7 @@ rbac:
|
||||
create: true
|
||||
|
||||
nodeSelector:
|
||||
beta.kubernetes.io/arch: arm64
|
||||
|
||||
kubernetes.io/arch: amd64
|
||||
|
||||
persistence:
|
||||
transcode:
|
||||
@@ -30,14 +29,20 @@ persistence:
|
||||
config:
|
||||
claimName: "plex-config"
|
||||
|
||||
# GPU support for hardware-accelerated transcoding
|
||||
gpu:
|
||||
enabled: true
|
||||
hostPath: "/dev/dri"
|
||||
mountPath: "/dev/dri"
|
||||
|
||||
resources:
|
||||
requests:
|
||||
memory: "2Gi"
|
||||
cpu: "3"
|
||||
cpu: "1"
|
||||
ephemeral-storage: "50Mi"
|
||||
limits:
|
||||
memory: "6Gi"
|
||||
cpu: "4"
|
||||
memory: "10Gi"
|
||||
cpu: "3"
|
||||
ephemeral-storage: "1Gi"
|
||||
podAnnotations: {}
|
||||
proxy:
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
image:
|
||||
repository: lscr.io/linuxserver/prowlarr
|
||||
tag: 1.23.1
|
||||
tag: 1.37.0.5076-ls121
|
||||
pullPolicy: Always
|
||||
|
||||
env:
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: ghcr.io/linuxserver/radarr
|
||||
tag: 5.10.4
|
||||
tag: 5.26.2
|
||||
pullPolicy: Always
|
||||
|
||||
env:
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: ghcr.io/linuxserver/sonarr
|
||||
tag: 4.0.9
|
||||
tag: 4.0.15
|
||||
pullPolicy: Always
|
||||
|
||||
env:
|
||||
|
||||
@@ -51,9 +51,10 @@ volumeMounts:
|
||||
mountPath: "/dev/net/tun" # Needed for VPN
|
||||
- name: "plex-data"
|
||||
mountPath: "/etc/openvpn/custom/"
|
||||
subPath: "airvpn" # Path /mnt/ssd/media/downloads/transmission where transmission downloads Torrents
|
||||
subPath: "airvpn"
|
||||
|
||||
securityContext:
|
||||
capabilities: # Needed for VPN
|
||||
add:
|
||||
- NET_ADMIN
|
||||
privileged: true
|
||||
|
||||
nodeSelector:
|
||||
kubernetes.io/arch: arm64
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
MASTER_NODE="turing1"
|
||||
WORKER_NODES=("turing2" "turing3" "turing4")
|
||||
BEELINK_NODE="beelink.lan"
|
||||
MASTER_IP="192.168.222.237"
|
||||
TOKEN="torino"
|
||||
SSH_PASSWORD="turing"
|
||||
|
||||
# Function to print colored output
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Function to check if sshpass is available
|
||||
check_dependencies() {
|
||||
if ! command -v sshpass &> /dev/null; then
|
||||
print_warning "sshpass not found, installing..."
|
||||
if command -v pacman &> /dev/null; then
|
||||
sudo pacman -S sshpass --noconfirm
|
||||
elif command -v apt-get &> /dev/null; then
|
||||
sudo apt-get update && sudo apt-get install -y sshpass
|
||||
else
|
||||
print_error "Cannot install sshpass automatically. Please install it manually."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to upgrade master node
|
||||
upgrade_master() {
|
||||
print_status "Upgrading master node: $MASTER_NODE"
|
||||
|
||||
sshpass -p "$SSH_PASSWORD" ssh -o StrictHostKeyChecking=no root@$MASTER_NODE '
|
||||
curl -sfL https://get.k3s.io | INSTALL_K3S_SKIP_DOWNLOAD=false sh -s - \
|
||||
--write-kubeconfig-mode 644 \
|
||||
--disable servicelb \
|
||||
--token torino \
|
||||
--node-ip 192.168.222.237 \
|
||||
--disable-cloud-controller \
|
||||
--disable local-storage
|
||||
'
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
print_status "Master node $MASTER_NODE upgraded successfully"
|
||||
else
|
||||
print_error "Failed to upgrade master node $MASTER_NODE"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to upgrade worker nodes
|
||||
upgrade_worker() {
|
||||
local node=$1
|
||||
print_status "Upgrading worker node: $node"
|
||||
|
||||
sshpass -p "$SSH_PASSWORD" ssh -o StrictHostKeyChecking=no root@$node "
|
||||
curl -sfL https://get.k3s.io | INSTALL_K3S_SKIP_DOWNLOAD=false \
|
||||
K3S_URL=https://$MASTER_IP:6443 \
|
||||
K3S_TOKEN=$TOKEN sh -
|
||||
"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
print_status "Worker node $node upgraded successfully"
|
||||
else
|
||||
print_error "Failed to upgrade worker node $node"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to upgrade beelink node
|
||||
upgrade_beelink() {
|
||||
print_status "Upgrading beelink node: $BEELINK_NODE"
|
||||
|
||||
ssh -o PasswordAuthentication=no -o StrictHostKeyChecking=no gilgamezh@$BEELINK_NODE "
|
||||
sudo curl -sfL https://get.k3s.io | INSTALL_K3S_SKIP_DOWNLOAD=false \
|
||||
K3S_URL=https://$MASTER_IP:6443 \
|
||||
K3S_TOKEN=$TOKEN sh -
|
||||
"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
print_status "Beelink node $BEELINK_NODE upgraded successfully"
|
||||
else
|
||||
print_error "Failed to upgrade beelink node $BEELINK_NODE"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to verify cluster health
|
||||
verify_cluster() {
|
||||
print_status "Verifying cluster health..."
|
||||
|
||||
# Wait a moment for nodes to register
|
||||
sleep 10
|
||||
|
||||
print_status "Cluster nodes:"
|
||||
kubectl get nodes
|
||||
|
||||
print_status "Checking for unhealthy pods..."
|
||||
unhealthy_pods=$(kubectl get pods --all-namespaces | grep -v Running | grep -v Completed | wc -l)
|
||||
|
||||
if [ "$unhealthy_pods" -gt 1 ]; then # Greater than 1 because header line counts
|
||||
print_warning "Found unhealthy pods:"
|
||||
kubectl get pods --all-namespaces | grep -v Running | grep -v Completed
|
||||
else
|
||||
print_status "All pods are healthy"
|
||||
fi
|
||||
|
||||
print_status "Cluster upgrade completed successfully!"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
print_status "Starting K3s cluster upgrade..."
|
||||
print_status "This will upgrade all nodes in the TuringPi cluster"
|
||||
|
||||
# Check dependencies
|
||||
check_dependencies
|
||||
|
||||
# Show current cluster state
|
||||
print_status "Current cluster state:"
|
||||
kubectl get nodes
|
||||
|
||||
read -p "Do you want to continue with the upgrade? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
print_status "Upgrade cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Upgrade master node first
|
||||
upgrade_master
|
||||
|
||||
# Wait a bit for master to stabilize
|
||||
sleep 15
|
||||
|
||||
# Upgrade worker nodes
|
||||
failed_workers=0
|
||||
for worker in "${WORKER_NODES[@]}"; do
|
||||
if ! upgrade_worker "$worker"; then
|
||||
((failed_workers++))
|
||||
fi
|
||||
sleep 5 # Brief pause between worker upgrades
|
||||
done
|
||||
|
||||
# Upgrade beelink node
|
||||
if ! upgrade_beelink; then
|
||||
print_warning "Beelink node upgrade failed, but continuing..."
|
||||
fi
|
||||
|
||||
# Verify cluster health
|
||||
verify_cluster
|
||||
|
||||
if [ $failed_workers -gt 0 ]; then
|
||||
print_warning "Upgrade completed with $failed_workers failed worker node(s)"
|
||||
exit 1
|
||||
else
|
||||
print_status "All nodes upgraded successfully!"
|
||||
fi
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user