Initial monorepo scaffold
Turborepo + pnpm monorepo for k3s homelab cluster on Intel NUCs. - Apps: Next.js web frontend, Express API (TypeScript, Dockerfiles, k8s manifests) - Packages: shared UI, ESLint config, TypeScript config, Drizzle DB schemas - Infra/Ansible: bare-metal provisioning with roles for common, k3s-server, k3s-agent, hardening - Infra/Kubernetes: ArgoCD GitOps (app-of-apps + ApplicationSets), platform components (cert-manager, Traefik, CloudNativePG, Valkey, Longhorn, Sealed Secrets), namespaces - Observability: kube-prometheus-stack, Loki, Promtail as ArgoCD Applications - CI/CD: GitHub Actions for PR builds, preview deploys, production deploys - DX: Taskfile, utility scripts, copier templates, Ubiquiti network docs
This commit is contained in:
23
scripts/kubeconfig-fetch.sh
Executable file
23
scripts/kubeconfig-fetch.sh
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
SERVER_HOST="${K3S_SERVER_HOST:-10.0.10.11}"
|
||||
SSH_USER="${SSH_USER:-julia}"
|
||||
KUBECONFIG_PATH="${KUBECONFIG_PATH:-$HOME/.kube/homelab}"
|
||||
|
||||
echo "Fetching kubeconfig from ${SERVER_HOST}..."
|
||||
|
||||
ssh "${SSH_USER}@${SERVER_HOST}" "sudo cat /etc/rancher/k3s/k3s.yaml" \
|
||||
| sed "s/127.0.0.1/${SERVER_HOST}/g" \
|
||||
> "$KUBECONFIG_PATH"
|
||||
|
||||
chmod 600 "$KUBECONFIG_PATH"
|
||||
|
||||
echo "Kubeconfig written to ${KUBECONFIG_PATH}"
|
||||
echo ""
|
||||
echo "To use:"
|
||||
echo " export KUBECONFIG=${KUBECONFIG_PATH}"
|
||||
echo " kubectl get nodes"
|
||||
49
scripts/new-app.sh
Executable file
49
scripts/new-app.sh
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
echo "Create a new app from template"
|
||||
echo ""
|
||||
echo "Available templates:"
|
||||
echo " 1) node-api - Express API service"
|
||||
echo " 2) nextjs-app - Next.js application"
|
||||
echo ""
|
||||
read -rp "Select template (1-2): " choice
|
||||
|
||||
case $choice in
|
||||
1) template="node-api" ;;
|
||||
2) template="nextjs-app" ;;
|
||||
*) echo "Invalid choice"; exit 1 ;;
|
||||
esac
|
||||
|
||||
read -rp "App name (kebab-case): " app_name
|
||||
|
||||
if [[ ! "$app_name" =~ ^[a-z][a-z0-9-]*$ ]]; then
|
||||
echo "Error: App name must be kebab-case (lowercase, hyphens only)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -d "$ROOT_DIR/apps/$app_name" ]]; then
|
||||
echo "Error: apps/$app_name already exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Creating $app_name from $template template..."
|
||||
|
||||
if command -v copier &>/dev/null; then
|
||||
copier copy "$ROOT_DIR/templates/$template" "$ROOT_DIR/apps/" --data "app_name=$app_name"
|
||||
else
|
||||
echo "Warning: copier not installed. Install with: pipx install copier"
|
||||
echo "Falling back to manual copy..."
|
||||
mkdir -p "$ROOT_DIR/apps/$app_name"
|
||||
echo "Created apps/$app_name/ — populate manually from templates/$template/"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Done! Next steps:"
|
||||
echo " cd apps/$app_name"
|
||||
echo " pnpm install"
|
||||
echo " pnpm dev"
|
||||
18
scripts/port-forward.sh
Executable file
18
scripts/port-forward.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "Available services to port-forward:"
|
||||
echo " 1) Grafana → localhost:3001"
|
||||
echo " 2) ArgoCD → localhost:8080"
|
||||
echo " 3) PostgreSQL → localhost:5432"
|
||||
echo " 4) Valkey → localhost:6379"
|
||||
echo ""
|
||||
read -rp "Select service (1-4): " choice
|
||||
|
||||
case $choice in
|
||||
1) kubectl port-forward -n observability svc/kube-prometheus-stack-grafana 3001:80 ;;
|
||||
2) kubectl port-forward -n argocd svc/argocd-server 8080:443 ;;
|
||||
3) kubectl port-forward -n platform svc/homelab-pg-rw 5432:5432 ;;
|
||||
4) kubectl port-forward -n platform svc/valkey 6379:6379 ;;
|
||||
*) echo "Invalid choice"; exit 1 ;;
|
||||
esac
|
||||
41
scripts/seal-secret.sh
Executable file
41
scripts/seal-secret.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if ! command -v kubeseal &>/dev/null; then
|
||||
echo "Error: kubeseal is not installed"
|
||||
echo "Install: brew install kubeseal"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $# -lt 3 ]]; then
|
||||
echo "Usage: $0 <secret-name> <namespace> <key=value> [key=value...]"
|
||||
echo ""
|
||||
echo "Example:"
|
||||
echo " $0 api-secrets apps database-url=postgres://... valkey-url=redis://..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SECRET_NAME="$1"
|
||||
NAMESPACE="$2"
|
||||
shift 2
|
||||
|
||||
LITERAL_ARGS=()
|
||||
for pair in "$@"; do
|
||||
LITERAL_ARGS+=("--from-literal=$pair")
|
||||
done
|
||||
|
||||
echo "Sealing secret '$SECRET_NAME' in namespace '$NAMESPACE'..."
|
||||
|
||||
kubectl create secret generic "$SECRET_NAME" \
|
||||
--namespace "$NAMESPACE" \
|
||||
--dry-run=client \
|
||||
-o yaml \
|
||||
"${LITERAL_ARGS[@]}" \
|
||||
| kubeseal \
|
||||
--format yaml \
|
||||
--controller-namespace kube-system \
|
||||
--controller-name sealed-secrets \
|
||||
> "${SECRET_NAME}-sealed.yaml"
|
||||
|
||||
echo "Sealed secret written to ${SECRET_NAME}-sealed.yaml"
|
||||
echo "Move this file to the appropriate k8s directory and commit it."
|
||||
Reference in New Issue
Block a user