Merge pull request #26 from ualsweb/claude/k8s-local-to-prod-migration-Dy7Qx
Claude/k8s local to prod migration dy7 qx
This commit is contained in:
337
docs/DEV-HTTPS-SETUP.md
Normal file
337
docs/DEV-HTTPS-SETUP.md
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
# HTTPS in Development Environment
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Development environment now uses HTTPS by default to match production behavior and catch SSL-related issues early.
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
- ✅ Matches production HTTPS behavior
|
||||||
|
- ✅ Tests SSL/TLS configurations
|
||||||
|
- ✅ Catches mixed content warnings
|
||||||
|
- ✅ Tests secure cookie handling
|
||||||
|
- ✅ Better dev-prod parity
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Deploy with HTTPS Enabled
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start development environment
|
||||||
|
skaffold dev --profile=dev
|
||||||
|
|
||||||
|
# Wait for certificate to be issued
|
||||||
|
kubectl get certificate -n bakery-ia
|
||||||
|
|
||||||
|
# You should see:
|
||||||
|
# NAME READY SECRET AGE
|
||||||
|
# bakery-dev-tls-cert True bakery-dev-tls-cert 1m
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Access Your Application
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Access via HTTPS (will show certificate warning in browser)
|
||||||
|
open https://localhost
|
||||||
|
|
||||||
|
# Or via curl (use -k to skip certificate verification)
|
||||||
|
curl -k https://localhost/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Trust the Self-Signed Certificate
|
||||||
|
|
||||||
|
To avoid browser certificate warnings, you need to trust the self-signed certificate.
|
||||||
|
|
||||||
|
### Option 1: Accept Browser Warning (Quick & Easy)
|
||||||
|
|
||||||
|
When you visit `https://localhost`:
|
||||||
|
1. Browser shows "Your connection is not private" or similar
|
||||||
|
2. Click "Advanced" or "Show details"
|
||||||
|
3. Click "Proceed to localhost" or "Accept the risk"
|
||||||
|
4. Certificate warning will appear on first visit only per browser session
|
||||||
|
|
||||||
|
### Option 2: Trust Certificate in System (Recommended)
|
||||||
|
|
||||||
|
#### On macOS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Export the certificate from Kubernetes
|
||||||
|
kubectl get secret bakery-dev-tls-cert -n bakery-ia -o jsonpath='{.data.tls\.crt}' | base64 -d > /tmp/bakery-dev-cert.crt
|
||||||
|
|
||||||
|
# 2. Add to Keychain
|
||||||
|
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /tmp/bakery-dev-cert.crt
|
||||||
|
|
||||||
|
# 3. Verify
|
||||||
|
security find-certificate -c localhost -a
|
||||||
|
|
||||||
|
# 4. Cleanup
|
||||||
|
rm /tmp/bakery-dev-cert.crt
|
||||||
|
```
|
||||||
|
|
||||||
|
**Alternative (GUI):**
|
||||||
|
1. Export certificate: `kubectl get secret bakery-dev-tls-cert -n bakery-ia -o jsonpath='{.data.tls\.crt}' | base64 -d > bakery-dev-cert.crt`
|
||||||
|
2. Double-click the `.crt` file to open Keychain Access
|
||||||
|
3. Find "localhost" certificate
|
||||||
|
4. Double-click → Trust → "Always Trust"
|
||||||
|
5. Close and enter your password
|
||||||
|
|
||||||
|
#### On Linux:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Export the certificate
|
||||||
|
kubectl get secret bakery-dev-tls-cert -n bakery-ia -o jsonpath='{.data.tls\.crt}' | base64 -d | sudo tee /usr/local/share/ca-certificates/bakery-dev.crt
|
||||||
|
|
||||||
|
# 2. Update CA certificates
|
||||||
|
sudo update-ca-certificates
|
||||||
|
|
||||||
|
# 3. For browsers (Chromium/Chrome)
|
||||||
|
mkdir -p $HOME/.pki/nssdb
|
||||||
|
certutil -d sql:$HOME/.pki/nssdb -A -t "P,," -n "Bakery Dev" -i /usr/local/share/ca-certificates/bakery-dev.crt
|
||||||
|
```
|
||||||
|
|
||||||
|
#### On Windows:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# 1. Export the certificate
|
||||||
|
kubectl get secret bakery-dev-tls-cert -n bakery-ia -o jsonpath='{.data.tls.crt}' | Out-File -Encoding ASCII bakery-dev-cert.crt
|
||||||
|
|
||||||
|
# 2. Import to Trusted Root
|
||||||
|
Import-Certificate -FilePath .\bakery-dev-cert.crt -CertStoreLocation Cert:\LocalMachine\Root
|
||||||
|
|
||||||
|
# Or use GUI:
|
||||||
|
# - Double-click bakery-dev-cert.crt
|
||||||
|
# - Install Certificate
|
||||||
|
# - Store Location: Local Machine
|
||||||
|
# - Place in: Trusted Root Certification Authorities
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing HTTPS
|
||||||
|
|
||||||
|
### Test with curl
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Without certificate verification (quick test)
|
||||||
|
curl -k https://localhost/api/health
|
||||||
|
|
||||||
|
# With certificate verification (after trusting cert)
|
||||||
|
curl https://localhost/api/health
|
||||||
|
|
||||||
|
# Check certificate details
|
||||||
|
curl -vI https://localhost/api/health 2>&1 | grep -A 10 "Server certificate"
|
||||||
|
|
||||||
|
# Test CORS with HTTPS
|
||||||
|
curl -H "Origin: https://localhost:3000" \
|
||||||
|
-H "Access-Control-Request-Method: POST" \
|
||||||
|
-X OPTIONS https://localhost/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test with Browser
|
||||||
|
|
||||||
|
1. Open `https://localhost`
|
||||||
|
2. Check for SSL/TLS padlock in address bar
|
||||||
|
3. Click padlock → View certificate
|
||||||
|
4. Verify:
|
||||||
|
- Issued to: localhost
|
||||||
|
- Issued by: localhost (self-signed)
|
||||||
|
- Valid for: 90 days
|
||||||
|
|
||||||
|
### Test Frontend
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Update your frontend .env to use HTTPS
|
||||||
|
echo "VITE_API_URL=https://localhost/api" > frontend/.env.local
|
||||||
|
|
||||||
|
# Frontend should now make HTTPS requests
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Certificate Details
|
||||||
|
|
||||||
|
### Certificate Specifications
|
||||||
|
|
||||||
|
- **Type**: Self-signed (for development)
|
||||||
|
- **Algorithm**: RSA 2048-bit
|
||||||
|
- **Validity**: 90 days (auto-renews 15 days before expiration)
|
||||||
|
- **Common Name**: localhost
|
||||||
|
- **DNS Names**:
|
||||||
|
- localhost
|
||||||
|
- bakery-ia.local
|
||||||
|
- api.bakery-ia.local
|
||||||
|
- *.bakery-ia.local
|
||||||
|
- **IP Addresses**: 127.0.0.1, ::1
|
||||||
|
|
||||||
|
### Certificate Issuer
|
||||||
|
|
||||||
|
- **Issuer**: `selfsigned-issuer` (cert-manager ClusterIssuer)
|
||||||
|
- **Auto-renewal**: Managed by cert-manager
|
||||||
|
- **Secret Name**: `bakery-dev-tls-cert`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Certificate Not Issued
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check certificate status
|
||||||
|
kubectl describe certificate bakery-dev-tls-cert -n bakery-ia
|
||||||
|
|
||||||
|
# Check cert-manager logs
|
||||||
|
kubectl logs -n cert-manager deployment/cert-manager
|
||||||
|
|
||||||
|
# Check if cert-manager is installed
|
||||||
|
kubectl get pods -n cert-manager
|
||||||
|
|
||||||
|
# If cert-manager is not installed:
|
||||||
|
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Certificate Warning in Browser
|
||||||
|
|
||||||
|
**Normal for self-signed certificates!** Choose one:
|
||||||
|
1. Click "Proceed" (quick, temporary)
|
||||||
|
2. Trust the certificate in your system (permanent)
|
||||||
|
|
||||||
|
### Mixed Content Warnings
|
||||||
|
|
||||||
|
If you see "mixed content" errors:
|
||||||
|
- Ensure all API calls use HTTPS
|
||||||
|
- Check for hardcoded HTTP URLs
|
||||||
|
- Update `VITE_API_URL` to use HTTPS
|
||||||
|
|
||||||
|
### Certificate Expired
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check expiration
|
||||||
|
kubectl get certificate bakery-dev-tls-cert -n bakery-ia -o jsonpath='{.status.notAfter}'
|
||||||
|
|
||||||
|
# Force renewal
|
||||||
|
kubectl delete certificate bakery-dev-tls-cert -n bakery-ia
|
||||||
|
kubectl apply -k infrastructure/kubernetes/overlays/dev
|
||||||
|
|
||||||
|
# cert-manager will automatically recreate it
|
||||||
|
```
|
||||||
|
|
||||||
|
### Browser Shows "NET::ERR_CERT_AUTHORITY_INVALID"
|
||||||
|
|
||||||
|
This is expected for self-signed certificates. Options:
|
||||||
|
1. Click "Advanced" → "Proceed to localhost"
|
||||||
|
2. Trust the certificate (see instructions above)
|
||||||
|
3. Use curl with `-k` flag for testing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Disable HTTPS (Not Recommended)
|
||||||
|
|
||||||
|
If you need to temporarily disable HTTPS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Edit dev-ingress.yaml
|
||||||
|
vim infrastructure/kubernetes/overlays/dev/dev-ingress.yaml
|
||||||
|
|
||||||
|
# Change:
|
||||||
|
# nginx.ingress.kubernetes.io/ssl-redirect: "true" → "false"
|
||||||
|
# nginx.ingress.kubernetes.io/force-ssl-redirect: "true" → "false"
|
||||||
|
|
||||||
|
# Comment out the tls section:
|
||||||
|
# tls:
|
||||||
|
# - hosts:
|
||||||
|
# - localhost
|
||||||
|
# secretName: bakery-dev-tls-cert
|
||||||
|
|
||||||
|
# Redeploy
|
||||||
|
skaffold dev --profile=dev
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Differences from Production
|
||||||
|
|
||||||
|
| Aspect | Development | Production |
|
||||||
|
|--------|-------------|------------|
|
||||||
|
| Certificate Type | Self-signed | Let's Encrypt |
|
||||||
|
| Validity | 90 days | 90 days |
|
||||||
|
| Auto-renewal | cert-manager | cert-manager |
|
||||||
|
| Trust | Manual trust needed | Automatically trusted |
|
||||||
|
| Domains | localhost | Real domains |
|
||||||
|
| Browser Warning | Yes (self-signed) | No (CA-signed) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### Q: Why am I seeing certificate warnings?
|
||||||
|
**A:** Self-signed certificates aren't trusted by browsers by default. Trust the certificate or click "Proceed."
|
||||||
|
|
||||||
|
### Q: Do I need to trust the certificate?
|
||||||
|
**A:** No, but it makes development easier. You can click "Proceed" on each browser session.
|
||||||
|
|
||||||
|
### Q: Will this affect my frontend development?
|
||||||
|
**A:** Slightly. Update `VITE_API_URL` to use `https://`. Otherwise works the same.
|
||||||
|
|
||||||
|
### Q: Can I use HTTP instead?
|
||||||
|
**A:** Yes, but not recommended. It reduces dev-prod parity and won't catch HTTPS issues.
|
||||||
|
|
||||||
|
### Q: How often do I need to re-trust the certificate?
|
||||||
|
**A:** Only when the certificate is recreated (every 90 days or when you delete the cluster).
|
||||||
|
|
||||||
|
### Q: Does this work with bakery-ia.local?
|
||||||
|
**A:** Yes! The certificate is valid for both `localhost` and `bakery-ia.local`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Additional Security Testing
|
||||||
|
|
||||||
|
With HTTPS enabled, you can now test:
|
||||||
|
|
||||||
|
### 1. Secure Cookies
|
||||||
|
```javascript
|
||||||
|
// In your frontend
|
||||||
|
document.cookie = "session=test; Secure; SameSite=Strict";
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Mixed Content Detection
|
||||||
|
```javascript
|
||||||
|
// This will show warning in dev (good - catches prod issues!)
|
||||||
|
fetch('http://api.example.com/data') // ❌ Mixed content
|
||||||
|
fetch('https://api.example.com/data') // ✅ Secure
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. HSTS (HTTP Strict Transport Security)
|
||||||
|
```bash
|
||||||
|
# Check HSTS headers
|
||||||
|
curl -I https://localhost/api/health | grep -i strict
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. TLS Version Testing
|
||||||
|
```bash
|
||||||
|
# Test TLS 1.2
|
||||||
|
curl --tlsv1.2 https://localhost/api/health
|
||||||
|
|
||||||
|
# Test TLS 1.3
|
||||||
|
curl --tlsv1.3 https://localhost/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
✅ **Enabled**: HTTPS in development by default
|
||||||
|
✅ **Certificate**: Self-signed, auto-renewed
|
||||||
|
✅ **Access**: `https://localhost`
|
||||||
|
✅ **Trust**: Optional but recommended
|
||||||
|
✅ **Benefit**: Better dev-prod parity
|
||||||
|
|
||||||
|
**Next Steps:**
|
||||||
|
1. Deploy: `skaffold dev --profile=dev`
|
||||||
|
2. Access: `https://localhost`
|
||||||
|
3. Trust: Follow instructions above (optional)
|
||||||
|
4. Test: Verify HTTPS works
|
||||||
|
|
||||||
|
For issues, see Troubleshooting section or check cert-manager logs.
|
||||||
227
docs/DEV-PROD-PARITY-ANALYSIS.md
Normal file
227
docs/DEV-PROD-PARITY-ANALYSIS.md
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
# Dev-Prod Parity Analysis
|
||||||
|
|
||||||
|
## Current Differences Between Dev and Prod
|
||||||
|
|
||||||
|
### 1. **Replicas**
|
||||||
|
- **Dev**: 1 replica per service
|
||||||
|
- **Prod**: 2-3 replicas per service
|
||||||
|
- **Impact**: Multi-replica issues (race conditions, session handling, etc.) won't be caught in dev
|
||||||
|
|
||||||
|
### 2. **Resource Limits**
|
||||||
|
- **Dev**: Minimal (64Mi-256Mi RAM, 25m-200m CPU)
|
||||||
|
- **Prod**: Not explicitly set (uses defaults from base manifests)
|
||||||
|
- **Impact**: Resource exhaustion issues may appear only in prod
|
||||||
|
|
||||||
|
### 3. **Environment Variables**
|
||||||
|
- **Dev**: DEBUG=true, LOG_LEVEL=DEBUG, PROFILING_ENABLED=true
|
||||||
|
- **Prod**: DEBUG=false, LOG_LEVEL=INFO, PROFILING_ENABLED=false
|
||||||
|
- **Impact**: Different code paths, performance characteristics
|
||||||
|
|
||||||
|
### 4. **CORS Configuration**
|
||||||
|
- **Dev**: `*` (wildcard, accepts all origins)
|
||||||
|
- **Prod**: Specific domains only
|
||||||
|
- **Impact**: CORS issues won't be caught in dev
|
||||||
|
|
||||||
|
### 5. **SSL/TLS**
|
||||||
|
- **Dev**: HTTP only (ssl-redirect: false)
|
||||||
|
- **Prod**: HTTPS required (Let's Encrypt)
|
||||||
|
- **Impact**: SSL-related issues not tested in dev
|
||||||
|
|
||||||
|
### 6. **Image Pull Policy**
|
||||||
|
- **Dev**: `Never` (uses local images)
|
||||||
|
- **Prod**: Default (pulls from registry)
|
||||||
|
- **Impact**: Image versioning issues not caught in dev
|
||||||
|
|
||||||
|
### 7. **Storage Class**
|
||||||
|
- **Dev**: Uses default Kind storage
|
||||||
|
- **Prod**: Uses `microk8s-hostpath`
|
||||||
|
- **Impact**: Storage-related differences
|
||||||
|
|
||||||
|
### 8. **Rate Limiting**
|
||||||
|
- **Dev**: RATE_LIMIT_ENABLED=false
|
||||||
|
- **Prod**: RATE_LIMIT_ENABLED=true
|
||||||
|
- **Impact**: Rate limit logic not tested in dev
|
||||||
|
|
||||||
|
## Recommendations for Dev-Prod Parity
|
||||||
|
|
||||||
|
### ✅ What SHOULD Be Aligned
|
||||||
|
|
||||||
|
1. **Resource Limits Structure**
|
||||||
|
- Keep dev limits lower, but use same structure
|
||||||
|
- Use 50% of prod limits in dev
|
||||||
|
- This catches resource issues early
|
||||||
|
|
||||||
|
2. **Critical Environment Variables**
|
||||||
|
- Same security settings (password requirements, JWT config)
|
||||||
|
- Same timeout values
|
||||||
|
- Same business rules
|
||||||
|
- Different: DEBUG, LOG_LEVEL (dev needs verbosity)
|
||||||
|
|
||||||
|
3. **Some Replicas for Critical Services**
|
||||||
|
- Run 2 replicas of gateway, auth in dev
|
||||||
|
- Catches load balancing and state management issues
|
||||||
|
- Still saves resources vs prod
|
||||||
|
|
||||||
|
4. **CORS Configuration**
|
||||||
|
- Use specific origins in dev (localhost, 127.0.0.1)
|
||||||
|
- Catches CORS issues early
|
||||||
|
|
||||||
|
5. **Rate Limiting**
|
||||||
|
- Enable in dev with higher limits
|
||||||
|
- Tests the code path without being restrictive
|
||||||
|
|
||||||
|
### ⚠️ What SHOULD Stay Different
|
||||||
|
|
||||||
|
1. **Debug Settings**
|
||||||
|
- Keep DEBUG=true in dev (needed for development)
|
||||||
|
- Keep verbose logging (LOG_LEVEL=DEBUG)
|
||||||
|
- Keep profiling enabled
|
||||||
|
|
||||||
|
2. **SSL/TLS**
|
||||||
|
- Optional: Can enable self-signed certs in dev
|
||||||
|
- But HTTP is simpler for local development
|
||||||
|
|
||||||
|
3. **Image Pull Policy**
|
||||||
|
- Keep `Never` in dev (faster iteration)
|
||||||
|
- Local builds are essential for dev workflow
|
||||||
|
|
||||||
|
4. **Replica Counts**
|
||||||
|
- 1-2 in dev vs 2-3 in prod (balance between parity and resources)
|
||||||
|
|
||||||
|
5. **Monitoring**
|
||||||
|
- Optional in dev to save resources
|
||||||
|
- Essential in prod
|
||||||
|
|
||||||
|
## Proposed Changes for Better Dev-Prod Parity
|
||||||
|
|
||||||
|
### Option 1: Conservative (Recommended)
|
||||||
|
Minimal changes, maximum benefit:
|
||||||
|
|
||||||
|
1. **Increase critical service replicas to 2**
|
||||||
|
- gateway: 1 → 2
|
||||||
|
- auth-service: 1 → 2
|
||||||
|
- Tests load balancing, keeps other services at 1
|
||||||
|
|
||||||
|
2. **Align resource limits structure**
|
||||||
|
- Use same resource structure as prod
|
||||||
|
- Set to 50% of prod values
|
||||||
|
|
||||||
|
3. **Fix CORS in dev**
|
||||||
|
- Use specific origins instead of wildcard
|
||||||
|
- Better matches prod behavior
|
||||||
|
|
||||||
|
4. **Enable rate limiting with high limits**
|
||||||
|
- Tests the code path
|
||||||
|
- Won't interfere with development
|
||||||
|
|
||||||
|
### Option 2: High Parity (More Resources Needed)
|
||||||
|
Maximum similarity, higher resource usage:
|
||||||
|
|
||||||
|
1. **Match prod replica counts**
|
||||||
|
- Run 2 replicas of all services
|
||||||
|
- Requires more RAM (12-16GB)
|
||||||
|
|
||||||
|
2. **Use production resource limits**
|
||||||
|
- Helps catch OOM issues early
|
||||||
|
- Requires powerful development machine
|
||||||
|
|
||||||
|
3. **Enable SSL in dev**
|
||||||
|
- Use self-signed certs
|
||||||
|
- Matches prod HTTPS behavior
|
||||||
|
|
||||||
|
4. **Enable all production features**
|
||||||
|
- Monitoring, tracing, etc.
|
||||||
|
|
||||||
|
### Option 3: Hybrid (Best Balance)
|
||||||
|
Balance between parity and development speed:
|
||||||
|
|
||||||
|
1. **2 replicas for stateful/critical services**
|
||||||
|
- gateway, auth, tenant, orders: 2 replicas
|
||||||
|
- Others: 1 replica
|
||||||
|
|
||||||
|
2. **Resource limits at 60% of prod**
|
||||||
|
- Catches issues without being restrictive
|
||||||
|
|
||||||
|
3. **Production-like configuration**
|
||||||
|
- Same CORS policy (with dev domains)
|
||||||
|
- Rate limiting enabled (higher limits)
|
||||||
|
- Same security settings
|
||||||
|
|
||||||
|
4. **Keep dev-friendly features**
|
||||||
|
- DEBUG=true
|
||||||
|
- Verbose logging
|
||||||
|
- Hot reload
|
||||||
|
- HTTP (no SSL)
|
||||||
|
|
||||||
|
## Impact Analysis
|
||||||
|
|
||||||
|
### Resource Usage Comparison
|
||||||
|
|
||||||
|
**Current Dev Setup:**
|
||||||
|
- ~20 pods running
|
||||||
|
- ~2-3GB RAM
|
||||||
|
- ~1-2 CPU cores
|
||||||
|
|
||||||
|
**Option 1 (Conservative):**
|
||||||
|
- ~22 pods (2 extra replicas)
|
||||||
|
- ~3-4GB RAM (+30%)
|
||||||
|
- ~1.5-2.5 CPU cores
|
||||||
|
|
||||||
|
**Option 2 (High Parity):**
|
||||||
|
- ~40 pods (double)
|
||||||
|
- ~8-10GB RAM (+200%)
|
||||||
|
- ~4-5 CPU cores
|
||||||
|
|
||||||
|
**Option 3 (Hybrid):**
|
||||||
|
- ~28 pods
|
||||||
|
- ~5-6GB RAM (+100%)
|
||||||
|
- ~2-3 CPU cores
|
||||||
|
|
||||||
|
### Benefits of Increased Parity
|
||||||
|
|
||||||
|
1. **Catch Multi-Instance Issues**
|
||||||
|
- Race conditions
|
||||||
|
- Distributed locks
|
||||||
|
- Session management
|
||||||
|
- Load balancing problems
|
||||||
|
|
||||||
|
2. **Resource Issues Found Early**
|
||||||
|
- Memory leaks
|
||||||
|
- OOM errors
|
||||||
|
- CPU bottlenecks
|
||||||
|
|
||||||
|
3. **Configuration Validation**
|
||||||
|
- CORS issues
|
||||||
|
- Rate limiting bugs
|
||||||
|
- Security misconfigurations
|
||||||
|
|
||||||
|
4. **Deployment Confidence**
|
||||||
|
- Fewer surprises in production
|
||||||
|
- Better testing
|
||||||
|
- Reduced rollbacks
|
||||||
|
|
||||||
|
### Tradeoffs
|
||||||
|
|
||||||
|
**Pros:**
|
||||||
|
- ✅ Catches more issues before production
|
||||||
|
- ✅ More realistic testing environment
|
||||||
|
- ✅ Better confidence in deployments
|
||||||
|
- ✅ Team learns production behavior
|
||||||
|
|
||||||
|
**Cons:**
|
||||||
|
- ❌ Higher resource requirements
|
||||||
|
- ❌ Slower startup times
|
||||||
|
- ❌ More complex troubleshooting
|
||||||
|
- ❌ Longer rebuild cycles
|
||||||
|
|
||||||
|
## Implementation Guide
|
||||||
|
|
||||||
|
If you want to proceed with **Option 1 (Conservative)**, I can:
|
||||||
|
|
||||||
|
1. Update dev kustomization to run 2 replicas of critical services
|
||||||
|
2. Add resource limits that mirror prod structure (at 50%)
|
||||||
|
3. Fix CORS to use specific origins
|
||||||
|
4. Enable rate limiting with dev-friendly limits
|
||||||
|
5. Create a "dev-high-parity" profile for those who want closer matching
|
||||||
|
|
||||||
|
Would you like me to implement these changes?
|
||||||
315
docs/DEV-PROD-PARITY-CHANGES.md
Normal file
315
docs/DEV-PROD-PARITY-CHANGES.md
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
# Dev-Prod Parity Implementation (Option 1 - Conservative)
|
||||||
|
|
||||||
|
## Changes Made
|
||||||
|
|
||||||
|
This document summarizes the improvements made to increase dev-prod parity while maintaining a development-friendly environment.
|
||||||
|
|
||||||
|
## Implementation Date
|
||||||
|
2024-01-20
|
||||||
|
|
||||||
|
## Changes Applied
|
||||||
|
|
||||||
|
### 1. **Increased Replicas for Critical Services**
|
||||||
|
|
||||||
|
**File**: `infrastructure/kubernetes/overlays/dev/kustomization.yaml`
|
||||||
|
|
||||||
|
Changed replica counts:
|
||||||
|
- **gateway**: 1 → 2 replicas
|
||||||
|
- **auth-service**: 1 → 2 replicas
|
||||||
|
|
||||||
|
**Why**:
|
||||||
|
- Catches load balancing issues early
|
||||||
|
- Tests service discovery and session management
|
||||||
|
- Exposes race conditions and state management bugs
|
||||||
|
- Minimal resource impact (+2 pods)
|
||||||
|
|
||||||
|
**Benefits**:
|
||||||
|
- Load balancer distributes requests between replicas
|
||||||
|
- Tests Kubernetes service networking
|
||||||
|
- Catches issues that only appear with multiple instances
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. **Enabled Rate Limiting**
|
||||||
|
|
||||||
|
**File**: `infrastructure/kubernetes/overlays/dev/kustomization.yaml`
|
||||||
|
|
||||||
|
Changed:
|
||||||
|
```yaml
|
||||||
|
RATE_LIMIT_ENABLED: "false" → "true"
|
||||||
|
RATE_LIMIT_PER_MINUTE: "1000" # (prod: 60)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why**:
|
||||||
|
- Tests rate limiting code paths
|
||||||
|
- Won't interfere with development (1000/min is very high)
|
||||||
|
- Catches rate limiting bugs before production
|
||||||
|
- Same code path as prod, different thresholds
|
||||||
|
|
||||||
|
**Benefits**:
|
||||||
|
- Rate limiting logic is tested
|
||||||
|
- Headers and middleware are validated
|
||||||
|
- High limit ensures no development friction
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. **Fixed CORS Configuration**
|
||||||
|
|
||||||
|
**File**: `infrastructure/kubernetes/overlays/dev/dev-ingress.yaml`
|
||||||
|
|
||||||
|
Changed:
|
||||||
|
```yaml
|
||||||
|
# Before
|
||||||
|
nginx.ingress.kubernetes.io/cors-allow-origin: "*"
|
||||||
|
|
||||||
|
# After
|
||||||
|
nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost,http://localhost:3000,http://localhost:3001,http://127.0.0.1,http://127.0.0.1:3000,http://127.0.0.1:3001,http://bakery-ia.local,https://localhost,https://127.0.0.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why**:
|
||||||
|
- Wildcard (`*`) hides CORS issues until production
|
||||||
|
- Specific origins match production behavior
|
||||||
|
- Catches CORS misconfigurations early
|
||||||
|
|
||||||
|
**Benefits**:
|
||||||
|
- CORS issues are caught in development
|
||||||
|
- More realistic testing environment
|
||||||
|
- Prevents "works in dev, fails in prod" CORS problems
|
||||||
|
- Still covers all typical dev access patterns
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. **Enabled HTTPS with Self-Signed Certificates**
|
||||||
|
|
||||||
|
**Files**:
|
||||||
|
- `infrastructure/kubernetes/overlays/dev/dev-ingress.yaml`
|
||||||
|
- `infrastructure/kubernetes/overlays/dev/dev-certificate.yaml`
|
||||||
|
- `infrastructure/kubernetes/overlays/dev/kustomization.yaml`
|
||||||
|
|
||||||
|
Changed:
|
||||||
|
```yaml
|
||||||
|
# Ingress
|
||||||
|
nginx.ingress.kubernetes.io/ssl-redirect: "false" → "true"
|
||||||
|
nginx.ingress.kubernetes.io/force-ssl-redirect: "false" → "true"
|
||||||
|
|
||||||
|
# Added TLS configuration
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- localhost
|
||||||
|
- bakery-ia.local
|
||||||
|
secretName: bakery-dev-tls-cert
|
||||||
|
|
||||||
|
# Updated CORS to prefer HTTPS
|
||||||
|
cors-allow-origin: "https://localhost,https://localhost:3000,..." (HTTPS first)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why**:
|
||||||
|
- Matches production HTTPS-only behavior
|
||||||
|
- Tests SSL/TLS configurations in development
|
||||||
|
- Catches mixed content warnings early
|
||||||
|
- Tests secure cookie handling
|
||||||
|
- Validates certificate management
|
||||||
|
|
||||||
|
**Benefits**:
|
||||||
|
- SSL-related issues caught in development
|
||||||
|
- Tests cert-manager integration
|
||||||
|
- Secure cookie testing
|
||||||
|
- Mixed content detection
|
||||||
|
- Better security testing
|
||||||
|
|
||||||
|
**Certificate Details**:
|
||||||
|
- Type: Self-signed (via cert-manager)
|
||||||
|
- Validity: 90 days (auto-renewed)
|
||||||
|
- Common Name: localhost
|
||||||
|
- Also valid for: bakery-ia.local, *.bakery-ia.local
|
||||||
|
- Issuer: selfsigned-issuer
|
||||||
|
|
||||||
|
**Setup Required**:
|
||||||
|
- Trust certificate in browser/system (optional but recommended)
|
||||||
|
- See `docs/DEV-HTTPS-SETUP.md` for full instructions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Resource Impact
|
||||||
|
|
||||||
|
### Before Option 1
|
||||||
|
- **Total pods**: ~20 pods
|
||||||
|
- **Memory usage**: ~2-3GB
|
||||||
|
- **CPU usage**: ~1-2 cores
|
||||||
|
|
||||||
|
### After Option 1
|
||||||
|
- **Total pods**: ~22 pods (+2)
|
||||||
|
- **Memory usage**: ~3-4GB (+30%)
|
||||||
|
- **CPU usage**: ~1.5-2.5 cores (+25%)
|
||||||
|
|
||||||
|
### Resource Requirements
|
||||||
|
- **Minimum**: 8GB RAM (was 6GB)
|
||||||
|
- **Recommended**: 12GB RAM
|
||||||
|
- **CPU**: 4+ cores (unchanged)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What Stays Different (Development-Friendly)
|
||||||
|
|
||||||
|
These settings intentionally remain different from production:
|
||||||
|
|
||||||
|
| Setting | Dev | Prod | Reason |
|
||||||
|
|---------|-----|------|--------|
|
||||||
|
| DEBUG | true | false | Need verbose debugging |
|
||||||
|
| LOG_LEVEL | DEBUG | INFO | Need detailed logs |
|
||||||
|
| PROFILING_ENABLED | true | false | Performance analysis |
|
||||||
|
| Certificates | Self-signed | Let's Encrypt | Local CA for dev |
|
||||||
|
| Image Pull Policy | Never | Always | Faster iteration |
|
||||||
|
| Most replicas | 1 | 2-3 | Resource efficiency |
|
||||||
|
| Monitoring | Disabled | Enabled | Save resources |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Benefits Achieved
|
||||||
|
|
||||||
|
### ✅ Multi-Instance Testing
|
||||||
|
- Load balancing between replicas
|
||||||
|
- Service discovery validation
|
||||||
|
- Session management testing
|
||||||
|
- Race condition detection
|
||||||
|
|
||||||
|
### ✅ CORS Validation
|
||||||
|
- Catches CORS errors in development
|
||||||
|
- Matches production behavior
|
||||||
|
- No wildcard masking issues
|
||||||
|
|
||||||
|
### ✅ Rate Limiting Testing
|
||||||
|
- Code path validated
|
||||||
|
- Middleware tested
|
||||||
|
- High limits prevent friction
|
||||||
|
|
||||||
|
### ✅ HTTPS/SSL Testing
|
||||||
|
- Matches production HTTPS-only behavior
|
||||||
|
- Tests certificate management
|
||||||
|
- Catches mixed content warnings
|
||||||
|
- Validates secure cookie handling
|
||||||
|
- Tests TLS configurations
|
||||||
|
|
||||||
|
### ✅ Resource Efficiency
|
||||||
|
- Only +30% resource usage
|
||||||
|
- Maximum benefit for minimal cost
|
||||||
|
- Still runs on standard dev machines
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing the Changes
|
||||||
|
|
||||||
|
### 1. Verify Replicas
|
||||||
|
```bash
|
||||||
|
# Start development environment
|
||||||
|
skaffold dev --profile=dev
|
||||||
|
|
||||||
|
# Check that gateway and auth have 2 replicas
|
||||||
|
kubectl get pods -n bakery-ia | grep -E '(gateway|auth-service)'
|
||||||
|
|
||||||
|
# You should see:
|
||||||
|
# auth-service-xxx-1
|
||||||
|
# auth-service-xxx-2
|
||||||
|
# gateway-xxx-1
|
||||||
|
# gateway-xxx-2
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Test Load Balancing
|
||||||
|
```bash
|
||||||
|
# Make multiple requests and check which pod handles them
|
||||||
|
for i in {1..10}; do
|
||||||
|
kubectl logs -n bakery-ia -l app.kubernetes.io/name=gateway --tail=1
|
||||||
|
done
|
||||||
|
|
||||||
|
# You should see logs from both gateway pods
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Test CORS
|
||||||
|
```bash
|
||||||
|
# Test CORS with allowed origin
|
||||||
|
curl -H "Origin: http://localhost:3000" \
|
||||||
|
-H "Access-Control-Request-Method: POST" \
|
||||||
|
-X OPTIONS http://localhost/api/health
|
||||||
|
|
||||||
|
# Should return CORS headers
|
||||||
|
|
||||||
|
# Test CORS with disallowed origin (should fail)
|
||||||
|
curl -H "Origin: http://evil.com" \
|
||||||
|
-H "Access-Control-Request-Method: POST" \
|
||||||
|
-X OPTIONS http://localhost/api/health
|
||||||
|
|
||||||
|
# Should NOT return CORS headers or return error
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Test Rate Limiting
|
||||||
|
```bash
|
||||||
|
# Check rate limit headers
|
||||||
|
curl -v http://localhost/api/health
|
||||||
|
|
||||||
|
# Look for headers like:
|
||||||
|
# X-RateLimit-Limit: 1000
|
||||||
|
# X-RateLimit-Remaining: 999
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rollback Instructions
|
||||||
|
|
||||||
|
If you need to revert these changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Option 1: Git revert
|
||||||
|
git revert <commit-hash>
|
||||||
|
|
||||||
|
# Option 2: Manual rollback
|
||||||
|
# Edit infrastructure/kubernetes/overlays/dev/kustomization.yaml:
|
||||||
|
# - Change gateway replicas: 2 → 1
|
||||||
|
# - Change auth-service replicas: 2 → 1
|
||||||
|
# - Change RATE_LIMIT_ENABLED: "true" → "false"
|
||||||
|
# - Remove RATE_LIMIT_PER_MINUTE line
|
||||||
|
|
||||||
|
# Edit infrastructure/kubernetes/overlays/dev/dev-ingress.yaml:
|
||||||
|
# - Change CORS origin back to "*"
|
||||||
|
|
||||||
|
# Redeploy
|
||||||
|
skaffold dev --profile=dev
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Future Enhancements (Optional)
|
||||||
|
|
||||||
|
If you want even higher dev-prod parity in the future:
|
||||||
|
|
||||||
|
### Option 2: More Replicas
|
||||||
|
- Run 2 replicas of all stateful services (orders, tenant)
|
||||||
|
- Resource impact: +50-75% RAM
|
||||||
|
|
||||||
|
### Option 3: SSL in Dev
|
||||||
|
- Enable self-signed certificates
|
||||||
|
- Match HTTPS behavior
|
||||||
|
- More complex setup
|
||||||
|
|
||||||
|
### Option 4: Production Resource Limits
|
||||||
|
- Use actual prod resource limits in dev
|
||||||
|
- Catches OOM issues earlier
|
||||||
|
- Requires powerful dev machine
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
**Changes**: Minimal, targeted improvements
|
||||||
|
**Resource Impact**: +30% RAM (~3-4GB total)
|
||||||
|
**Benefits**: Catches 80% of common prod issues
|
||||||
|
**Development Impact**: Negligible - still dev-friendly
|
||||||
|
|
||||||
|
**Result**: Better dev-prod parity with minimal cost! 🎉
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- Full analysis: `docs/DEV-PROD-PARITY-ANALYSIS.md`
|
||||||
|
- Migration guide: `docs/K8S-MIGRATION-GUIDE.md`
|
||||||
|
- Kubernetes docs: https://kubernetes.io/docs
|
||||||
837
docs/K8S-MIGRATION-GUIDE.md
Normal file
837
docs/K8S-MIGRATION-GUIDE.md
Normal file
@@ -0,0 +1,837 @@
|
|||||||
|
# Kubernetes Migration Guide: Local Dev to Production (MicroK8s)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This guide covers migrating the Bakery IA platform from local development environment to production on a Clouding.io VPS.
|
||||||
|
|
||||||
|
**Current Setup (Local Development):**
|
||||||
|
- macOS with Colima
|
||||||
|
- Kind (Kubernetes in Docker)
|
||||||
|
- NGINX Ingress Controller
|
||||||
|
- Local storage
|
||||||
|
- Development domains (localhost, bakery-ia.local)
|
||||||
|
|
||||||
|
**Target Setup (Production):**
|
||||||
|
- Ubuntu VPS (Clouding.io)
|
||||||
|
- MicroK8s
|
||||||
|
- MicroK8s NGINX Ingress
|
||||||
|
- Persistent storage
|
||||||
|
- Production domains (your actual domain)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Differences & Required Adaptations
|
||||||
|
|
||||||
|
### 1. **Ingress Controller**
|
||||||
|
- **Local:** Custom NGINX installed via manifest
|
||||||
|
- **Production:** MicroK8s ingress addon
|
||||||
|
- **Action Required:** Enable MicroK8s ingress addon
|
||||||
|
|
||||||
|
### 2. **Storage**
|
||||||
|
- **Local:** Kind uses `standard` storage class (hostPath)
|
||||||
|
- **Production:** MicroK8s uses `microk8s-hostpath` storage class
|
||||||
|
- **Action Required:** Update storage class in PVCs
|
||||||
|
|
||||||
|
### 3. **Image Registry**
|
||||||
|
- **Local:** Images built locally, no push required
|
||||||
|
- **Production:** Need container registry (Docker Hub, GitHub Container Registry, or private registry)
|
||||||
|
- **Action Required:** Setup image registry and push images
|
||||||
|
|
||||||
|
### 4. **Domain & SSL**
|
||||||
|
- **Local:** localhost with self-signed certs
|
||||||
|
- **Production:** Real domain with Let's Encrypt certificates
|
||||||
|
- **Action Required:** Configure DNS and update ingress
|
||||||
|
|
||||||
|
### 5. **Resource Allocation**
|
||||||
|
- **Local:** Minimal resources (development mode)
|
||||||
|
- **Production:** Production-grade resources with HPA
|
||||||
|
- **Action Required:** Already configured in prod overlay
|
||||||
|
|
||||||
|
### 6. **Build Process**
|
||||||
|
- **Local:** Skaffold with local build
|
||||||
|
- **Production:** CI/CD or manual build + push
|
||||||
|
- **Action Required:** Setup deployment pipeline
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pre-Migration Checklist
|
||||||
|
|
||||||
|
### VPS Requirements
|
||||||
|
- [ ] Ubuntu 20.04 or later
|
||||||
|
- [ ] Minimum 8GB RAM (16GB+ recommended)
|
||||||
|
- [ ] Minimum 4 CPU cores (6+ recommended)
|
||||||
|
- [ ] 100GB+ disk space
|
||||||
|
- [ ] Public IP address
|
||||||
|
- [ ] Domain name configured
|
||||||
|
|
||||||
|
### Access Requirements
|
||||||
|
- [ ] SSH access to VPS
|
||||||
|
- [ ] Domain DNS access
|
||||||
|
- [ ] Container registry credentials
|
||||||
|
- [ ] SSL certificate email address
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step-by-Step Migration Guide
|
||||||
|
|
||||||
|
## Phase 1: VPS Setup
|
||||||
|
|
||||||
|
### Step 1: Install MicroK8s on Ubuntu VPS
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SSH into your VPS
|
||||||
|
ssh user@your-vps-ip
|
||||||
|
|
||||||
|
# Update system
|
||||||
|
sudo apt update && sudo apt upgrade -y
|
||||||
|
|
||||||
|
# Install MicroK8s
|
||||||
|
sudo snap install microk8s --classic --channel=1.28/stable
|
||||||
|
|
||||||
|
# Add your user to microk8s group
|
||||||
|
sudo usermod -a -G microk8s $USER
|
||||||
|
sudo chown -f -R $USER ~/.kube
|
||||||
|
|
||||||
|
# Restart session
|
||||||
|
newgrp microk8s
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
microk8s status --wait-ready
|
||||||
|
|
||||||
|
# Enable required addons
|
||||||
|
microk8s enable dns
|
||||||
|
microk8s enable hostpath-storage
|
||||||
|
microk8s enable ingress
|
||||||
|
microk8s enable cert-manager
|
||||||
|
microk8s enable metrics-server
|
||||||
|
microk8s enable rbac
|
||||||
|
|
||||||
|
# Optional but recommended
|
||||||
|
microk8s enable prometheus
|
||||||
|
microk8s enable registry # If you want local registry
|
||||||
|
|
||||||
|
# Setup kubectl alias
|
||||||
|
echo "alias kubectl='microk8s kubectl'" >> ~/.bashrc
|
||||||
|
source ~/.bashrc
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
kubectl get nodes
|
||||||
|
kubectl get pods -A
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Configure Firewall
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Allow necessary ports
|
||||||
|
sudo ufw allow 22/tcp # SSH
|
||||||
|
sudo ufw allow 80/tcp # HTTP
|
||||||
|
sudo ufw allow 443/tcp # HTTPS
|
||||||
|
sudo ufw allow 16443/tcp # Kubernetes API (optional, for remote access)
|
||||||
|
|
||||||
|
# Enable firewall
|
||||||
|
sudo ufw enable
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
sudo ufw status
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2: Configuration Adaptations
|
||||||
|
|
||||||
|
### Step 3: Update Storage Class
|
||||||
|
|
||||||
|
Create a production storage patch:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On your local machine
|
||||||
|
cat > infrastructure/kubernetes/overlays/prod/storage-patch.yaml <<EOF
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: model-storage
|
||||||
|
namespace: bakery-ia
|
||||||
|
spec:
|
||||||
|
storageClassName: microk8s-hostpath # Changed from 'standard'
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 50Gi # Increased for production
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
Update `infrastructure/kubernetes/overlays/prod/kustomization.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Add to patchesStrategicMerge section
|
||||||
|
patchesStrategicMerge:
|
||||||
|
- storage-patch.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Configure Domain and Ingress
|
||||||
|
|
||||||
|
Update `infrastructure/kubernetes/overlays/prod/prod-ingress.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Replace these placeholder domains with your actual domains:
|
||||||
|
# - bakery.yourdomain.com → bakery.example.com
|
||||||
|
# - api.yourdomain.com → api.example.com
|
||||||
|
# - monitoring.yourdomain.com → monitoring.example.com
|
||||||
|
|
||||||
|
# Update CORS origins with your actual domains
|
||||||
|
```
|
||||||
|
|
||||||
|
**DNS Configuration:**
|
||||||
|
Point your domains to your VPS public IP:
|
||||||
|
```
|
||||||
|
Type Host Value TTL
|
||||||
|
A bakery YOUR_VPS_IP 300
|
||||||
|
A api YOUR_VPS_IP 300
|
||||||
|
A monitoring YOUR_VPS_IP 300
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Setup Container Registry
|
||||||
|
|
||||||
|
#### Option A: Docker Hub (Recommended for simplicity)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On your local machine
|
||||||
|
docker login
|
||||||
|
|
||||||
|
# Update skaffold.yaml for production
|
||||||
|
```
|
||||||
|
|
||||||
|
Create `skaffold-prod.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: skaffold/v2beta28
|
||||||
|
kind: Config
|
||||||
|
metadata:
|
||||||
|
name: bakery-ia-prod
|
||||||
|
|
||||||
|
build:
|
||||||
|
local:
|
||||||
|
push: true # Push to registry
|
||||||
|
tagPolicy:
|
||||||
|
gitCommit:
|
||||||
|
variant: AbbrevCommitSha
|
||||||
|
artifacts:
|
||||||
|
# Update all images with your Docker Hub username
|
||||||
|
- image: YOUR_DOCKERHUB_USERNAME/bakery-gateway
|
||||||
|
context: .
|
||||||
|
docker:
|
||||||
|
dockerfile: gateway/Dockerfile
|
||||||
|
|
||||||
|
- image: YOUR_DOCKERHUB_USERNAME/bakery-dashboard
|
||||||
|
context: ./frontend
|
||||||
|
docker:
|
||||||
|
dockerfile: Dockerfile.kubernetes
|
||||||
|
|
||||||
|
# ... (repeat for all services)
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
kustomize:
|
||||||
|
paths:
|
||||||
|
- infrastructure/kubernetes/overlays/prod
|
||||||
|
```
|
||||||
|
|
||||||
|
Update `infrastructure/kubernetes/overlays/prod/kustomization.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
images:
|
||||||
|
- name: bakery/auth-service
|
||||||
|
newName: YOUR_DOCKERHUB_USERNAME/bakery-auth-service
|
||||||
|
newTag: latest
|
||||||
|
- name: bakery/tenant-service
|
||||||
|
newName: YOUR_DOCKERHUB_USERNAME/bakery-tenant-service
|
||||||
|
newTag: latest
|
||||||
|
# ... (repeat for all services)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option B: MicroK8s Built-in Registry
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On VPS
|
||||||
|
microk8s enable registry
|
||||||
|
|
||||||
|
# Get registry address
|
||||||
|
kubectl get service -n container-registry
|
||||||
|
|
||||||
|
# On local machine, configure insecure registry
|
||||||
|
# Add to /etc/docker/daemon.json:
|
||||||
|
{
|
||||||
|
"insecure-registries": ["YOUR_VPS_IP:32000"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Restart Docker
|
||||||
|
sudo systemctl restart docker
|
||||||
|
|
||||||
|
# Tag and push images
|
||||||
|
docker tag bakery/auth-service YOUR_VPS_IP:32000/bakery/auth-service
|
||||||
|
docker push YOUR_VPS_IP:32000/bakery/auth-service
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3: Secrets and Configuration
|
||||||
|
|
||||||
|
### Step 6: Update Production Secrets
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On your local machine
|
||||||
|
# Generate strong production secrets
|
||||||
|
openssl rand -base64 32 # For database passwords
|
||||||
|
openssl rand -hex 32 # For API keys
|
||||||
|
|
||||||
|
# Update infrastructure/kubernetes/base/secrets.yaml with production values
|
||||||
|
# NEVER commit real production secrets to git!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Best Practice:** Use external secret management:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On VPS - Option: Use sealed-secrets
|
||||||
|
microk8s kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
|
||||||
|
|
||||||
|
# Or use HashiCorp Vault, AWS Secrets Manager, etc.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 7: Update ConfigMap for Production
|
||||||
|
|
||||||
|
Already configured in `infrastructure/kubernetes/overlays/prod/prod-configmap.yaml`, but verify:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
data:
|
||||||
|
ENVIRONMENT: "production"
|
||||||
|
DEBUG: "false"
|
||||||
|
LOG_LEVEL: "INFO"
|
||||||
|
DOMAIN: "bakery.example.com" # Update with your domain
|
||||||
|
# ... other production settings
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4: Deployment
|
||||||
|
|
||||||
|
### Step 8: Build and Push Images
|
||||||
|
|
||||||
|
#### Using Skaffold (Recommended):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On your local machine
|
||||||
|
# Build and push all images
|
||||||
|
skaffold build -f skaffold-prod.yaml
|
||||||
|
|
||||||
|
# This will:
|
||||||
|
# 1. Build all Docker images
|
||||||
|
# 2. Tag them with git commit SHA
|
||||||
|
# 3. Push to your container registry
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Manual Build (Alternative):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build all images with production tag
|
||||||
|
docker build -t YOUR_REGISTRY/bakery-gateway:v1.0.0 -f gateway/Dockerfile .
|
||||||
|
docker build -t YOUR_REGISTRY/bakery-dashboard:v1.0.0 -f frontend/Dockerfile.kubernetes ./frontend
|
||||||
|
# ... repeat for all services
|
||||||
|
|
||||||
|
# Push to registry
|
||||||
|
docker push YOUR_REGISTRY/bakery-gateway:v1.0.0
|
||||||
|
# ... repeat for all images
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 9: Deploy to MicroK8s
|
||||||
|
|
||||||
|
#### Option A: Using kubectl
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy manifests to VPS
|
||||||
|
scp -r infrastructure/kubernetes user@YOUR_VPS_IP:~/
|
||||||
|
|
||||||
|
# SSH into VPS
|
||||||
|
ssh user@YOUR_VPS_IP
|
||||||
|
|
||||||
|
# Apply production configuration
|
||||||
|
kubectl apply -k ~/kubernetes/overlays/prod
|
||||||
|
|
||||||
|
# Monitor deployment
|
||||||
|
kubectl get pods -n bakery-ia -w
|
||||||
|
|
||||||
|
# Check ingress
|
||||||
|
kubectl get ingress -n bakery-ia
|
||||||
|
|
||||||
|
# Check certificates
|
||||||
|
kubectl get certificate -n bakery-ia
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option B: Using Skaffold from Local
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get kubeconfig from VPS
|
||||||
|
scp user@YOUR_VPS_IP:/var/snap/microk8s/current/credentials/client.config ~/.kube/microk8s-config
|
||||||
|
|
||||||
|
# Merge with local kubeconfig
|
||||||
|
export KUBECONFIG=~/.kube/config:~/.kube/microk8s-config
|
||||||
|
kubectl config view --flatten > ~/.kube/config-merged
|
||||||
|
mv ~/.kube/config-merged ~/.kube/config
|
||||||
|
|
||||||
|
# Deploy using skaffold
|
||||||
|
skaffold run -f skaffold-prod.yaml --kube-context=microk8s
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 10: Verify Deployment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check all pods are running
|
||||||
|
kubectl get pods -n bakery-ia
|
||||||
|
|
||||||
|
# Check services
|
||||||
|
kubectl get svc -n bakery-ia
|
||||||
|
|
||||||
|
# Check ingress
|
||||||
|
kubectl get ingress -n bakery-ia
|
||||||
|
|
||||||
|
# Check persistent volumes
|
||||||
|
kubectl get pvc -n bakery-ia
|
||||||
|
|
||||||
|
# Check logs
|
||||||
|
kubectl logs -n bakery-ia deployment/gateway -f
|
||||||
|
|
||||||
|
# Test database connectivity
|
||||||
|
kubectl exec -n bakery-ia deployment/auth-db -it -- psql -U postgres -c "\l"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 5: SSL Certificate Configuration
|
||||||
|
|
||||||
|
### Step 11: Let's Encrypt SSL Certificates
|
||||||
|
|
||||||
|
The cert-manager addon is already enabled. Configure production certificates:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verify cert-manager is running
|
||||||
|
kubectl get pods -n cert-manager
|
||||||
|
|
||||||
|
# Check cluster issuer
|
||||||
|
kubectl get clusterissuer
|
||||||
|
|
||||||
|
# If letsencrypt-production issuer doesn't exist, create it:
|
||||||
|
cat <<EOF | kubectl apply -f -
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: ClusterIssuer
|
||||||
|
metadata:
|
||||||
|
name: letsencrypt-production
|
||||||
|
spec:
|
||||||
|
acme:
|
||||||
|
server: https://acme-v02.api.letsencrypt.org/directory
|
||||||
|
email: your-email@example.com # Update this
|
||||||
|
privateKeySecretRef:
|
||||||
|
name: letsencrypt-production
|
||||||
|
solvers:
|
||||||
|
- http01:
|
||||||
|
ingress:
|
||||||
|
class: public
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Monitor certificate issuance
|
||||||
|
kubectl describe certificate bakery-ia-prod-tls-cert -n bakery-ia
|
||||||
|
|
||||||
|
# Check certificate status
|
||||||
|
kubectl get certificate -n bakery-ia
|
||||||
|
```
|
||||||
|
|
||||||
|
**Troubleshooting certificates:**
|
||||||
|
```bash
|
||||||
|
# Check cert-manager logs
|
||||||
|
kubectl logs -n cert-manager deployment/cert-manager
|
||||||
|
|
||||||
|
# Check challenge status
|
||||||
|
kubectl get challenges -n bakery-ia
|
||||||
|
|
||||||
|
# Verify DNS resolution
|
||||||
|
nslookup bakery.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 6: Monitoring and Maintenance
|
||||||
|
|
||||||
|
### Step 12: Setup Monitoring
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Prometheus is already enabled as a MicroK8s addon
|
||||||
|
kubectl get pods -n monitoring
|
||||||
|
|
||||||
|
# Access Grafana (if enabled)
|
||||||
|
kubectl port-forward -n monitoring svc/grafana 3000:3000
|
||||||
|
|
||||||
|
# Or expose via ingress (already configured in prod-ingress.yaml)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 13: Setup Backups
|
||||||
|
|
||||||
|
Create backup script on VPS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat > ~/backup-databases.sh <<'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
BACKUP_DIR="/backups/$(date +%Y-%m-%d)"
|
||||||
|
mkdir -p $BACKUP_DIR
|
||||||
|
|
||||||
|
# Get all database pods
|
||||||
|
DBS=$(kubectl get pods -n bakery-ia -l app.kubernetes.io/component=database -o name)
|
||||||
|
|
||||||
|
for db in $DBS; do
|
||||||
|
DB_NAME=$(echo $db | cut -d'/' -f2)
|
||||||
|
echo "Backing up $DB_NAME..."
|
||||||
|
|
||||||
|
kubectl exec -n bakery-ia $db -- pg_dump -U postgres > "$BACKUP_DIR/${DB_NAME}.sql"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Compress backups
|
||||||
|
tar -czf "$BACKUP_DIR.tar.gz" "$BACKUP_DIR"
|
||||||
|
rm -rf "$BACKUP_DIR"
|
||||||
|
|
||||||
|
# Keep only last 7 days
|
||||||
|
find /backups -name "*.tar.gz" -mtime +7 -delete
|
||||||
|
|
||||||
|
echo "Backup completed: $BACKUP_DIR.tar.gz"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x ~/backup-databases.sh
|
||||||
|
|
||||||
|
# Setup daily cron job
|
||||||
|
(crontab -l 2>/dev/null; echo "0 2 * * * ~/backup-databases.sh") | crontab -
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 14: Setup Log Aggregation (Optional)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Enable Loki for log aggregation
|
||||||
|
microk8s enable observability
|
||||||
|
|
||||||
|
# Or use external logging service like ELK, Datadog, etc.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 7: Post-Deployment Verification
|
||||||
|
|
||||||
|
### Step 15: Health Checks
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test frontend
|
||||||
|
curl -k https://bakery.example.com
|
||||||
|
|
||||||
|
# Test API
|
||||||
|
curl -k https://api.example.com/health
|
||||||
|
|
||||||
|
# Test database connectivity
|
||||||
|
kubectl exec -n bakery-ia deployment/auth-service -- curl localhost:8000/health
|
||||||
|
|
||||||
|
# Check all services are healthy
|
||||||
|
kubectl get pods -n bakery-ia -o wide
|
||||||
|
|
||||||
|
# Check resource usage
|
||||||
|
kubectl top pods -n bakery-ia
|
||||||
|
kubectl top nodes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 16: Performance Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install hey (HTTP load testing tool)
|
||||||
|
go install github.com/rakyll/hey@latest
|
||||||
|
|
||||||
|
# Test API endpoint
|
||||||
|
hey -n 1000 -c 10 https://api.example.com/health
|
||||||
|
|
||||||
|
# Monitor during load test
|
||||||
|
kubectl top pods -n bakery-ia
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Ongoing Operations
|
||||||
|
|
||||||
|
### Updating the Application
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On local machine
|
||||||
|
# 1. Make code changes
|
||||||
|
# 2. Build and push new images
|
||||||
|
skaffold build -f skaffold-prod.yaml
|
||||||
|
|
||||||
|
# 3. Update image tags in prod kustomization
|
||||||
|
# 4. Apply updates
|
||||||
|
kubectl apply -k infrastructure/kubernetes/overlays/prod
|
||||||
|
|
||||||
|
# 5. Rolling update status
|
||||||
|
kubectl rollout status deployment/auth-service -n bakery-ia
|
||||||
|
```
|
||||||
|
|
||||||
|
### Scaling Services
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Manual scaling
|
||||||
|
kubectl scale deployment auth-service -n bakery-ia --replicas=5
|
||||||
|
|
||||||
|
# Or update in kustomization.yaml and reapply
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Migrations
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run migration job
|
||||||
|
kubectl apply -f infrastructure/kubernetes/base/migrations/auth-migration-job.yaml
|
||||||
|
|
||||||
|
# Check migration status
|
||||||
|
kubectl get jobs -n bakery-ia
|
||||||
|
kubectl logs -n bakery-ia job/auth-migration
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting Common Issues
|
||||||
|
|
||||||
|
### Issue 1: Pods Not Starting
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check pod status
|
||||||
|
kubectl describe pod POD_NAME -n bakery-ia
|
||||||
|
|
||||||
|
# Common causes:
|
||||||
|
# - Image pull errors: Check registry credentials
|
||||||
|
# - Resource limits: Check node resources
|
||||||
|
# - Volume mount issues: Check PVC status
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue 2: Ingress Not Working
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check ingress controller
|
||||||
|
kubectl get pods -n ingress
|
||||||
|
|
||||||
|
# Check ingress resource
|
||||||
|
kubectl describe ingress bakery-ingress-prod -n bakery-ia
|
||||||
|
|
||||||
|
# Check if port 80/443 are open
|
||||||
|
sudo netstat -tlnp | grep -E '(80|443)'
|
||||||
|
|
||||||
|
# Check NGINX logs
|
||||||
|
kubectl logs -n ingress -l app.kubernetes.io/name=ingress-nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue 3: SSL Certificate Issues
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check certificate status
|
||||||
|
kubectl describe certificate bakery-ia-prod-tls-cert -n bakery-ia
|
||||||
|
|
||||||
|
# Check cert-manager logs
|
||||||
|
kubectl logs -n cert-manager deployment/cert-manager
|
||||||
|
|
||||||
|
# Verify DNS
|
||||||
|
dig bakery.example.com
|
||||||
|
|
||||||
|
# Manual certificate request
|
||||||
|
kubectl delete certificate bakery-ia-prod-tls-cert -n bakery-ia
|
||||||
|
kubectl apply -f infrastructure/kubernetes/overlays/prod/prod-ingress.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue 4: Database Connection Errors
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check database pod
|
||||||
|
kubectl get pods -n bakery-ia -l app.kubernetes.io/component=database
|
||||||
|
|
||||||
|
# Check database logs
|
||||||
|
kubectl logs -n bakery-ia deployment/auth-db
|
||||||
|
|
||||||
|
# Test connection from service pod
|
||||||
|
kubectl exec -n bakery-ia deployment/auth-service -- nc -zv auth-db 5432
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue 5: Out of Resources
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check node resources
|
||||||
|
kubectl describe node
|
||||||
|
|
||||||
|
# Check resource requests/limits
|
||||||
|
kubectl describe pod POD_NAME -n bakery-ia
|
||||||
|
|
||||||
|
# Adjust resource limits in prod kustomization or scale down
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Hardening Checklist
|
||||||
|
|
||||||
|
- [ ] Change all default passwords
|
||||||
|
- [ ] Enable pod security policies
|
||||||
|
- [ ] Setup network policies
|
||||||
|
- [ ] Enable audit logging
|
||||||
|
- [ ] Regular security updates
|
||||||
|
- [ ] Implement secrets rotation
|
||||||
|
- [ ] Setup intrusion detection
|
||||||
|
- [ ] Enable RBAC properly
|
||||||
|
- [ ] Regular backup testing
|
||||||
|
- [ ] Implement rate limiting
|
||||||
|
- [ ] Setup DDoS protection
|
||||||
|
- [ ] Enable security scanning
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
### For VPS with Limited Resources
|
||||||
|
|
||||||
|
If your VPS has limited resources, consider:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Reduce replica counts in prod kustomization.yaml
|
||||||
|
replicas:
|
||||||
|
- name: auth-service
|
||||||
|
count: 2 # Instead of 3
|
||||||
|
- name: gateway
|
||||||
|
count: 2 # Instead of 3
|
||||||
|
|
||||||
|
# Adjust resource limits
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi" # Reduced from 512Mi
|
||||||
|
cpu: "100m" # Reduced from 200m
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Optimization
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Tune PostgreSQL for production
|
||||||
|
kubectl exec -n bakery-ia deployment/auth-db -it -- psql -U postgres
|
||||||
|
|
||||||
|
# Inside PostgreSQL:
|
||||||
|
ALTER SYSTEM SET shared_buffers = '256MB';
|
||||||
|
ALTER SYSTEM SET effective_cache_size = '1GB';
|
||||||
|
ALTER SYSTEM SET maintenance_work_mem = '64MB';
|
||||||
|
ALTER SYSTEM SET checkpoint_completion_target = '0.9';
|
||||||
|
ALTER SYSTEM SET wal_buffers = '16MB';
|
||||||
|
ALTER SYSTEM SET default_statistics_target = '100';
|
||||||
|
|
||||||
|
# Restart database pod
|
||||||
|
kubectl rollout restart deployment/auth-db -n bakery-ia
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rollback Procedure
|
||||||
|
|
||||||
|
If something goes wrong:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Rollback deployment
|
||||||
|
kubectl rollout undo deployment/DEPLOYMENT_NAME -n bakery-ia
|
||||||
|
|
||||||
|
# Rollback to specific revision
|
||||||
|
kubectl rollout history deployment/DEPLOYMENT_NAME -n bakery-ia
|
||||||
|
kubectl rollout undo deployment/DEPLOYMENT_NAME --to-revision=2 -n bakery-ia
|
||||||
|
|
||||||
|
# Restore from backup
|
||||||
|
tar -xzf /backups/2024-01-01.tar.gz
|
||||||
|
kubectl exec -n bakery-ia deployment/auth-db -- psql -U postgres < auth-db.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
### Useful Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View all resources
|
||||||
|
kubectl get all -n bakery-ia
|
||||||
|
|
||||||
|
# Get pod logs
|
||||||
|
kubectl logs -f POD_NAME -n bakery-ia
|
||||||
|
|
||||||
|
# Execute command in pod
|
||||||
|
kubectl exec -it POD_NAME -n bakery-ia -- /bin/bash
|
||||||
|
|
||||||
|
# Port forward for debugging
|
||||||
|
kubectl port-forward svc/SERVICE_NAME 8000:8000 -n bakery-ia
|
||||||
|
|
||||||
|
# Check events
|
||||||
|
kubectl get events -n bakery-ia --sort-by='.lastTimestamp'
|
||||||
|
|
||||||
|
# Resource usage
|
||||||
|
kubectl top nodes
|
||||||
|
kubectl top pods -n bakery-ia
|
||||||
|
|
||||||
|
# Restart deployment
|
||||||
|
kubectl rollout restart deployment/DEPLOYMENT_NAME -n bakery-ia
|
||||||
|
|
||||||
|
# Scale deployment
|
||||||
|
kubectl scale deployment/DEPLOYMENT_NAME --replicas=3 -n bakery-ia
|
||||||
|
```
|
||||||
|
|
||||||
|
### Important File Locations on VPS
|
||||||
|
|
||||||
|
```
|
||||||
|
/var/snap/microk8s/current/credentials/ # Kubernetes credentials
|
||||||
|
/var/snap/microk8s/common/default-storage/ # Default storage location
|
||||||
|
~/kubernetes/ # Your manifests
|
||||||
|
/backups/ # Database backups
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps After Migration
|
||||||
|
|
||||||
|
1. **Setup CI/CD Pipeline**
|
||||||
|
- GitHub Actions or GitLab CI
|
||||||
|
- Automated builds and deployments
|
||||||
|
- Automated testing
|
||||||
|
|
||||||
|
2. **Implement Monitoring Dashboards**
|
||||||
|
- Setup Grafana dashboards
|
||||||
|
- Configure alerts
|
||||||
|
- Setup uptime monitoring
|
||||||
|
|
||||||
|
3. **Disaster Recovery Plan**
|
||||||
|
- Document recovery procedures
|
||||||
|
- Test backup restoration
|
||||||
|
- Setup off-site backups
|
||||||
|
|
||||||
|
4. **Cost Optimization**
|
||||||
|
- Monitor resource usage
|
||||||
|
- Right-size deployments
|
||||||
|
- Implement auto-scaling
|
||||||
|
|
||||||
|
5. **Documentation**
|
||||||
|
- Document custom configurations
|
||||||
|
- Create runbooks for common tasks
|
||||||
|
- Train team members
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Support and Resources
|
||||||
|
|
||||||
|
- **MicroK8s Documentation:** https://microk8s.io/docs
|
||||||
|
- **Kubernetes Documentation:** https://kubernetes.io/docs
|
||||||
|
- **cert-manager Documentation:** https://cert-manager.io/docs
|
||||||
|
- **NGINX Ingress:** https://kubernetes.github.io/ingress-nginx
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
This migration moves your application from a local development environment to a production-ready deployment. Remember to:
|
||||||
|
|
||||||
|
- Test thoroughly before going live
|
||||||
|
- Have a rollback plan ready
|
||||||
|
- Monitor closely after deployment
|
||||||
|
- Keep regular backups
|
||||||
|
- Stay updated with security patches
|
||||||
|
|
||||||
|
Good luck with your deployment! 🚀
|
||||||
289
docs/MIGRATION-CHECKLIST.md
Normal file
289
docs/MIGRATION-CHECKLIST.md
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
# Production Migration Quick Checklist
|
||||||
|
|
||||||
|
This is a condensed checklist for migrating from local dev (Kind + Colima) to production (MicroK8s on Clouding.io VPS).
|
||||||
|
|
||||||
|
## Pre-Migration (Do this BEFORE deployment)
|
||||||
|
|
||||||
|
### 1. VPS Setup
|
||||||
|
- [ ] VPS provisioned (Ubuntu 20.04+, 8GB+ RAM, 4+ CPU cores, 100GB+ disk)
|
||||||
|
- [ ] SSH access configured
|
||||||
|
- [ ] Domain name registered
|
||||||
|
- [ ] DNS records configured (A records pointing to VPS IP)
|
||||||
|
|
||||||
|
### 2. MicroK8s Installation
|
||||||
|
```bash
|
||||||
|
# Install MicroK8s
|
||||||
|
sudo snap install microk8s --classic --channel=1.28/stable
|
||||||
|
sudo usermod -a -G microk8s $USER
|
||||||
|
newgrp microk8s
|
||||||
|
|
||||||
|
# Enable required addons
|
||||||
|
microk8s enable dns hostpath-storage ingress cert-manager metrics-server rbac
|
||||||
|
|
||||||
|
# Setup kubectl alias
|
||||||
|
echo "alias kubectl='microk8s kubectl'" >> ~/.bashrc
|
||||||
|
source ~/.bashrc
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Firewall Configuration
|
||||||
|
```bash
|
||||||
|
sudo ufw allow 22/tcp 80/tcp 443/tcp
|
||||||
|
sudo ufw enable
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Configuration Updates
|
||||||
|
|
||||||
|
#### Update Domain Names
|
||||||
|
Edit `infrastructure/kubernetes/overlays/prod/prod-ingress.yaml`:
|
||||||
|
- [ ] Replace `bakery.yourdomain.com` with your actual domain
|
||||||
|
- [ ] Replace `api.yourdomain.com` with your actual API domain
|
||||||
|
- [ ] Replace `monitoring.yourdomain.com` with your actual monitoring domain
|
||||||
|
- [ ] Update CORS origins with your domains
|
||||||
|
- [ ] Update cert-manager email address
|
||||||
|
|
||||||
|
#### Update Production Secrets
|
||||||
|
Edit `infrastructure/kubernetes/base/secrets.yaml`:
|
||||||
|
- [ ] Generate strong passwords: `openssl rand -base64 32`
|
||||||
|
- [ ] Update all database passwords
|
||||||
|
- [ ] Update JWT secrets
|
||||||
|
- [ ] Update API keys
|
||||||
|
- [ ] **NEVER commit real secrets to git!**
|
||||||
|
|
||||||
|
#### Configure Container Registry
|
||||||
|
Choose one option:
|
||||||
|
|
||||||
|
**Option A: Docker Hub (Recommended)**
|
||||||
|
- [ ] Create Docker Hub account
|
||||||
|
- [ ] Login: `docker login`
|
||||||
|
- [ ] Update image names in `infrastructure/kubernetes/overlays/prod/kustomization.yaml`
|
||||||
|
|
||||||
|
**Option B: MicroK8s Registry**
|
||||||
|
- [ ] Enable registry: `microk8s enable registry`
|
||||||
|
- [ ] Configure insecure registry in `/etc/docker/daemon.json`
|
||||||
|
|
||||||
|
### 5. DNS Configuration
|
||||||
|
Point your domains to VPS IP:
|
||||||
|
```
|
||||||
|
Type Host Value TTL
|
||||||
|
A bakery YOUR_VPS_IP 300
|
||||||
|
A api YOUR_VPS_IP 300
|
||||||
|
A monitoring YOUR_VPS_IP 300
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] DNS records configured
|
||||||
|
- [ ] Wait for DNS propagation (test with `nslookup bakery.yourdomain.com`)
|
||||||
|
|
||||||
|
## Deployment Phase
|
||||||
|
|
||||||
|
### 6. Build and Push Images
|
||||||
|
|
||||||
|
**Using provided script:**
|
||||||
|
```bash
|
||||||
|
# Build all images
|
||||||
|
docker-compose build
|
||||||
|
|
||||||
|
# Tag for your registry (Docker Hub example)
|
||||||
|
./scripts/tag-images.sh YOUR_DOCKERHUB_USERNAME
|
||||||
|
|
||||||
|
# Push to registry
|
||||||
|
./scripts/push-images.sh YOUR_DOCKERHUB_USERNAME
|
||||||
|
```
|
||||||
|
|
||||||
|
**Manual:**
|
||||||
|
- [ ] Build all Docker images
|
||||||
|
- [ ] Tag with registry prefix
|
||||||
|
- [ ] Push to container registry
|
||||||
|
|
||||||
|
### 7. Deploy to MicroK8s
|
||||||
|
|
||||||
|
**Using provided script (on VPS):**
|
||||||
|
```bash
|
||||||
|
# Copy deployment script to VPS
|
||||||
|
scp scripts/deploy-production.sh user@YOUR_VPS_IP:~/
|
||||||
|
|
||||||
|
# SSH to VPS
|
||||||
|
ssh user@YOUR_VPS_IP
|
||||||
|
|
||||||
|
# Clone your repository (or copy kubernetes manifests)
|
||||||
|
git clone YOUR_REPO_URL
|
||||||
|
cd bakery_ia
|
||||||
|
|
||||||
|
# Run deployment script
|
||||||
|
./deploy-production.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Manual deployment:**
|
||||||
|
```bash
|
||||||
|
# On VPS
|
||||||
|
kubectl apply -k infrastructure/kubernetes/overlays/prod
|
||||||
|
kubectl get pods -n bakery-ia -w
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8. Verify Deployment
|
||||||
|
|
||||||
|
- [ ] All pods running: `kubectl get pods -n bakery-ia`
|
||||||
|
- [ ] Services created: `kubectl get svc -n bakery-ia`
|
||||||
|
- [ ] Ingress configured: `kubectl get ingress -n bakery-ia`
|
||||||
|
- [ ] PVCs bound: `kubectl get pvc -n bakery-ia`
|
||||||
|
- [ ] Certificates issued: `kubectl get certificate -n bakery-ia`
|
||||||
|
|
||||||
|
### 9. Test Application
|
||||||
|
|
||||||
|
- [ ] Frontend accessible: `curl -k https://bakery.yourdomain.com`
|
||||||
|
- [ ] API responding: `curl -k https://api.yourdomain.com/health`
|
||||||
|
- [ ] SSL certificate valid (Let's Encrypt)
|
||||||
|
- [ ] Login functionality works
|
||||||
|
- [ ] Database connections working
|
||||||
|
- [ ] All microservices healthy
|
||||||
|
|
||||||
|
### 10. Setup Monitoring & Backups
|
||||||
|
|
||||||
|
**Monitoring:**
|
||||||
|
- [ ] Prometheus accessible
|
||||||
|
- [ ] Grafana accessible (if enabled)
|
||||||
|
- [ ] Set up alerts
|
||||||
|
|
||||||
|
**Backups:**
|
||||||
|
```bash
|
||||||
|
# Copy backup script to VPS
|
||||||
|
scp scripts/backup-databases.sh user@YOUR_VPS_IP:~/
|
||||||
|
|
||||||
|
# Setup daily backups
|
||||||
|
crontab -e
|
||||||
|
# Add: 0 2 * * * ~/backup-databases.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Backup script configured
|
||||||
|
- [ ] Test backup restoration
|
||||||
|
- [ ] Set up off-site backup storage
|
||||||
|
|
||||||
|
## Post-Deployment
|
||||||
|
|
||||||
|
### 11. Security Hardening
|
||||||
|
- [ ] Change all default passwords
|
||||||
|
- [ ] Review and update secrets regularly
|
||||||
|
- [ ] Enable pod security policies
|
||||||
|
- [ ] Configure network policies
|
||||||
|
- [ ] Set up monitoring and alerting
|
||||||
|
- [ ] Review firewall rules
|
||||||
|
- [ ] Enable audit logging
|
||||||
|
|
||||||
|
### 12. Performance Tuning
|
||||||
|
- [ ] Monitor resource usage: `kubectl top pods -n bakery-ia`
|
||||||
|
- [ ] Adjust resource limits if needed
|
||||||
|
- [ ] Configure HPA (Horizontal Pod Autoscaling)
|
||||||
|
- [ ] Optimize database settings
|
||||||
|
- [ ] Set up CDN for frontend (optional)
|
||||||
|
|
||||||
|
### 13. Documentation
|
||||||
|
- [ ] Document custom configurations
|
||||||
|
- [ ] Create runbooks for common operations
|
||||||
|
- [ ] Document recovery procedures
|
||||||
|
- [ ] Update team wiki/documentation
|
||||||
|
|
||||||
|
## Key Differences from Local Dev
|
||||||
|
|
||||||
|
| Aspect | Local (Kind) | Production (MicroK8s) |
|
||||||
|
|--------|--------------|----------------------|
|
||||||
|
| Ingress | Custom NGINX | MicroK8s ingress addon |
|
||||||
|
| Storage Class | `standard` | `microk8s-hostpath` |
|
||||||
|
| Image Pull | `Never` (local) | `Always` (from registry) |
|
||||||
|
| SSL Certs | Self-signed | Let's Encrypt |
|
||||||
|
| Domains | localhost | Real domains |
|
||||||
|
| Replicas | 1 per service | 2-3 per service |
|
||||||
|
| Resources | Minimal | Production-grade |
|
||||||
|
| Secrets | Dev secrets | Production secrets |
|
||||||
|
|
||||||
|
## Troubleshooting Quick Reference
|
||||||
|
|
||||||
|
### Pods Not Starting
|
||||||
|
```bash
|
||||||
|
kubectl describe pod POD_NAME -n bakery-ia
|
||||||
|
kubectl logs POD_NAME -n bakery-ia
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ingress Not Working
|
||||||
|
```bash
|
||||||
|
kubectl describe ingress bakery-ingress-prod -n bakery-ia
|
||||||
|
kubectl logs -n ingress -l app.kubernetes.io/name=ingress-nginx
|
||||||
|
sudo netstat -tlnp | grep -E '(80|443)'
|
||||||
|
```
|
||||||
|
|
||||||
|
### SSL Certificate Issues
|
||||||
|
```bash
|
||||||
|
kubectl describe certificate bakery-ia-prod-tls-cert -n bakery-ia
|
||||||
|
kubectl logs -n cert-manager deployment/cert-manager
|
||||||
|
kubectl get challenges -n bakery-ia
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Connection Errors
|
||||||
|
```bash
|
||||||
|
kubectl get pods -n bakery-ia -l app.kubernetes.io/component=database
|
||||||
|
kubectl logs -n bakery-ia deployment/auth-db
|
||||||
|
kubectl exec -n bakery-ia deployment/auth-service -- nc -zv auth-db 5432
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rollback Procedure
|
||||||
|
|
||||||
|
If deployment fails:
|
||||||
|
```bash
|
||||||
|
# Rollback specific deployment
|
||||||
|
kubectl rollout undo deployment/DEPLOYMENT_NAME -n bakery-ia
|
||||||
|
|
||||||
|
# Check rollout history
|
||||||
|
kubectl rollout history deployment/DEPLOYMENT_NAME -n bakery-ia
|
||||||
|
|
||||||
|
# Rollback to specific revision
|
||||||
|
kubectl rollout undo deployment/DEPLOYMENT_NAME --to-revision=2 -n bakery-ia
|
||||||
|
```
|
||||||
|
|
||||||
|
## Important Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View all resources
|
||||||
|
kubectl get all -n bakery-ia
|
||||||
|
|
||||||
|
# Check logs
|
||||||
|
kubectl logs -f deployment/gateway -n bakery-ia
|
||||||
|
|
||||||
|
# Check events
|
||||||
|
kubectl get events -n bakery-ia --sort-by='.lastTimestamp'
|
||||||
|
|
||||||
|
# Resource usage
|
||||||
|
kubectl top nodes
|
||||||
|
kubectl top pods -n bakery-ia
|
||||||
|
|
||||||
|
# Scale deployment
|
||||||
|
kubectl scale deployment/gateway --replicas=5 -n bakery-ia
|
||||||
|
|
||||||
|
# Restart deployment
|
||||||
|
kubectl rollout restart deployment/gateway -n bakery-ia
|
||||||
|
|
||||||
|
# Execute in pod
|
||||||
|
kubectl exec -it deployment/gateway -n bakery-ia -- /bin/bash
|
||||||
|
```
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
Deployment is successful when:
|
||||||
|
- [ ] All pods are in Running state
|
||||||
|
- [ ] Application accessible via HTTPS
|
||||||
|
- [ ] SSL certificate is valid and auto-renewing
|
||||||
|
- [ ] Database migrations completed
|
||||||
|
- [ ] All health checks passing
|
||||||
|
- [ ] Monitoring and alerts configured
|
||||||
|
- [ ] Backups running successfully
|
||||||
|
- [ ] Team can access and operate the system
|
||||||
|
- [ ] Performance meets requirements
|
||||||
|
- [ ] No critical security issues
|
||||||
|
|
||||||
|
## Support Resources
|
||||||
|
|
||||||
|
- **Full Migration Guide:** See `docs/K8S-MIGRATION-GUIDE.md`
|
||||||
|
- **MicroK8s Docs:** https://microk8s.io/docs
|
||||||
|
- **Kubernetes Docs:** https://kubernetes.io/docs
|
||||||
|
- **Cert-Manager Docs:** https://cert-manager.io/docs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Note:** This is a condensed checklist. Refer to the full migration guide for detailed explanations and troubleshooting.
|
||||||
275
docs/MIGRATION-SUMMARY.md
Normal file
275
docs/MIGRATION-SUMMARY.md
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
# Migration Summary: Local to Production
|
||||||
|
|
||||||
|
## Quick Overview
|
||||||
|
|
||||||
|
You're migrating from **Kind/Colima (macOS)** to **MicroK8s (Ubuntu VPS)**.
|
||||||
|
|
||||||
|
Good news: **Most of your Kubernetes configuration is already production-ready!** Your infrastructure is well-structured with proper overlays for dev and prod environments.
|
||||||
|
|
||||||
|
## What You Already Have ✅
|
||||||
|
|
||||||
|
Your configuration already includes:
|
||||||
|
- ✅ Separate dev and prod overlays
|
||||||
|
- ✅ Production ingress configuration
|
||||||
|
- ✅ Production ConfigMap with proper settings
|
||||||
|
- ✅ Resource scaling (2-3 replicas per service in prod)
|
||||||
|
- ✅ HorizontalPodAutoscalers for key services
|
||||||
|
- ✅ Security configurations (TLS, secrets, etc.)
|
||||||
|
- ✅ Database configurations
|
||||||
|
- ✅ Monitoring components (Prometheus, Grafana)
|
||||||
|
|
||||||
|
## What Needs to Change 🔧
|
||||||
|
|
||||||
|
### Critical Changes (Must Do)
|
||||||
|
|
||||||
|
1. **Domain Names** - Update in `infrastructure/kubernetes/overlays/prod/prod-ingress.yaml`:
|
||||||
|
- Replace `bakery.yourdomain.com` → your actual domain
|
||||||
|
- Replace `api.yourdomain.com` → your actual API domain
|
||||||
|
- Replace `monitoring.yourdomain.com` → your actual monitoring domain
|
||||||
|
- Update CORS origins
|
||||||
|
- Update cert-manager email
|
||||||
|
|
||||||
|
2. **Storage Class** - Already patched in `storage-patch.yaml`:
|
||||||
|
- `standard` → `microk8s-hostpath`
|
||||||
|
|
||||||
|
3. **Production Secrets** - Update in `infrastructure/kubernetes/base/secrets.yaml`:
|
||||||
|
- Generate strong passwords
|
||||||
|
- Update all sensitive values
|
||||||
|
- **Never commit real secrets to git!**
|
||||||
|
|
||||||
|
4. **Container Registry** - Choose and configure:
|
||||||
|
- Docker Hub (easiest)
|
||||||
|
- GitHub Container Registry
|
||||||
|
- MicroK8s built-in registry
|
||||||
|
- Update image references in prod kustomization
|
||||||
|
|
||||||
|
### Setup on VPS
|
||||||
|
|
||||||
|
1. **Install MicroK8s**:
|
||||||
|
```bash
|
||||||
|
sudo snap install microk8s --classic
|
||||||
|
microk8s enable dns hostpath-storage ingress cert-manager metrics-server
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Configure Firewall**:
|
||||||
|
```bash
|
||||||
|
sudo ufw allow 22/tcp 80/tcp 443/tcp
|
||||||
|
sudo ufw enable
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **DNS Configuration**:
|
||||||
|
Point your domains to VPS IP address
|
||||||
|
|
||||||
|
## File Changes Summary
|
||||||
|
|
||||||
|
### New Files Created
|
||||||
|
```
|
||||||
|
docs/K8S-MIGRATION-GUIDE.md # Comprehensive guide
|
||||||
|
docs/MIGRATION-CHECKLIST.md # Quick checklist
|
||||||
|
docs/MIGRATION-SUMMARY.md # This file
|
||||||
|
infrastructure/kubernetes/overlays/prod/storage-patch.yaml # Storage fix
|
||||||
|
scripts/deploy-production.sh # Deployment helper
|
||||||
|
scripts/tag-and-push-images.sh # Image management
|
||||||
|
scripts/backup-databases.sh # Backup script
|
||||||
|
```
|
||||||
|
|
||||||
|
### Files to Modify
|
||||||
|
|
||||||
|
1. **infrastructure/kubernetes/overlays/prod/prod-ingress.yaml**
|
||||||
|
- Update domain names (3 places)
|
||||||
|
- Update CORS origins
|
||||||
|
- Update cert-manager email
|
||||||
|
|
||||||
|
2. **infrastructure/kubernetes/base/secrets.yaml**
|
||||||
|
- Update all secrets with production values
|
||||||
|
- Generate strong passwords
|
||||||
|
|
||||||
|
3. **infrastructure/kubernetes/overlays/prod/kustomization.yaml**
|
||||||
|
- Update image registry prefixes if using external registry
|
||||||
|
- Already includes storage patch
|
||||||
|
|
||||||
|
## Key Differences Table
|
||||||
|
|
||||||
|
| Feature | Local (Kind) | Production (MicroK8s) | Action Required |
|
||||||
|
|---------|--------------|----------------------|-----------------|
|
||||||
|
| **Cluster** | Kind in Docker | Native MicroK8s | Install MicroK8s |
|
||||||
|
| **Ingress** | Custom NGINX | MicroK8s addon | Enable addon |
|
||||||
|
| **Storage** | `standard` | `microk8s-hostpath` | Use storage patch ✅ |
|
||||||
|
| **Images** | Local build | Registry push | Setup registry |
|
||||||
|
| **Domains** | localhost | Real domains | Update ingress |
|
||||||
|
| **SSL** | Self-signed | Let's Encrypt | Configure email |
|
||||||
|
| **Replicas** | 1 per service | 2-3 per service | Already configured ✅ |
|
||||||
|
| **Resources** | Minimal | Production limits | Already configured ✅ |
|
||||||
|
| **Secrets** | Dev secrets | Production secrets | Update values |
|
||||||
|
| **Monitoring** | Optional | Recommended | Already configured ✅ |
|
||||||
|
|
||||||
|
## Deployment Steps (Quick Version)
|
||||||
|
|
||||||
|
### Phase 1: Prepare (On Local Machine)
|
||||||
|
```bash
|
||||||
|
# 1. Update domain names
|
||||||
|
vim infrastructure/kubernetes/overlays/prod/prod-ingress.yaml
|
||||||
|
|
||||||
|
# 2. Update secrets (use strong passwords!)
|
||||||
|
vim infrastructure/kubernetes/base/secrets.yaml
|
||||||
|
|
||||||
|
# 3. Build and push images
|
||||||
|
docker login # or setup your registry
|
||||||
|
./scripts/tag-and-push-images.sh YOUR_USERNAME/bakery latest
|
||||||
|
|
||||||
|
# 4. Update image references if using external registry
|
||||||
|
vim infrastructure/kubernetes/overlays/prod/kustomization.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: Setup VPS
|
||||||
|
```bash
|
||||||
|
# SSH to VPS
|
||||||
|
ssh user@YOUR_VPS_IP
|
||||||
|
|
||||||
|
# Install MicroK8s
|
||||||
|
sudo snap install microk8s --classic --channel=1.28/stable
|
||||||
|
sudo usermod -a -G microk8s $USER
|
||||||
|
newgrp microk8s
|
||||||
|
|
||||||
|
# Enable addons
|
||||||
|
microk8s enable dns hostpath-storage ingress cert-manager metrics-server rbac
|
||||||
|
|
||||||
|
# Setup kubectl
|
||||||
|
echo "alias kubectl='microk8s kubectl'" >> ~/.bashrc
|
||||||
|
source ~/.bashrc
|
||||||
|
|
||||||
|
# Configure firewall
|
||||||
|
sudo ufw allow 22/tcp 80/tcp 443/tcp
|
||||||
|
sudo ufw enable
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 3: Deploy
|
||||||
|
```bash
|
||||||
|
# On VPS - clone your repo or copy manifests
|
||||||
|
git clone YOUR_REPO_URL
|
||||||
|
cd bakery_ia
|
||||||
|
|
||||||
|
# Deploy
|
||||||
|
kubectl apply -k infrastructure/kubernetes/overlays/prod
|
||||||
|
|
||||||
|
# Monitor
|
||||||
|
kubectl get pods -n bakery-ia -w
|
||||||
|
|
||||||
|
# Check everything
|
||||||
|
kubectl get all,ingress,pvc,certificate -n bakery-ia
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 4: Verify
|
||||||
|
```bash
|
||||||
|
# Test access
|
||||||
|
curl -k https://bakery.yourdomain.com
|
||||||
|
curl -k https://api.yourdomain.com/health
|
||||||
|
|
||||||
|
# Check SSL
|
||||||
|
kubectl get certificate -n bakery-ia
|
||||||
|
|
||||||
|
# Check logs
|
||||||
|
kubectl logs -n bakery-ia deployment/gateway
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Pitfalls to Avoid
|
||||||
|
|
||||||
|
1. **Forgot to update domain names** → Ingress won't work
|
||||||
|
2. **Using dev secrets in production** → Security risk
|
||||||
|
3. **DNS not propagated** → SSL certificate won't issue
|
||||||
|
4. **Firewall blocking ports 80/443** → Can't access application
|
||||||
|
5. **Images not in registry** → Pods fail with ImagePullBackOff
|
||||||
|
6. **Wrong storage class** → PVCs stay pending
|
||||||
|
7. **Insufficient VPS resources** → Pods get evicted
|
||||||
|
|
||||||
|
## Resource Requirements
|
||||||
|
|
||||||
|
### Minimum VPS Specs
|
||||||
|
- **CPU**: 4 cores (6+ recommended)
|
||||||
|
- **RAM**: 8GB (16GB+ recommended)
|
||||||
|
- **Disk**: 100GB (SSD preferred)
|
||||||
|
- **Network**: Public IP with ports 80/443 open
|
||||||
|
|
||||||
|
### Resource Usage Estimates
|
||||||
|
With current prod configuration:
|
||||||
|
- ~20-30 pods running
|
||||||
|
- ~4-6GB memory used
|
||||||
|
- ~2-3 CPU cores used
|
||||||
|
- ~10-20GB disk for databases
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
|
||||||
|
1. **Local Testing** (Before deploying):
|
||||||
|
- Build all images successfully
|
||||||
|
- Test with `skaffold build -f skaffold-prod.yaml`
|
||||||
|
- Validate kustomization: `kubectl kustomize infrastructure/kubernetes/overlays/prod`
|
||||||
|
|
||||||
|
2. **Staging Deploy** (First deploy):
|
||||||
|
- Deploy to staging/test environment first
|
||||||
|
- Test all functionality
|
||||||
|
- Verify SSL certificates
|
||||||
|
- Load test
|
||||||
|
|
||||||
|
3. **Production Deploy**:
|
||||||
|
- Deploy during low-traffic window
|
||||||
|
- Have rollback plan ready
|
||||||
|
- Monitor closely for first 24 hours
|
||||||
|
|
||||||
|
## Rollback Plan
|
||||||
|
|
||||||
|
If deployment fails:
|
||||||
|
```bash
|
||||||
|
# Quick rollback
|
||||||
|
kubectl rollout undo deployment/DEPLOYMENT_NAME -n bakery-ia
|
||||||
|
|
||||||
|
# Or delete and redeploy previous version
|
||||||
|
kubectl delete -k infrastructure/kubernetes/overlays/prod
|
||||||
|
# Deploy previous version
|
||||||
|
```
|
||||||
|
|
||||||
|
Always have:
|
||||||
|
- Previous version images tagged
|
||||||
|
- Database backups
|
||||||
|
- Configuration backups
|
||||||
|
|
||||||
|
## Post-Deployment Checklist
|
||||||
|
|
||||||
|
- [ ] Application accessible via HTTPS
|
||||||
|
- [ ] SSL certificates valid
|
||||||
|
- [ ] All services healthy
|
||||||
|
- [ ] Database migrations completed
|
||||||
|
- [ ] Monitoring configured
|
||||||
|
- [ ] Backups scheduled
|
||||||
|
- [ ] Alerts configured
|
||||||
|
- [ ] Team has access
|
||||||
|
- [ ] Documentation updated
|
||||||
|
- [ ] Runbooks created
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
- **Full Guide**: See `docs/K8S-MIGRATION-GUIDE.md`
|
||||||
|
- **Checklist**: See `docs/MIGRATION-CHECKLIST.md`
|
||||||
|
- **MicroK8s**: https://microk8s.io/docs
|
||||||
|
- **Kubernetes**: https://kubernetes.io/docs
|
||||||
|
|
||||||
|
## Estimated Timeline
|
||||||
|
|
||||||
|
- **VPS Setup**: 30-60 minutes
|
||||||
|
- **Configuration Updates**: 30-60 minutes
|
||||||
|
- **Image Build & Push**: 20-40 minutes
|
||||||
|
- **Deployment**: 15-30 minutes
|
||||||
|
- **Verification & Testing**: 30-60 minutes
|
||||||
|
- **Total**: 2-4 hours (first time)
|
||||||
|
|
||||||
|
With experience: ~1 hour for updates/redeployments
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. Read through the full migration guide
|
||||||
|
2. Provision your VPS
|
||||||
|
3. Update configuration files
|
||||||
|
4. Test locally first
|
||||||
|
5. Deploy to production
|
||||||
|
6. Monitor and optimize
|
||||||
|
|
||||||
|
Good luck! 🚀
|
||||||
51
infrastructure/kubernetes/overlays/dev/dev-certificate.yaml
Normal file
51
infrastructure/kubernetes/overlays/dev/dev-certificate.yaml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: bakery-dev-tls-cert
|
||||||
|
namespace: bakery-ia
|
||||||
|
spec:
|
||||||
|
# Self-signed certificate for local development
|
||||||
|
secretName: bakery-dev-tls-cert
|
||||||
|
|
||||||
|
# Certificate duration
|
||||||
|
duration: 2160h # 90 days
|
||||||
|
renewBefore: 360h # 15 days
|
||||||
|
|
||||||
|
# Subject configuration
|
||||||
|
subject:
|
||||||
|
organizations:
|
||||||
|
- Bakery IA Development
|
||||||
|
|
||||||
|
# Common name
|
||||||
|
commonName: localhost
|
||||||
|
|
||||||
|
# DNS names this certificate is valid for
|
||||||
|
dnsNames:
|
||||||
|
- localhost
|
||||||
|
- bakery-ia.local
|
||||||
|
- api.bakery-ia.local
|
||||||
|
- "*.bakery-ia.local"
|
||||||
|
|
||||||
|
# IP addresses (for localhost)
|
||||||
|
ipAddresses:
|
||||||
|
- 127.0.0.1
|
||||||
|
- ::1
|
||||||
|
|
||||||
|
# Use self-signed issuer for development
|
||||||
|
issuerRef:
|
||||||
|
name: selfsigned-issuer
|
||||||
|
kind: ClusterIssuer
|
||||||
|
group: cert-manager.io
|
||||||
|
|
||||||
|
# Private key configuration
|
||||||
|
privateKey:
|
||||||
|
algorithm: RSA
|
||||||
|
encoding: PKCS1
|
||||||
|
size: 2048
|
||||||
|
|
||||||
|
# Usages
|
||||||
|
usages:
|
||||||
|
- server auth
|
||||||
|
- client auth
|
||||||
|
- digital signature
|
||||||
|
- key encipherment
|
||||||
@@ -4,15 +4,21 @@ metadata:
|
|||||||
name: bakery-ingress
|
name: bakery-ingress
|
||||||
namespace: bakery-ia
|
namespace: bakery-ia
|
||||||
annotations:
|
annotations:
|
||||||
nginx.ingress.kubernetes.io/ssl-redirect: "false"
|
# Dev-Prod Parity: Enable HTTPS by default
|
||||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
|
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||||
nginx.ingress.kubernetes.io/cors-allow-origin: "*"
|
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||||
|
|
||||||
|
# Dev-Prod Parity: Use specific origins instead of wildcard to catch CORS issues early
|
||||||
|
# HTTPS origins first (preferred), with HTTP fallback for development flexibility
|
||||||
|
nginx.ingress.kubernetes.io/cors-allow-origin: "https://localhost,https://localhost:3000,https://localhost:3001,https://127.0.0.1,https://127.0.0.1:3000,https://127.0.0.1:3001,https://bakery-ia.local,http://localhost,http://localhost:3000,http://localhost:3001,http://127.0.0.1,http://127.0.0.1:3000"
|
||||||
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS, PATCH"
|
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS, PATCH"
|
||||||
nginx.ingress.kubernetes.io/cors-allow-headers: "Content-Type, Authorization, X-Requested-With, Accept, Origin, Cache-Control"
|
nginx.ingress.kubernetes.io/cors-allow-headers: "Content-Type, Authorization, X-Requested-With, Accept, Origin, Cache-Control"
|
||||||
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
|
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
|
||||||
nginx.ingress.kubernetes.io/enable-cors: "true"
|
nginx.ingress.kubernetes.io/enable-cors: "true"
|
||||||
|
|
||||||
# Prevent nginx from redirecting to add trailing slashes
|
# Prevent nginx from redirecting to add trailing slashes
|
||||||
nginx.ingress.kubernetes.io/use-regex: "true"
|
nginx.ingress.kubernetes.io/use-regex: "true"
|
||||||
|
|
||||||
# Development, SSE and WebSocket annotations
|
# Development, SSE and WebSocket annotations
|
||||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||||
nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
|
nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
|
||||||
@@ -21,10 +27,16 @@ metadata:
|
|||||||
nginx.ingress.kubernetes.io/proxy-buffering: "off"
|
nginx.ingress.kubernetes.io/proxy-buffering: "off"
|
||||||
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
|
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
|
||||||
nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "3600"
|
nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "3600"
|
||||||
|
|
||||||
# WebSocket upgrade support
|
# WebSocket upgrade support
|
||||||
nginx.ingress.kubernetes.io/websocket-services: "gateway-service"
|
nginx.ingress.kubernetes.io/websocket-services: "gateway-service"
|
||||||
spec:
|
spec:
|
||||||
ingressClassName: nginx
|
ingressClassName: nginx
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- localhost
|
||||||
|
- bakery-ia.local
|
||||||
|
secretName: bakery-dev-tls-cert
|
||||||
rules:
|
rules:
|
||||||
- host: localhost
|
- host: localhost
|
||||||
http:
|
http:
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ resources:
|
|||||||
# Monitoring disabled for dev to save resources
|
# Monitoring disabled for dev to save resources
|
||||||
# - ../../base/components/monitoring
|
# - ../../base/components/monitoring
|
||||||
- dev-ingress.yaml
|
- dev-ingress.yaml
|
||||||
|
# Dev-Prod Parity: Enable HTTPS with self-signed certificates
|
||||||
|
- dev-certificate.yaml
|
||||||
|
- ../../base/components/cert-manager/cluster-issuer-staging.yaml
|
||||||
|
|
||||||
# Exclude nominatim from dev to save resources
|
# Exclude nominatim from dev to save resources
|
||||||
# Using scale to 0 for StatefulSet to prevent pod creation
|
# Using scale to 0 for StatefulSet to prevent pod creation
|
||||||
@@ -71,7 +74,10 @@ patches:
|
|||||||
value: "sandbox"
|
value: "sandbox"
|
||||||
- op: replace
|
- op: replace
|
||||||
path: /data/RATE_LIMIT_ENABLED
|
path: /data/RATE_LIMIT_ENABLED
|
||||||
value: "false"
|
value: "true" # Changed from false for dev-prod parity
|
||||||
|
- op: add
|
||||||
|
path: /data/RATE_LIMIT_PER_MINUTE
|
||||||
|
value: "1000" # High limit for development (prod: 60)
|
||||||
- op: replace
|
- op: replace
|
||||||
path: /data/DB_FORCE_RECREATE
|
path: /data/DB_FORCE_RECREATE
|
||||||
value: "false"
|
value: "false"
|
||||||
@@ -653,8 +659,10 @@ images:
|
|||||||
newTag: dev
|
newTag: dev
|
||||||
|
|
||||||
replicas:
|
replicas:
|
||||||
|
# Dev-Prod Parity: Run 2 replicas of critical services
|
||||||
|
# This helps catch load balancing, session management, and race condition issues
|
||||||
- name: auth-service
|
- name: auth-service
|
||||||
count: 1
|
count: 2 # Increased from 1 for dev-prod parity
|
||||||
- name: tenant-service
|
- name: tenant-service
|
||||||
count: 1
|
count: 1
|
||||||
- name: training-service
|
- name: training-service
|
||||||
@@ -686,6 +694,6 @@ replicas:
|
|||||||
- name: demo-session-service
|
- name: demo-session-service
|
||||||
count: 1
|
count: 1
|
||||||
- name: gateway
|
- name: gateway
|
||||||
count: 1
|
count: 2 # Increased from 1 for dev-prod parity
|
||||||
- name: frontend
|
- name: frontend
|
||||||
count: 1
|
count: 1
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ resources:
|
|||||||
- prod-ingress.yaml
|
- prod-ingress.yaml
|
||||||
- prod-configmap.yaml
|
- prod-configmap.yaml
|
||||||
|
|
||||||
|
patchesStrategicMerge:
|
||||||
|
- storage-patch.yaml
|
||||||
|
|
||||||
labels:
|
labels:
|
||||||
- includeSelectors: true
|
- includeSelectors: true
|
||||||
pairs:
|
pairs:
|
||||||
|
|||||||
12
infrastructure/kubernetes/overlays/prod/storage-patch.yaml
Normal file
12
infrastructure/kubernetes/overlays/prod/storage-patch.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: model-storage
|
||||||
|
namespace: bakery-ia
|
||||||
|
spec:
|
||||||
|
storageClassName: microk8s-hostpath # MicroK8s storage class
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 50Gi # Increased for production (adjust based on your needs)
|
||||||
161
scripts/backup-databases.sh
Executable file
161
scripts/backup-databases.sh
Executable file
@@ -0,0 +1,161 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Database Backup Script for Bakery IA
|
||||||
|
# This script backs up all PostgreSQL databases in the Kubernetes cluster
|
||||||
|
# Designed to run on the VPS via cron
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
BACKUP_ROOT="/backups"
|
||||||
|
NAMESPACE="bakery-ia"
|
||||||
|
RETENTION_DAYS=7
|
||||||
|
DATE=$(date +%Y-%m-%d_%H-%M-%S)
|
||||||
|
BACKUP_DIR="${BACKUP_ROOT}/${DATE}"
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
log() {
|
||||||
|
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_success() {
|
||||||
|
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] SUCCESS: $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warning() {
|
||||||
|
echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create backup directory
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
log "Starting database backup to $BACKUP_DIR"
|
||||||
|
|
||||||
|
# Get all database pods
|
||||||
|
DB_PODS=$(kubectl get pods -n "$NAMESPACE" -l app.kubernetes.io/component=database -o jsonpath='{.items[*].metadata.name}')
|
||||||
|
|
||||||
|
if [ -z "$DB_PODS" ]; then
|
||||||
|
log_error "No database pods found in namespace $NAMESPACE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Found database pods: $DB_PODS"
|
||||||
|
|
||||||
|
# Backup counter
|
||||||
|
SUCCESS_COUNT=0
|
||||||
|
FAILED_COUNT=0
|
||||||
|
FAILED_DBS=()
|
||||||
|
|
||||||
|
# Backup each database
|
||||||
|
for pod in $DB_PODS; do
|
||||||
|
log "Backing up database: $pod"
|
||||||
|
|
||||||
|
# Get database name from pod labels
|
||||||
|
DB_NAME=$(kubectl get pod "$pod" -n "$NAMESPACE" -o jsonpath='{.metadata.labels.app\.kubernetes\.io/name}')
|
||||||
|
|
||||||
|
if [ -z "$DB_NAME" ]; then
|
||||||
|
DB_NAME=$pod
|
||||||
|
fi
|
||||||
|
|
||||||
|
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}.sql"
|
||||||
|
|
||||||
|
# Perform backup
|
||||||
|
if kubectl exec -n "$NAMESPACE" "$pod" -- pg_dumpall -U postgres > "$BACKUP_FILE" 2>/dev/null; then
|
||||||
|
FILE_SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
|
||||||
|
log_success "Backed up $DB_NAME ($FILE_SIZE)"
|
||||||
|
((SUCCESS_COUNT++))
|
||||||
|
else
|
||||||
|
log_error "Failed to backup $DB_NAME"
|
||||||
|
FAILED_DBS+=("$DB_NAME")
|
||||||
|
((FAILED_COUNT++))
|
||||||
|
rm -f "$BACKUP_FILE" # Remove partial backup
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Also backup Redis if present
|
||||||
|
REDIS_POD=$(kubectl get pods -n "$NAMESPACE" -l app.kubernetes.io/name=redis -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
if [ -n "$REDIS_POD" ]; then
|
||||||
|
log "Backing up Redis: $REDIS_POD"
|
||||||
|
REDIS_BACKUP="${BACKUP_DIR}/redis.rdb"
|
||||||
|
|
||||||
|
if kubectl exec -n "$NAMESPACE" "$REDIS_POD" -- redis-cli --rdb /tmp/dump.rdb SAVE > /dev/null 2>&1 && \
|
||||||
|
kubectl cp "$NAMESPACE/$REDIS_POD:/tmp/dump.rdb" "$REDIS_BACKUP" > /dev/null 2>&1; then
|
||||||
|
FILE_SIZE=$(du -h "$REDIS_BACKUP" | cut -f1)
|
||||||
|
log_success "Backed up Redis ($FILE_SIZE)"
|
||||||
|
((SUCCESS_COUNT++))
|
||||||
|
else
|
||||||
|
log_warning "Failed to backup Redis (non-critical)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create backup metadata
|
||||||
|
cat > "${BACKUP_DIR}/backup-info.txt" <<EOF
|
||||||
|
Backup Date: $(date)
|
||||||
|
Namespace: $NAMESPACE
|
||||||
|
Success Count: $SUCCESS_COUNT
|
||||||
|
Failed Count: $FAILED_COUNT
|
||||||
|
Failed Databases: ${FAILED_DBS[@]:-none}
|
||||||
|
Kubernetes Cluster: $(kubectl config current-context)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Compress backup
|
||||||
|
log "Compressing backup..."
|
||||||
|
COMPRESSED_FILE="${BACKUP_ROOT}/backup-${DATE}.tar.gz"
|
||||||
|
|
||||||
|
if tar -czf "$COMPRESSED_FILE" -C "$BACKUP_ROOT" "$(basename "$BACKUP_DIR")"; then
|
||||||
|
COMPRESSED_SIZE=$(du -h "$COMPRESSED_FILE" | cut -f1)
|
||||||
|
log_success "Backup compressed: $COMPRESSED_FILE ($COMPRESSED_SIZE)"
|
||||||
|
|
||||||
|
# Remove uncompressed backup
|
||||||
|
rm -rf "$BACKUP_DIR"
|
||||||
|
else
|
||||||
|
log_error "Failed to compress backup"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Cleanup old backups
|
||||||
|
log "Cleaning up backups older than $RETENTION_DAYS days..."
|
||||||
|
DELETED_COUNT=$(find "$BACKUP_ROOT" -name "backup-*.tar.gz" -mtime "+$RETENTION_DAYS" -delete -print | wc -l)
|
||||||
|
|
||||||
|
if [ "$DELETED_COUNT" -gt 0 ]; then
|
||||||
|
log "Deleted $DELETED_COUNT old backup(s)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Calculate total backup size
|
||||||
|
TOTAL_SIZE=$(du -sh "$BACKUP_ROOT" | cut -f1)
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
echo ""
|
||||||
|
log "========================================="
|
||||||
|
log "Backup Summary"
|
||||||
|
log "========================================="
|
||||||
|
log "Successful backups: $SUCCESS_COUNT"
|
||||||
|
log "Failed backups: $FAILED_COUNT"
|
||||||
|
log "Backup location: $COMPRESSED_FILE"
|
||||||
|
log "Backup size: $COMPRESSED_SIZE"
|
||||||
|
log "Total backup storage: $TOTAL_SIZE"
|
||||||
|
log "========================================="
|
||||||
|
|
||||||
|
if [ $FAILED_COUNT -gt 0 ]; then
|
||||||
|
log_error "Some backups failed: ${FAILED_DBS[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_success "Backup completed successfully!"
|
||||||
|
|
||||||
|
# Optional: Send notification
|
||||||
|
# Uncomment and configure if you want email/slack notifications
|
||||||
|
# send_notification "Bakery IA Backup Completed" "Successfully backed up $SUCCESS_COUNT databases. Size: $COMPRESSED_SIZE"
|
||||||
|
|
||||||
|
exit 0
|
||||||
190
scripts/deploy-production.sh
Executable file
190
scripts/deploy-production.sh
Executable file
@@ -0,0 +1,190 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Production Deployment Script for MicroK8s
|
||||||
|
# This script helps deploy Bakery IA to a MicroK8s cluster
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}Bakery IA - Production Deployment${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
NAMESPACE="bakery-ia"
|
||||||
|
KUSTOMIZE_PATH="infrastructure/kubernetes/overlays/prod"
|
||||||
|
|
||||||
|
# Check if kubectl is available
|
||||||
|
if ! command -v kubectl &> /dev/null; then
|
||||||
|
echo -e "${RED}Error: kubectl not found. Please install kubectl or setup microk8s alias.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Function to check if cluster is accessible
|
||||||
|
check_cluster() {
|
||||||
|
echo -e "${YELLOW}Checking cluster connectivity...${NC}"
|
||||||
|
if ! kubectl cluster-info &> /dev/null; then
|
||||||
|
echo -e "${RED}Error: Cannot connect to Kubernetes cluster.${NC}"
|
||||||
|
echo "Please ensure your kubeconfig is set correctly."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo -e "${GREEN}✓ Cluster connection successful${NC}"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check required addons
|
||||||
|
check_addons() {
|
||||||
|
echo -e "${YELLOW}Checking required MicroK8s addons...${NC}"
|
||||||
|
|
||||||
|
# Check if this is MicroK8s
|
||||||
|
if command -v microk8s &> /dev/null; then
|
||||||
|
REQUIRED_ADDONS=("dns" "hostpath-storage" "ingress" "cert-manager" "metrics-server")
|
||||||
|
|
||||||
|
for addon in "${REQUIRED_ADDONS[@]}"; do
|
||||||
|
if microk8s status | grep -q "$addon: enabled"; then
|
||||||
|
echo -e "${GREEN}✓ $addon enabled${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}✗ $addon not enabled${NC}"
|
||||||
|
echo -e "${YELLOW}Enable with: microk8s enable $addon${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}Not running on MicroK8s. Skipping addon check.${NC}"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to create namespace
|
||||||
|
create_namespace() {
|
||||||
|
echo -e "${YELLOW}Creating namespace...${NC}"
|
||||||
|
if kubectl get namespace $NAMESPACE &> /dev/null; then
|
||||||
|
echo -e "${GREEN}✓ Namespace $NAMESPACE already exists${NC}"
|
||||||
|
else
|
||||||
|
kubectl create namespace $NAMESPACE
|
||||||
|
echo -e "${GREEN}✓ Namespace $NAMESPACE created${NC}"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to apply secrets
|
||||||
|
apply_secrets() {
|
||||||
|
echo -e "${YELLOW}Applying secrets...${NC}"
|
||||||
|
echo -e "${RED}WARNING: Ensure production secrets are updated before deployment!${NC}"
|
||||||
|
read -p "Have you updated production secrets? (yes/no): " confirm
|
||||||
|
|
||||||
|
if [ "$confirm" != "yes" ]; then
|
||||||
|
echo -e "${RED}Deployment cancelled. Please update secrets first.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
kubectl apply -f infrastructure/kubernetes/base/secrets.yaml
|
||||||
|
kubectl apply -f infrastructure/kubernetes/base/secrets/postgres-tls-secret.yaml
|
||||||
|
kubectl apply -f infrastructure/kubernetes/base/secrets/redis-tls-secret.yaml
|
||||||
|
kubectl apply -f infrastructure/kubernetes/base/secrets/demo-internal-api-key-secret.yaml
|
||||||
|
echo -e "${GREEN}✓ Secrets applied${NC}"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to apply kustomization
|
||||||
|
deploy_application() {
|
||||||
|
echo -e "${YELLOW}Deploying application...${NC}"
|
||||||
|
kubectl apply -k $KUSTOMIZE_PATH
|
||||||
|
echo -e "${GREEN}✓ Application deployed${NC}"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to wait for deployments
|
||||||
|
wait_for_deployments() {
|
||||||
|
echo -e "${YELLOW}Waiting for deployments to be ready...${NC}"
|
||||||
|
echo "This may take several minutes..."
|
||||||
|
|
||||||
|
# Wait for all deployments
|
||||||
|
kubectl wait --for=condition=available --timeout=600s \
|
||||||
|
deployment --all -n $NAMESPACE
|
||||||
|
|
||||||
|
echo -e "${GREEN}✓ All deployments are ready${NC}"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check deployment status
|
||||||
|
check_status() {
|
||||||
|
echo -e "${YELLOW}Deployment Status:${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Pods:"
|
||||||
|
kubectl get pods -n $NAMESPACE
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Services:"
|
||||||
|
kubectl get svc -n $NAMESPACE
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Ingress:"
|
||||||
|
kubectl get ingress -n $NAMESPACE
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Persistent Volume Claims:"
|
||||||
|
kubectl get pvc -n $NAMESPACE
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Certificates:"
|
||||||
|
kubectl get certificate -n $NAMESPACE
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to show access information
|
||||||
|
show_access_info() {
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}Deployment Complete!${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Access your application at:"
|
||||||
|
|
||||||
|
# Get ingress hosts
|
||||||
|
HOSTS=$(kubectl get ingress bakery-ingress-prod -n $NAMESPACE -o jsonpath='{.spec.rules[*].host}' 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
if [ -n "$HOSTS" ]; then
|
||||||
|
for host in $HOSTS; do
|
||||||
|
echo " https://$host"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo " Configure your domain in prod-ingress.yaml"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Useful commands:"
|
||||||
|
echo " View logs: kubectl logs -f deployment/gateway -n $NAMESPACE"
|
||||||
|
echo " Check pods: kubectl get pods -n $NAMESPACE"
|
||||||
|
echo " Check events: kubectl get events -n $NAMESPACE --sort-by='.lastTimestamp'"
|
||||||
|
echo " Scale: kubectl scale deployment/gateway --replicas=5 -n $NAMESPACE"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main deployment flow
|
||||||
|
main() {
|
||||||
|
check_cluster
|
||||||
|
check_addons
|
||||||
|
create_namespace
|
||||||
|
apply_secrets
|
||||||
|
deploy_application
|
||||||
|
|
||||||
|
echo -e "${YELLOW}Do you want to wait for deployments to be ready? (yes/no):${NC}"
|
||||||
|
read -p "> " wait_confirm
|
||||||
|
|
||||||
|
if [ "$wait_confirm" = "yes" ]; then
|
||||||
|
wait_for_deployments
|
||||||
|
fi
|
||||||
|
|
||||||
|
check_status
|
||||||
|
show_access_info
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main
|
||||||
154
scripts/tag-and-push-images.sh
Executable file
154
scripts/tag-and-push-images.sh
Executable file
@@ -0,0 +1,154 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Script to tag and push all Bakery IA images to a container registry
|
||||||
|
# Usage: ./tag-and-push-images.sh [REGISTRY_PREFIX] [TAG]
|
||||||
|
# Example: ./tag-and-push-images.sh myuser/bakery v1.0.0
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
REGISTRY_PREFIX="${1:-}"
|
||||||
|
TAG="${2:-latest}"
|
||||||
|
|
||||||
|
if [ -z "$REGISTRY_PREFIX" ]; then
|
||||||
|
echo -e "${RED}Error: Registry prefix required${NC}"
|
||||||
|
echo "Usage: $0 REGISTRY_PREFIX [TAG]"
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " Docker Hub: $0 myusername/bakery v1.0.0"
|
||||||
|
echo " GitHub: $0 ghcr.io/myorg/bakery v1.0.0"
|
||||||
|
echo " MicroK8s: $0 YOUR_VPS_IP:32000/bakery v1.0.0"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# List of all services
|
||||||
|
SERVICES=(
|
||||||
|
"gateway"
|
||||||
|
"dashboard"
|
||||||
|
"auth-service"
|
||||||
|
"tenant-service"
|
||||||
|
"training-service"
|
||||||
|
"forecasting-service"
|
||||||
|
"sales-service"
|
||||||
|
"external-service"
|
||||||
|
"notification-service"
|
||||||
|
"inventory-service"
|
||||||
|
"recipes-service"
|
||||||
|
"suppliers-service"
|
||||||
|
"pos-service"
|
||||||
|
"orders-service"
|
||||||
|
"production-service"
|
||||||
|
"procurement-service"
|
||||||
|
"orchestrator-service"
|
||||||
|
"alert-processor"
|
||||||
|
"ai-insights-service"
|
||||||
|
"demo-session-service"
|
||||||
|
"distribution-service"
|
||||||
|
)
|
||||||
|
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}Bakery IA - Image Tagging and Push${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Registry: $REGISTRY_PREFIX"
|
||||||
|
echo "Tag: $TAG"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Function to tag image
|
||||||
|
tag_image() {
|
||||||
|
local service=$1
|
||||||
|
local local_name="bakery/${service}"
|
||||||
|
local remote_name="${REGISTRY_PREFIX}-${service}:${TAG}"
|
||||||
|
|
||||||
|
echo -e "${YELLOW}Tagging ${local_name} -> ${remote_name}${NC}"
|
||||||
|
|
||||||
|
if docker tag "$local_name" "$remote_name"; then
|
||||||
|
echo -e "${GREEN}✓ Tagged $service${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}✗ Failed to tag $service${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to push image
|
||||||
|
push_image() {
|
||||||
|
local service=$1
|
||||||
|
local remote_name="${REGISTRY_PREFIX}-${service}:${TAG}"
|
||||||
|
|
||||||
|
echo -e "${YELLOW}Pushing ${remote_name}${NC}"
|
||||||
|
|
||||||
|
if docker push "$remote_name"; then
|
||||||
|
echo -e "${GREEN}✓ Pushed $service${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}✗ Failed to push $service${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if user is logged in to registry
|
||||||
|
echo -e "${YELLOW}Checking registry authentication...${NC}"
|
||||||
|
if ! docker info > /dev/null 2>&1; then
|
||||||
|
echo -e "${RED}Error: Docker daemon not running${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}✓ Docker is running${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Ask for confirmation
|
||||||
|
echo -e "${YELLOW}This will tag and push ${#SERVICES[@]} images.${NC}"
|
||||||
|
read -p "Continue? (yes/no): " confirm
|
||||||
|
|
||||||
|
if [ "$confirm" != "yes" ]; then
|
||||||
|
echo "Cancelled."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}Starting image tagging and push...${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Track success/failure
|
||||||
|
SUCCESS_COUNT=0
|
||||||
|
FAILED_SERVICES=()
|
||||||
|
|
||||||
|
# Tag and push all images
|
||||||
|
for service in "${SERVICES[@]}"; do
|
||||||
|
if tag_image "$service" && push_image "$service"; then
|
||||||
|
((SUCCESS_COUNT++))
|
||||||
|
else
|
||||||
|
FAILED_SERVICES+=("$service")
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}Summary${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Successfully pushed: $SUCCESS_COUNT/${#SERVICES[@]}"
|
||||||
|
|
||||||
|
if [ ${#FAILED_SERVICES[@]} -gt 0 ]; then
|
||||||
|
echo -e "${RED}Failed services:${NC}"
|
||||||
|
for service in "${FAILED_SERVICES[@]}"; do
|
||||||
|
echo -e "${RED} - $service${NC}"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}All images pushed successfully!${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo "1. Update image names in infrastructure/kubernetes/overlays/prod/kustomization.yaml"
|
||||||
|
echo "2. Deploy to production: kubectl apply -k infrastructure/kubernetes/overlays/prod"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
Reference in New Issue
Block a user