Moving to github

This commit is contained in:
2026-03-28 19:24:29 -04:00
commit 036fa7ab33
302 changed files with 17838 additions and 0 deletions

306
k8s/README.md Normal file
View File

@@ -0,0 +1,306 @@
# TurboVault Kubernetes Deployment
This directory contains Kubernetes manifests for deploying TurboVault to your k3s cluster.
## Prerequisites
- Kubernetes cluster (k3s, k8s, or any other)
- `kubectl` configured to access your cluster
- Docker registry (Docker Hub, GitHub Container Registry, or private registry)
- PostgreSQL database (external or in-cluster)
## Quick Start
### 1. Build and Push Docker Image
**Option A: Use GitHub Actions (Recommended)**
Push a tag and GitHub Actions will build and push automatically:
```bash
git tag v1.0.0
git push origin v1.0.0
```
Image will be at: `ghcr.io/your-username/turbovault:v1.0.0`
**Option B: Build Locally**
```bash
# Build the image
docker build -t ghcr.io/your-username/turbovault:latest .
# Login to GitHub Container Registry
echo $GITHUB_TOKEN | docker login ghcr.io -u your-username --password-stdin
# Push to registry
docker push ghcr.io/your-username/turbovault:latest
```
### 1.5. Create Registry Secret (if using private registry)
**For Public GitHub Container Registry:** No secret needed!
**For Private Registry:**
```bash
kubectl create secret docker-registry registry-secret \
--docker-server=your-registry.com \
--docker-username=your-username \
--docker-password=your-token \
--docker-email=your-email@example.com \
--namespace=turbovault
```
Then uncomment `imagePullSecrets` in `deployment.yaml` and `migrate-job.yaml`.
### 2. Configure Secrets
```bash
# Copy the example secrets file
cp k8s/secrets.yaml.example k8s/secrets.yaml
# Edit with your actual values
nano k8s/secrets.yaml
# Generate a SECRET_KEY_BASE
rails secret
# Copy the output to secrets.yaml
```
### 3. Update Configuration
Edit `k8s/deployment.yaml` and update:
- `image: your-registry/turbovault:latest` (line 28)
- Database configuration in `k8s/configmap.yaml`
- Domain in `k8s/ingress.yaml`
### 4. Deploy to Kubernetes
```bash
# Create namespace
kubectl apply -f k8s/namespace.yaml
# Create ConfigMap
kubectl apply -f k8s/configmap.yaml
# Create Secrets
kubectl apply -f k8s/secrets.yaml
# Run database migrations
kubectl apply -f k8s/migrate-job.yaml
# Wait for migration to complete
kubectl wait --for=condition=complete --timeout=300s job/turbovault-migrate -n turbovault
# Deploy application
kubectl apply -f k8s/deployment.yaml
# Create service
kubectl apply -f k8s/service.yaml
# Create ingress (for external access)
kubectl apply -f k8s/ingress.yaml
```
### 5. Verify Deployment
```bash
# Check pods
kubectl get pods -n turbovault
# Check logs
kubectl logs -f deployment/turbovault -n turbovault
# Check service
kubectl get svc -n turbovault
# Check ingress
kubectl get ingress -n turbovault
```
## Database Setup
### Option 1: External PostgreSQL
Update `k8s/configmap.yaml` with your external PostgreSQL details:
```yaml
DATABASE_HOST: "your-postgres-host"
DATABASE_PORT: "5432"
DATABASE_NAME: "turbovault_production"
DATABASE_USERNAME: "turbovault"
```
And add the password to `k8s/secrets.yaml`:
```yaml
DATABASE_PASSWORD: "your-secure-password"
```
### Option 2: In-Cluster PostgreSQL
Deploy PostgreSQL in your cluster:
```bash
# Using Helm
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install postgres bitnami/postgresql \
--namespace turbovault \
--set auth.database=turbovault_production \
--set auth.username=turbovault \
--set auth.password=changeme
```
## Environment Variables
### Required
- `DATABASE_HOST` - PostgreSQL host
- `DATABASE_PASSWORD` - PostgreSQL password
- `SECRET_KEY_BASE` - Rails secret key (generate with `rails secret`)
### Optional
- `IGDB_CLIENT_ID` - IGDB API client ID (for game metadata)
- `IGDB_CLIENT_SECRET` - IGDB API client secret
- `SMTP_ADDRESS` - SMTP server for emails
- `SMTP_PORT` - SMTP port
- `SMTP_USERNAME` - SMTP username
- `SMTP_PASSWORD` - SMTP password
## Scaling
Scale the deployment:
```bash
kubectl scale deployment turbovault --replicas=3 -n turbovault
```
## Updating
### Deploy New Version
```bash
# Option 1: Use GitHub Actions (Recommended)
git tag v2.0.0
git push origin v2.0.0
# Wait for build to complete in Actions tab
# Option 2: Build locally
docker build -t ghcr.io/username/turbovault:v2.0.0 .
docker push ghcr.io/username/turbovault:v2.0.0
# Update deployment image
kubectl set image deployment/turbovault turbovault=ghcr.io/username/turbovault:v2.0.0 -n turbovault
# Run migrations if needed
kubectl delete job turbovault-migrate -n turbovault
kubectl apply -f k8s/migrate-job.yaml
kubectl wait --for=condition=complete --timeout=300s job/turbovault-migrate -n turbovault
```
## Troubleshooting
### Pods Not Starting
```bash
# Check pod status
kubectl describe pod -l app=turbovault -n turbovault
# Check logs
kubectl logs -l app=turbovault -n turbovault
```
### Database Connection Issues
```bash
# Test database connection
kubectl run -it --rm debug --image=postgres:15 --restart=Never -n turbovault -- \
psql -h postgres-service -U turbovault -d turbovault_production
```
### Migration Failures
```bash
# Check migration job logs
kubectl logs job/turbovault-migrate -n turbovault
# Re-run migrations
kubectl delete job turbovault-migrate -n turbovault
kubectl apply -f k8s/migrate-job.yaml
```
## Monitoring
### Check Application Health
```bash
# Via kubectl
kubectl port-forward svc/turbovault-service 3000:80 -n turbovault
# Visit http://localhost:3000/up in your browser
```
### View Logs
```bash
# All pods
kubectl logs -f -l app=turbovault -n turbovault
# Specific pod
kubectl logs -f turbovault-xxxxx-xxxxx -n turbovault
# Previous logs (if pod crashed)
kubectl logs --previous turbovault-xxxxx-xxxxx -n turbovault
```
## Backup
### Database Backup
```bash
# Backup database
kubectl exec -it postgres-xxxxx -n turbovault -- \
pg_dump -U turbovault turbovault_production > backup.sql
# Restore database
kubectl exec -i postgres-xxxxx -n turbovault -- \
psql -U turbovault turbovault_production < backup.sql
```
## Security
### Best Practices
1. **Use secrets management** - Consider using Sealed Secrets or External Secrets Operator
2. **Enable TLS** - Uncomment TLS section in `ingress.yaml`
3. **Network policies** - Restrict pod-to-pod communication
4. **Resource limits** - Already configured in deployment.yaml
5. **Regular updates** - Keep dependencies and images up to date
### Sealed Secrets (Recommended)
```bash
# Install Sealed Secrets controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.18.0/controller.yaml
# Create sealed secret
kubeseal --format yaml < k8s/secrets.yaml > k8s/sealed-secrets.yaml
# Apply sealed secret (safe to commit)
kubectl apply -f k8s/sealed-secrets.yaml
```
## Clean Up
Remove TurboVault from cluster:
```bash
kubectl delete namespace turbovault
```
## Support
For issues or questions:
- GitHub Issues: https://github.com/yourusername/turbovault/issues
- Documentation: https://github.com/yourusername/turbovault

15
k8s/configmap.yaml Normal file
View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: turbovault-config
namespace: turbovault
data:
RAILS_ENV: "production"
RAILS_LOG_TO_STDOUT: "true"
RAILS_SERVE_STATIC_FILES: "true"
RAILS_MAX_THREADS: "5"
# Update these values for your environment
DATABASE_HOST: "postgres-service" # Your PostgreSQL service name or external host
DATABASE_PORT: "5432"
DATABASE_NAME: "turbovault_production"
DATABASE_USERNAME: "turbovault"

133
k8s/deployment.yaml Normal file
View File

@@ -0,0 +1,133 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: turbovault
namespace: turbovault
labels:
app: turbovault
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: turbovault
template:
metadata:
labels:
app: turbovault
spec:
# Pull images from container registry
# For private registries, uncomment and create secret:
# imagePullSecrets:
# - name: registry-secret
containers:
- name: turbovault
# UPDATE THIS: Replace with your registry path
# Examples:
# - GitHub Container Registry: ghcr.io/username/turbovault:latest
# - Docker Hub: docker.io/username/turbovault:latest
# - Private registry: registry.example.com/turbovault:latest
image: ghcr.io/username/turbovault:latest
imagePullPolicy: Always
ports:
- containerPort: 3000
name: http
protocol: TCP
env:
# Load from ConfigMap
- name: RAILS_ENV
valueFrom:
configMapKeyRef:
name: turbovault-config
key: RAILS_ENV
- name: RAILS_LOG_TO_STDOUT
valueFrom:
configMapKeyRef:
name: turbovault-config
key: RAILS_LOG_TO_STDOUT
- name: RAILS_SERVE_STATIC_FILES
valueFrom:
configMapKeyRef:
name: turbovault-config
key: RAILS_SERVE_STATIC_FILES
- name: RAILS_MAX_THREADS
valueFrom:
configMapKeyRef:
name: turbovault-config
key: RAILS_MAX_THREADS
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: turbovault-config
key: DATABASE_HOST
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: turbovault-config
key: DATABASE_PORT
- name: DATABASE_NAME
valueFrom:
configMapKeyRef:
name: turbovault-config
key: DATABASE_NAME
- name: DATABASE_USERNAME
valueFrom:
configMapKeyRef:
name: turbovault-config
key: DATABASE_USERNAME
# Load from Secrets
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: turbovault-secrets
key: DATABASE_PASSWORD
- name: SECRET_KEY_BASE
valueFrom:
secretKeyRef:
name: turbovault-secrets
key: SECRET_KEY_BASE
- name: IGDB_CLIENT_ID
valueFrom:
secretKeyRef:
name: turbovault-secrets
key: IGDB_CLIENT_ID
optional: true
- name: IGDB_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: turbovault-secrets
key: IGDB_CLIENT_SECRET
optional: true
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /up
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /up
port: 3000
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
volumeMounts:
- name: storage
mountPath: /app/storage
volumes:
- name: storage
emptyDir: {} # Replace with PersistentVolumeClaim for production

27
k8s/ingress.yaml Normal file
View File

@@ -0,0 +1,27 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: turbovault-ingress
namespace: turbovault
annotations:
# Update these based on your ingress controller
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
# cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx # Or traefik, depending on your setup
rules:
- host: turbovault.example.com # Update with your domain
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: turbovault-service
port:
number: 80
# Uncomment for TLS/HTTPS
# tls:
# - hosts:
# - turbovault.example.com
# secretName: turbovault-tls

63
k8s/migrate-job.yaml Normal file
View File

@@ -0,0 +1,63 @@
apiVersion: batch/v1
kind: Job
metadata:
name: turbovault-migrate
namespace: turbovault
labels:
app: turbovault
job: migrate
spec:
template:
metadata:
labels:
app: turbovault
job: migrate
spec:
restartPolicy: OnFailure
# For private registries, uncomment and create secret:
# imagePullSecrets:
# - name: registry-secret
containers:
- name: migrate
# UPDATE THIS: Replace with your registry path (same as deployment.yaml)
image: ghcr.io/username/turbovault:latest
command: ["bundle", "exec", "rails", "db:migrate"]
env:
# Load from ConfigMap
- name: RAILS_ENV
valueFrom:
configMapKeyRef:
name: turbovault-config
key: RAILS_ENV
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: turbovault-config
key: DATABASE_HOST
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: turbovault-config
key: DATABASE_PORT
- name: DATABASE_NAME
valueFrom:
configMapKeyRef:
name: turbovault-config
key: DATABASE_NAME
- name: DATABASE_USERNAME
valueFrom:
configMapKeyRef:
name: turbovault-config
key: DATABASE_USERNAME
# Load from Secrets
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: turbovault-secrets
key: DATABASE_PASSWORD
- name: SECRET_KEY_BASE
valueFrom:
secretKeyRef:
name: turbovault-secrets
key: SECRET_KEY_BASE
backoffLimit: 3

7
k8s/namespace.yaml Normal file
View File

@@ -0,0 +1,7 @@
apiVersion: v1
kind: Namespace
metadata:
name: turbovault
labels:
name: turbovault
app: turbovault

26
k8s/secrets.yaml.example Normal file
View File

@@ -0,0 +1,26 @@
# TurboVault Secrets Template
# Copy this file to secrets.yaml and update with your actual values
# DO NOT commit secrets.yaml to version control!
apiVersion: v1
kind: Secret
metadata:
name: turbovault-secrets
namespace: turbovault
type: Opaque
stringData:
# Database password
DATABASE_PASSWORD: "changeme"
# Rails master key (generate with: rails secret)
SECRET_KEY_BASE: "changeme-use-rails-secret-to-generate"
# IGDB API credentials (optional, for game metadata)
IGDB_CLIENT_ID: "your_igdb_client_id"
IGDB_CLIENT_SECRET: "your_igdb_client_secret"
# Email configuration (optional, for password resets)
SMTP_ADDRESS: "smtp.example.com"
SMTP_PORT: "587"
SMTP_USERNAME: "your_smtp_username"
SMTP_PASSWORD: "your_smtp_password"

16
k8s/service.yaml Normal file
View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: turbovault-service
namespace: turbovault
labels:
app: turbovault
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 3000
protocol: TCP
name: http
selector:
app: turbovault