Add helm chart
This commit is contained in:
parent
09d5c79e8d
commit
6886f94888
20
motm_app/helm-chart/motm-app/Chart.yaml
Normal file
20
motm_app/helm-chart/motm-app/Chart.yaml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: motm-app
|
||||||
|
description: A Helm chart for MOTM (Man of the Match) Hockey Voting Application
|
||||||
|
type: application
|
||||||
|
version: 1.0.0
|
||||||
|
appVersion: "1.0.0"
|
||||||
|
home: https://github.com/your-org/motm-app
|
||||||
|
sources:
|
||||||
|
- https://github.com/your-org/motm-app
|
||||||
|
maintainers:
|
||||||
|
- name: Your Name
|
||||||
|
email: your.email@example.com
|
||||||
|
keywords:
|
||||||
|
- flask
|
||||||
|
- hockey
|
||||||
|
- voting
|
||||||
|
- web-application
|
||||||
|
annotations:
|
||||||
|
category: Sports
|
||||||
|
licenses: MIT
|
||||||
359
motm_app/helm-chart/motm-app/DEPLOYMENT.md
Normal file
359
motm_app/helm-chart/motm-app/DEPLOYMENT.md
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
# MOTM App Kubernetes Deployment Guide
|
||||||
|
|
||||||
|
This guide provides step-by-step instructions for deploying the MOTM (Man of the Match) Hockey Voting Application to a Kubernetes cluster using Helm.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
### Required Tools
|
||||||
|
- **Kubernetes Cluster** (version 1.19+)
|
||||||
|
- **Helm** (version 3.0+)
|
||||||
|
- **kubectl** (configured for your cluster)
|
||||||
|
- **Docker** (for building images)
|
||||||
|
|
||||||
|
### Required Services
|
||||||
|
- **PostgreSQL Database** (or MySQL/SQLite)
|
||||||
|
- **S3-compatible Storage** (optional, for asset management)
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Build and Push Docker Image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to the application directory
|
||||||
|
cd /home/jonny/Projects/gcp-hockey-results/motm_app
|
||||||
|
|
||||||
|
# Build the Docker image
|
||||||
|
docker build -t your-registry/motm-app:latest .
|
||||||
|
|
||||||
|
# Push to your container registry
|
||||||
|
docker push your-registry/motm-app:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Deploy to Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to the helm chart directory
|
||||||
|
cd helm-chart/motm-app
|
||||||
|
|
||||||
|
# Update the image repository in values-development.yaml
|
||||||
|
sed -i 's/your-registry\/motm-app/your-actual-registry\/motm-app/g' values-development.yaml
|
||||||
|
|
||||||
|
# Deploy using the deployment script
|
||||||
|
./scripts/deploy.sh development install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Deploy to Production
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Update production values
|
||||||
|
cp values-production.yaml my-production-values.yaml
|
||||||
|
# Edit my-production-values.yaml with your production settings
|
||||||
|
|
||||||
|
# Deploy to production
|
||||||
|
./scripts/deploy.sh production install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Manual Deployment
|
||||||
|
|
||||||
|
### 1. Customize Values
|
||||||
|
|
||||||
|
Edit the appropriate values file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# For development
|
||||||
|
vim values-development.yaml
|
||||||
|
|
||||||
|
# For production
|
||||||
|
vim values-production.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Key values to update:
|
||||||
|
- `image.repository`: Your container registry
|
||||||
|
- `database.host`: Database service name
|
||||||
|
- `ingress.hosts[0].host`: Your domain name
|
||||||
|
- `secrets.*`: Database and S3 credentials
|
||||||
|
|
||||||
|
### 2. Install with Helm
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Development
|
||||||
|
helm install motm-app ./motm-app \
|
||||||
|
--namespace motm-app \
|
||||||
|
--values values-development.yaml \
|
||||||
|
--create-namespace
|
||||||
|
|
||||||
|
# Production
|
||||||
|
helm install motm-app ./motm-app \
|
||||||
|
--namespace motm-app \
|
||||||
|
--values values-production.yaml \
|
||||||
|
--create-namespace
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Database Setup
|
||||||
|
|
||||||
|
The application supports multiple database types:
|
||||||
|
|
||||||
|
#### PostgreSQL (Recommended)
|
||||||
|
```yaml
|
||||||
|
database:
|
||||||
|
type: "postgresql"
|
||||||
|
host: "postgresql-service"
|
||||||
|
port: 5432
|
||||||
|
name: "motm"
|
||||||
|
username: "motm_user"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### MySQL
|
||||||
|
```yaml
|
||||||
|
database:
|
||||||
|
type: "mysql"
|
||||||
|
host: "mysql-service"
|
||||||
|
port: 3306
|
||||||
|
name: "motm"
|
||||||
|
username: "motm_user"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### SQLite (Development only)
|
||||||
|
```yaml
|
||||||
|
database:
|
||||||
|
type: "sqlite"
|
||||||
|
# Other fields ignored for SQLite
|
||||||
|
```
|
||||||
|
|
||||||
|
### S3 Configuration
|
||||||
|
|
||||||
|
For asset management (logos, images):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
s3:
|
||||||
|
enabled: true
|
||||||
|
endpoint: "https://s3.amazonaws.com"
|
||||||
|
region: "us-east-1"
|
||||||
|
bucket: "motm-assets"
|
||||||
|
# Credentials set via secrets
|
||||||
|
```
|
||||||
|
|
||||||
|
### Security Configuration
|
||||||
|
|
||||||
|
#### Secrets Management
|
||||||
|
|
||||||
|
Set secrets via Helm values or external secret management:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
secrets:
|
||||||
|
dbPassword: "your-database-password"
|
||||||
|
s3AccessKey: "your-s3-access-key"
|
||||||
|
s3SecretKey: "your-s3-secret-key"
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use external secret management:
|
||||||
|
```bash
|
||||||
|
# Create secrets manually
|
||||||
|
kubectl create secret generic motm-app-secrets \
|
||||||
|
--from-literal=db-password=your-password \
|
||||||
|
--from-literal=s3-access-key=your-key \
|
||||||
|
--from-literal=s3-secret-key=your-secret \
|
||||||
|
--namespace motm-app
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Network Policies
|
||||||
|
|
||||||
|
For enhanced security, create network policies:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# network-policy.yaml
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: motm-app-netpol
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: motm-app
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
- Egress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
name: ingress-nginx
|
||||||
|
egress:
|
||||||
|
- to:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
name: postgresql
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring and Observability
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
|
||||||
|
The application includes built-in health checks:
|
||||||
|
- **Liveness Probe**: Checks if the application is running
|
||||||
|
- **Readiness Probe**: Checks if the application is ready to serve traffic
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
|
||||||
|
Configure log levels in values:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
logging:
|
||||||
|
level: "INFO" # DEBUG, INFO, WARNING, ERROR
|
||||||
|
format: "json" # json, text
|
||||||
|
```
|
||||||
|
|
||||||
|
### Metrics (Optional)
|
||||||
|
|
||||||
|
Add Prometheus metrics endpoint:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
monitoring:
|
||||||
|
enabled: true
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: true
|
||||||
|
interval: 30s
|
||||||
|
```
|
||||||
|
|
||||||
|
## Scaling
|
||||||
|
|
||||||
|
### Horizontal Pod Autoscaling
|
||||||
|
|
||||||
|
Enable HPA for production:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
autoscaling:
|
||||||
|
enabled: true
|
||||||
|
minReplicas: 2
|
||||||
|
maxReplicas: 10
|
||||||
|
targetCPUUtilizationPercentage: 70
|
||||||
|
targetMemoryUtilizationPercentage: 80
|
||||||
|
```
|
||||||
|
|
||||||
|
### Resource Limits
|
||||||
|
|
||||||
|
Adjust based on your cluster capacity:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 1000m
|
||||||
|
memory: 1Gi
|
||||||
|
requests:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 512Mi
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
#### 1. Pod Not Starting
|
||||||
|
```bash
|
||||||
|
# Check pod status
|
||||||
|
kubectl get pods -n motm-app -l app.kubernetes.io/name=motm-app
|
||||||
|
|
||||||
|
# Check pod logs
|
||||||
|
kubectl logs -n motm-app -l app.kubernetes.io/name=motm-app
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Database Connection Issues
|
||||||
|
```bash
|
||||||
|
# Test database connectivity
|
||||||
|
kubectl exec -n motm-app -it deployment/motm-app -- python -c "
|
||||||
|
from database import sql_read_static
|
||||||
|
from sqlalchemy import text
|
||||||
|
try:
|
||||||
|
result = sql_read_static(text('SELECT 1'))
|
||||||
|
print('Database connection successful')
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Database connection failed: {e}')
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. S3 Connection Issues
|
||||||
|
```bash
|
||||||
|
# Check S3 configuration
|
||||||
|
kubectl exec -n motm-app -it deployment/motm-app -- cat /app/s3_config.json
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. Ingress Issues
|
||||||
|
```bash
|
||||||
|
# Check ingress status
|
||||||
|
kubectl get ingress -n motm-app
|
||||||
|
|
||||||
|
# Check ingress controller logs
|
||||||
|
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debugging Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get all resources
|
||||||
|
kubectl get all -n motm-app
|
||||||
|
|
||||||
|
# Describe deployment
|
||||||
|
kubectl describe deployment -n motm-app motm-app
|
||||||
|
|
||||||
|
# Check events
|
||||||
|
kubectl get events -n motm-app --sort-by='.lastTimestamp'
|
||||||
|
|
||||||
|
# Port forward for local testing
|
||||||
|
kubectl port-forward -n motm-app svc/motm-app 8080:80
|
||||||
|
```
|
||||||
|
|
||||||
|
## Maintenance
|
||||||
|
|
||||||
|
### Updates
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Update application
|
||||||
|
helm upgrade motm-app ./motm-app \
|
||||||
|
--namespace motm-app \
|
||||||
|
--values values-production.yaml
|
||||||
|
|
||||||
|
# Rollback if needed
|
||||||
|
helm rollback motm-app 1 --namespace motm-app
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Backup database (PostgreSQL)
|
||||||
|
kubectl exec -n postgresql postgresql-0 -- pg_dump -U motm_user motm > backup.sql
|
||||||
|
|
||||||
|
# Backup application data
|
||||||
|
kubectl exec -n motm-app deployment/motm-app -- tar -czf /tmp/data-backup.tar.gz /app/data
|
||||||
|
kubectl cp motm-app/deployment/motm-app:/tmp/data-backup.tar.gz ./data-backup.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cleanup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Uninstall application
|
||||||
|
helm uninstall motm-app --namespace motm-app
|
||||||
|
|
||||||
|
# Delete namespace (if no other resources)
|
||||||
|
kubectl delete namespace motm-app
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
1. **Use Non-Root Containers**: The application runs as non-root user (UID 1000)
|
||||||
|
2. **Read-Only Root Filesystem**: Enable in production values
|
||||||
|
3. **Network Policies**: Implement to restrict pod-to-pod communication
|
||||||
|
4. **RBAC**: Use dedicated service accounts with minimal permissions
|
||||||
|
5. **Secret Management**: Use external secret management solutions
|
||||||
|
6. **Image Security**: Scan images for vulnerabilities
|
||||||
|
7. **TLS**: Enable TLS for all ingress traffic
|
||||||
|
8. **Resource Limits**: Set appropriate CPU and memory limits
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues and questions:
|
||||||
|
1. Check the application logs
|
||||||
|
2. Review Kubernetes events
|
||||||
|
3. Consult the Helm chart documentation
|
||||||
|
4. Create an issue in the repository
|
||||||
239
motm_app/helm-chart/motm-app/README.md
Normal file
239
motm_app/helm-chart/motm-app/README.md
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
# MOTM App Helm Chart
|
||||||
|
|
||||||
|
This Helm chart deploys the MOTM (Man of the Match) Hockey Voting Application to a Kubernetes cluster.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Kubernetes 1.19+
|
||||||
|
- Helm 3.0+
|
||||||
|
- PostgreSQL database (or MySQL/SQLite)
|
||||||
|
- S3-compatible storage (optional)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### 1. Build and Push Docker Image
|
||||||
|
|
||||||
|
First, build and push your Docker image to a registry:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build the image
|
||||||
|
docker build -t your-registry/motm-app:latest .
|
||||||
|
|
||||||
|
# Push to registry
|
||||||
|
docker push your-registry/motm-app:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Configure Values
|
||||||
|
|
||||||
|
Copy the default values file and customize it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp values.yaml my-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Key values to update in `my-values.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Image configuration
|
||||||
|
image:
|
||||||
|
repository: your-registry/motm-app
|
||||||
|
tag: "latest"
|
||||||
|
|
||||||
|
# Database configuration
|
||||||
|
database:
|
||||||
|
host: "your-postgresql-service"
|
||||||
|
name: "motm"
|
||||||
|
username: "motm_user"
|
||||||
|
|
||||||
|
# S3 configuration (if using S3)
|
||||||
|
s3:
|
||||||
|
enabled: true
|
||||||
|
endpoint: "https://s3.amazonaws.com"
|
||||||
|
bucket: "your-bucket-name"
|
||||||
|
|
||||||
|
# Ingress configuration
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
hosts:
|
||||||
|
- host: motm.yourdomain.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: motm-app-tls
|
||||||
|
hosts:
|
||||||
|
- motm.yourdomain.com
|
||||||
|
|
||||||
|
# Secrets (set these via --set or separate secret management)
|
||||||
|
secrets:
|
||||||
|
dbPassword: "your-db-password"
|
||||||
|
s3AccessKey: "your-s3-access-key"
|
||||||
|
s3SecretKey: "your-s3-secret-key"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Deploy with Helm
|
||||||
|
|
||||||
|
#### Option A: Using values file
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install motm-app ./motm-app -f my-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option B: Using command line parameters
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install motm-app ./motm-app \
|
||||||
|
--set image.repository=your-registry/motm-app \
|
||||||
|
--set database.host=your-postgresql-service \
|
||||||
|
--set ingress.hosts[0].host=motm.yourdomain.com \
|
||||||
|
--set secrets.dbPassword=your-db-password
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option C: Using external secret management
|
||||||
|
|
||||||
|
If using external secret management (e.g., Sealed Secrets, External Secrets Operator), create the secrets separately and set:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
secrets:
|
||||||
|
dbPassword: "" # Will be managed externally
|
||||||
|
s3AccessKey: "" # Will be managed externally
|
||||||
|
s3SecretKey: "" # Will be managed externally
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Database Setup
|
||||||
|
|
||||||
|
The application supports PostgreSQL, MySQL, and SQLite. Configure your database connection in the values file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
database:
|
||||||
|
type: "postgresql" # postgresql, mysql, or sqlite
|
||||||
|
host: "postgresql-service"
|
||||||
|
port: 5432
|
||||||
|
name: "motm"
|
||||||
|
username: "motm_user"
|
||||||
|
```
|
||||||
|
|
||||||
|
### S3 Configuration
|
||||||
|
|
||||||
|
Configure S3-compatible storage for asset management:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
s3:
|
||||||
|
enabled: true
|
||||||
|
endpoint: "https://s3.amazonaws.com"
|
||||||
|
region: "us-east-1"
|
||||||
|
bucket: "motm-assets"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Resource Limits
|
||||||
|
|
||||||
|
Adjust resource limits based on your cluster capacity:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
```
|
||||||
|
|
||||||
|
### Autoscaling
|
||||||
|
|
||||||
|
Enable horizontal pod autoscaling:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
autoscaling:
|
||||||
|
enabled: true
|
||||||
|
minReplicas: 2
|
||||||
|
maxReplicas: 10
|
||||||
|
targetCPUUtilizationPercentage: 80
|
||||||
|
```
|
||||||
|
|
||||||
|
## Upgrading
|
||||||
|
|
||||||
|
To upgrade the application:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade motm-app ./motm-app -f my-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Uninstalling
|
||||||
|
|
||||||
|
To uninstall the application:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm uninstall motm-app
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Check Pod Status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl get pods -l app.kubernetes.io/name=motm-app
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl logs -l app.kubernetes.io/name=motm-app
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Service
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl get svc -l app.kubernetes.io/name=motm-app
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug Database Connection
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl exec -it deployment/motm-app -- python -c "
|
||||||
|
from database import sql_read_static
|
||||||
|
from sqlalchemy import text
|
||||||
|
try:
|
||||||
|
result = sql_read_static(text('SELECT 1'))
|
||||||
|
print('Database connection successful')
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Database connection failed: {e}')
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Values Reference
|
||||||
|
|
||||||
|
| Key | Type | Default | Description |
|
||||||
|
|-----|------|---------|-------------|
|
||||||
|
| `image.repository` | string | `"your-registry/motm-app"` | Image repository |
|
||||||
|
| `image.tag` | string | `"latest"` | Image tag |
|
||||||
|
| `service.type` | string | `"ClusterIP"` | Service type |
|
||||||
|
| `ingress.enabled` | bool | `true` | Enable ingress |
|
||||||
|
| `database.type` | string | `"postgresql"` | Database type |
|
||||||
|
| `database.host` | string | `"postgresql-service"` | Database host |
|
||||||
|
| `s3.enabled` | bool | `true` | Enable S3 storage |
|
||||||
|
| `resources.limits.cpu` | string | `"500m"` | CPU limit |
|
||||||
|
| `resources.limits.memory` | string | `"512Mi"` | Memory limit |
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
1. **Secrets Management**: Use proper secret management solutions (e.g., Sealed Secrets, External Secrets Operator)
|
||||||
|
2. **Network Policies**: Implement network policies to restrict pod-to-pod communication
|
||||||
|
3. **RBAC**: Configure proper RBAC for service accounts
|
||||||
|
4. **Image Security**: Use non-root containers and scan images for vulnerabilities
|
||||||
|
5. **TLS**: Enable TLS for ingress and internal communication
|
||||||
|
|
||||||
|
## Monitoring
|
||||||
|
|
||||||
|
The chart includes basic health checks. For production deployments, consider adding:
|
||||||
|
|
||||||
|
- Prometheus metrics endpoint
|
||||||
|
- ServiceMonitor for Prometheus Operator
|
||||||
|
- Grafana dashboards
|
||||||
|
- Alerting rules
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues and questions, please refer to the application documentation or create an issue in the repository.
|
||||||
256
motm_app/helm-chart/motm-app/scripts/deploy.sh
Executable file
256
motm_app/helm-chart/motm-app/scripts/deploy.sh
Executable file
@ -0,0 +1,256 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# MOTM App Helm Deployment Script
|
||||||
|
# Usage: ./deploy.sh [environment] [action]
|
||||||
|
# Environment: development, staging, production
|
||||||
|
# Action: install, upgrade, uninstall, template
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
ENVIRONMENT=${1:-development}
|
||||||
|
ACTION=${2:-install}
|
||||||
|
RELEASE_NAME="motm-app"
|
||||||
|
CHART_PATH="./motm-app"
|
||||||
|
NAMESPACE="motm-app"
|
||||||
|
|
||||||
|
# Function to print colored output
|
||||||
|
print_status() {
|
||||||
|
echo -e "${BLUE}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check prerequisites
|
||||||
|
check_prerequisites() {
|
||||||
|
print_status "Checking prerequisites..."
|
||||||
|
|
||||||
|
# Check if helm is installed
|
||||||
|
if ! command -v helm &> /dev/null; then
|
||||||
|
print_error "Helm is not installed. Please install Helm 3.0+"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if kubectl is installed
|
||||||
|
if ! command -v kubectl &> /dev/null; then
|
||||||
|
print_error "kubectl is not installed. Please install kubectl"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if we can connect to Kubernetes cluster
|
||||||
|
if ! kubectl cluster-info &> /dev/null; then
|
||||||
|
print_error "Cannot connect to Kubernetes cluster"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_success "Prerequisites check passed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to create namespace
|
||||||
|
create_namespace() {
|
||||||
|
print_status "Creating namespace: $NAMESPACE"
|
||||||
|
kubectl create namespace $NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
print_success "Namespace created/verified"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate values file
|
||||||
|
validate_values() {
|
||||||
|
local values_file="values-${ENVIRONMENT}.yaml"
|
||||||
|
|
||||||
|
if [[ ! -f "$values_file" ]]; then
|
||||||
|
print_error "Values file $values_file not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Validating values file: $values_file"
|
||||||
|
|
||||||
|
# Check for required values
|
||||||
|
if ! grep -q "repository:" "$values_file"; then
|
||||||
|
print_error "Image repository not specified in $values_file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! grep -q "host:" "$values_file"; then
|
||||||
|
print_error "Database host not specified in $values_file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_success "Values file validation passed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to template the chart
|
||||||
|
template_chart() {
|
||||||
|
local values_file="values-${ENVIRONMENT}.yaml"
|
||||||
|
|
||||||
|
print_status "Generating Kubernetes manifests..."
|
||||||
|
helm template $RELEASE_NAME $CHART_PATH \
|
||||||
|
--namespace $NAMESPACE \
|
||||||
|
--values $values_file \
|
||||||
|
--output-dir ./generated-manifests
|
||||||
|
|
||||||
|
print_success "Manifests generated in ./generated-manifests/"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to install the chart
|
||||||
|
install_chart() {
|
||||||
|
local values_file="values-${ENVIRONMENT}.yaml"
|
||||||
|
|
||||||
|
print_status "Installing MOTM App in $ENVIRONMENT environment..."
|
||||||
|
|
||||||
|
helm install $RELEASE_NAME $CHART_PATH \
|
||||||
|
--namespace $NAMESPACE \
|
||||||
|
--values $values_file \
|
||||||
|
--create-namespace \
|
||||||
|
--wait \
|
||||||
|
--timeout 10m
|
||||||
|
|
||||||
|
print_success "MOTM App installed successfully"
|
||||||
|
|
||||||
|
# Show status
|
||||||
|
kubectl get pods -n $NAMESPACE -l app.kubernetes.io/name=motm-app
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to upgrade the chart
|
||||||
|
upgrade_chart() {
|
||||||
|
local values_file="values-${ENVIRONMENT}.yaml"
|
||||||
|
|
||||||
|
print_status "Upgrading MOTM App in $ENVIRONMENT environment..."
|
||||||
|
|
||||||
|
helm upgrade $RELEASE_NAME $CHART_PATH \
|
||||||
|
--namespace $NAMESPACE \
|
||||||
|
--values $values_file \
|
||||||
|
--wait \
|
||||||
|
--timeout 10m
|
||||||
|
|
||||||
|
print_success "MOTM App upgraded successfully"
|
||||||
|
|
||||||
|
# Show status
|
||||||
|
kubectl get pods -n $NAMESPACE -l app.kubernetes.io/name=motm-app
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to uninstall the chart
|
||||||
|
uninstall_chart() {
|
||||||
|
print_warning "Uninstalling MOTM App from $ENVIRONMENT environment..."
|
||||||
|
|
||||||
|
read -p "Are you sure you want to uninstall? (y/N): " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
helm uninstall $RELEASE_NAME --namespace $NAMESPACE
|
||||||
|
print_success "MOTM App uninstalled successfully"
|
||||||
|
else
|
||||||
|
print_status "Uninstall cancelled"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to show status
|
||||||
|
show_status() {
|
||||||
|
print_status "Showing MOTM App status..."
|
||||||
|
|
||||||
|
echo "=== Helm Release Status ==="
|
||||||
|
helm status $RELEASE_NAME --namespace $NAMESPACE
|
||||||
|
|
||||||
|
echo -e "\n=== Pods Status ==="
|
||||||
|
kubectl get pods -n $NAMESPACE -l app.kubernetes.io/name=motm-app
|
||||||
|
|
||||||
|
echo -e "\n=== Services ==="
|
||||||
|
kubectl get svc -n $NAMESPACE -l app.kubernetes.io/name=motm-app
|
||||||
|
|
||||||
|
echo -e "\n=== Ingress ==="
|
||||||
|
kubectl get ingress -n $NAMESPACE -l app.kubernetes.io/name=motm-app
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to show logs
|
||||||
|
show_logs() {
|
||||||
|
print_status "Showing MOTM App logs..."
|
||||||
|
kubectl logs -n $NAMESPACE -l app.kubernetes.io/name=motm-app --tail=100 -f
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to show help
|
||||||
|
show_help() {
|
||||||
|
echo "MOTM App Helm Deployment Script"
|
||||||
|
echo ""
|
||||||
|
echo "Usage: $0 [environment] [action]"
|
||||||
|
echo ""
|
||||||
|
echo "Environments:"
|
||||||
|
echo " development Deploy to development environment"
|
||||||
|
echo " staging Deploy to staging environment"
|
||||||
|
echo " production Deploy to production environment"
|
||||||
|
echo ""
|
||||||
|
echo "Actions:"
|
||||||
|
echo " install Install the application (default)"
|
||||||
|
echo " upgrade Upgrade the application"
|
||||||
|
echo " uninstall Uninstall the application"
|
||||||
|
echo " template Generate Kubernetes manifests"
|
||||||
|
echo " status Show application status"
|
||||||
|
echo " logs Show application logs"
|
||||||
|
echo " help Show this help message"
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " $0 development install"
|
||||||
|
echo " $0 production upgrade"
|
||||||
|
echo " $0 staging template"
|
||||||
|
echo " $0 development status"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
main() {
|
||||||
|
case $ACTION in
|
||||||
|
install)
|
||||||
|
check_prerequisites
|
||||||
|
create_namespace
|
||||||
|
validate_values
|
||||||
|
install_chart
|
||||||
|
;;
|
||||||
|
upgrade)
|
||||||
|
check_prerequisites
|
||||||
|
create_namespace
|
||||||
|
validate_values
|
||||||
|
upgrade_chart
|
||||||
|
;;
|
||||||
|
uninstall)
|
||||||
|
check_prerequisites
|
||||||
|
uninstall_chart
|
||||||
|
;;
|
||||||
|
template)
|
||||||
|
check_prerequisites
|
||||||
|
validate_values
|
||||||
|
template_chart
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
check_prerequisites
|
||||||
|
show_status
|
||||||
|
;;
|
||||||
|
logs)
|
||||||
|
check_prerequisites
|
||||||
|
show_logs
|
||||||
|
;;
|
||||||
|
help|--help|-h)
|
||||||
|
show_help
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_error "Unknown action: $ACTION"
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main "$@"
|
||||||
65
motm_app/helm-chart/motm-app/templates/_helpers.tpl
Normal file
65
motm_app/helm-chart/motm-app/templates/_helpers.tpl
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "motm-app.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "motm-app.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride }}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||||
|
{{- if contains $name .Release.Name }}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "motm-app.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "motm-app.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "motm-app.chart" . }}
|
||||||
|
{{ include "motm-app.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- with .Values.labels }}
|
||||||
|
{{- toYaml . | nindent 0 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "motm-app.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "motm-app.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the service account to use
|
||||||
|
*/}}
|
||||||
|
{{- define "motm-app.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
{{- default (include "motm-app.fullname" .) .Values.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
43
motm_app/helm-chart/motm-app/templates/configmap.yaml
Normal file
43
motm_app/helm-chart/motm-app/templates/configmap.yaml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ include "motm-app.fullname" . }}-config
|
||||||
|
labels:
|
||||||
|
{{- include "motm-app.labels" . | nindent 4 }}
|
||||||
|
data:
|
||||||
|
database_config.ini: |
|
||||||
|
[DATABASE]
|
||||||
|
type = {{ .Values.database.type }}
|
||||||
|
sqlite_database_path = hockey_results.db
|
||||||
|
|
||||||
|
[MYSQL]
|
||||||
|
host = {{ .Values.database.host }}
|
||||||
|
port = {{ .Values.database.port }}
|
||||||
|
database = {{ .Values.database.name }}
|
||||||
|
username = {{ .Values.database.username }}
|
||||||
|
charset = utf8mb4
|
||||||
|
|
||||||
|
[POSTGRESQL]
|
||||||
|
host = {{ .Values.database.host }}
|
||||||
|
port = {{ .Values.database.port }}
|
||||||
|
database = {{ .Values.database.name }}
|
||||||
|
username = {{ .Values.database.username }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ include "motm-app.fullname" . }}-s3-config
|
||||||
|
labels:
|
||||||
|
{{- include "motm-app.labels" . | nindent 4 }}
|
||||||
|
data:
|
||||||
|
s3_config.json: |
|
||||||
|
{
|
||||||
|
"enable_s3": {{ .Values.s3.enabled }},
|
||||||
|
"aws_access_key_id": "",
|
||||||
|
"aws_secret_access_key": "",
|
||||||
|
"aws_region": "{{ .Values.s3.region }}",
|
||||||
|
"bucket_name": "{{ .Values.s3.bucket }}",
|
||||||
|
"endpoint_url": "{{ .Values.s3.endpoint }}",
|
||||||
|
"use_ssl": true,
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
134
motm_app/helm-chart/motm-app/templates/deployment.yaml
Normal file
134
motm_app/helm-chart/motm-app/templates/deployment.yaml
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "motm-app.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "motm-app.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
{{- if not .Values.autoscaling.enabled }}
|
||||||
|
replicas: {{ .Values.replicaCount | default 1 }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "motm-app.selectorLabels" . | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
{{- include "motm-app.selectorLabels" . | nindent 8 }}
|
||||||
|
{{- with .Values.podLabels }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "motm-app.serviceAccountName" . }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 5000
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
# Application environment variables
|
||||||
|
{{- range $key, $value := .Values.env }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
value: {{ $value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
# Database configuration
|
||||||
|
- name: DB_HOST
|
||||||
|
value: {{ .Values.database.host | quote }}
|
||||||
|
- name: DB_PORT
|
||||||
|
value: {{ .Values.database.port | quote }}
|
||||||
|
- name: DB_NAME
|
||||||
|
value: {{ .Values.database.name | quote }}
|
||||||
|
- name: DB_USER
|
||||||
|
value: {{ .Values.database.username | quote }}
|
||||||
|
- name: DB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "motm-app.fullname" . }}-secrets
|
||||||
|
key: db-password
|
||||||
|
# S3 configuration
|
||||||
|
{{- if .Values.s3.enabled }}
|
||||||
|
- name: S3_ENDPOINT
|
||||||
|
value: {{ .Values.s3.endpoint | quote }}
|
||||||
|
- name: S3_REGION
|
||||||
|
value: {{ .Values.s3.region | quote }}
|
||||||
|
- name: S3_BUCKET
|
||||||
|
value: {{ .Values.s3.bucket | quote }}
|
||||||
|
- name: S3_ACCESS_KEY_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "motm-app.fullname" . }}-secrets
|
||||||
|
key: s3-access-key
|
||||||
|
- name: S3_SECRET_ACCESS_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "motm-app.fullname" . }}-secrets
|
||||||
|
key: s3-secret-key
|
||||||
|
{{- end }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: {{ .Values.healthCheck.path }}
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: {{ .Values.healthCheck.initialDelaySeconds }}
|
||||||
|
periodSeconds: {{ .Values.healthCheck.periodSeconds }}
|
||||||
|
timeoutSeconds: {{ .Values.healthCheck.timeoutSeconds }}
|
||||||
|
failureThreshold: {{ .Values.healthCheck.failureThreshold }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: {{ .Values.healthCheck.path }}
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 3
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: config-volume
|
||||||
|
mountPath: /app/database_config.ini
|
||||||
|
subPath: database_config.ini
|
||||||
|
- name: s3-config-volume
|
||||||
|
mountPath: /app/s3_config.json
|
||||||
|
subPath: s3_config.json
|
||||||
|
{{- if .Values.persistence.enabled }}
|
||||||
|
- name: data-volume
|
||||||
|
mountPath: /app/data
|
||||||
|
{{- end }}
|
||||||
|
volumes:
|
||||||
|
- name: config-volume
|
||||||
|
configMap:
|
||||||
|
name: {{ include "motm-app.fullname" . }}-config
|
||||||
|
- name: s3-config-volume
|
||||||
|
configMap:
|
||||||
|
name: {{ include "motm-app.fullname" . }}-s3-config
|
||||||
|
{{- if .Values.persistence.enabled }}
|
||||||
|
- name: data-volume
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: {{ include "motm-app.fullname" . }}-pvc
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
32
motm_app/helm-chart/motm-app/templates/hpa.yaml
Normal file
32
motm_app/helm-chart/motm-app/templates/hpa.yaml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{{- if .Values.autoscaling.enabled }}
|
||||||
|
apiVersion: autoscaling/v2
|
||||||
|
kind: HorizontalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: {{ include "motm-app.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "motm-app.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: {{ include "motm-app.fullname" . }}
|
||||||
|
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
||||||
|
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
||||||
|
metrics:
|
||||||
|
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: cpu
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: memory
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
59
motm_app/helm-chart/motm-app/templates/ingress.yaml
Normal file
59
motm_app/helm-chart/motm-app/templates/ingress.yaml
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{{- if .Values.ingress.enabled -}}
|
||||||
|
{{- $fullName := include "motm-app.fullname" . -}}
|
||||||
|
{{- $svcPort := .Values.service.port -}}
|
||||||
|
{{- if and .Values.ingress.className (not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class")) }}
|
||||||
|
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
|
||||||
|
{{- end }}
|
||||||
|
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||||
|
apiVersion: networking.k8s.io/v1beta1
|
||||||
|
{{- else -}}
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
{{- end }}
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
labels:
|
||||||
|
{{- include "motm-app.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||||
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- range .Values.ingress.tls }}
|
||||||
|
- hosts:
|
||||||
|
{{- range .hosts }}
|
||||||
|
- {{ . | quote }}
|
||||||
|
{{- end }}
|
||||||
|
secretName: {{ .secretName }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
- host: {{ .host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
|
{{- end }}
|
||||||
|
backend:
|
||||||
|
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
||||||
|
service:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
port:
|
||||||
|
number: {{ $svcPort }}
|
||||||
|
{{- else }}
|
||||||
|
serviceName: {{ $fullName }}
|
||||||
|
servicePort: {{ $svcPort }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
18
motm_app/helm-chart/motm-app/templates/pdb.yaml
Normal file
18
motm_app/helm-chart/motm-app/templates/pdb.yaml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{{- if .Values.podDisruptionBudget.enabled }}
|
||||||
|
apiVersion: policy/v1
|
||||||
|
kind: PodDisruptionBudget
|
||||||
|
metadata:
|
||||||
|
name: {{ include "motm-app.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "motm-app.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.podDisruptionBudget.minAvailable }}
|
||||||
|
minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.podDisruptionBudget.maxUnavailable }}
|
||||||
|
maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "motm-app.selectorLabels" . | nindent 6 }}
|
||||||
|
{{- end }}
|
||||||
21
motm_app/helm-chart/motm-app/templates/pvc.yaml
Normal file
21
motm_app/helm-chart/motm-app/templates/pvc.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{{- if .Values.persistence.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: {{ include "motm-app.fullname" . }}-pvc
|
||||||
|
labels:
|
||||||
|
{{- include "motm-app.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- {{ .Values.persistence.accessMode }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.persistence.size }}
|
||||||
|
{{- if .Values.persistence.storageClass }}
|
||||||
|
{{- if (eq "-" .Values.persistence.storageClass) }}
|
||||||
|
storageClassName: ""
|
||||||
|
{{- else }}
|
||||||
|
storageClassName: "{{ .Values.persistence.storageClass }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
29
motm_app/helm-chart/motm-app/templates/secret.yaml
Normal file
29
motm_app/helm-chart/motm-app/templates/secret.yaml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "motm-app.fullname" . }}-secrets
|
||||||
|
labels:
|
||||||
|
{{- include "motm-app.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
# Database password
|
||||||
|
{{- if .Values.secrets.dbPassword }}
|
||||||
|
db-password: {{ .Values.secrets.dbPassword | b64enc | quote }}
|
||||||
|
{{- else }}
|
||||||
|
db-password: {{ "changeme" | b64enc | quote }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if .Values.s3.enabled }}
|
||||||
|
# S3 credentials
|
||||||
|
{{- if .Values.secrets.s3AccessKey }}
|
||||||
|
s3-access-key: {{ .Values.secrets.s3AccessKey | b64enc | quote }}
|
||||||
|
{{- else }}
|
||||||
|
s3-access-key: {{ "changeme" | b64enc | quote }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if .Values.secrets.s3SecretKey }}
|
||||||
|
s3-secret-key: {{ .Values.secrets.s3SecretKey | b64enc | quote }}
|
||||||
|
{{- else }}
|
||||||
|
s3-secret-key: {{ "changeme" | b64enc | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
19
motm_app/helm-chart/motm-app/templates/service.yaml
Normal file
19
motm_app/helm-chart/motm-app/templates/service.yaml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "motm-app.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "motm-app.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.service.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.service.port }}
|
||||||
|
targetPort: {{ .Values.service.targetPort }}
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
{{- include "motm-app.selectorLabels" . | nindent 4 }}
|
||||||
12
motm_app/helm-chart/motm-app/templates/serviceaccount.yaml
Normal file
12
motm_app/helm-chart/motm-app/templates/serviceaccount.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{{- if .Values.serviceAccount.create -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "motm-app.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "motm-app.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
128
motm_app/helm-chart/motm-app/values-development.yaml
Normal file
128
motm_app/helm-chart/motm-app/values-development.yaml
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# Development values for MOTM App
|
||||||
|
# Use this file for development/staging environments
|
||||||
|
|
||||||
|
# Application Configuration
|
||||||
|
app:
|
||||||
|
name: motm-app-dev
|
||||||
|
version: "dev"
|
||||||
|
|
||||||
|
# Image Configuration
|
||||||
|
image:
|
||||||
|
repository: your-registry/motm-app
|
||||||
|
tag: "dev" # Use dev tag for development
|
||||||
|
pullPolicy: Always # Always pull latest dev image
|
||||||
|
|
||||||
|
# Resource Limits for Development (lighter)
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
|
||||||
|
# No autoscaling for development
|
||||||
|
autoscaling:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Pod Disruption Budget
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Security Context (more permissive for development)
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
readOnlyRootFilesystem: false # Allow writing for development
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
|
||||||
|
# Service Configuration
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 80
|
||||||
|
targetPort: 5000
|
||||||
|
|
||||||
|
# Ingress Configuration for Development
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: "nginx"
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
nginx.ingress.kubernetes.io/ssl-redirect: "false" # No SSL for dev
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-staging"
|
||||||
|
hosts:
|
||||||
|
- host: motm-dev.yourdomain.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: motm-app-dev-tls
|
||||||
|
hosts:
|
||||||
|
- motm-dev.yourdomain.com
|
||||||
|
|
||||||
|
# Database Configuration for Development
|
||||||
|
database:
|
||||||
|
type: "postgresql"
|
||||||
|
host: "postgresql-dev-service"
|
||||||
|
port: 5432
|
||||||
|
name: "motm_dev"
|
||||||
|
username: "motm_user"
|
||||||
|
|
||||||
|
# S3 Configuration for Development
|
||||||
|
s3:
|
||||||
|
enabled: true
|
||||||
|
endpoint: "https://s3.amazonaws.com"
|
||||||
|
region: "us-east-1"
|
||||||
|
bucket: "motm-assets-dev"
|
||||||
|
|
||||||
|
# Environment Variables for Development
|
||||||
|
env:
|
||||||
|
FLASK_ENV: "development"
|
||||||
|
FLASK_APP: "main.py"
|
||||||
|
FLASK_RUN_HOST: "0.0.0.0"
|
||||||
|
FLASK_RUN_PORT: "5000"
|
||||||
|
PYTHONUNBUFFERED: "1"
|
||||||
|
PYTHONDONTWRITEBYTECODE: "1"
|
||||||
|
FLASK_DEBUG: "1" # Enable debug mode for development
|
||||||
|
|
||||||
|
# Health Checks
|
||||||
|
healthCheck:
|
||||||
|
enabled: true
|
||||||
|
path: "/"
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 30
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 5
|
||||||
|
|
||||||
|
# Persistence for Development
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: "standard" # Use standard storage class
|
||||||
|
accessMode: ReadWriteOnce
|
||||||
|
size: 1Gi
|
||||||
|
|
||||||
|
# Monitoring (disabled for development)
|
||||||
|
monitoring:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
logging:
|
||||||
|
level: "DEBUG"
|
||||||
|
format: "text"
|
||||||
|
|
||||||
|
# Labels and Annotations
|
||||||
|
labels:
|
||||||
|
environment: "development"
|
||||||
|
team: "development"
|
||||||
|
|
||||||
|
annotations:
|
||||||
|
deployment.kubernetes.io/revision: "dev"
|
||||||
|
|
||||||
|
podLabels:
|
||||||
|
environment: "development"
|
||||||
|
|
||||||
|
podAnnotations:
|
||||||
|
debug: "true"
|
||||||
166
motm_app/helm-chart/motm-app/values-production.yaml
Normal file
166
motm_app/helm-chart/motm-app/values-production.yaml
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
# Production values for MOTM App
|
||||||
|
# Use this file as a template for production deployment
|
||||||
|
|
||||||
|
# Application Configuration
|
||||||
|
app:
|
||||||
|
name: motm-app
|
||||||
|
version: "1.0.0"
|
||||||
|
|
||||||
|
# Image Configuration
|
||||||
|
image:
|
||||||
|
repository: your-registry/motm-app
|
||||||
|
tag: "v1.0.0" # Use specific version tags in production
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
# Resource Limits for Production
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 1000m
|
||||||
|
memory: 1Gi
|
||||||
|
requests:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
# Autoscaling for Production
|
||||||
|
autoscaling:
|
||||||
|
enabled: true
|
||||||
|
minReplicas: 2
|
||||||
|
maxReplicas: 10
|
||||||
|
targetCPUUtilizationPercentage: 70
|
||||||
|
targetMemoryUtilizationPercentage: 80
|
||||||
|
|
||||||
|
# Pod Disruption Budget
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: true
|
||||||
|
minAvailable: 1
|
||||||
|
|
||||||
|
# Security Context
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
|
||||||
|
# Service Configuration
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 80
|
||||||
|
targetPort: 5000
|
||||||
|
|
||||||
|
# Ingress Configuration for Production
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: "nginx"
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||||
|
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
nginx.ingress.kubernetes.io/rate-limit: "100"
|
||||||
|
nginx.ingress.kubernetes.io/rate-limit-window: "1m"
|
||||||
|
hosts:
|
||||||
|
- host: motm.yourdomain.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: motm-app-tls
|
||||||
|
hosts:
|
||||||
|
- motm.yourdomain.com
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
database:
|
||||||
|
type: "postgresql"
|
||||||
|
host: "postgresql-primary-service"
|
||||||
|
port: 5432
|
||||||
|
name: "motm_prod"
|
||||||
|
username: "motm_user"
|
||||||
|
|
||||||
|
# S3 Configuration for Production
|
||||||
|
s3:
|
||||||
|
enabled: true
|
||||||
|
endpoint: "https://s3.amazonaws.com"
|
||||||
|
region: "us-east-1"
|
||||||
|
bucket: "motm-assets-prod"
|
||||||
|
|
||||||
|
# Environment Variables
|
||||||
|
env:
|
||||||
|
FLASK_ENV: "production"
|
||||||
|
FLASK_APP: "main.py"
|
||||||
|
FLASK_RUN_HOST: "0.0.0.0"
|
||||||
|
FLASK_RUN_PORT: "5000"
|
||||||
|
PYTHONUNBUFFERED: "1"
|
||||||
|
PYTHONDONTWRITEBYTECODE: "1"
|
||||||
|
|
||||||
|
# Health Checks
|
||||||
|
healthCheck:
|
||||||
|
enabled: true
|
||||||
|
path: "/"
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
|
||||||
|
# Persistence for Production
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: "fast-ssd" # Use fast storage class
|
||||||
|
accessMode: ReadWriteOnce
|
||||||
|
size: 10Gi
|
||||||
|
|
||||||
|
# Monitoring
|
||||||
|
monitoring:
|
||||||
|
enabled: true
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: true
|
||||||
|
interval: 30s
|
||||||
|
scrapeTimeout: 10s
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
logging:
|
||||||
|
level: "INFO"
|
||||||
|
format: "json"
|
||||||
|
|
||||||
|
# Node Selector for Production
|
||||||
|
nodeSelector:
|
||||||
|
node-type: "production"
|
||||||
|
|
||||||
|
# Tolerations
|
||||||
|
tolerations:
|
||||||
|
- key: "production"
|
||||||
|
operator: "Equal"
|
||||||
|
value: "true"
|
||||||
|
effect: "NoSchedule"
|
||||||
|
|
||||||
|
# Affinity Rules
|
||||||
|
affinity:
|
||||||
|
podAntiAffinity:
|
||||||
|
preferredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- weight: 100
|
||||||
|
podAffinityTerm:
|
||||||
|
labelSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: app.kubernetes.io/name
|
||||||
|
operator: In
|
||||||
|
values:
|
||||||
|
- motm-app
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
|
||||||
|
# Labels and Annotations
|
||||||
|
labels:
|
||||||
|
environment: "production"
|
||||||
|
team: "platform"
|
||||||
|
|
||||||
|
annotations:
|
||||||
|
deployment.kubernetes.io/revision: "1"
|
||||||
|
|
||||||
|
podLabels:
|
||||||
|
environment: "production"
|
||||||
|
|
||||||
|
podAnnotations:
|
||||||
|
prometheus.io/scrape: "true"
|
||||||
|
prometheus.io/port: "5000"
|
||||||
|
prometheus.io/path: "/metrics"
|
||||||
194
motm_app/helm-chart/motm-app/values.yaml
Normal file
194
motm_app/helm-chart/motm-app/values.yaml
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
# Default values for motm-app
|
||||||
|
# This is a YAML-formatted file.
|
||||||
|
# Declare variables to be passed into your templates.
|
||||||
|
|
||||||
|
# Application Configuration
|
||||||
|
app:
|
||||||
|
name: motm-app
|
||||||
|
version: "1.0.0"
|
||||||
|
description: "MOTM Hockey Voting Application"
|
||||||
|
|
||||||
|
# Image Configuration
|
||||||
|
image:
|
||||||
|
repository: your-registry/motm-app
|
||||||
|
tag: "latest"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
# Overrides the image tag whose default is the chart appVersion.
|
||||||
|
# tag: ""
|
||||||
|
|
||||||
|
# Image pull secrets
|
||||||
|
imagePullSecrets: []
|
||||||
|
nameOverride: ""
|
||||||
|
fullnameOverride: ""
|
||||||
|
|
||||||
|
# Service Account
|
||||||
|
serviceAccount:
|
||||||
|
# Specifies whether a service account should be created
|
||||||
|
create: true
|
||||||
|
# Annotations to add to the service account
|
||||||
|
annotations: {}
|
||||||
|
# The name of the service account to use.
|
||||||
|
# If not set and create is true, a name is generated using the fullname template
|
||||||
|
name: ""
|
||||||
|
|
||||||
|
# Pod Security Context
|
||||||
|
podSecurityContext:
|
||||||
|
fsGroup: 1000
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
|
||||||
|
# Container Security Context
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
readOnlyRootFilesystem: false
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
|
||||||
|
# Service Configuration
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 80
|
||||||
|
targetPort: 5000
|
||||||
|
annotations: {}
|
||||||
|
|
||||||
|
# Ingress Configuration
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: ""
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
hosts:
|
||||||
|
- host: motm.yourdomain.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: motm-app-tls
|
||||||
|
hosts:
|
||||||
|
- motm.yourdomain.com
|
||||||
|
|
||||||
|
# Resource Limits and Requests
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
|
||||||
|
# Autoscaling
|
||||||
|
autoscaling:
|
||||||
|
enabled: false
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 10
|
||||||
|
targetCPUUtilizationPercentage: 80
|
||||||
|
targetMemoryUtilizationPercentage: 80
|
||||||
|
|
||||||
|
# Node Selector
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
# Tolerations
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
# Affinity
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
# Pod Disruption Budget
|
||||||
|
podDisruptionBudget:
|
||||||
|
enabled: false
|
||||||
|
minAvailable: 1
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
database:
|
||||||
|
type: "postgresql" # postgresql, mysql, sqlite
|
||||||
|
host: "postgresql-service"
|
||||||
|
port: 5432
|
||||||
|
name: "motm"
|
||||||
|
username: "motm_user"
|
||||||
|
# Password should be set via secret
|
||||||
|
# password: ""
|
||||||
|
|
||||||
|
# S3 Configuration
|
||||||
|
s3:
|
||||||
|
enabled: true
|
||||||
|
endpoint: "https://s3.amazonaws.com"
|
||||||
|
region: "us-east-1"
|
||||||
|
bucket: "motm-assets"
|
||||||
|
accessKeyId: ""
|
||||||
|
secretAccessKey: ""
|
||||||
|
# These should be set via secret
|
||||||
|
|
||||||
|
# Environment Variables
|
||||||
|
env:
|
||||||
|
FLASK_ENV: "production"
|
||||||
|
FLASK_APP: "main.py"
|
||||||
|
FLASK_RUN_HOST: "0.0.0.0"
|
||||||
|
FLASK_RUN_PORT: "5000"
|
||||||
|
PYTHONUNBUFFERED: "1"
|
||||||
|
PYTHONDONTWRITEBYTECODE: "1"
|
||||||
|
|
||||||
|
# ConfigMap for application configuration
|
||||||
|
configMap:
|
||||||
|
databaseConfig: |
|
||||||
|
[DATABASE]
|
||||||
|
type = {{ .Values.database.type }}
|
||||||
|
|
||||||
|
[MYSQL]
|
||||||
|
host = {{ .Values.database.host }}
|
||||||
|
port = {{ .Values.database.port }}
|
||||||
|
database = {{ .Values.database.name }}
|
||||||
|
username = {{ .Values.database.username }}
|
||||||
|
|
||||||
|
[POSTGRESQL]
|
||||||
|
host = {{ .Values.database.host }}
|
||||||
|
port = {{ .Values.database.port }}
|
||||||
|
database = {{ .Values.database.name }}
|
||||||
|
username = {{ .Values.database.username }}
|
||||||
|
|
||||||
|
# Secrets
|
||||||
|
secrets:
|
||||||
|
# Database password
|
||||||
|
dbPassword: ""
|
||||||
|
# S3 credentials
|
||||||
|
s3AccessKey: ""
|
||||||
|
s3SecretKey: ""
|
||||||
|
|
||||||
|
# Health Checks
|
||||||
|
healthCheck:
|
||||||
|
enabled: true
|
||||||
|
path: "/"
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
|
||||||
|
# Persistence
|
||||||
|
persistence:
|
||||||
|
enabled: false
|
||||||
|
# storageClass: ""
|
||||||
|
accessMode: ReadWriteOnce
|
||||||
|
size: 1Gi
|
||||||
|
|
||||||
|
# Monitoring
|
||||||
|
monitoring:
|
||||||
|
enabled: false
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: false
|
||||||
|
interval: 30s
|
||||||
|
scrapeTimeout: 10s
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
logging:
|
||||||
|
level: "INFO"
|
||||||
|
format: "json"
|
||||||
|
|
||||||
|
# Labels and Annotations
|
||||||
|
labels: {}
|
||||||
|
annotations: {}
|
||||||
|
podLabels: {}
|
||||||
|
podAnnotations: {}
|
||||||
@ -136,14 +136,15 @@
|
|||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
background-color: #e9ecef; /* Light gray background for empty bars */
|
||||||
}
|
}
|
||||||
|
|
||||||
.poty-bar-motm {
|
.poty-bar-motm {
|
||||||
background: linear-gradient(90deg, #28a745, #20c997);
|
background-color: rgba(40, 167, 69, 0.1); /* Very light green background */
|
||||||
}
|
}
|
||||||
|
|
||||||
.poty-bar-dotd {
|
.poty-bar-dotd {
|
||||||
background: linear-gradient(90deg, #dc3545, #fd7e14);
|
background-color: rgba(220, 53, 69, 0.1); /* Very light red background */
|
||||||
}
|
}
|
||||||
|
|
||||||
.poty-bar-fill {
|
.poty-bar-fill {
|
||||||
@ -238,7 +239,7 @@ function renderPOTYChart(data) {
|
|||||||
return a.dotdTotal - b.dotdTotal;
|
return a.dotdTotal - b.dotdTotal;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Find max values for scaling - each bar scales independently
|
// Find max values for independent scaling - each bar type scales to its own maximum
|
||||||
const maxMotm = Math.max(...data.map(p => p.motmTotal || 0));
|
const maxMotm = Math.max(...data.map(p => p.motmTotal || 0));
|
||||||
const maxDotd = Math.max(...data.map(p => p.dotdTotal || 0));
|
const maxDotd = Math.max(...data.map(p => p.dotdTotal || 0));
|
||||||
|
|
||||||
@ -249,6 +250,9 @@ function renderPOTYChart(data) {
|
|||||||
const ranking = index + 1;
|
const ranking = index + 1;
|
||||||
const rankingClass = ranking === 1 ? 'gold' : ranking === 2 ? 'silver' : ranking === 3 ? 'bronze' : '';
|
const rankingClass = ranking === 1 ? 'gold' : ranking === 2 ? 'silver' : ranking === 3 ? 'bronze' : '';
|
||||||
|
|
||||||
|
const motmVotes = player.motmTotal || 0;
|
||||||
|
const dotdVotes = player.dotdTotal || 0;
|
||||||
|
|
||||||
html += '<div class="poty-player-card">';
|
html += '<div class="poty-player-card">';
|
||||||
html += '<div class="d-flex align-items-center">';
|
html += '<div class="d-flex align-items-center">';
|
||||||
html += '<div class="poty-ranking ' + rankingClass + '">' + ranking + '</div>';
|
html += '<div class="poty-ranking ' + rankingClass + '">' + ranking + '</div>';
|
||||||
@ -256,19 +260,19 @@ function renderPOTYChart(data) {
|
|||||||
html += '<div class="poty-player-name">' + (player.playerName || 'Unknown Player') + '</div>';
|
html += '<div class="poty-player-name">' + (player.playerName || 'Unknown Player') + '</div>';
|
||||||
html += '<div class="poty-stats">';
|
html += '<div class="poty-stats">';
|
||||||
html += '<div class="poty-stat">';
|
html += '<div class="poty-stat">';
|
||||||
html += '<div class="poty-stat-value text-success">' + (player.motmTotal || 0) + '</div>';
|
html += '<div class="poty-stat-value text-success">' + motmVotes + '</div>';
|
||||||
html += '<div class="poty-stat-label">MOTM</div>';
|
html += '<div class="poty-stat-label">MOTM</div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '<div class="poty-stat">';
|
html += '<div class="poty-stat">';
|
||||||
html += '<div class="poty-stat-value text-danger">' + (player.dotdTotal || 0) + '</div>';
|
html += '<div class="poty-stat-value text-danger">' + dotdVotes + '</div>';
|
||||||
html += '<div class="poty-stat-label">DotD</div>';
|
html += '<div class="poty-stat-label">DotD</div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '<div class="poty-bar-container">';
|
html += '<div class="poty-bar-container">';
|
||||||
html += '<div class="poty-bar poty-bar-motm">';
|
html += '<div class="poty-bar poty-bar-motm">';
|
||||||
html += '<div class="poty-bar-fill" style="width: ' + (maxMotm > 0 ? ((player.motmTotal || 0) / maxMotm * 100) : 0) + '%"></div>';
|
html += '<div class="poty-bar-fill" style="width: ' + (maxMotm > 0 ? (motmVotes / maxMotm * 100) : 0) + '%"></div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '<div class="poty-bar poty-bar-dotd">';
|
html += '<div class="poty-bar poty-bar-dotd">';
|
||||||
html += '<div class="poty-bar-fill" style="width: ' + (maxDotd > 0 ? ((player.dotdTotal || 0) / maxDotd * 100) : 0) + '%"></div>';
|
html += '<div class="poty-bar-fill" style="width: ' + (maxDotd > 0 ? (dotdVotes / maxDotd * 100) : 0) + '%"></div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
|||||||
@ -136,14 +136,15 @@
|
|||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
background-color: #e9ecef; /* Light gray background for empty bars */
|
||||||
}
|
}
|
||||||
|
|
||||||
.vote-bar-motm {
|
.vote-bar-motm {
|
||||||
background: linear-gradient(90deg, #28a745, #20c997);
|
background-color: rgba(40, 167, 69, 0.1); /* Very light green background */
|
||||||
}
|
}
|
||||||
|
|
||||||
.vote-bar-dotd {
|
.vote-bar-dotd {
|
||||||
background: linear-gradient(90deg, #dc3545, #fd7e14);
|
background-color: rgba(220, 53, 69, 0.1); /* Very light red background */
|
||||||
}
|
}
|
||||||
|
|
||||||
.vote-bar-fill {
|
.vote-bar-fill {
|
||||||
@ -250,12 +251,14 @@ function renderVoteChart(data) {
|
|||||||
return aDotd - bDotd;
|
return aDotd - bDotd;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Find max values for scaling - each bar scales independently
|
// Find max values for independent scaling - each bar type scales to its own maximum
|
||||||
const maxMotm = Math.max(...data.map(p => p[motmKey] || 0));
|
const maxMotm = Math.max(...data.map(p => p[motmKey] || 0));
|
||||||
const maxDotd = Math.max(...data.map(p => p[dotdKey] || 0));
|
const maxDotd = Math.max(...data.map(p => p[dotdKey] || 0));
|
||||||
|
|
||||||
let html = '';
|
let html = '';
|
||||||
|
|
||||||
|
console.log('Max values calculated:', {maxMotm, maxDotd});
|
||||||
|
|
||||||
data.forEach((player, index) => {
|
data.forEach((player, index) => {
|
||||||
console.log('Processing vote player:', player);
|
console.log('Processing vote player:', player);
|
||||||
const ranking = index + 1;
|
const ranking = index + 1;
|
||||||
@ -264,6 +267,8 @@ function renderVoteChart(data) {
|
|||||||
const motmVotes = player[motmKey] || 0;
|
const motmVotes = player[motmKey] || 0;
|
||||||
const dotdVotes = player[dotdKey] || 0;
|
const dotdVotes = player[dotdKey] || 0;
|
||||||
|
|
||||||
|
console.log(`${player.playerName}: MOTM=${motmVotes}, DotD=${dotdVotes}`);
|
||||||
|
|
||||||
html += '<div class="vote-player-card">';
|
html += '<div class="vote-player-card">';
|
||||||
html += '<div class="d-flex align-items-center">';
|
html += '<div class="d-flex align-items-center">';
|
||||||
html += '<div class="vote-ranking ' + rankingClass + '">' + ranking + '</div>';
|
html += '<div class="vote-ranking ' + rankingClass + '">' + ranking + '</div>';
|
||||||
@ -278,12 +283,18 @@ function renderVoteChart(data) {
|
|||||||
html += '<div class="vote-stat-value text-danger">' + dotdVotes + '</div>';
|
html += '<div class="vote-stat-value text-danger">' + dotdVotes + '</div>';
|
||||||
html += '<div class="vote-stat-label">DotD</div>';
|
html += '<div class="vote-stat-label">DotD</div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
// Calculate percentages with debugging
|
||||||
|
const motmPercent = maxMotm > 0 ? (motmVotes / maxMotm * 100) : 0;
|
||||||
|
const dotdPercent = maxDotd > 0 ? (dotdVotes / maxDotd * 100) : 0;
|
||||||
|
|
||||||
|
console.log(`${player.playerName} percentages: MOTM=${motmPercent.toFixed(1)}%, DotD=${dotdPercent.toFixed(1)}%`);
|
||||||
|
|
||||||
html += '<div class="vote-bar-container">';
|
html += '<div class="vote-bar-container">';
|
||||||
html += '<div class="vote-bar vote-bar-motm">';
|
html += '<div class="vote-bar vote-bar-motm">';
|
||||||
html += '<div class="vote-bar-fill" style="width: ' + (maxMotm > 0 ? (motmVotes / maxMotm * 100) : 0) + '%"></div>';
|
html += '<div class="vote-bar-fill" style="width: ' + motmPercent + '%"></div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '<div class="vote-bar vote-bar-dotd">';
|
html += '<div class="vote-bar vote-bar-dotd">';
|
||||||
html += '<div class="vote-bar-fill" style="width: ' + (maxDotd > 0 ? (dotdVotes / maxDotd * 100) : 0) + '%"></div>';
|
html += '<div class="vote-bar-fill" style="width: ' + dotdPercent + '%"></div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
@ -294,6 +305,11 @@ function renderVoteChart(data) {
|
|||||||
|
|
||||||
container.innerHTML = html;
|
container.innerHTML = html;
|
||||||
|
|
||||||
|
// Verify bar widths are set correctly
|
||||||
|
setTimeout(() => {
|
||||||
|
verifyBarWidths();
|
||||||
|
}, 100);
|
||||||
|
|
||||||
// Animate bars after a short delay
|
// Animate bars after a short delay
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const bars = container.querySelectorAll('.vote-bar-fill');
|
const bars = container.querySelectorAll('.vote-bar-fill');
|
||||||
@ -326,5 +342,15 @@ function testVoteChart() {
|
|||||||
console.log('Testing with sample vote data:', testData);
|
console.log('Testing with sample vote data:', testData);
|
||||||
renderVoteChart(testData);
|
renderVoteChart(testData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a simple test to verify bar widths are being set
|
||||||
|
function verifyBarWidths() {
|
||||||
|
const bars = document.querySelectorAll('.vote-bar-fill');
|
||||||
|
console.log('Found bars:', bars.length);
|
||||||
|
bars.forEach((bar, index) => {
|
||||||
|
const width = bar.style.width;
|
||||||
|
console.log(`Bar ${index}: width = ${width}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Loading…
Reference in New Issue
Block a user