revised complete k8s deployment
This commit is contained in:
parent
0167ffdd18
commit
77f8e1554c
@ -56,7 +56,7 @@ jobs:
|
||||
|
||||
- name: Create secrets file
|
||||
run: |
|
||||
cat > ./chart/secrets.prod.yml << EOF
|
||||
cat > ./chart/secrets.prod.yaml << EOF
|
||||
backend:
|
||||
env:
|
||||
POSTGRES_PASSWORD: "${{ secrets.POSTGRES_PASSWORD }}"
|
||||
@ -72,8 +72,8 @@ jobs:
|
||||
helm upgrade --install fusero ./chart \
|
||||
--namespace fusero-prod \
|
||||
--create-namespace \
|
||||
--values ./chart/values.prod.yml \
|
||||
--values ./chart/secrets.prod.yml \
|
||||
--values ./chart/values.prod.yaml \
|
||||
--values ./chart/secrets.prod.yaml \
|
||||
--set backend.image.repository=registry.liquidrinu.com/fusero-backend \
|
||||
--set frontend.image.repository=registry.liquidrinu.com/fusero-frontend
|
||||
|
||||
|
16
.gitignore
vendored
16
.gitignore
vendored
@ -125,20 +125,20 @@ values.dev.*
|
||||
values.prod.*
|
||||
|
||||
# Secrets
|
||||
chart/secrets.prod.yml
|
||||
chart/secrets.*.yml
|
||||
chart/secrets.prod.yaml
|
||||
chart/secrets.*.yaml
|
||||
*.env
|
||||
.env.*
|
||||
|
||||
# Development values with secrets
|
||||
chart/values.dev.yml
|
||||
chart/values.dev.yaml
|
||||
|
||||
# Production secrets
|
||||
chart/secrets.prod.yml
|
||||
chart/secrets.*.yml
|
||||
chart/secrets.prod.yaml
|
||||
chart/secrets.*.yaml
|
||||
|
||||
# Keep templates and public configs
|
||||
!chart/secrets.prod.template.yml
|
||||
!chart/values.prod.template.yml
|
||||
!chart/values.prod.public.yml
|
||||
!chart/secrets.prod.template.yaml
|
||||
!chart/values.prod.template.yaml
|
||||
!chart/values.prod.public.yaml
|
||||
|
||||
|
106
README.md
106
README.md
@ -17,7 +17,7 @@ A full-stack application boilerplate with a React frontend and Node.js backend
|
||||
- [To seed the database:](#to-seed-the-database)
|
||||
- [Alternate: Running Services in Separate Terminals](#alternate-running-services-in-separate-terminals)
|
||||
- [🛠️ Environment Setup](#️-environment-setup)
|
||||
- [For Kubernetes, these are set in chart/values.yml:](#for-kubernetes-these-are-set-in-chartvaluesyml)
|
||||
- [For Kubernetes, these are set in chart/values.yaml:](#for-kubernetes-these-are-set-in-chartvaluesyaml)
|
||||
- [POSTGRES\_NAME=fusero-boilerplate-db](#postgres_namefusero-boilerplate-db)
|
||||
- [POSTGRES\_HOSTNAME=postgres-service](#postgres_hostnamepostgres-service)
|
||||
- [POSTGRES\_PORT=19095](#postgres_port19095)
|
||||
@ -53,6 +53,7 @@ A full-stack application boilerplate with a React frontend and Node.js backend
|
||||
- [Port-Forwarding for Local Access](#port-forwarding-for-local-access)
|
||||
- [Frontend (React app)](#frontend-react-app)
|
||||
- [Backend (API)](#backend-api)
|
||||
- [Database](#database)
|
||||
- [NGINX Backend Service Name: Docker Compose vs Kubernetes](#nginx-backend-service-name-docker-compose-vs-kubernetes)
|
||||
- [How to update the NGINX config for Kubernetes](#how-to-update-the-nginx-config-for-kubernetes)
|
||||
- [Cleaning Up Duplicate or Crashing Deployments and Pods in Kubernetes](#cleaning-up-duplicate-or-crashing-deployments-and-pods-in-kubernetes)
|
||||
@ -79,6 +80,7 @@ A full-stack application boilerplate with a React frontend and Node.js backend
|
||||
- [Database Backup](#database-backup)
|
||||
- [CI/CD \& Automated Testing](#cicd--automated-testing)
|
||||
- [Troubleshooting Production](#troubleshooting-production)
|
||||
- [🆕 Recent Improvements \& Troubleshooting](#-recent-improvements--troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
@ -88,7 +90,7 @@ fusero-app-boilerplate/
|
||||
├── chart/ # Helm chart for Kubernetes
|
||||
│ ├── Chart.yaml
|
||||
│ ├── values.dev.yaml
|
||||
│ ├── values.prod.yml
|
||||
│ ├── values.prod.yaml
|
||||
│ └── templates/
|
||||
├── config/
|
||||
├── coverage/
|
||||
@ -102,10 +104,10 @@ fusero-app-boilerplate/
|
||||
├── node_modules/
|
||||
├── package.json
|
||||
├── package-lock.json
|
||||
├── docker-compose.yml
|
||||
├── docker-compose.dev.yml
|
||||
├── docker-compose.yaml
|
||||
├── docker-compose.dev.yaml
|
||||
├── .gitignore
|
||||
├── .gitea-ci.yml
|
||||
├── .gitea-ci.yaml
|
||||
├── .prettierrc.json
|
||||
├── .eslintrc.json
|
||||
├── architecture.excalidraw
|
||||
@ -192,7 +194,7 @@ POSTGRES_USER=root
|
||||
POSTGRES_PASSWORD=root123
|
||||
JWT_SECRET=your_jwt_secret_key_here
|
||||
|
||||
# For Kubernetes, these are set in chart/values.yml:
|
||||
# For Kubernetes, these are set in chart/values.yaml:
|
||||
# POSTGRES_NAME=fusero-boilerplate-db
|
||||
# POSTGRES_HOSTNAME=postgres-service
|
||||
# POSTGRES_PORT=19095
|
||||
@ -248,7 +250,6 @@ docker exec -it fusero-app-backend npm run migrate
|
||||
docker exec -it fusero-app-backend npm run seed
|
||||
|
||||
3. Ensure all required environment variables are configured.
|
||||
Never commit `.env` files.
|
||||
|
||||
---
|
||||
|
||||
@ -275,7 +276,7 @@ Wrong: to="/dashboard/canvas/canvas-endpoints"
|
||||
Generate a self-signed cert:
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./nginx/ssl/nginx.key -out ./nginx/ssl/nginx.crt
|
||||
|
||||
Ensure `docker-compose.yml` mounts the certs:
|
||||
Ensure `docker-compose.yaml` mounts the certs:
|
||||
volumes:
|
||||
- ./nginx/ssl:/etc/nginx/ssl
|
||||
|
||||
@ -286,7 +287,7 @@ Configure NGINX to use the cert in production.
|
||||
## 🧠 Development Best Practices
|
||||
|
||||
- Always run the DB via Docker
|
||||
- Use `docker-compose.dev.yml` for development
|
||||
- Use `docker-compose.dev.yaml` for development
|
||||
- Never run PostgreSQL directly on host
|
||||
- Run frontend and backend separately for hot reload
|
||||
- Use `.env.example` as a template
|
||||
@ -341,8 +342,8 @@ lsof -i :14000
|
||||
Database Issues:
|
||||
Ensure DB is in Docker and configured correctly
|
||||
Try restarting:
|
||||
docker-compose -f docker-compose.dev.yml down
|
||||
docker-compose -f docker-compose.dev.yml up db
|
||||
docker-compose -f docker-compose.dev.yaml down
|
||||
docker-compose -f docker-compose.dev.yaml up db
|
||||
|
||||
CORS Issues:
|
||||
Check API base URL in frontend `.env`
|
||||
@ -384,7 +385,7 @@ docker push <your-registry>/fusero-backend-dev:local
|
||||
|
||||
### 3. Upgrade the Helm release with the latest values
|
||||
```bash
|
||||
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yml
|
||||
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yaml
|
||||
```
|
||||
|
||||
### 4. Restart the backend deployment to pick up new images and env vars
|
||||
@ -430,7 +431,7 @@ docker push <your-registry>/fusero-frontend-dev:local
|
||||
|
||||
### 3. Upgrade the Helm release
|
||||
```bash
|
||||
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yml
|
||||
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yaml
|
||||
```
|
||||
|
||||
### 4. Restart the frontend deployment
|
||||
@ -446,16 +447,22 @@ To access your services running in Kubernetes from your local machine, use these
|
||||
|
||||
### Frontend (React app)
|
||||
```bash
|
||||
kubectl port-forward -n fusero svc/fusero-frontend-service 3000:80
|
||||
kubectl port-forward -n fusero-dev svc/fusero-frontend-service 3000:80
|
||||
```
|
||||
- Access at: http://localhost:3000
|
||||
|
||||
### Backend (API)
|
||||
```bash
|
||||
kubectl port-forward -n fusero svc/fusero-backend-service 14000:14000
|
||||
kubectl port-forward -n fusero-dev svc/fusero-backend-service 14000:14000
|
||||
```
|
||||
- Access at: http://localhost:14000
|
||||
|
||||
### Database
|
||||
```bash
|
||||
kubectl port-forward -n fusero-dev svc/postgres-service 5432:5432
|
||||
```
|
||||
- Access at: localhost:5432
|
||||
|
||||
---
|
||||
|
||||
## NGINX Backend Service Name: Docker Compose vs Kubernetes
|
||||
@ -482,7 +489,7 @@ Then rebuild and redeploy the frontend:
|
||||
```bash
|
||||
docker build -t fusero-frontend-dev:local ./frontend
|
||||
# (push if needed)
|
||||
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yml
|
||||
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yaml
|
||||
kubectl rollout restart deployment/fusero-frontend -n fusero
|
||||
```
|
||||
|
||||
@ -546,7 +553,7 @@ This means NGINX is trying to load an SSL certificate that does not exist in the
|
||||
3. (If using a remote registry) Push the image.
|
||||
4. Redeploy with Helm:
|
||||
```bash
|
||||
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yml
|
||||
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yaml
|
||||
```
|
||||
5. Check pod status:
|
||||
```bash
|
||||
@ -592,7 +599,7 @@ kubectl create namespace fusero-dev
|
||||
kubectl config set-context --current --namespace=fusero-dev
|
||||
|
||||
# Deploy to development namespace
|
||||
helm upgrade --install fusero ./chart -n fusero-dev -f chart/values.dev.yml
|
||||
helm upgrade --install fusero ./chart -n fusero-dev -f chart/values.dev.yaml
|
||||
```
|
||||
|
||||
### Production Namespace Setup
|
||||
@ -604,7 +611,7 @@ kubectl create namespace fusero-prod
|
||||
kubectl config set-context --current --namespace=fusero-prod
|
||||
|
||||
# Deploy to production namespace
|
||||
helm upgrade --install fusero ./chart -n fusero-prod -f chart/values.prod.yml
|
||||
helm upgrade --install fusero ./chart -n fusero-prod -f chart/values.prod.yaml
|
||||
```
|
||||
|
||||
### Namespace Management Commands
|
||||
@ -656,8 +663,8 @@ kubectl delete namespace <namespace-name>
|
||||
You have configured your Kubernetes development environment to use a dedicated namespace (`fusero-dev`) for all core services (backend, frontend, and database). This ensures resource isolation and easier management between development and production.
|
||||
|
||||
### What was changed:
|
||||
- All Kubernetes service templates (`backend-service.yml`, `frontend-service.yml`, `postgres-service.yml`) now use a namespace variable.
|
||||
- The development values file (`chart/values.dev.yml`) sets `global.namespace: fusero-dev` and updates all internal service hostnames to use this namespace.
|
||||
- All Kubernetes service templates (`backend-service.yaml`, `frontend-service.yaml`, `postgres-service.yaml`) now use a namespace variable.
|
||||
- The development values file (`chart/values.dev.yaml`) sets `global.namespace: fusero-dev` and updates all internal service hostnames to use this namespace.
|
||||
- Helm deployments now target the `fusero-dev` namespace for all dev resources.
|
||||
|
||||
### How to use:
|
||||
@ -668,7 +675,7 @@ You have configured your Kubernetes development environment to use a dedicated n
|
||||
|
||||
2. **Deploy all services to the namespace:**
|
||||
```bash
|
||||
helm upgrade --install fusero ./chart -n fusero-dev -f chart/values.dev.yml
|
||||
helm upgrade --install fusero ./chart -n fusero-dev -f chart/values.dev.yaml
|
||||
```
|
||||
|
||||
3. **Check running pods and services:**
|
||||
@ -681,7 +688,7 @@ You have configured your Kubernetes development environment to use a dedicated n
|
||||
5. **If you see errors about immutable fields (e.g., for Jobs), delete the old Job before redeploying:**
|
||||
```bash
|
||||
kubectl delete job <job-name> -n fusero-dev
|
||||
helm upgrade --install fusero ./chart -n fusero-dev -f chart/values.dev.yml
|
||||
helm upgrade --install fusero ./chart -n fusero-dev -f chart/values.dev.yaml
|
||||
```
|
||||
|
||||
### Why use namespaces?
|
||||
@ -703,7 +710,7 @@ The application uses a secure secrets management approach:
|
||||
|
||||
2. **Production Environment**:
|
||||
- Secrets are managed through Gitea CI/CD secrets
|
||||
- Template file: `chart/secrets.prod.template.yml`
|
||||
- Template file: `chart/secrets.prod.template.yaml`
|
||||
- Actual secrets are generated during deployment
|
||||
- Never commit actual secrets to the repository
|
||||
|
||||
@ -716,7 +723,7 @@ The application uses a secure secrets management approach:
|
||||
4. **Secrets in CI/CD**:
|
||||
- Secrets are stored in Gitea CI/CD settings
|
||||
- Automatically injected during deployment
|
||||
- Used to generate `secrets.prod.yml` at runtime
|
||||
- Used to generate `secrets.prod.yaml` at runtime
|
||||
|
||||
5. **Security Best Practices**:
|
||||
- All secrets files are gitignored
|
||||
@ -757,7 +764,7 @@ The application uses a secure secrets management approach:
|
||||
- name: Run Tests
|
||||
run: npm test
|
||||
- name: Deploy to Kubernetes
|
||||
run: helm upgrade --install fusero ./chart -n fusero-prod -f chart/values.prod.yml
|
||||
run: helm upgrade --install fusero ./chart -n fusero-prod -f chart/values.prod.yaml
|
||||
```
|
||||
|
||||
### Troubleshooting Production
|
||||
@ -767,3 +774,50 @@ The application uses a secure secrets management approach:
|
||||
- Rollback: Use `helm rollback fusero <revision> -n fusero-prod`.
|
||||
|
||||
---
|
||||
|
||||
## 🆕 Recent Improvements & Troubleshooting
|
||||
|
||||
- **Consistent File Extensions:** All Kubernetes and Helm YAML files now use the `.yaml` extension for consistency.
|
||||
- **Secrets Management:**
|
||||
- Development secrets are stored in `chart/secrets.dev.yaml` (gitignored).
|
||||
- Production secrets are generated by CI/CD as `chart/secrets.prod.yaml` from Gitea secrets.
|
||||
- All values files (`values.dev.yaml`, `values.prod.yaml`) reference secrets via environment variables.
|
||||
- **CORS Configuration:**
|
||||
- For local development, set `CORS_ORIGIN: "http://localhost:3000"` in `chart/values.dev.yaml` to allow credentialed requests from the frontend.
|
||||
- Do **not** use `*` for CORS origin if you need credentials.
|
||||
- **Kubernetes Job Immutability:**
|
||||
- If you update environment variables or secrets, you must delete the old migration/seed job before redeploying:
|
||||
```bash
|
||||
kubectl delete job fusero-backend-db-init -n fusero-dev
|
||||
helm upgrade --install fusero ./chart -n fusero-dev -f chart/values.dev.yaml -f chart/secrets.dev.yaml
|
||||
```
|
||||
- **Port Forwarding for Local Access:**
|
||||
- Backend:
|
||||
```bash
|
||||
kubectl port-forward -n fusero-dev svc/fusero-backend-service 14000:14000
|
||||
```
|
||||
- Frontend:
|
||||
```bash
|
||||
kubectl port-forward -n fusero-dev svc/fusero-frontend-service 3000:80
|
||||
```
|
||||
- Database:
|
||||
```bash
|
||||
kubectl port-forward -n fusero-dev svc/postgres-service 5432:5432
|
||||
```
|
||||
- **Testing Login with curl:**
|
||||
```bash
|
||||
curl -i -X POST http://localhost:14000/api/v1/app/users/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Origin: http://localhost:3000" \
|
||||
-d '{"username":"admin","password":"admin123"}'
|
||||
```
|
||||
- **Troubleshooting 401 Errors:**
|
||||
- If login fails after a redeploy:
|
||||
- Ensure secrets and values are in sync.
|
||||
- Re-run the seed job as above.
|
||||
- Check backend logs for authentication errors:
|
||||
```bash
|
||||
kubectl logs -n fusero-dev -l app=fusero-backend --tail=100
|
||||
```
|
||||
|
||||
---
|
||||
|
6
chart/Chart.yaml
Normal file
6
chart/Chart.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: fusero
|
||||
description: Fusero App Boilerplate Helm Chart
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "1.0.0"
|
@ -1,6 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: fusero
|
||||
description: Fusero application Helm chart
|
||||
description: Fusero App Boilerplate Helm Chart
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "1.0.0"
|
||||
|
@ -1,26 +0,0 @@
|
||||
backend:
|
||||
env:
|
||||
# Database
|
||||
POSTGRES_NAME: "fusero-boilerplate-db"
|
||||
POSTGRES_HOSTNAME: "postgres-service.fusero-prod.svc.cluster.local"
|
||||
POSTGRES_PORT: "5432"
|
||||
POSTGRES_USER: "root"
|
||||
POSTGRES_PASSWORD: "REPLACE_ME"
|
||||
|
||||
# Admin User
|
||||
DEFAULT_ADMIN_USERNAME: "admin"
|
||||
DEFAULT_ADMIN_EMAIL: "admin@fusero.nl"
|
||||
DEFAULT_ADMIN_PASSWORD: "REPLACE_ME"
|
||||
|
||||
# Security
|
||||
ENCRYPTION_KEY: "REPLACE_ME"
|
||||
JWT_SECRET: "REPLACE_ME"
|
||||
|
||||
# API Keys
|
||||
CHATGPT_API_KEY: "REPLACE_ME"
|
||||
CANVAS_API_KEY: "REPLACE_ME"
|
||||
CANVAS_API_URL: "https://talnet.instructure.com/api/v1"
|
||||
|
||||
# Server
|
||||
FASTIFY_PORT: "14000"
|
||||
NODE_ENV: "production"
|
18
chart/templates/postgres-configmap.yaml
Normal file
18
chart/templates/postgres-configmap.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: postgres-config
|
||||
data:
|
||||
pg_hba.conf: |
|
||||
# TYPE DATABASE USER ADDRESS METHOD
|
||||
local all all trust
|
||||
host all all 127.0.0.1/32 trust
|
||||
host all all ::1/128 trust
|
||||
host all all 0.0.0.0/0 md5
|
||||
postgresql.conf: |
|
||||
listen_addresses = '*'
|
||||
max_connections = 100
|
||||
shared_buffers = 128MB
|
||||
dynamic_shared_memory_type = posix
|
||||
max_wal_size = 1GB
|
||||
min_wal_size = 80MB
|
@ -27,7 +27,16 @@ spec:
|
||||
volumeMounts:
|
||||
- mountPath: /var/lib/postgresql/data
|
||||
name: postgres-data
|
||||
- mountPath: /etc/postgresql/pg_hba.conf
|
||||
name: postgres-config
|
||||
subPath: pg_hba.conf
|
||||
- mountPath: /etc/postgresql/postgresql.conf
|
||||
name: postgres-config
|
||||
subPath: postgresql.conf
|
||||
volumes:
|
||||
- name: postgres-data
|
||||
persistentVolumeClaim:
|
||||
claimName: postgres-pvc-fresh
|
||||
- name: postgres-config
|
||||
configMap:
|
||||
name: postgres-config
|
@ -1,64 +0,0 @@
|
||||
global:
|
||||
namespace: fusero-prod
|
||||
security:
|
||||
cors:
|
||||
origin: "https://app.fusero.nl"
|
||||
methods: "GET,POST,PUT,DELETE"
|
||||
credentials: true
|
||||
https:
|
||||
enabled: true
|
||||
certSecret: "fusero-tls-secret"
|
||||
logging:
|
||||
level: "info"
|
||||
format: "json"
|
||||
monitoring:
|
||||
prometheus:
|
||||
enabled: true
|
||||
path: "/metrics"
|
||||
|
||||
backend:
|
||||
image: registry.liquidrinu.com/fusero-backend:latest
|
||||
resources:
|
||||
requests:
|
||||
cpu: "200m"
|
||||
memory: "256Mi"
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: "512Mi"
|
||||
env:
|
||||
POSTGRES_HOST: postgres-service
|
||||
POSTGRES_PORT: "5432"
|
||||
POSTGRES_NAME: fusero-db
|
||||
POSTGRES_USER: prod_admin
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
DEFAULT_ADMIN_USERNAME: admin
|
||||
DEFAULT_ADMIN_EMAIL: admin@fusero.nl
|
||||
DEFAULT_ADMIN_PASSWORD: ${DEFAULT_ADMIN_PASSWORD}
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
|
||||
JWT_SECRET: ${JWT_SECRET}
|
||||
CHATGPT_API_KEY: ${CHATGPT_API_KEY}
|
||||
CANVAS_API_KEY: ${CANVAS_API_KEY}
|
||||
CANVAS_API_URL: https://talnet.instructure.com/api/v1
|
||||
|
||||
frontend:
|
||||
image: registry.liquidrinu.com/fusero-frontend:latest
|
||||
resources:
|
||||
requests:
|
||||
cpu: "100m"
|
||||
memory: "128Mi"
|
||||
limits:
|
||||
cpu: "300m"
|
||||
memory: "256Mi"
|
||||
env:
|
||||
VITE_API_BASE_URL: https://app.fusero.nl
|
||||
|
||||
postgres:
|
||||
image: postgres:15
|
||||
storage: 5Gi
|
||||
resources:
|
||||
requests:
|
||||
cpu: "200m"
|
||||
memory: "256Mi"
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: "512Mi"
|
@ -29,7 +29,7 @@
|
||||
"migrate": "npx mikro-orm migration:up",
|
||||
"seed": "ts-node -r tsconfig-paths/register src/database/seeds/run-seed.ts",
|
||||
"app:generate": "node ./utils/generate-app.js",
|
||||
"k8s:dev:apply": "kubectl apply -f k8s/frontend/deployment.dev.yml",
|
||||
"k8s:dev:apply": "kubectl apply -f k8s/frontend/deployment.dev.yaml",
|
||||
"k8s:dev:delete": "kubectl delete deployment fusero-frontend-dev 2>/dev/null || true",
|
||||
"k8s:dev:run": "kubectl port-forward svc/fusero-frontend-service 3000:80",
|
||||
"k8s:dev:describe": "kubectl describe pod -l app=fusero-frontend",
|
||||
|
Loading…
Reference in New Issue
Block a user