From eb46d77fe701fd0a45699fe2b9e5056072587eaf Mon Sep 17 00:00:00 2001 From: Khang Duy LAI Date: Wed, 11 Mar 2026 12:16:18 +0100 Subject: [PATCH] first commit --- .gitignore | 21 ++++++ README.md | 58 +++++++++++++++ apps/gitea/ingress.yaml | 24 ++++++ apps/gitea/kustomization.yaml | 12 +++ apps/gitea/namespace.yaml | 6 ++ apps/gitea/values.yaml | 83 +++++++++++++++++++++ apps/headlamp/ingress.yaml | 26 +++++++ apps/headlamp/kustomization.yaml | 11 +++ apps/headlamp/namespace.yaml | 6 ++ apps/headlamp/values.yaml | 43 +++++++++++ scripts/deploy.sh | 122 +++++++++++++++++++++++++++++++ 11 files changed, 412 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 apps/gitea/ingress.yaml create mode 100644 apps/gitea/kustomization.yaml create mode 100644 apps/gitea/namespace.yaml create mode 100644 apps/gitea/values.yaml create mode 100644 apps/headlamp/ingress.yaml create mode 100644 apps/headlamp/kustomization.yaml create mode 100644 apps/headlamp/namespace.yaml create mode 100644 apps/headlamp/values.yaml create mode 100755 scripts/deploy.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7494d7b --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Secrets - never commit these +*.secret.yaml +*.secret.yml +secrets/ +*.pem +*.key + +# Local overrides +values.local.yaml +*.local.yaml + +# Editor files +*.swp +*.swo +*~ +.idea/ +.vscode/ + +# OS files +.DS_Store +Thumbs.db diff --git a/README.md b/README.md new file mode 100644 index 0000000..c8b68a9 --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# Kubernetes Configuration + +Cluster configuration for the roamflow k3s cluster. + +## Structure + +``` +kube-config/ +├── apps/ # Application deployments +│ ├── headlamp/ # Kubernetes dashboard +│ └── ... +├── infrastructure/ # Cluster infrastructure +│ └── ... +└── scripts/ # Deployment scripts + └── deploy.sh +``` + +## Usage + +### Deploy a specific app +```bash +./scripts/deploy.sh headlamp +``` + +### Deploy all apps +```bash +./scripts/deploy.sh --all +``` + +## Cluster Access + +```bash +# Start SSH tunnel +ssh -f -N -L 6443:127.0.0.1:6443 roamflow-1 + +# Use kubectl +KUBECONFIG=~/.kube/config-roamflow kubectl get pods -A +``` + +## Apps + +| App | Namespace | Description | URL | +|-----|-----------|-------------|-----| +| headlamp | headlamp | Kubernetes dashboard | headlamp.duylai.duckdns.org | +| gitea | gitea | Git hosting | gitea.duylai.duckdns.org | +| vikunja | vikunja | Task management | tasks.duylai.duckdns.org | + +## Memory Configuration + +The following memory limits have been adjusted to prevent OOM kills: + +| Service | Limit | Request | +|---------|-------|---------| +| PostgreSQL (per pod) | 768Mi | 512Mi | +| Pgpool | 512Mi | 384Mi | +| Valkey | 192Mi | 128Mi | + +These are saved in `apps/gitea/values.yaml` for future upgrades. diff --git a/apps/gitea/ingress.yaml b/apps/gitea/ingress.yaml new file mode 100644 index 0000000..bf57bb5 --- /dev/null +++ b/apps/gitea/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: gitea-ingress + namespace: gitea + annotations: + kubernetes.io/ingress.class: traefik + cert-manager.io/cluster-issuer: letsencrypt-prod +spec: + rules: + - host: gitea.duylai.duckdns.org + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: gitea-http + port: + number: 3000 + tls: + - hosts: + - gitea.duylai.duckdns.org + secretName: gitea-tls-secret diff --git a/apps/gitea/kustomization.yaml b/apps/gitea/kustomization.yaml new file mode 100644 index 0000000..01ea386 --- /dev/null +++ b/apps/gitea/kustomization.yaml @@ -0,0 +1,12 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: gitea + +resources: + - namespace.yaml + - ingress.yaml + +# Helm values are in values.yaml +# Deploy with: +# helm upgrade --install gitea gitea-charts/gitea -f values.yaml -n gitea --create-namespace diff --git a/apps/gitea/namespace.yaml b/apps/gitea/namespace.yaml new file mode 100644 index 0000000..deb14ec --- /dev/null +++ b/apps/gitea/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: gitea + labels: + name: gitea diff --git a/apps/gitea/values.yaml b/apps/gitea/values.yaml new file mode 100644 index 0000000..b62a921 --- /dev/null +++ b/apps/gitea/values.yaml @@ -0,0 +1,83 @@ +# Gitea Helm Values +# Reference: https://gitea.com/gitea/helm-chart/ + +# Gitea server configuration +gitea: + config: + server: + DOMAIN: gitea.duylai.duckdns.org + ROOT_URL: https://gitea.duylai.duckdns.org/ + SSH_DOMAIN: gitea.duylai.duckdns.org + SSH_LISTEN_PORT: 22 + SSH_PORT: 30222 + +# Service configuration +service: + http: + type: ClusterIP + clusterIP: "" + ssh: + type: NodePort + nodePort: 30222 + +# Persistence for Git data +persistence: + enabled: true + create: true + claimName: gitea-shared-storage + size: 10Gi + accessModes: + - ReadWriteOnce + annotations: + helm.sh/resource-policy: keep + +# PostgreSQL HA configuration +postgresql-ha: + enabled: true + + postgresql: + # Number of PostgreSQL replicas (minimum 3 for HA) + replicaCount: 3 + + # Resource limits (fixed for OOM issues) + resources: + limits: + cpu: 375m + memory: 768Mi + requests: + cpu: 250m + memory: 512Mi + + persistence: + size: 10Gi + + pgpool: + enabled: true + + # Resource limits (fixed for OOM issues) + resources: + limits: + cpu: 375m + memory: 512Mi + requests: + cpu: 250m + memory: 384Mi + +# Valkey (Redis) cluster configuration +valkey-cluster: + cluster: + # Number of nodes (minimum 3 for cluster) + nodes: 3 + + # Resource limits + resources: + limits: + cpu: 150m + memory: 192Mi + requests: + cpu: 100m + memory: 128Mi + +# Disable single PostgreSQL (using HA version) +postgresql: + enabled: false diff --git a/apps/headlamp/ingress.yaml b/apps/headlamp/ingress.yaml new file mode 100644 index 0000000..a3a5ba5 --- /dev/null +++ b/apps/headlamp/ingress.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: headlamp-ingress + namespace: headlamp + annotations: + kubernetes.io/ingress.class: traefik + cert-manager.io/cluster-issuer: letsencrypt-prod + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.tls: "true" +spec: + rules: + - host: headlamp.duylai.duckdns.org + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: headlamp + port: + number: 80 + tls: + - hosts: + - headlamp.duylai.duckdns.org + secretName: headlamp-tls diff --git a/apps/headlamp/kustomization.yaml b/apps/headlamp/kustomization.yaml new file mode 100644 index 0000000..7a9cf61 --- /dev/null +++ b/apps/headlamp/kustomization.yaml @@ -0,0 +1,11 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: headlamp + +resources: + - namespace.yaml + - ingress.yaml + +# Helm values are in values.yaml +# Use: helm upgrade --install headlamp headlamp/headlamp -f values.yaml -n headlamp diff --git a/apps/headlamp/namespace.yaml b/apps/headlamp/namespace.yaml new file mode 100644 index 0000000..d7dd983 --- /dev/null +++ b/apps/headlamp/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: headlamp + labels: + name: headlamp diff --git a/apps/headlamp/values.yaml b/apps/headlamp/values.yaml new file mode 100644 index 0000000..fe024a7 --- /dev/null +++ b/apps/headlamp/values.yaml @@ -0,0 +1,43 @@ +# Headlamp Helm Values +# Reference: https://artifacthub.io/packages/helm/headlamp/headlamp + +replicaCount: 1 + +image: + repository: ghcr.io/headlamp-k8s/headlamp + tag: "" + pullPolicy: IfNotPresent + +# Service configuration +service: + type: ClusterIP + port: 80 + +# Ingress managed via kustomize (see ingress.yaml) +ingress: + enabled: false + +# Resources +resources: + limits: + cpu: 200m + memory: 256Mi + requests: + cpu: 100m + memory: 128Mi + +# Persistent volume for plugins +persistentVolumeClaim: + enabled: false + +# Service account for cluster access +serviceAccount: + create: true + annotations: {} + +# RBAC - give Headlamp full cluster access +rbac: + create: true + clusterRole: + create: true + name: cluster-admin diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100755 index 0000000..cc2fb40 --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,122 @@ +#!/bin/bash +# Deploy applications to the Kubernetes cluster + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +KUBECONFIG="${KUBECONFIG:-$HOME/.kube/config-roamflow}" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Ensure SSH tunnel is running +ensure_tunnel() { + if ! pgrep -f "ssh.*6443.*roamflow-1" > /dev/null; then + log_info "Starting SSH tunnel..." + ssh -f -N -L 6443:127.0.0.1:6443 roamflow-1 + sleep 1 + fi +} + +# Helm chart mappings: app -> (repo_name, repo_url, chart_name) +declare -A HELM_CHARTS=( + ["headlamp"]="headlamp|https://headlamp-k8s.github.io/headlamp/|headlamp" + ["gitea"]="gitea-charts|https://dl.gitea.com/charts/|gitea" +) + +# Add Helm repositories +add_repos() { + log_info "Adding Helm repositories..." + for app in "${!HELM_CHARTS[@]}"; do + IFS='|' read -r repo_name repo_url chart_name <<< "${HELM_CHARTS[$app]}" + helm repo add "$repo_name" "$repo_url" 2>/dev/null || true + done + helm repo update +} + +# Deploy a specific app +deploy_app() { + local app=$1 + local app_dir="$PROJECT_ROOT/apps/$app" + + if [[ ! -d "$app_dir" ]]; then + log_error "App '$app' not found in $PROJECT_ROOT/apps/" + exit 1 + fi + + log_info "Deploying $app..." + + # Apply namespace and other kustomize resources first + if [[ -f "$app_dir/kustomization.yaml" ]]; then + kubectl apply -k "$app_dir" --kubeconfig "$KUBECONFIG" + fi + + # Deploy with Helm if values.yaml exists + if [[ -f "$app_dir/values.yaml" ]]; then + if [[ -n "${HELM_CHARTS[$app]}" ]]; then + IFS='|' read -r repo_name repo_url chart_name <<< "${HELM_CHARTS[$app]}" + helm upgrade --install "$app" "$repo_name/$chart_name" \ + -f "$app_dir/values.yaml" \ + -n "$app" \ + --kubeconfig "$KUBECONFIG" \ + --create-namespace + else + log_warn "No Helm chart configured for $app, skipping Helm deployment" + fi + fi + + log_info "$app deployed successfully!" +} + +# List available apps +list_apps() { + echo "Available apps:" + for app_dir in "$PROJECT_ROOT/apps"/*/; do + if [[ -d "$app_dir" ]]; then + app_name=$(basename "$app_dir") + echo " - $app_name" + fi + done +} + +# Main +main() { + ensure_tunnel + add_repos + + if [[ "$1" == "--all" ]]; then + log_info "Deploying all apps..." + for app_dir in "$PROJECT_ROOT/apps"/*/; do + if [[ -d "$app_dir" ]]; then + app_name=$(basename "$app_dir") + deploy_app "$app_name" + fi + done + elif [[ "$1" == "--list" ]]; then + list_apps + elif [[ -n "$1" ]]; then + deploy_app "$1" + else + echo "Usage: $0 " + list_apps + exit 1 + fi +} + +main "$@"