Add new infra architecture

This commit is contained in:
Urtzi Alfaro
2026-01-19 11:55:17 +01:00
parent 21d35ea92b
commit 35f164f0cd
311 changed files with 13241 additions and 3700 deletions

View File

@@ -886,7 +886,7 @@ microk8s kubectl apply -f infrastructure/ci-cd/tekton/pipelines/
microk8s kubectl apply -f infrastructure/ci-cd/tekton/triggers/ microk8s kubectl apply -f infrastructure/ci-cd/tekton/triggers/
# Apply Flux configurations # Apply Flux configurations
microk8s kubectl apply -f infrastructure/ci-cd/flux/ microk8s kubectl apply -k infrastructure/ci-cd/flux/
``` ```
--- ---

View File

@@ -1,120 +0,0 @@
# Docker Maintenance Guide for Local Development
## The Problem
When developing with Tilt and local Kubernetes (Kind), Docker accumulates:
- **Multiple image versions** from each code change (Tilt rebuilds)
- **Unused volumes** from previous cluster runs
- **Build cache** that grows over time
This quickly fills up disk space, causing pods to fail with "No space left on device" errors.
## Quick Fix (When You Hit Disk Issues)
```bash
# Clean up all unused Docker resources
docker system prune -a --volumes -f
```
This removes:
- All unused images
- All unused volumes
- All build cache
**Expected recovery**: 60-100GB
## Regular Maintenance
### Option 1: Use the Cleanup Script (Recommended)
Run the maintenance script weekly:
```bash
./scripts/cleanup-docker.sh
```
Or run it automatically without confirmation:
```bash
./scripts/cleanup-docker.sh --auto
```
### Option 2: Manual Commands
```bash
# Remove images older than 24 hours
docker image prune -af --filter "until=24h"
# Remove unused volumes
docker volume prune -f
# Remove build cache
docker builder prune -af
```
### Option 3: Set Up Automated Cleanup
Add to your crontab (run every Sunday at 2 AM):
```bash
crontab -e
# Add this line:
0 2 * * 0 /Users/urtzialfaro/Documents/bakery-ia/scripts/cleanup-docker.sh --auto >> /tmp/docker-cleanup.log 2>&1
```
## Monitoring Disk Usage
### Check Docker disk usage:
```bash
docker system df
```
### Check Kind node disk usage:
```bash
docker exec bakery-ia-local-control-plane df -h /var
```
### Alert thresholds:
- **< 70%**: Healthy
- **70-85%**: Consider cleanup soon
- **> 85%**: Run cleanup immediately 🚨
- **> 95%**: Critical - pods will fail ❌
## Prevention Tips
1. **Run cleanup weekly** to prevent accumulation
2. **Monitor disk usage** before long dev sessions
3. **Delete old Kind clusters** when switching projects:
```bash
kind delete cluster --name bakery-ia-local
```
4. **Increase Docker disk allocation** in Docker Desktop settings if you frequently rebuild many services
## Troubleshooting
### Pods in CrashLoopBackOff after disk issues:
1. Run cleanup (see Quick Fix above)
2. Restart failed pods:
```bash
kubectl get pods -n bakery-ia | grep -E "(CrashLoopBackOff|Error)" | awk '{print $1}' | xargs kubectl delete pod -n bakery-ia
```
### Cleanup didn't free enough space:
If still above 90% after cleanup:
```bash
# Nuclear option - rebuild everything
kind delete cluster --name bakery-ia-local
docker system prune -a --volumes -f
# Then recreate cluster with your setup scripts
```
## What Happened Today (2026-01-12)
- **Issue**: Disk was 100% full (113GB/113GB), causing database pods to crash
- **Root cause**: 122 unused Docker images + 16 unused volumes + 6GB build cache
- **Solution**: Ran `docker system prune -a --volumes -f`
- **Result**: Freed 89GB, disk now at 22% usage (24GB/113GB)
- **All services recovered successfully**

View File

@@ -1,413 +0,0 @@
# Infrastructure Reorganization Proposal for Bakery-IA
## Executive Summary
This document presents a comprehensive analysis of the current infrastructure organization and proposes a restructured layout that improves maintainability, scalability, and operational efficiency. The proposal is based on a detailed examination of the existing 177 files across 31 directories in the infrastructure folder.
## Current Infrastructure Analysis
### Current Structure Overview
```
infrastructure/
├── ci-cd/ # 18 files - CI/CD pipeline components
├── helm/ # 8 files - Helm charts and scripts
├── kubernetes/ # 103 files - Kubernetes manifests and configs
├── signoz/ # 11 files - Monitoring dashboards and scripts
└── tls/ # 37 files - TLS certificates and generation scripts
```
### Key Findings
1. **Kubernetes Base Components (103 files)**: The most complex area with:
- 20+ service deployments across 15+ microservices
- 20+ database configurations (PostgreSQL, RabbitMQ, MinIO)
- 19 migration jobs for different services
- Infrastructure components (gateway, monitoring, etc.)
2. **CI/CD Pipeline (18 files)**:
- Tekton tasks and pipelines for GitOps workflow
- Flux CD configuration for continuous delivery
- Gitea configuration for Git repository management
3. **Monitoring (11 files)**:
- SigNoz dashboards for comprehensive observability
- Import scripts for dashboard management
4. **TLS Certificates (37 files)**:
- CA certificates and generation scripts
- Service-specific certificates (PostgreSQL, Redis, MinIO)
- Certificate signing requests and configurations
### Strengths of Current Organization
1. **Logical Grouping**: Components are generally well-grouped by function
2. **Base/Overlay Pattern**: Kubernetes uses proper base/overlay structure
3. **Comprehensive Monitoring**: SigNoz dashboards cover all major aspects
4. **Security Focus**: Dedicated TLS certificate management
### Challenges Identified
1. **Complexity in Kubernetes Base**: 103 files make navigation difficult
2. **Mixed Component Types**: Services, databases, and infrastructure mixed together
3. **Limited Environment Separation**: Only dev/prod overlays, no staging
4. **Script Scattering**: Automation scripts spread across directories
5. **Documentation Gaps**: Some components lack clear documentation
## Proposed Infrastructure Organization
### High-Level Structure
```
infrastructure/
├── environments/ # Environment-specific configurations
├── platform/ # Platform-level infrastructure
├── services/ # Application services and microservices
├── monitoring/ # Observability and monitoring
├── cicd/ # CI/CD pipeline components
├── security/ # Security configurations and certificates
├── scripts/ # Automation and utility scripts
├── docs/ # Infrastructure documentation
└── README.md # Top-level infrastructure guide
```
### Detailed Structure Proposal
```
infrastructure/
├── environments/ # Environment-specific configurations
│ ├── dev/
│ │ ├── k8s-manifests/
│ │ │ ├── base/
│ │ │ │ ├── namespace.yaml
│ │ │ │ ├── configmap.yaml
│ │ │ │ ├── secrets.yaml
│ │ │ │ └── ingress-https.yaml
│ │ │ ├── components/
│ │ │ │ ├── databases/
│ │ │ │ ├── infrastructure/
│ │ │ │ ├── microservices/
│ │ │ │ └── cert-manager/
│ │ │ ├── configs/
│ │ │ ├── cronjobs/
│ │ │ ├── jobs/
│ │ │ └── migrations/
│ │ ├── kustomization.yaml
│ │ └── values/
│ ├── staging/ # New staging environment
│ │ ├── k8s-manifests/
│ │ └── values/
│ └── prod/
│ ├── k8s-manifests/
│ ├── terraform/ # Production-specific IaC
│ └── values/
├── platform/ # Platform-level infrastructure
│ ├── cluster/
│ │ ├── eks/ # AWS EKS configuration
│ │ │ ├── terraform/
│ │ │ └── manifests/
│ │ └── kind/ # Local development cluster
│ │ ├── config.yaml
│ │ └── manifests/
│ ├── networking/
│ │ ├── dns/
│ │ ├── load-balancers/
│ │ └── ingress/
│ │ ├── nginx/
│ │ └── cert-manager/
│ ├── security/
│ │ ├── rbac/
│ │ ├── network-policies/
│ │ └── tls/
│ │ ├── ca/
│ │ ├── postgres/
│ │ ├── redis/
│ │ └── minio/
│ └── storage/
│ ├── postgres/
│ ├── redis/
│ └── minio/
├── services/ # Application services
│ ├── databases/
│ │ ├── postgres/
│ │ │ ├── k8s-manifests/
│ │ │ ├── backups/
│ │ │ ├── monitoring/
│ │ │ └── maintenance/
│ │ ├── redis/
│ │ │ ├── configs/
│ │ │ └── monitoring/
│ │ └── minio/
│ │ ├── buckets/
│ │ └── policies/
│ ├── api-gateway/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ └── microservices/
│ ├── auth/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── tenant/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── training/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── forecasting/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── sales/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── external/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── notification/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── inventory/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── recipes/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── suppliers/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── pos/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── orders/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── production/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── procurement/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── orchestrator/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── alert-processor/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── ai-insights/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ ├── demo-session/
│ │ ├── k8s-manifests/
│ │ └── configs/
│ └── frontend/
│ ├── k8s-manifests/
│ └── configs/
├── monitoring/ # Observability stack
│ ├── signoz/
│ │ ├── manifests/
│ │ ├── dashboards/
│ │ │ ├── alert-management.json
│ │ │ ├── api-performance.json
│ │ │ ├── application-performance.json
│ │ │ ├── database-performance.json
│ │ │ ├── error-tracking.json
│ │ │ ├── index.json
│ │ │ ├── infrastructure-monitoring.json
│ │ │ ├── log-analysis.json
│ │ │ ├── system-health.json
│ │ │ └── user-activity.json
│ │ ├── values-dev.yaml
│ │ ├── values-prod.yaml
│ │ ├── deploy-signoz.sh
│ │ ├── verify-signoz.sh
│ │ └── generate-test-traffic.sh
│ └── opentelemetry/
│ ├── collector/
│ └── agent/
├── cicd/ # CI/CD pipeline
│ ├── gitea/
│ │ ├── values.yaml
│ │ └── ingress.yaml
│ ├── tekton/
│ │ ├── tasks/
│ │ │ ├── git-clone.yaml
│ │ │ ├── detect-changes.yaml
│ │ │ ├── kaniko-build.yaml
│ │ │ └── update-gitops.yaml
│ │ ├── pipelines/
│ │ └── triggers/
│ └── flux/
│ ├── git-repository.yaml
│ └── kustomization.yaml
├── security/ # Security configurations
│ ├── policies/
│ │ ├── network-policies.yaml
│ │ ├── pod-security.yaml
│ │ └── rbac.yaml
│ ├── certificates/
│ │ ├── ca/
│ │ ├── services/
│ │ └── rotation-scripts/
│ ├── scanning/
│ │ ├── trivy/
│ │ └── policies/
│ └── compliance/
│ ├── cis-benchmarks/
│ └── audit-scripts/
├── scripts/ # Automation scripts
│ ├── setup/
│ │ ├── generate-certificates.sh
│ │ ├── generate-minio-certificates.sh
│ │ └── setup-dockerhub-secrets.sh
│ ├── deployment/
│ │ ├── deploy-signoz.sh
│ │ └── verify-signoz.sh
│ ├── maintenance/
│ │ ├── regenerate_migrations_k8s.sh
│ │ └── kubernetes_restart.sh
│ └── verification/
│ └── verify-registry.sh
├── docs/ # Infrastructure documentation
│ ├── architecture/
│ │ ├── diagrams/
│ │ └── decisions/
│ ├── operations/
│ │ ├── runbooks/
│ │ └── troubleshooting/
│ ├── onboarding/
│ └── reference/
│ ├── api/
│ └── configurations/
└── README.md
```
## Migration Strategy
### Phase 1: Preparation and Planning
1. **Inventory Analysis**: Complete detailed inventory of all current files
2. **Dependency Mapping**: Identify dependencies between components
3. **Impact Assessment**: Determine which components can be moved safely
4. **Backup Strategy**: Ensure all files are backed up before migration
### Phase 2: Non-Critical Components
1. **Documentation**: Move and update all documentation files
2. **Scripts**: Organize automation scripts into new structure
3. **Monitoring**: Migrate SigNoz dashboards and configurations
4. **CI/CD**: Reorganize pipeline components
### Phase 3: Environment-Specific Components
1. **Create Environment Structure**: Set up dev/staging/prod directories
2. **Migrate Kubernetes Manifests**: Move base components to appropriate locations
3. **Update References**: Ensure all cross-references are corrected
4. **Environment Validation**: Test each environment separately
### Phase 4: Service Components
1. **Database Migration**: Move database configurations to services/databases
2. **Microservice Organization**: Group microservices by domain
3. **Infrastructure Components**: Move gateway and other infrastructure
4. **Service Validation**: Test each service in isolation
### Phase 5: Finalization
1. **Integration Testing**: Test complete infrastructure workflow
2. **Documentation Update**: Finalize all documentation
3. **Team Training**: Conduct training on new structure
4. **Cleanup**: Remove old structure and temporary files
## Benefits of Proposed Structure
### 1. Improved Navigation
- **Clear Hierarchy**: Logical grouping by function and environment
- **Consistent Patterns**: Standardized structure across all components
- **Reduced Cognitive Load**: Easier to find specific components
### 2. Enhanced Maintainability
- **Environment Isolation**: Clear separation of dev/staging/prod
- **Component Grouping**: Related components grouped together
- **Standardized Structure**: Consistent patterns across services
### 3. Better Scalability
- **Modular Design**: Easy to add new services or environments
- **Domain Separation**: Services organized by business domain
- **Infrastructure Independence**: Platform components separate from services
### 4. Improved Security
- **Centralized Security**: All security configurations in one place
- **Environment-Specific Policies**: Tailored security for each environment
- **Better Secret Management**: Clear structure for sensitive data
### 5. Enhanced Observability
- **Comprehensive Monitoring**: All observability tools grouped
- **Standardized Dashboards**: Consistent monitoring across services
- **Centralized Logging**: Better log management structure
## Implementation Considerations
### Tools and Technologies
- **Terraform**: For infrastructure as code (IaC)
- **Kustomize**: For Kubernetes manifest management
- **Helm**: For complex application deployments
- **SOPS/Sealed Secrets**: For secret management
- **Trivy**: For vulnerability scanning
### Team Adaptation
- **Training Plan**: Develop comprehensive training materials
- **Migration Guide**: Create step-by-step migration documentation
- **Support Period**: Provide dedicated support during transition
- **Feedback Mechanism**: Establish channels for team feedback
### Risk Mitigation
- **Phased Approach**: Implement changes incrementally
- **Rollback Plan**: Develop comprehensive rollback procedures
- **Testing Strategy**: Implement thorough testing at each phase
- **Monitoring**: Enhanced monitoring during migration period
## Expected Outcomes
1. **Reduced Time-to-Find**: 40-60% reduction in time spent locating files
2. **Improved Deployment Speed**: 25-35% faster deployment cycles
3. **Enhanced Collaboration**: Better team coordination and understanding
4. **Reduced Errors**: 30-50% reduction in configuration errors
5. **Better Scalability**: Easier to add new services and features
## Conclusion
The proposed infrastructure reorganization represents a significant improvement over the current structure. By implementing a clear, logical hierarchy with proper separation of concerns, the new organization will:
- **Improve operational efficiency** through better navigation and maintainability
- **Enhance security** with centralized security management
- **Support growth** with a scalable, modular design
- **Reduce errors** through standardized patterns and structures
- **Facilitate collaboration** with intuitive organization
The key to successful implementation is a phased approach with thorough testing and team involvement at each stage. With proper planning and execution, this reorganization will provide long-term benefits for the Bakery-IA project's infrastructure management.
## Appendix: File Migration Mapping
### Current → Proposed Mapping
**Kubernetes Components:**
- `infrastructure/kubernetes/base/components/*``infrastructure/services/microservices/*/`
- `infrastructure/kubernetes/base/components/databases/*``infrastructure/services/databases/*/`
- `infrastructure/kubernetes/base/migrations/*``infrastructure/services/microservices/*/migrations/`
- `infrastructure/kubernetes/base/configs/*``infrastructure/environments/*/values/`
**CI/CD Components:**
- `infrastructure/ci-cd/*``infrastructure/cicd/*/`
**Monitoring Components:**
- `infrastructure/signoz/*``infrastructure/monitoring/signoz/*/`
- `infrastructure/helm/*``infrastructure/monitoring/signoz/*/` (signoz-related)
**Security Components:**
- `infrastructure/tls/*``infrastructure/security/certificates/*/`
**Scripts:**
- `infrastructure/kubernetes/*.sh``infrastructure/scripts/*/`
- `infrastructure/helm/*.sh``infrastructure/scripts/deployment/*/`
- `infrastructure/tls/*.sh``infrastructure/scripts/setup/*/`
This mapping provides a clear path for migrating each component to its new location while maintaining functionality and relationships between components.

View File

@@ -81,7 +81,7 @@ For production deployment on clouding.io with Kubernetes:
3. Configure production-specific values 3. Configure production-specific values
4. Deploy using the production kustomization: 4. Deploy using the production kustomization:
```bash ```bash
kubectl apply -k infrastructure/kubernetes/environments/production/ kubectl apply -k infrastructure/environments/prod/k8s-manifests
``` ```
## 🤝 Contributing ## 🤝 Contributing

335
Tiltfile
View File

@@ -17,6 +17,43 @@
# ============================================================================= # =============================================================================
# =============================================================================
# PREPULL BASE IMAGES STEP - CRITICAL FIRST STEP
# =============================================================================
# Run the prepull script first - if this fails, don't continue
local_resource(
'prepull-base-images',
cmd='''#!/usr/bin/env bash
echo "=========================================="
echo "PREPULLING BASE IMAGES - CRITICAL STEP"
echo "=========================================="
echo ""
# Run the prepull script
if ./scripts/prepull-base-images.sh; then
echo ""
echo "✓ Base images prepull completed successfully"
echo "=========================================="
echo "CONTINUING WITH TILT SETUP..."
echo "=========================================="
exit 0
else
echo ""
echo "❌ Base images prepull FAILED - stopping Tilt execution"
echo "This usually happens due to Docker Hub rate limits"
echo "Please try again later or configure Docker Hub credentials"
echo "=========================================="
# Exit with error code to prevent further execution
exit 1
fi
''',
labels=['00-prepull'],
auto_init=True,
allow_parallel=False
)
# ============================================================================= # =============================================================================
# TILT CONFIGURATION # TILT CONFIGURATION
# ============================================================================= # =============================================================================
@@ -191,132 +228,68 @@ Monitoring:
Applying security configurations... Applying security configurations...
""") """)
# Create Docker Hub secret for image pulls (if credentials are available)
local_resource(
'dockerhub-secret',
cmd='''
echo "Setting up Docker Hub image pull secret..."
# Check if Docker Hub credentials are available
if [ -n "$DOCKERHUB_USERNAME" ] && [ -n "$DOCKERHUB_PASSWORD" ]; then
echo " Found DOCKERHUB_USERNAME and DOCKERHUB_PASSWORD environment variables"
./infrastructure/kubernetes/create-dockerhub-secret.sh
elif [ -f "$HOME/.docker/config.json" ]; then
echo " Attempting to use Docker CLI credentials..."
./infrastructure/kubernetes/create-dockerhub-secret.sh
else
echo " Docker Hub credentials not found"
echo " To enable automatic Docker Hub authentication:"
echo " 1. Run 'docker login', OR"
echo " 2. Set environment variables:"
echo " export DOCKERHUB_USERNAME='your-username'"
echo " export DOCKERHUB_PASSWORD='your-password-or-token'"
echo ""
echo " Continuing without Docker Hub authentication..."
echo " (This is OK for local development using local registry)"
fi
''',
labels=['00-security'],
auto_init=True
)
# Apply security configurations before loading main manifests # Apply security configurations before loading main manifests
local_resource( local_resource(
'security-setup', 'security-setup',
cmd=''' cmd='''
echo "Applying security secrets and configurations..." echo "Applying security secrets and configurations..."
kubectl apply -f infrastructure/kubernetes/base/secrets.yaml
kubectl apply -f infrastructure/kubernetes/base/secrets/postgres-tls-secret.yaml # First, ensure all required namespaces exist
kubectl apply -f infrastructure/kubernetes/base/secrets/redis-tls-secret.yaml echo "Creating namespaces..."
kubectl apply -f infrastructure/kubernetes/base/configs/postgres-init-config.yaml kubectl apply -f infrastructure/namespaces/bakery-ia.yaml
kubectl apply -f infrastructure/kubernetes/base/configmaps/postgres-logging-config.yaml kubectl apply -f infrastructure/namespaces/tekton-pipelines.yaml
kubectl apply -f infrastructure/namespaces/flux-system.yaml
# Wait for namespaces to be ready
echo "Waiting for namespaces to be ready..."
for ns in bakery-ia tekton-pipelines flux-system; do
until kubectl get namespace $ns 2>/dev/null; do
echo "Waiting for namespace $ns to be created..."
sleep 2
done
echo "Namespace $ns is available"
done
# Apply common secrets and configs
kubectl apply -f infrastructure/environments/common/configs/configmap.yaml
kubectl apply -f infrastructure/environments/common/configs/secrets.yaml
# Apply database secrets and configs
kubectl apply -f infrastructure/platform/storage/postgres/secrets/postgres-tls-secret.yaml
kubectl apply -f infrastructure/platform/storage/postgres/configs/postgres-init-config.yaml
kubectl apply -f infrastructure/platform/storage/postgres/configs/postgres-logging-config.yaml
# Apply Redis secrets
kubectl apply -f infrastructure/platform/storage/redis/secrets/redis-tls-secret.yaml
# Apply MinIO secrets and configs
kubectl apply -f infrastructure/platform/storage/minio/minio-secrets.yaml
kubectl apply -f infrastructure/platform/storage/minio/secrets/minio-tls-secret.yaml
# Apply Mail/SMTP secrets
kubectl apply -f infrastructure/platform/mail/mailu/mailu-secrets.yaml
# Apply CI/CD secrets
kubectl apply -f infrastructure/cicd/tekton/secrets/secrets.yaml
echo "Security configurations applied" echo "Security configurations applied"
''', ''',
resource_deps=['dockerhub-secret'], resource_deps=['prepull-base-images'], # Removed dockerhub-secret dependency
labels=['00-security'], labels=['00-security'],
auto_init=True auto_init=True
) )
# Verify TLS certificates are mounted correctly # Verify TLS certificates are mounted correctly
local_resource(
'verify-tls',
cmd='''
echo "Verifying TLS configuration..."
sleep 5 # Wait for pods to be ready
# Check if auth-db pod exists and has TLS certs
AUTH_POD=$(kubectl get pods -n bakery-ia -l app.kubernetes.io/name=auth-db -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "")
if [ -n "$AUTH_POD" ]; then
echo " Checking PostgreSQL TLS certificates..."
kubectl exec -n bakery-ia "$AUTH_POD" -- ls -la /tls/ 2>/dev/null && \
echo " PostgreSQL TLS certificates mounted" || \
echo " PostgreSQL TLS certificates not found (pods may still be starting)"
fi
# Check if redis pod exists and has TLS certs
REDIS_POD=$(kubectl get pods -n bakery-ia -l app.kubernetes.io/name=redis -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "")
if [ -n "$REDIS_POD" ]; then
echo " Checking Redis TLS certificates..."
kubectl exec -n bakery-ia "$REDIS_POD" -- ls -la /tls/ 2>/dev/null && \
echo " Redis TLS certificates mounted" || \
echo " Redis TLS certificates not found (pods may still be starting)"
fi
echo "TLS verification complete"
''',
resource_deps=['auth-db', 'redis'],
auto_init=True,
labels=['00-security']
)
# Verify PVCs are bound
local_resource(
'verify-pvcs',
cmd='''
echo "Verifying PersistentVolumeClaims..."
kubectl get pvc -n bakery-ia | grep -E "NAME|db-pvc" || echo " PVCs not yet bound"
PVC_COUNT=$(kubectl get pvc -n bakery-ia -o json | jq '.items | length')
echo " Found $PVC_COUNT PVCs"
echo "PVC verification complete"
''',
resource_deps=['auth-db'],
auto_init=True,
labels=['00-security']
)
# Install and verify cert-manager
local_resource(
'cert-manager-install',
cmd='''
echo "Installing cert-manager..."
# Check if cert-manager CRDs already exist
if kubectl get crd certificates.cert-manager.io >/dev/null 2>&1; then
echo " cert-manager CRDs already installed"
else
echo " Installing cert-manager v1.13.2..."
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.yaml
echo " Waiting for cert-manager to be ready..."
kubectl wait --for=condition=available --timeout=120s deployment/cert-manager -n cert-manager
kubectl wait --for=condition=available --timeout=120s deployment/cert-manager-webhook -n cert-manager
echo " cert-manager installed and ready"
fi
echo "cert-manager verification complete"
''',
labels=['00-security'],
auto_init=True
)
# ============================================================================= # =============================================================================
# LOAD KUBERNETES MANIFESTS # LOAD KUBERNETES MANIFESTS
# ============================================================================= # =============================================================================
k8s_yaml(kustomize('infrastructure/kubernetes/overlays/dev')) # Load the main kustomize overlay for the dev environment
k8s_yaml(kustomize('infrastructure/environments/dev/k8s-manifests'))
# ============================================================================= # =============================================================================
# DOCKER BUILD HELPERS # DOCKER BUILD HELPERS
@@ -509,6 +482,9 @@ k8s_resource('nominatim', labels=['01-infrastructure'])
k8s_resource('minio', resource_deps=['security-setup'], labels=['01-infrastructure']) k8s_resource('minio', resource_deps=['security-setup'], labels=['01-infrastructure'])
k8s_resource('minio-bucket-init', resource_deps=['minio'], labels=['01-infrastructure']) k8s_resource('minio-bucket-init', resource_deps=['minio'], labels=['01-infrastructure'])
# Mail Infrastructure (Mailu)
k8s_resource('mailu-front', resource_deps=['security-setup'], labels=['01-infrastructure'])
# ============================================================================= # =============================================================================
# MONITORING RESOURCES - SigNoz (Unified Observability) # MONITORING RESOURCES - SigNoz (Unified Observability)
# ============================================================================= # =============================================================================
@@ -520,15 +496,6 @@ local_resource(
echo "Deploying SigNoz Monitoring Stack..." echo "Deploying SigNoz Monitoring Stack..."
echo "" echo ""
# Ensure Docker Hub secret exists in bakery-ia namespace
echo "Ensuring Docker Hub secret exists in bakery-ia namespace..."
if ! kubectl get secret dockerhub-creds -n bakery-ia &>/dev/null; then
echo " Docker Hub secret not found, attempting to create..."
./infrastructure/kubernetes/create-dockerhub-secret.sh || echo " Continuing without Docker Hub authentication..."
else
echo " Docker Hub secret exists"
fi
echo ""
# Check if SigNoz is already deployed # Check if SigNoz is already deployed
if helm list -n bakery-ia | grep -q signoz; then if helm list -n bakery-ia | grep -q signoz; then
@@ -544,7 +511,7 @@ local_resource(
# Install SigNoz with custom values in the bakery-ia namespace # Install SigNoz with custom values in the bakery-ia namespace
helm upgrade --install signoz signoz/signoz \ helm upgrade --install signoz signoz/signoz \
-n bakery-ia \ -n bakery-ia \
-f infrastructure/helm/signoz-values-dev.yaml \ -f infrastructure/monitoring/signoz/signoz-values-dev.yaml \
--timeout 10m \ --timeout 10m \
--wait --wait
@@ -568,43 +535,6 @@ local_resource(
auto_init=False, auto_init=False,
) )
# Track SigNoz pods in Tilt UI using workload tracking
# These will automatically discover pods once SigNoz is deployed
local_resource(
'signoz-status',
cmd='''
echo "SigNoz Status Check"
echo ""
# Check pod status
echo "Current SigNoz pods:"
kubectl get pods -n bakery-ia -l app.kubernetes.io/instance=signoz -o wide 2>/dev/null || echo "No pods found"
echo ""
echo "SigNoz Services:"
kubectl get svc -n bakery-ia -l app.kubernetes.io/instance=signoz 2>/dev/null || echo "No services found"
# Check if all pods are ready
TOTAL_PODS=$(kubectl get pods -n bakery-ia -l app.kubernetes.io/instance=signoz --no-headers 2>/dev/null | wc -l | tr -d ' ')
READY_PODS=$(kubectl get pods -n bakery-ia -l app.kubernetes.io/instance=signoz --field-selector=status.phase=Running --no-headers 2>/dev/null | wc -l | tr -d ' ')
if [ "$TOTAL_PODS" -gt 0 ]; then
echo ""
echo "Pod Status: $READY_PODS/$TOTAL_PODS ready"
if [ "$READY_PODS" -eq "$TOTAL_PODS" ]; then
echo "All SigNoz pods are running!"
echo ""
echo "Access SigNoz at: https://monitoring.bakery-ia.local"
echo "Credentials: admin / admin"
else
echo "Waiting for pods to become ready..."
fi
fi
''',
labels=['05-monitoring'],
auto_init=False,
)
# Optional exporters (in monitoring namespace) - DISABLED since using SigNoz # Optional exporters (in monitoring namespace) - DISABLED since using SigNoz
# k8s_resource('node-exporter', labels=['05-monitoring']) # k8s_resource('node-exporter', labels=['05-monitoring'])
@@ -774,6 +704,98 @@ watch_settings(
] ]
) )
# =============================================================================
# CI/CD INFRASTRUCTURE - MANUAL TRIGGERS
# =============================================================================
# Tekton Pipelines - Manual trigger for local development
local_resource(
'tekton-pipelines',
cmd='''
echo "Setting up Tekton Pipelines for CI/CD..."
echo ""
# Check if Tekton CRDs are already installed
if kubectl get crd pipelines.tekton.dev >/dev/null 2>&1; then
echo " Tekton CRDs already installed"
else
echo " Installing Tekton v0.57.0..."
kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
echo " Waiting for Tekton to be ready..."
kubectl wait --for=condition=available --timeout=180s deployment/tekton-pipelines-controller -n tekton-pipelines
kubectl wait --for=condition=available --timeout=180s deployment/tekton-pipelines-webhook -n tekton-pipelines
echo " Tekton installed and ready"
fi
echo ""
echo "Applying Tekton configurations..."
kubectl apply -f infrastructure/cicd/tekton/kustomization.yaml
kubectl apply -f infrastructure/cicd/tekton/rbac/
kubectl apply -f infrastructure/cicd/tekton/tasks/
kubectl apply -f infrastructure/cicd/tekton/pipelines/
echo ""
echo "Tekton setup complete!"
echo "To check status: kubectl get pods -n tekton-pipelines"
''',
labels=['99-cicd'],
auto_init=False, # Manual trigger only
)
# Flux CD - Manual trigger for GitOps
local_resource(
'flux-cd',
cmd='''
echo "Setting up Flux CD for GitOps..."
echo ""
# Check if Flux CRDs are already installed
if kubectl get crd gitrepositories.source.toolkit.fluxcd.io >/dev/null 2>&1; then
echo " Flux CRDs already installed"
else
echo " Installing Flux v2.2.3..."
curl -sL https://fluxcd.io/install.sh | sudo bash
flux install --version=latest
echo " Flux installed and ready"
fi
echo ""
echo "Applying Flux configurations..."
kubectl apply -f infrastructure/cicd/flux/
echo ""
echo "Flux setup complete!"
echo "To check status: flux check"
''',
labels=['99-cicd'],
auto_init=False, # Manual trigger only
)
# Gitea - Manual trigger for local Git server
local_resource(
'gitea',
cmd='''
echo "Setting up Gitea for local Git server..."
echo ""
# Apply Gitea configurations
kubectl create namespace gitea || true
kubectl apply -f infrastructure/cicd/gitea/
echo ""
echo "Gitea setup complete!"
echo "Access Gitea at: http://gitea.local (add to /etc/hosts)"
echo "Default credentials: admin/admin123 (change after first login)"
echo "To check status: kubectl get pods -n gitea"
''',
labels=['99-cicd'],
auto_init=False, # Manual trigger only
)
# ============================================================================= # =============================================================================
# STARTUP SUMMARY # STARTUP SUMMARY
# ============================================================================= # =============================================================================
@@ -804,11 +826,16 @@ Access your application:
SigNoz (Unified Observability): SigNoz (Unified Observability):
Deploy via Tilt: Trigger 'signoz-deployment' resource Deploy via Tilt: Trigger 'signoz-deployment' resource
Manual deploy: ./infrastructure/helm/deploy-signoz.sh dev Manual deploy: ./infrastructure/monitoring/signoz/deploy-signoz.sh dev
Access (if deployed): https://monitoring.bakery-ia.local Access (if deployed): https://monitoring.bakery-ia.local
Username: admin Username: admin
Password: admin Password: admin
CI/CD Infrastructure (Manual Triggers):
Tekton: Trigger 'tekton-pipelines' resource
Flux: Trigger 'flux-cd' resource
Gitea: Trigger 'gitea' resource
Verify security: Verify security:
kubectl get pvc -n bakery-ia kubectl get pvc -n bakery-ia
kubectl get secrets -n bakery-ia | grep tls kubectl get secrets -n bakery-ia | grep tls

View File

@@ -685,7 +685,7 @@ kubectl scale deployment auth-service -n bakery-ia --replicas=2
# 2. Install MicroK8s (follow pilot launch guide) # 2. Install MicroK8s (follow pilot launch guide)
# 3. Copy latest backup to new VPS # 3. Copy latest backup to new VPS
# 4. Deploy infrastructure and databases # 4. Deploy infrastructure and databases
kubectl apply -k infrastructure/kubernetes/overlays/prod kubectl apply -k infrastructure/environments/prod/k8s-manifests
# 5. Wait for databases to be ready # 5. Wait for databases to be ready
kubectl wait --for=condition=ready pod -l app.kubernetes.io/component=database -n bakery-ia kubectl wait --for=condition=ready pod -l app.kubernetes.io/component=database -n bakery-ia
@@ -699,7 +699,7 @@ for backup in /backups/latest/*.sql; do
done done
# 7. Deploy services # 7. Deploy services
kubectl apply -k infrastructure/kubernetes/overlays/prod kubectl apply -k infrastructure/environments/prod/k8s-manifests
# 8. Update DNS to point to new VPS # 8. Update DNS to point to new VPS
# 9. Verify all services healthy # 9. Verify all services healthy
@@ -830,12 +830,12 @@ nproc
kubectl scale deployment orders-service -n bakery-ia --replicas=5 kubectl scale deployment orders-service -n bakery-ia --replicas=5
# Or update in kustomization for persistence # Or update in kustomization for persistence
# Edit: infrastructure/kubernetes/overlays/prod/kustomization.yaml # Edit: infrastructure/environments/prod/k8s-manifests/kustomization.yaml
replicas: replicas:
- name: orders-service - name: orders-service
count: 5 count: 5
kubectl apply -k infrastructure/kubernetes/overlays/prod kubectl apply -k infrastructure/environments/prod/k8s-manifests
``` ```
### Auto-Scaling (HPA) ### Auto-Scaling (HPA)
@@ -976,7 +976,7 @@ resources:
memory: "1Gi" # Increased from 512Mi memory: "1Gi" # Increased from 512Mi
# 4. Redeploy # 4. Redeploy
kubectl apply -k infrastructure/kubernetes/overlays/prod kubectl apply -k infrastructure/environments/prod/k8s-manifests
``` ```
#### Incident: Certificate Expired #### Incident: Certificate Expired

View File

@@ -324,12 +324,12 @@ log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
**Renewal Process:** **Renewal Process:**
```bash ```bash
# 1. Regenerate certificates (90 days before expiry) # 1. Regenerate certificates (90 days before expiry)
cd infrastructure/tls && ./generate-certificates.sh cd infrastructure/security/certificates && ./generate-certificates.sh
# 2. Update Kubernetes secrets # 2. Update Kubernetes secrets
kubectl delete secret postgres-tls redis-tls -n bakery-ia kubectl delete secret postgres-tls redis-tls -n bakery-ia
kubectl apply -f infrastructure/kubernetes/base/secrets/postgres-tls-secret.yaml kubectl apply -f infrastructure/environments/dev/k8s-manifests/base/secrets/postgres-tls-secret.yaml
kubectl apply -f infrastructure/kubernetes/base/secrets/redis-tls-secret.yaml kubectl apply -f infrastructure/environments/dev/k8s-manifests/base/secrets/redis-tls-secret.yaml
# 3. Restart database pods (automatic) # 3. Restart database pods (automatic)
kubectl rollout restart deployment -l app.kubernetes.io/component=database -n bakery-ia kubectl rollout restart deployment -l app.kubernetes.io/component=database -n bakery-ia
@@ -351,7 +351,7 @@ kubectl rollout restart deployment -l app.kubernetes.io/component=database -n ba
./scripts/update-k8s-secrets.sh ./scripts/update-k8s-secrets.sh
# 4. Apply secrets # 4. Apply secrets
kubectl apply -f infrastructure/kubernetes/base/secrets.yaml kubectl apply -f infrastructure/environments/common/configs/secrets.yaml
# 5. Restart databases and services # 5. Restart databases and services
kubectl rollout restart deployment -n bakery-ia kubectl rollout restart deployment -n bakery-ia

View File

@@ -1,10 +1,10 @@
# Add this stage at the top of each service Dockerfile # Add this stage at the top of each service Dockerfile
FROM python:3.11-slim AS shared FROM localhost:5000/python_3.11-slim AS shared
WORKDIR /shared WORKDIR /shared
COPY shared/ /shared/ COPY shared/ /shared/
# Then your main service stage # Then your main service stage
FROM python:3.11-slim FROM localhost:5000/python_3.11-slim
# Create non-root user for security # Create non-root user for security
RUN groupadd -r appgroup && useradd -r -g appgroup appuser RUN groupadd -r appgroup && useradd -r -g appgroup appuser

View File

@@ -0,0 +1,119 @@
# Bakery-IA Namespace Management
## Overview
This document explains the namespace strategy for the Bakery-IA platform and how to properly manage namespaces during deployment.
## Namespace Architecture
The Bakery-IA platform uses the following namespaces:
### Core Namespaces
1. **`bakery-ia`** - Main application namespace
- Contains all microservices, databases, and application components
- Defined in: `infrastructure/namespaces/bakery-ia.yaml`
2. **`tekton-pipelines`** - CI/CD pipeline namespace
- Contains Tekton pipeline resources, tasks, and triggers
- Defined in: `infrastructure/namespaces/tekton-pipelines.yaml`
3. **`flux-system`** - GitOps namespace
- Contains Flux CD components for GitOps deployments
- Defined in: `infrastructure/namespaces/flux-system.yaml`
### Infrastructure Namespaces
Additional namespaces may be created for:
- Monitoring components
- Logging components
- Security components
## Deployment Order
**CRITICAL**: Namespaces must be created BEFORE any resources that depend on them.
### Correct Deployment Sequence
```bash
# 1. Create namespaces first
kubectl apply -f infrastructure/namespaces/
# 2. Apply common configurations (depends on bakery-ia namespace)
kubectl apply -f infrastructure/environments/common/configs/
# 3. Apply platform components
kubectl apply -f infrastructure/platform/
# 4. Apply CI/CD components (depends on tekton-pipelines and flux-system)
kubectl apply -f infrastructure/cicd/
# 5. Apply monitoring components
kubectl apply -f infrastructure/monitoring/
```
## Common Issues and Solutions
### Issue: "namespace not found" errors
**Symptoms**: Errors like:
```
Error from server (NotFound): error when creating "path/to/resource.yaml": namespaces "[namespace-name]" not found
```
**Solutions**:
1. **Ensure namespaces are created first** - Use the deployment script that applies namespaces before other resources
2. **Check for templating issues** - If you see names like `[redacted secret rabbitmq-secrets:RABBITMQ_USER]-ia`, there may be environment variable substitution happening incorrectly
3. **Verify namespace YAML files** - Ensure the namespace files exist and are properly formatted
### Issue: Resource conflicts across namespaces
**Solution**: Use proper namespace isolation and RBAC policies to prevent cross-namespace conflicts.
## Best Practices
1. **Namespace Isolation**: Keep resources properly isolated by namespace
2. **RBAC**: Use namespace-specific RBAC roles and bindings
3. **Resource Quotas**: Apply resource quotas per namespace
4. **Network Policies**: Use network policies to control cross-namespace communication
## Troubleshooting
### Verify namespaces exist
```bash
kubectl get namespaces
```
### Check namespace labels
```bash
kubectl get namespace bakery-ia --show-labels
```
### View namespace events
```bash
kubectl describe namespace bakery-ia
```
## Migration from Old Structure
If you're migrating from the old structure where namespaces were scattered across different directories:
1. **Remove old namespace files** from:
- `infrastructure/environments/common/configs/namespace.yaml`
- `infrastructure/cicd/flux/namespace.yaml`
2. **Update kustomization files** to reference the centralized namespace files
3. **Use the new deployment script** that follows the correct order
## Future Enhancements
- Add namespace lifecycle management
- Implement namespace cleanup scripts
- Add namespace validation checks to CI/CD pipelines

57
infrastructure/README.md Normal file
View File

@@ -0,0 +1,57 @@
# Bakery-IA Infrastructure
This directory contains all infrastructure-as-code for the Bakery-IA project, organized according to best practices for maintainability and scalability.
## Directory Structure
```
infrastructure/
├── environments/ # Environment-specific configurations
│ ├── dev/ # Development environment
│ │ ├── k8s-manifests/ # Kubernetes manifests for dev
│ │ └── values/ # Environment-specific values
│ ├── staging/ # Staging environment
│ │ ├── k8s-manifests/
│ │ └── values/
│ └── prod/ # Production environment
│ ├── k8s-manifests/
│ ├── terraform/ # Production-specific IaC
│ └── values/
├── platform/ # Platform-level infrastructure
│ ├── cluster/ # Cluster configuration (EKS, Kind)
│ ├── networking/ # Network configuration
│ ├── security/ # Security policies and TLS
│ └── storage/ # Storage configuration
├── services/ # Application services
│ ├── databases/ # Database configurations
│ ├── api-gateway/ # API gateway configuration
│ └── microservices/ # Individual microservice configs
├── monitoring/ # Observability stack
│ └── signoz/ # SigNoz configuration
├── cicd/ # CI/CD pipeline components
├── security/ # Security configurations
├── scripts/ # Automation scripts
└── docs/ # Infrastructure documentation
```
## Environments
Each environment (dev, staging, prod) has its own configuration with appropriate isolation and security settings.
## Services
Services are organized by business domain with clear separation between databases, microservices, and infrastructure components.
## Getting Started
1. **Local Development**: Use `tilt up` to start the development environment
2. **Deployment**: Use `skaffold run` to deploy to your target environment
3. **CI/CD**: Tekton pipelines manage automated deployments
## Security
Security configurations are centralized in the `security/` directory with:
- TLS certificates and rotation scripts
- Network policies
- RBAC configurations
- Compliance checks

View File

@@ -1,27 +0,0 @@
# Flux Kustomization for Bakery-IA Production Deployment
# This resource tells Flux how to deploy the application
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: bakery-ia-prod
namespace: flux-system
spec:
interval: 5m
path: ./infrastructure/kubernetes/overlays/prod
prune: true
sourceRef:
kind: GitRepository
name: bakery-ia
targetNamespace: bakery-ia
timeout: 5m
retryInterval: 1m
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: auth-service
namespace: bakery-ia
- apiVersion: apps/v1
kind: Deployment
name: gateway
namespace: bakery-ia

View File

@@ -1,25 +0,0 @@
# Gitea Ingress configuration for Bakery-IA CI/CD
# This provides external access to Gitea within the cluster
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gitea-ingress
namespace: gitea
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
spec:
rules:
- host: gitea.bakery-ia.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gitea-http
port:
number: 3000

View File

@@ -1,38 +0,0 @@
# Gitea Helm values configuration for Bakery-IA CI/CD
# This configuration sets up Gitea with registry support and appropriate storage
service:
type: ClusterIP
httpPort: 3000
sshPort: 2222
persistence:
enabled: true
size: 50Gi
storageClass: "microk8s-hostpath"
gitea:
config:
server:
DOMAIN: gitea.bakery-ia.local
SSH_DOMAIN: gitea.bakery-ia.local
ROOT_URL: http://gitea.bakery-ia.local
repository:
ENABLE_PUSH_CREATE_USER: true
ENABLE_PUSH_CREATE_ORG: true
registry:
ENABLED: true
postgresql:
enabled: true
persistence:
size: 20Gi
# Resource configuration for production environment
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi

View File

@@ -1,70 +0,0 @@
# OpenTelemetry Collector for Bakery-IA CI/CD Monitoring
# This collects metrics and traces from Tekton pipelines
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: tekton-otel
namespace: tekton-pipelines
spec:
config: |
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
prometheus:
config:
scrape_configs:
- job_name: 'tekton-pipelines'
scrape_interval: 30s
static_configs:
- targets: ['tekton-pipelines-controller.tekton-pipelines.svc.cluster.local:9090']
processors:
batch:
timeout: 5s
send_batch_size: 1000
memory_limiter:
check_interval: 2s
limit_percentage: 75
spike_limit_percentage: 20
exporters:
otlp:
endpoint: "signoz-otel-collector.monitoring.svc.cluster.local:4317"
tls:
insecure: true
retry_on_failure:
enabled: true
initial_interval: 5s
max_interval: 30s
max_elapsed_time: 300s
logging:
logLevel: debug
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp, logging]
metrics:
receivers: [otlp, prometheus]
processors: [memory_limiter, batch]
exporters: [otlp, logging]
telemetry:
logs:
level: "info"
encoding: "json"
mode: deployment
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 200m
memory: 256Mi

View File

@@ -1,83 +0,0 @@
# Main CI Pipeline for Bakery-IA
# This pipeline orchestrates the build, test, and deploy process
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: bakery-ia-ci
namespace: tekton-pipelines
spec:
workspaces:
- name: shared-workspace
- name: docker-credentials
params:
- name: git-url
type: string
description: Repository URL
- name: git-revision
type: string
description: Git revision/commit hash
- name: registry
type: string
description: Container registry URL
default: "gitea.bakery-ia.local:5000"
tasks:
- name: fetch-source
taskRef:
name: git-clone
workspaces:
- name: output
workspace: shared-workspace
params:
- name: url
value: $(params.git-url)
- name: revision
value: $(params.git-revision)
- name: detect-changes
runAfter: [fetch-source]
taskRef:
name: detect-changed-services
workspaces:
- name: source
workspace: shared-workspace
- name: build-and-push
runAfter: [detect-changes]
taskRef:
name: kaniko-build
when:
- input: "$(tasks.detect-changes.results.changed-services)"
operator: notin
values: ["none"]
workspaces:
- name: source
workspace: shared-workspace
- name: docker-credentials
workspace: docker-credentials
params:
- name: services
value: $(tasks.detect-changes.results.changed-services)
- name: registry
value: $(params.registry)
- name: git-revision
value: $(params.git-revision)
- name: update-gitops-manifests
runAfter: [build-and-push]
taskRef:
name: update-gitops
when:
- input: "$(tasks.detect-changes.results.changed-services)"
operator: notin
values: ["none"]
workspaces:
- name: source
workspace: shared-workspace
params:
- name: services
value: $(tasks.detect-changes.results.changed-services)
- name: registry
value: $(params.registry)
- name: git-revision
value: $(params.git-revision)

View File

@@ -1,64 +0,0 @@
# Tekton Detect Changed Services Task for Bakery-IA CI/CD
# This task identifies which services have changed in the repository
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: detect-changed-services
namespace: tekton-pipelines
spec:
workspaces:
- name: source
results:
- name: changed-services
description: Comma-separated list of changed services
steps:
- name: detect
image: alpine/git
script: |
#!/bin/sh
set -e
cd $(workspaces.source.path)
echo "Detecting changed files..."
# Get list of changed files compared to previous commit
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git diff --name-only HEAD)
echo "Changed files: $CHANGED_FILES"
# Map files to services
CHANGED_SERVICES=()
for file in $CHANGED_FILES; do
if [[ $file == services/* ]]; then
SERVICE=$(echo $file | cut -d'/' -f2)
# Only add unique service names
if [[ ! " ${CHANGED_SERVICES[@]} " =~ " ${SERVICE} " ]]; then
CHANGED_SERVICES+=("$SERVICE")
fi
elif [[ $file == frontend/* ]]; then
CHANGED_SERVICES+=("frontend")
break
elif [[ $file == gateway/* ]]; then
CHANGED_SERVICES+=("gateway")
break
fi
done
# If no specific services changed, check for infrastructure changes
if [ ${#CHANGED_SERVICES[@]} -eq 0 ]; then
for file in $CHANGED_FILES; do
if [[ $file == infrastructure/* ]]; then
CHANGED_SERVICES+=("infrastructure")
break
fi
done
fi
# Output result
if [ ${#CHANGED_SERVICES[@]} -eq 0 ]; then
echo "No service changes detected"
echo "none" | tee $(results.changed-services.path)
else
echo "Detected changes in services: ${CHANGED_SERVICES[@]}"
echo $(printf "%s," "${CHANGED_SERVICES[@]}" | sed 's/,$//') | tee $(results.changed-services.path)
fi

View File

@@ -1,31 +0,0 @@
# Tekton Git Clone Task for Bakery-IA CI/CD
# This task clones the source code repository
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: git-clone
namespace: tekton-pipelines
spec:
workspaces:
- name: output
params:
- name: url
type: string
description: Repository URL to clone
- name: revision
type: string
description: Git revision to checkout
default: "main"
steps:
- name: clone
image: alpine/git
script: |
#!/bin/sh
set -e
echo "Cloning repository: $(params.url)"
git clone $(params.url) $(workspaces.output.path)
cd $(workspaces.output.path)
echo "Checking out revision: $(params.revision)"
git checkout $(params.revision)
echo "Repository cloned successfully"

View File

@@ -1,40 +0,0 @@
# Tekton Kaniko Build Task for Bakery-IA CI/CD
# This task builds and pushes container images using Kaniko
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: kaniko-build
namespace: tekton-pipelines
spec:
workspaces:
- name: source
- name: docker-credentials
params:
- name: services
type: string
description: Comma-separated list of services to build
- name: registry
type: string
description: Container registry URL
default: "gitea.bakery-ia.local:5000"
- name: git-revision
type: string
description: Git revision for image tag
default: "latest"
steps:
- name: build-and-push
image: gcr.io/kaniko-project/executor:v1.9.0
args:
- --dockerfile=$(workspaces.source.path)/services/$(params.services)/Dockerfile
- --context=$(workspaces.source.path)
- --destination=$(params.registry)/bakery/$(params.services):$(params.git-revision)
- --verbosity=info
volumeMounts:
- name: docker-config
mountPath: /kaniko/.docker
securityContext:
runAsUser: 0
volumes:
- name: docker-config
emptyDir: {}

View File

@@ -1,66 +0,0 @@
# Tekton Update GitOps Manifests Task for Bakery-IA CI/CD
# This task updates Kubernetes manifests with new image tags
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: update-gitops
namespace: tekton-pipelines
spec:
workspaces:
- name: source
params:
- name: services
type: string
description: Comma-separated list of services to update
- name: registry
type: string
description: Container registry URL
- name: git-revision
type: string
description: Git revision for image tag
steps:
- name: update-manifests
image: bitnami/kubectl
script: |
#!/bin/sh
set -e
cd $(workspaces.source.path)
echo "Updating GitOps manifests for services: $(params.services)"
# Split services by comma
IFS=',' read -ra SERVICES <<< "$(params.services)"
for service in "${SERVICES[@]}"; do
echo "Processing service: $service"
# Find and update Kubernetes manifests
if [ "$service" = "frontend" ]; then
# Update frontend deployment
if [ -f "infrastructure/kubernetes/overlays/prod/frontend-deployment.yaml" ]; then
sed -i "s|image:.*|image: $(params.registry)/bakery/frontend:$(params.git-revision)|g" \
"infrastructure/kubernetes/overlays/prod/frontend-deployment.yaml"
fi
elif [ "$service" = "gateway" ]; then
# Update gateway deployment
if [ -f "infrastructure/kubernetes/overlays/prod/gateway-deployment.yaml" ]; then
sed -i "s|image:.*|image: $(params.registry)/bakery/gateway:$(params.git-revision)|g" \
"infrastructure/kubernetes/overlays/prod/gateway-deployment.yaml"
fi
else
# Update service deployment
DEPLOYMENT_FILE="infrastructure/kubernetes/overlays/prod/${service}-deployment.yaml"
if [ -f "$DEPLOYMENT_FILE" ]; then
sed -i "s|image:.*|image: $(params.registry)/bakery/${service}:$(params.git-revision)|g" \
"$DEPLOYMENT_FILE"
fi
fi
done
# Commit changes
git config --global user.name "bakery-ia-ci"
git config --global user.email "ci@bakery-ia.local"
git add .
git commit -m "CI: Update image tags for $(params.services) to $(params.git-revision)"
git push origin HEAD

View File

@@ -1,26 +0,0 @@
# Tekton EventListener for Bakery-IA CI/CD
# This listener receives webhook events and triggers pipelines
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
name: bakery-ia-listener
namespace: tekton-pipelines
spec:
serviceAccountName: tekton-triggers-sa
triggers:
- name: bakery-ia-gitea-trigger
bindings:
- ref: bakery-ia-trigger-binding
template:
ref: bakery-ia-trigger-template
interceptors:
- ref:
name: "gitlab"
params:
- name: "secretRef"
value:
secretName: gitea-webhook-secret
secretKey: secretToken
- name: "eventTypes"
value: ["push"]

View File

@@ -1,14 +0,0 @@
# GitLab/Gitea Webhook Interceptor for Tekton Triggers
# This interceptor validates and processes Gitea webhook events
apiVersion: triggers.tekton.dev/v1alpha1
kind: ClusterInterceptor
metadata:
name: gitlab
spec:
clientConfig:
service:
name: tekton-triggers-core-interceptors
namespace: tekton-pipelines
path: "/v1/webhook/gitlab"
port: 8443

View File

@@ -1,16 +0,0 @@
# Tekton TriggerBinding for Bakery-IA CI/CD
# This binding extracts parameters from Gitea webhook events
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
name: bakery-ia-trigger-binding
namespace: tekton-pipelines
spec:
params:
- name: git-repo-url
value: $(body.repository.clone_url)
- name: git-revision
value: $(body.head_commit.id)
- name: git-repo-name
value: $(body.repository.name)

View File

@@ -1,43 +0,0 @@
# Tekton TriggerTemplate for Bakery-IA CI/CD
# This template defines how PipelineRuns are created when triggers fire
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
name: bakery-ia-trigger-template
namespace: tekton-pipelines
spec:
params:
- name: git-repo-url
description: The git repository URL
- name: git-revision
description: The git revision/commit hash
- name: git-repo-name
description: The git repository name
default: "bakery-ia"
resourcetemplates:
- apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: bakery-ia-ci-run-$(params.git-repo-name)-
spec:
pipelineRef:
name: bakery-ia-ci
workspaces:
- name: shared-workspace
volumeClaimTemplate:
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
- name: docker-credentials
secret:
secretName: gitea-registry-credentials
params:
- name: git-url
value: $(params.git-repo-url)
- name: git-revision
value: $(params.git-revision)
- name: registry
value: "gitea.bakery-ia.local:5000"

View File

@@ -19,8 +19,7 @@ graph TD
``` ```
infrastructure/ci-cd/ infrastructure/ci-cd/
├── gitea/ # Gitea configuration (Git server + registry) ├── gitea/ # Gitea configuration (Git server + registry)
── values.yaml # Helm values for Gitea ── values.yaml # Helm values for Gitea (ingress now in main config)
│ └── ingress.yaml # Ingress configuration
├── tekton/ # Tekton CI/CD pipeline configuration ├── tekton/ # Tekton CI/CD pipeline configuration
│ ├── tasks/ # Individual pipeline tasks │ ├── tasks/ # Individual pipeline tasks
│ │ ├── git-clone.yaml │ │ ├── git-clone.yaml
@@ -59,8 +58,8 @@ infrastructure/ci-cd/
-n gitea \ -n gitea \
-f infrastructure/ci-cd/gitea/values.yaml -f infrastructure/ci-cd/gitea/values.yaml
# Apply ingress # Note: Gitea ingress is now included in the main ingress configuration
microk8s kubectl apply -f infrastructure/ci-cd/gitea/ingress.yaml # No separate ingress needs to be applied
``` ```
2. **Deploy Tekton**: 2. **Deploy Tekton**:
@@ -85,8 +84,8 @@ infrastructure/ci-cd/
# Verify Flux installation # Verify Flux installation
microk8s kubectl get pods -n flux-system microk8s kubectl get pods -n flux-system
# Apply Flux configurations # Apply Flux configurations using kustomize
microk8s kubectl apply -f infrastructure/ci-cd/flux/ microk8s kubectl apply -k infrastructure/ci-cd/flux/
``` ```
### Phase 2: Configuration ### Phase 2: Configuration

View File

@@ -0,0 +1,76 @@
# Flux Kustomization for Bakery-IA Production Deployment
# This resource tells Flux how to deploy the application
#
# Prerequisites:
# 1. Flux CD must be installed: flux install
# 2. GitRepository 'bakery-ia' must be created and ready
# 3. Secret 'gitea-credentials' must exist in flux-system namespace
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: bakery-ia-prod
namespace: flux-system
labels:
app.kubernetes.io/name: bakery-ia
app.kubernetes.io/component: flux
spec:
# Wait for GitRepository to be ready before reconciling
dependsOn: []
interval: 5m
path: ./infrastructure/environments/prod
prune: true
sourceRef:
kind: GitRepository
name: bakery-ia
targetNamespace: bakery-ia
timeout: 10m
retryInterval: 1m
wait: true
# Health checks for critical services
healthChecks:
# Core Infrastructure
- apiVersion: apps/v1
kind: Deployment
name: gateway
namespace: bakery-ia
# Authentication & Authorization
- apiVersion: apps/v1
kind: Deployment
name: auth-service
namespace: bakery-ia
- apiVersion: apps/v1
kind: Deployment
name: tenant-service
namespace: bakery-ia
# Core Business Services
- apiVersion: apps/v1
kind: Deployment
name: inventory-service
namespace: bakery-ia
- apiVersion: apps/v1
kind: Deployment
name: orders-service
namespace: bakery-ia
- apiVersion: apps/v1
kind: Deployment
name: pos-service
namespace: bakery-ia
# Data Services
- apiVersion: apps/v1
kind: Deployment
name: forecasting-service
namespace: bakery-ia
- apiVersion: apps/v1
kind: Deployment
name: notification-service
namespace: bakery-ia
# Post-build variable substitution
postBuild:
substituteFrom:
- kind: ConfigMap
name: bakery-ia-config
optional: true
- kind: Secret
name: bakery-ia-secrets
optional: true

View File

@@ -0,0 +1,25 @@
# Kustomize build configuration for Flux resources
# This file is used to build and apply the Flux resources
#
# IMPORTANT: Apply resources in this order:
# 1. Install Flux CD first: flux install
# 2. Apply this kustomization: kubectl apply -k infrastructure/cicd/flux/
#
# The GitRepository must be ready before the Flux Kustomization can reconcile.
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# Resources to apply in order (namespace and secrets first, then sources, then kustomizations)
resources:
- namespace.yaml
- git-repository.yaml
- flux-kustomization.yaml
# Common labels for all resources
commonLabels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: flux
app.kubernetes.io/managed-by: kustomize
# Note: Do NOT set namespace here as resources already have explicit namespaces

View File

@@ -0,0 +1,15 @@
# Flux System Namespace
# This namespace is required for Flux CD components
# It should be created before any Flux resources are applied
apiVersion: v1
kind: Namespace
metadata:
name: flux-system
labels:
app.kubernetes.io/name: flux
app.kubernetes.io/component: system
kubernetes.io/metadata.name: flux-system
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted

View File

@@ -0,0 +1,44 @@
# Gitea Ingress Configuration
# Routes external traffic to Gitea service for web UI and Git HTTP access
#
# Prerequisites:
# - Gitea must be deployed in the 'gitea' namespace
# - Ingress controller must be installed (nginx, traefik, etc.)
# - For HTTPS: cert-manager with a ClusterIssuer named 'letsencrypt-prod' or 'local-ca-issuer'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gitea-ingress
namespace: gitea
labels:
app.kubernetes.io/name: gitea
app.kubernetes.io/component: ingress
app.kubernetes.io/part-of: bakery-ia-cicd
annotations:
# For nginx ingress controller
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
# For traefik ingress controller
traefik.ingress.kubernetes.io/router.entrypoints: web,websecure
# For TLS with cert-manager (uncomment for HTTPS)
# cert-manager.io/cluster-issuer: "local-ca-issuer"
spec:
ingressClassName: nginx
# Uncomment for HTTPS
# tls:
# - hosts:
# - gitea.bakery-ia.local
# secretName: gitea-tls
rules:
- host: gitea.bakery-ia.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gitea-http
port:
number: 3000

View File

@@ -0,0 +1,48 @@
#!/bin/bash
# Setup Gitea Admin Secret
#
# This script creates the Kubernetes secret required for Gitea admin credentials.
# Run this BEFORE installing Gitea with Helm.
#
# Usage:
# ./setup-admin-secret.sh [password]
#
# If password is not provided, a random one will be generated.
set -e
KUBECTL="kubectl"
NAMESPACE="gitea"
# Check if running in microk8s
if command -v microk8s &> /dev/null; then
KUBECTL="microk8s kubectl"
fi
# Get or generate password
if [ -n "$1" ]; then
ADMIN_PASSWORD="$1"
else
ADMIN_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=' | head -c 20)
echo "Generated admin password: $ADMIN_PASSWORD"
fi
# Create namespace if it doesn't exist
$KUBECTL create namespace "$NAMESPACE" --dry-run=client -o yaml | $KUBECTL apply -f -
# Create the secret
$KUBECTL create secret generic gitea-admin-secret \
--namespace "$NAMESPACE" \
--from-literal=username=bakery-admin \
--from-literal=password="$ADMIN_PASSWORD" \
--dry-run=client -o yaml | $KUBECTL apply -f -
echo ""
echo "Gitea admin secret created successfully!"
echo ""
echo "Admin credentials:"
echo " Username: bakery-admin"
echo " Password: $ADMIN_PASSWORD"
echo ""
echo "Now install Gitea with:"
echo " helm install gitea gitea/gitea -n gitea -f infrastructure/cicd/gitea/values.yaml"

View File

@@ -0,0 +1,83 @@
# Gitea Helm values configuration for Bakery-IA CI/CD
# This configuration sets up Gitea with registry support and appropriate storage
#
# Installation:
# helm repo add gitea https://dl.gitea.io/charts
# kubectl create namespace gitea
# helm install gitea gitea/gitea -n gitea -f infrastructure/cicd/gitea/values.yaml
#
# NOTE: The namespace is determined by the -n flag during helm install, not in this file.
service:
http:
type: ClusterIP
port: 3000
ssh:
type: ClusterIP
port: 2222
persistence:
enabled: true
size: 10Gi
# Use standard storage class (works with Kind's default provisioner)
# For microk8s: storageClass: "microk8s-hostpath"
# For Kind: leave empty or use "standard"
storageClass: ""
gitea:
admin:
username: bakery-admin
# IMPORTANT: Override this with --set gitea.admin.password=<secure-password>
# or use existingSecret
password: ""
email: admin@bakery-ia.local
existingSecret: gitea-admin-secret
config:
server:
DOMAIN: gitea.bakery-ia.local
SSH_DOMAIN: gitea.bakery-ia.local
# Use HTTP internally; TLS termination happens at ingress
ROOT_URL: http://gitea.bakery-ia.local
HTTP_PORT: 3000
# For external HTTPS access via ingress, set:
# ROOT_URL: https://gitea.bakery-ia.local
repository:
ENABLE_PUSH_CREATE_USER: true
ENABLE_PUSH_CREATE_ORG: true
packages:
ENABLED: true
webhook:
ALLOWED_HOST_LIST: "*"
# Allow internal cluster URLs for Tekton EventListener
SKIP_TLS_VERIFY: true
service:
DISABLE_REGISTRATION: false
REQUIRE_SIGNIN_VIEW: false
# Use embedded SQLite for simpler local development
# For production, enable postgresql
postgresql:
enabled: false
# Use embedded in-memory cache for local dev
redis-cluster:
enabled: false
# Resource configuration for local development
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 256Mi
# Init containers timeout
initContainers:
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi

View File

@@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- tekton/
- ../../namespaces/flux-system.yaml
# Gitea is managed via Helm, so we don't include it directly here
# The Gitea Helm chart is deployed separately and referenced in the ingress
# Flux configuration is a Flux Kustomization resource, not a kustomize config

View File

@@ -0,0 +1,222 @@
# Workspace and PipelineRun Cleanup for Bakery-IA CI/CD
# This CronJob cleans up old PipelineRuns and PVCs to prevent storage exhaustion
---
# ServiceAccount for cleanup job
apiVersion: v1
kind: ServiceAccount
metadata:
name: tekton-cleanup-sa
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: cleanup
---
# ClusterRole for cleanup operations
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: tekton-cleanup-role
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: cleanup
rules:
- apiGroups: ["tekton.dev"]
resources: ["pipelineruns", "taskruns"]
verbs: ["get", "list", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "delete"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "delete"]
---
# ClusterRoleBinding for cleanup
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tekton-cleanup-binding
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: cleanup
subjects:
- kind: ServiceAccount
name: tekton-cleanup-sa
namespace: tekton-pipelines
roleRef:
kind: ClusterRole
name: tekton-cleanup-role
apiGroup: rbac.authorization.k8s.io
---
# CronJob to clean up old PipelineRuns
apiVersion: batch/v1
kind: CronJob
metadata:
name: tekton-pipelinerun-cleanup
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: cleanup
spec:
# Run every 6 hours
schedule: "0 */6 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
ttlSecondsAfterFinished: 3600
template:
metadata:
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: cleanup
spec:
serviceAccountName: tekton-cleanup-sa
restartPolicy: OnFailure
containers:
- name: cleanup
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
#!/bin/sh
set -e
echo "============================================"
echo "Tekton Cleanup Job"
echo "Timestamp: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
echo "============================================"
# Configuration
NAMESPACE="tekton-pipelines"
MAX_AGE_HOURS=24
KEEP_RECENT=10
echo ""
echo "Configuration:"
echo " Namespace: $NAMESPACE"
echo " Max Age: ${MAX_AGE_HOURS} hours"
echo " Keep Recent: $KEEP_RECENT"
echo ""
# Get current timestamp
CURRENT_TIME=$(date +%s)
# Clean up completed PipelineRuns older than MAX_AGE_HOURS
echo "Cleaning up old PipelineRuns..."
# Get all completed PipelineRuns
COMPLETED_RUNS=$(kubectl get pipelineruns -n "$NAMESPACE" \
--no-headers \
-o custom-columns=NAME:.metadata.name,STATUS:.status.conditions[0].reason,AGE:.metadata.creationTimestamp \
2>/dev/null | grep -E "Succeeded|Failed" || true)
DELETED_COUNT=0
echo "$COMPLETED_RUNS" | while read -r line; do
if [ -z "$line" ]; then
continue
fi
RUN_NAME=$(echo "$line" | awk '{print $1}')
RUN_TIME=$(echo "$line" | awk '{print $3}')
if [ -z "$RUN_NAME" ] || [ -z "$RUN_TIME" ]; then
continue
fi
# Convert timestamp to seconds
RUN_TIMESTAMP=$(date -d "$RUN_TIME" +%s 2>/dev/null || echo "0")
if [ "$RUN_TIMESTAMP" = "0" ]; then
continue
fi
# Calculate age in hours
AGE_SECONDS=$((CURRENT_TIME - RUN_TIMESTAMP))
AGE_HOURS=$((AGE_SECONDS / 3600))
if [ "$AGE_HOURS" -gt "$MAX_AGE_HOURS" ]; then
echo "Deleting PipelineRun: $RUN_NAME (age: ${AGE_HOURS}h)"
kubectl delete pipelinerun "$RUN_NAME" -n "$NAMESPACE" --ignore-not-found=true
DELETED_COUNT=$((DELETED_COUNT + 1))
fi
done
echo "Deleted $DELETED_COUNT old PipelineRuns"
# Clean up orphaned PVCs (PVCs without associated PipelineRuns)
echo ""
echo "Cleaning up orphaned PVCs..."
ORPHANED_PVCS=$(kubectl get pvc -n "$NAMESPACE" \
-l tekton.dev/pipelineRun \
--no-headers \
-o custom-columns=NAME:.metadata.name,PIPELINERUN:.metadata.labels.tekton\\.dev/pipelineRun \
2>/dev/null || true)
echo "$ORPHANED_PVCS" | while read -r line; do
if [ -z "$line" ]; then
continue
fi
PVC_NAME=$(echo "$line" | awk '{print $1}')
PR_NAME=$(echo "$line" | awk '{print $2}')
if [ -z "$PVC_NAME" ]; then
continue
fi
# Check if associated PipelineRun exists
if ! kubectl get pipelinerun "$PR_NAME" -n "$NAMESPACE" > /dev/null 2>&1; then
echo "Deleting orphaned PVC: $PVC_NAME (PipelineRun $PR_NAME not found)"
kubectl delete pvc "$PVC_NAME" -n "$NAMESPACE" --ignore-not-found=true
fi
done
# Clean up completed/failed pods older than 1 hour
echo ""
echo "Cleaning up old completed pods..."
kubectl delete pods -n "$NAMESPACE" \
--field-selector=status.phase=Succeeded \
--ignore-not-found=true 2>/dev/null || true
kubectl delete pods -n "$NAMESPACE" \
--field-selector=status.phase=Failed \
--ignore-not-found=true 2>/dev/null || true
echo ""
echo "============================================"
echo "Cleanup complete"
echo "============================================"
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
---
# ConfigMap for cleanup configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: cleanup-config
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: cleanup
data:
# Maximum age of completed PipelineRuns to keep (in hours)
MAX_AGE_HOURS: "24"
# Number of recent PipelineRuns to keep regardless of age
KEEP_RECENT: "10"
# Cleanup schedule (cron format)
CLEANUP_SCHEDULE: "0 */6 * * *"

View File

@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cleanup.yaml

View File

@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- pipeline-config.yaml

View File

@@ -0,0 +1,41 @@
# CI/CD Pipeline Configuration for Bakery-IA
# This ConfigMap contains configurable values for the CI/CD pipeline
#
# IMPORTANT: When changing REGISTRY_URL, also update:
# - infrastructure/cicd/tekton/triggers/trigger-template.yaml (registry-url default)
# - infrastructure/cicd/tekton/secrets/secrets.yaml (registry credentials)
apiVersion: v1
kind: ConfigMap
metadata:
name: pipeline-config
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: config
data:
# Container Registry Configuration
# Change this to your actual registry URL
# Also update trigger-template.yaml and secrets when changing this!
REGISTRY_URL: "gitea.bakery-ia.local:5000"
# Git Configuration
GIT_BRANCH: "main"
GIT_USER_NAME: "bakery-ia-ci"
GIT_USER_EMAIL: "ci@bakery-ia.local"
# Build Configuration
BUILD_CACHE_TTL: "24h"
BUILD_VERBOSITY: "info"
# Test Configuration
SKIP_TESTS: "false"
SKIP_LINT: "false"
# Deployment Configuration
DEPLOY_NAMESPACE: "bakery-ia"
FLUX_NAMESPACE: "flux-system"
# Workspace Configuration
WORKSPACE_SIZE: "5Gi"
WORKSPACE_STORAGE_CLASS: "standard"

View File

@@ -0,0 +1,11 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- rbac/
- secrets/
- configs/
- tasks/
- triggers/
- pipelines/
- cleanup/

View File

@@ -0,0 +1,149 @@
# Main CI Pipeline for Bakery-IA
# This pipeline orchestrates the build, test, and deploy process
# Includes: fetch -> detect changes -> test -> build -> update gitops
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: bakery-ia-ci
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: pipeline
spec:
workspaces:
- name: shared-workspace
description: Shared workspace for source code
- name: docker-credentials
description: Docker registry credentials
- name: git-credentials
description: Git credentials for pushing GitOps updates
optional: true
params:
- name: git-url
type: string
description: Repository URL
- name: git-revision
type: string
description: Git revision/commit hash
- name: registry
type: string
description: Container registry URL
- name: git-branch
type: string
description: Target branch for GitOps updates
default: "main"
- name: skip-tests
type: string
description: Skip tests if "true"
default: "false"
- name: dry-run
type: string
description: Dry run mode - don't push changes
default: "false"
tasks:
# Stage 1: Fetch source code
- name: fetch-source
taskRef:
name: git-clone
workspaces:
- name: output
workspace: shared-workspace
params:
- name: url
value: $(params.git-url)
- name: revision
value: $(params.git-revision)
# Stage 2: Detect which services changed
- name: detect-changes
runAfter: [fetch-source]
taskRef:
name: detect-changed-services
workspaces:
- name: source
workspace: shared-workspace
# Stage 3: Run tests on changed services
- name: run-tests
runAfter: [detect-changes]
taskRef:
name: run-tests
when:
- input: "$(tasks.detect-changes.results.changed-services)"
operator: notin
values: ["none", "infrastructure"]
- input: "$(params.skip-tests)"
operator: notin
values: ["true"]
workspaces:
- name: source
workspace: shared-workspace
params:
- name: services
value: $(tasks.detect-changes.results.changed-services)
- name: skip-tests
value: $(params.skip-tests)
# Stage 4: Build and push container images
- name: build-and-push
runAfter: [run-tests]
taskRef:
name: kaniko-build
when:
- input: "$(tasks.detect-changes.results.changed-services)"
operator: notin
values: ["none", "infrastructure"]
workspaces:
- name: source
workspace: shared-workspace
- name: docker-credentials
workspace: docker-credentials
params:
- name: services
value: $(tasks.detect-changes.results.changed-services)
- name: registry
value: $(params.registry)
- name: git-revision
value: $(params.git-revision)
# Stage 5: Update GitOps manifests
- name: update-gitops-manifests
runAfter: [build-and-push]
taskRef:
name: update-gitops
when:
- input: "$(tasks.detect-changes.results.changed-services)"
operator: notin
values: ["none", "infrastructure"]
- input: "$(tasks.build-and-push.results.build-status)"
operator: in
values: ["success", "partial"]
workspaces:
- name: source
workspace: shared-workspace
- name: git-credentials
workspace: git-credentials
params:
- name: services
value: $(tasks.detect-changes.results.changed-services)
- name: registry
value: $(params.registry)
- name: git-revision
value: $(params.git-revision)
- name: git-branch
value: $(params.git-branch)
- name: dry-run
value: $(params.dry-run)
# Final tasks that run regardless of pipeline success/failure
finally:
- name: pipeline-summary
taskRef:
name: pipeline-summary
params:
- name: changed-services
value: $(tasks.detect-changes.results.changed-services)
- name: git-revision
value: $(params.git-revision)

View File

@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ci-pipeline.yaml
- prod-deploy-pipeline.yaml

View File

@@ -0,0 +1,118 @@
# Production Deployment Pipeline for Bakery-IA
# This pipeline handles production deployments with manual approval gate
# It should be triggered after the CI pipeline succeeds
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: bakery-ia-prod-deploy
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: pipeline
app.kubernetes.io/environment: production
spec:
workspaces:
- name: shared-workspace
description: Shared workspace for source code
- name: git-credentials
description: Git credentials for pushing GitOps updates
optional: true
params:
- name: git-url
type: string
description: Repository URL
- name: git-revision
type: string
description: Git revision/commit hash to deploy
- name: services
type: string
description: Comma-separated list of services to deploy
- name: registry
type: string
description: Container registry URL
- name: approver
type: string
description: Name of the person who approved this deployment
default: "automated"
- name: approval-ticket
type: string
description: Ticket/issue number for deployment approval
default: "N/A"
tasks:
# Stage 1: Fetch source code
- name: fetch-source
taskRef:
name: git-clone
workspaces:
- name: output
workspace: shared-workspace
params:
- name: url
value: $(params.git-url)
- name: revision
value: $(params.git-revision)
# Stage 2: Verify images exist in registry
- name: verify-images
runAfter: [fetch-source]
taskRef:
name: verify-images
params:
- name: services
value: $(params.services)
- name: registry
value: $(params.registry)
- name: git-revision
value: $(params.git-revision)
# Stage 3: Pre-deployment validation
- name: pre-deploy-validation
runAfter: [verify-images]
taskRef:
name: pre-deploy-validation
workspaces:
- name: source
workspace: shared-workspace
params:
- name: services
value: $(params.services)
- name: environment
value: "production"
# Stage 4: Update production manifests
- name: update-prod-manifests
runAfter: [pre-deploy-validation]
taskRef:
name: update-gitops
workspaces:
- name: source
workspace: shared-workspace
- name: git-credentials
workspace: git-credentials
params:
- name: services
value: $(params.services)
- name: registry
value: $(params.registry)
- name: git-revision
value: $(params.git-revision)
- name: git-branch
value: "main"
- name: dry-run
value: "false"
finally:
- name: deployment-summary
taskRef:
name: prod-deployment-summary
params:
- name: services
value: $(params.services)
- name: git-revision
value: $(params.git-revision)
- name: approver
value: $(params.approver)
- name: approval-ticket
value: $(params.approval-ticket)

View File

@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- rbac.yaml
- resource-quota.yaml

View File

@@ -0,0 +1,159 @@
# Tekton RBAC Configuration for Bakery-IA CI/CD
# This file defines ServiceAccounts, Roles, and RoleBindings for Tekton
---
# ServiceAccount for Tekton Triggers EventListener
apiVersion: v1
kind: ServiceAccount
metadata:
name: tekton-triggers-sa
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: triggers
---
# ServiceAccount for Pipeline execution
apiVersion: v1
kind: ServiceAccount
metadata:
name: tekton-pipeline-sa
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: pipeline
---
# ClusterRole for Tekton Triggers to create PipelineRuns
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: tekton-triggers-role
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: triggers
rules:
# Ability to create PipelineRuns from triggers
- apiGroups: ["tekton.dev"]
resources: ["pipelineruns", "taskruns"]
verbs: ["create", "get", "list", "watch"]
# Ability to read pipelines and tasks
- apiGroups: ["tekton.dev"]
resources: ["pipelines", "tasks", "clustertasks"]
verbs: ["get", "list", "watch"]
# Ability to manage PVCs for workspaces
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["create", "get", "list", "watch", "delete"]
# Ability to read secrets for credentials
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch"]
# Ability to read configmaps
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
# Ability to manage events for logging
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "patch"]
---
# ClusterRoleBinding for Tekton Triggers
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tekton-triggers-binding
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: triggers
subjects:
- kind: ServiceAccount
name: tekton-triggers-sa
namespace: tekton-pipelines
roleRef:
kind: ClusterRole
name: tekton-triggers-role
apiGroup: rbac.authorization.k8s.io
---
# ClusterRole for Pipeline execution (needed for git operations and deployments)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: tekton-pipeline-role
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: pipeline
rules:
# Ability to read/update deployments for GitOps
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "patch", "update"]
# Ability to read secrets for credentials
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch"]
# Ability to read configmaps
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
# Ability to manage pods for build operations
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
---
# ClusterRoleBinding for Pipeline execution
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tekton-pipeline-binding
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: pipeline
subjects:
- kind: ServiceAccount
name: tekton-pipeline-sa
namespace: tekton-pipelines
roleRef:
kind: ClusterRole
name: tekton-pipeline-role
apiGroup: rbac.authorization.k8s.io
---
# Role for EventListener to access triggers resources
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: tekton-triggers-eventlistener-role
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: triggers
rules:
- apiGroups: ["triggers.tekton.dev"]
resources: ["eventlisteners", "triggerbindings", "triggertemplates", "triggers", "interceptors"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list", "watch"]
---
# RoleBinding for EventListener
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: tekton-triggers-eventlistener-binding
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: triggers
subjects:
- kind: ServiceAccount
name: tekton-triggers-sa
namespace: tekton-pipelines
roleRef:
kind: Role
name: tekton-triggers-eventlistener-role
apiGroup: rbac.authorization.k8s.io

View File

@@ -0,0 +1,64 @@
# ResourceQuota for Tekton Pipelines Namespace
# Prevents resource exhaustion from runaway pipeline runs
#
# This quota limits:
# - Total CPU and memory that can be requested/used
# - Number of concurrent pods
# - Number of PVCs for workspaces
apiVersion: v1
kind: ResourceQuota
metadata:
name: tekton-pipelines-quota
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: quota
spec:
hard:
# Limit total CPU
requests.cpu: "8"
limits.cpu: "16"
# Limit total memory
requests.memory: "16Gi"
limits.memory: "32Gi"
# Limit number of pods (controls concurrent pipeline tasks)
pods: "20"
# Limit PVCs (controls workspace storage)
persistentvolumeclaims: "10"
# Limit storage
requests.storage: "50Gi"
---
# LimitRange to set defaults and limits for individual pods
# Ensures every pod has resource requests/limits
apiVersion: v1
kind: LimitRange
metadata:
name: tekton-pipelines-limits
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: quota
spec:
limits:
# Default limits for containers
- type: Container
default:
cpu: "1"
memory: "1Gi"
defaultRequest:
cpu: "100m"
memory: "256Mi"
max:
cpu: "4"
memory: "8Gi"
min:
cpu: "50m"
memory: "64Mi"
# Limits for PVCs
- type: PersistentVolumeClaim
max:
storage: "10Gi"
min:
storage: "1Gi"

View File

@@ -0,0 +1,4 @@
# Ignore generated secrets
.webhook-secret
*-actual.yaml
sealed-secrets.yaml

View File

@@ -0,0 +1,167 @@
#!/bin/bash
# Generate CI/CD Secrets for Bakery-IA
#
# This script creates Kubernetes secrets required for the CI/CD pipeline.
# Run this script once during initial setup.
#
# Usage:
# ./generate-secrets.sh [options]
#
# Options:
# --registry-url Container registry URL (default: gitea.bakery-ia.local:5000)
# --gitea-user Gitea username (will prompt if not provided)
# --gitea-password Gitea password (will prompt if not provided)
# --dry-run Print commands without executing
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Default values
REGISTRY_URL="${REGISTRY_URL:-gitea.bakery-ia.local:5000}"
DRY_RUN=false
KUBECTL="kubectl"
# Check if running in microk8s
if command -v microk8s &> /dev/null; then
KUBECTL="microk8s kubectl"
fi
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--registry-url)
REGISTRY_URL="$2"
shift 2
;;
--gitea-user)
GITEA_USERNAME="$2"
shift 2
;;
--gitea-password)
GITEA_PASSWORD="$2"
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
*)
echo -e "${RED}Unknown option: $1${NC}"
exit 1
;;
esac
done
echo "=========================================="
echo " Bakery-IA CI/CD Secrets Generator"
echo "=========================================="
echo ""
# Prompt for credentials if not provided
if [ -z "$GITEA_USERNAME" ]; then
read -p "Enter Gitea username: " GITEA_USERNAME
fi
if [ -z "$GITEA_PASSWORD" ]; then
read -s -p "Enter Gitea password: " GITEA_PASSWORD
echo ""
fi
# Generate webhook secret
WEBHOOK_SECRET=$(openssl rand -hex 32)
echo ""
echo -e "${YELLOW}Configuration:${NC}"
echo " Registry URL: $REGISTRY_URL"
echo " Gitea User: $GITEA_USERNAME"
echo " Webhook Secret: ${WEBHOOK_SECRET:0:8}..."
echo ""
# Function to create secret
create_secret() {
local cmd="$1"
if [ "$DRY_RUN" = true ]; then
echo -e "${YELLOW}[DRY-RUN]${NC} $cmd"
else
eval "$cmd"
fi
}
# Ensure namespaces exist
echo -e "${GREEN}Creating namespaces if they don't exist...${NC}"
create_secret "$KUBECTL create namespace tekton-pipelines --dry-run=client -o yaml | $KUBECTL apply -f -"
create_secret "$KUBECTL create namespace flux-system --dry-run=client -o yaml | $KUBECTL apply -f -"
echo ""
echo -e "${GREEN}Creating secrets...${NC}"
# 1. Webhook Secret
echo " Creating gitea-webhook-secret..."
create_secret "$KUBECTL create secret generic gitea-webhook-secret \
--namespace tekton-pipelines \
--from-literal=secretToken='$WEBHOOK_SECRET' \
--dry-run=client -o yaml | $KUBECTL apply -f -"
# 2. Registry Credentials (docker-registry type)
echo " Creating gitea-registry-credentials..."
create_secret "$KUBECTL create secret docker-registry gitea-registry-credentials \
--namespace tekton-pipelines \
--docker-server='$REGISTRY_URL' \
--docker-username='$GITEA_USERNAME' \
--docker-password='$GITEA_PASSWORD' \
--dry-run=client -o yaml | $KUBECTL apply -f -"
# 3. Git Credentials for Tekton
echo " Creating gitea-git-credentials..."
create_secret "$KUBECTL create secret generic gitea-git-credentials \
--namespace tekton-pipelines \
--from-literal=username='$GITEA_USERNAME' \
--from-literal=password='$GITEA_PASSWORD' \
--dry-run=client -o yaml | $KUBECTL apply -f -"
# 4. Flux Git Credentials
echo " Creating gitea-credentials for Flux..."
create_secret "$KUBECTL create secret generic gitea-credentials \
--namespace flux-system \
--from-literal=username='$GITEA_USERNAME' \
--from-literal=password='$GITEA_PASSWORD' \
--dry-run=client -o yaml | $KUBECTL apply -f -"
# Label all secrets
echo ""
echo -e "${GREEN}Adding labels to secrets...${NC}"
for ns in tekton-pipelines flux-system; do
for secret in gitea-webhook-secret gitea-registry-credentials gitea-git-credentials gitea-credentials; do
if $KUBECTL get secret "$secret" -n "$ns" &> /dev/null; then
create_secret "$KUBECTL label secret $secret -n $ns app.kubernetes.io/name=bakery-ia-cicd --overwrite 2>/dev/null || true"
fi
done
done
echo ""
echo "=========================================="
echo -e "${GREEN}Secrets created successfully!${NC}"
echo "=========================================="
echo ""
echo -e "${YELLOW}IMPORTANT:${NC} Save this webhook secret for Gitea webhook configuration:"
echo ""
echo " Webhook Secret: $WEBHOOK_SECRET"
echo ""
echo "Configure this in Gitea:"
echo " 1. Go to Repository Settings > Webhooks"
echo " 2. Add webhook with URL: http://el-bakery-ia-listener.tekton-pipelines.svc.cluster.local:8080"
echo " 3. Set Secret to the webhook secret above"
echo " 4. Select events: Push"
echo ""
# Save webhook secret to a file for reference (gitignored)
if [ "$DRY_RUN" = false ]; then
echo "$WEBHOOK_SECRET" > "$(dirname "$0")/.webhook-secret"
chmod 600 "$(dirname "$0")/.webhook-secret"
echo "Webhook secret saved to .webhook-secret (gitignored)"
fi

View File

@@ -0,0 +1,19 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- secrets.yaml
# Note: In production, use sealed-secrets or external-secrets-operator
# to manage secrets securely. The secrets.yaml file contains placeholder
# values that must be replaced before deployment.
#
# Example using sealed-secrets:
# 1. Install sealed-secrets controller
# 2. Create SealedSecret resources instead of plain Secrets
# 3. Commit the SealedSecret manifests to Git (safe to commit)
#
# Example using external-secrets-operator:
# 1. Install external-secrets-operator
# 2. Configure a SecretStore (AWS Secrets Manager, HashiCorp Vault, etc.)
# 3. Create ExternalSecret resources that reference the SecretStore

View File

@@ -0,0 +1,79 @@
# CI/CD Secrets Template for Tekton Pipelines
#
# DO NOT commit this file with actual credentials!
# Use the generate-secrets.sh script to create secrets safely.
#
# For production, use one of these approaches:
# 1. Sealed Secrets: kubeseal < secrets.yaml > sealed-secrets.yaml
# 2. External Secrets Operator: Configure with your secret store
# 3. Manual creation: kubectl create secret ... (see generate-secrets.sh)
---
# Secret for Gitea webhook validation
# Used by EventListener to validate incoming webhooks
apiVersion: v1
kind: Secret
metadata:
name: gitea-webhook-secret
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: triggers
type: Opaque
stringData:
# Generate with: openssl rand -hex 32
secretToken: "${WEBHOOK_SECRET_TOKEN}"
---
# Secret for Gitea container registry credentials
# Used by Kaniko to push images to Gitea registry
apiVersion: v1
kind: Secret
metadata:
name: gitea-registry-credentials
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: build
type: kubernetes.io/dockerconfigjson
stringData:
.dockerconfigjson: |
{
"auths": {
"${REGISTRY_URL}": {
"username": "${GITEA_USERNAME}",
"password": "${GITEA_PASSWORD}"
}
}
}
---
# Secret for Git credentials (used by pipeline to push GitOps updates)
apiVersion: v1
kind: Secret
metadata:
name: gitea-git-credentials
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: gitops
type: Opaque
stringData:
username: "${GITEA_USERNAME}"
password: "${GITEA_PASSWORD}"
---
# Secret for Flux GitRepository access
# Used by Flux to pull from Gitea repository
apiVersion: v1
kind: Secret
metadata:
name: gitea-credentials
namespace: flux-system
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: flux
type: Opaque
stringData:
username: "${GITEA_USERNAME}"
password: "${GITEA_PASSWORD}"

View File

@@ -0,0 +1,98 @@
# CI/CD Secrets for Tekton Pipelines
#
# WARNING: This file contains EXAMPLE values only!
# DO NOT use these values in production.
#
# To create actual secrets, use ONE of these methods:
#
# Method 1 (Recommended): Use the generate-secrets.sh script
# ./generate-secrets.sh --gitea-user <username> --gitea-password <password>
#
# Method 2: Create secrets manually with kubectl
# kubectl create secret generic gitea-webhook-secret \
# --namespace tekton-pipelines \
# --from-literal=secretToken="$(openssl rand -hex 32)"
#
# Method 3: Use Sealed Secrets for GitOps
# kubeseal < secrets-template.yaml > sealed-secrets.yaml
#
# Method 4: Use External Secrets Operator
# Configure ESO to pull from your secret store (Vault, AWS SM, etc.)
---
# Example Secret for Gitea webhook validation
# Used by EventListener to validate incoming webhooks
apiVersion: v1
kind: Secret
metadata:
name: gitea-webhook-secret
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: triggers
annotations:
note: "EXAMPLE - Replace with actual secret using generate-secrets.sh"
type: Opaque
stringData:
# Generate with: openssl rand -hex 32
secretToken: "example-webhook-token-do-not-use-in-production"
---
# Example Secret for Gitea container registry credentials
# Used by Kaniko to push images to Gitea registry
apiVersion: v1
kind: Secret
metadata:
name: gitea-registry-credentials
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: build
annotations:
note: "EXAMPLE - Replace with actual secret using generate-secrets.sh"
type: kubernetes.io/dockerconfigjson
stringData:
.dockerconfigjson: |
{
"auths": {
"gitea.bakery-ia.local:5000": {
"username": "example-user",
"password": "example-password"
}
}
}
---
# Example Secret for Git credentials (used by pipeline to push GitOps updates)
apiVersion: v1
kind: Secret
metadata:
name: gitea-git-credentials
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: gitops
annotations:
note: "EXAMPLE - Replace with actual secret using generate-secrets.sh"
type: Opaque
stringData:
username: "example-user"
password: "example-password"
---
# Example Secret for Flux GitRepository access
# Used by Flux to pull from Gitea repository
apiVersion: v1
kind: Secret
metadata:
name: gitea-credentials
namespace: flux-system
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: flux
annotations:
note: "EXAMPLE - Replace with actual secret using generate-secrets.sh"
type: Opaque
stringData:
username: "example-user"
password: "example-password"

View File

@@ -0,0 +1,154 @@
# Tekton Detect Changed Services Task for Bakery-IA CI/CD
# This task identifies which services have changed in the repository
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: detect-changed-services
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: detect
spec:
workspaces:
- name: source
description: Source code workspace
params:
- name: base-ref
type: string
description: Base reference for comparison (default HEAD~1)
default: "HEAD~1"
results:
- name: changed-services
description: Comma-separated list of changed services
- name: changed-files-count
description: Number of files changed
steps:
- name: detect
image: alpine/git:2.43.0
script: |
#!/bin/sh
set -e
SOURCE_PATH="$(workspaces.source.path)"
BASE_REF="$(params.base-ref)"
cd "$SOURCE_PATH"
echo "============================================"
echo "Detect Changed Services"
echo "============================================"
echo "Base ref: $BASE_REF"
echo "============================================"
# Get list of changed files compared to base reference
echo ""
echo "Detecting changed files..."
# Try to get diff, fall back to listing all files if this is the first commit
CHANGED_FILES=$(git diff --name-only "$BASE_REF" HEAD 2>/dev/null || git ls-tree -r HEAD --name-only)
FILE_COUNT=$(echo "$CHANGED_FILES" | grep -c "." || echo "0")
echo "Found $FILE_COUNT changed files"
echo "$FILE_COUNT" > $(results.changed-files-count.path)
if [ "$FILE_COUNT" = "0" ]; then
echo "No files changed"
echo "none" > $(results.changed-services.path)
exit 0
fi
echo ""
echo "Changed files:"
echo "$CHANGED_FILES" | head -20
if [ "$FILE_COUNT" -gt 20 ]; then
echo "... and $((FILE_COUNT - 20)) more files"
fi
# Map files to services using simple shell (no bash arrays)
echo ""
echo "Mapping files to services..."
CHANGED_SERVICES=""
# Process each file
echo "$CHANGED_FILES" | while read -r file; do
if [ -z "$file" ]; then
continue
fi
# Check services directory
if echo "$file" | grep -q "^services/"; then
SERVICE=$(echo "$file" | cut -d'/' -f2)
if [ -n "$SERVICE" ] && ! echo "$CHANGED_SERVICES" | grep -q "$SERVICE"; then
if [ -z "$CHANGED_SERVICES" ]; then
CHANGED_SERVICES="$SERVICE"
else
CHANGED_SERVICES="$CHANGED_SERVICES,$SERVICE"
fi
echo "$CHANGED_SERVICES" > /tmp/services.txt
fi
fi
# Check frontend
if echo "$file" | grep -q "^frontend/"; then
if ! echo "$CHANGED_SERVICES" | grep -q "frontend"; then
if [ -z "$CHANGED_SERVICES" ]; then
CHANGED_SERVICES="frontend"
else
CHANGED_SERVICES="$CHANGED_SERVICES,frontend"
fi
echo "$CHANGED_SERVICES" > /tmp/services.txt
fi
fi
# Check gateway
if echo "$file" | grep -q "^gateway/"; then
if ! echo "$CHANGED_SERVICES" | grep -q "gateway"; then
if [ -z "$CHANGED_SERVICES" ]; then
CHANGED_SERVICES="gateway"
else
CHANGED_SERVICES="$CHANGED_SERVICES,gateway"
fi
echo "$CHANGED_SERVICES" > /tmp/services.txt
fi
fi
# Check infrastructure
if echo "$file" | grep -q "^infrastructure/"; then
if ! echo "$CHANGED_SERVICES" | grep -q "infrastructure"; then
if [ -z "$CHANGED_SERVICES" ]; then
CHANGED_SERVICES="infrastructure"
else
CHANGED_SERVICES="$CHANGED_SERVICES,infrastructure"
fi
echo "$CHANGED_SERVICES" > /tmp/services.txt
fi
fi
done
# Read the accumulated services
if [ -f /tmp/services.txt ]; then
CHANGED_SERVICES=$(cat /tmp/services.txt)
fi
echo ""
echo "============================================"
# Output result
if [ -z "$CHANGED_SERVICES" ]; then
echo "No service changes detected"
echo "none" > $(results.changed-services.path)
else
echo "Detected changes in services: $CHANGED_SERVICES"
echo "$CHANGED_SERVICES" > $(results.changed-services.path)
fi
echo "============================================"
resources:
limits:
cpu: 200m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi

View File

@@ -0,0 +1,95 @@
# Tekton Git Clone Task for Bakery-IA CI/CD
# This task clones the source code repository
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: git-clone
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: source
spec:
workspaces:
- name: output
description: Workspace to clone the repository into
params:
- name: url
type: string
description: Repository URL to clone
- name: revision
type: string
description: Git revision to checkout
default: "main"
- name: depth
type: string
description: Git clone depth (0 for full history)
default: "1"
results:
- name: commit-sha
description: The commit SHA that was checked out
- name: commit-message
description: The commit message
steps:
- name: clone
image: alpine/git:2.43.0
script: |
#!/bin/sh
set -e
URL="$(params.url)"
REVISION="$(params.revision)"
DEPTH="$(params.depth)"
OUTPUT_PATH="$(workspaces.output.path)"
echo "============================================"
echo "Git Clone Task"
echo "============================================"
echo "URL: $URL"
echo "Revision: $REVISION"
echo "Depth: $DEPTH"
echo "============================================"
# Clone with depth for faster checkout
if [ "$DEPTH" = "0" ]; then
echo "Cloning full repository..."
git clone "$URL" "$OUTPUT_PATH"
else
echo "Cloning with depth $DEPTH..."
git clone --depth "$DEPTH" "$URL" "$OUTPUT_PATH"
fi
cd "$OUTPUT_PATH"
# Fetch the specific revision if needed
if [ "$REVISION" != "main" ] && [ "$REVISION" != "master" ]; then
echo "Fetching revision: $REVISION"
git fetch --depth 1 origin "$REVISION" 2>/dev/null || true
fi
# Checkout the revision
echo "Checking out: $REVISION"
git checkout "$REVISION" 2>/dev/null || git checkout "origin/$REVISION"
# Get commit info
COMMIT_SHA=$(git rev-parse HEAD)
COMMIT_MSG=$(git log -1 --pretty=format:"%s")
echo ""
echo "============================================"
echo "Clone Complete"
echo "============================================"
echo "Commit: $COMMIT_SHA"
echo "Message: $COMMIT_MSG"
echo "============================================"
# Write results
echo -n "$COMMIT_SHA" > $(results.commit-sha.path)
echo -n "$COMMIT_MSG" > $(results.commit-message.path)
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi

View File

@@ -0,0 +1,200 @@
# Tekton Kaniko Build Task for Bakery-IA CI/CD
# This task builds and pushes container images using Kaniko
# Supports building multiple services from a comma-separated list
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: kaniko-build
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: build
spec:
workspaces:
- name: source
description: Source code workspace
- name: docker-credentials
description: Docker registry credentials
params:
- name: services
type: string
description: Comma-separated list of services to build
- name: registry
type: string
description: Container registry URL
- name: git-revision
type: string
description: Git revision for image tag
default: "latest"
results:
- name: built-images
description: List of successfully built images
- name: build-status
description: Overall build status (success/failure)
steps:
# Step 1: Setup docker credentials
- name: setup-docker-config
image: alpine:3.18
script: |
#!/bin/sh
set -e
echo "Setting up Docker credentials..."
mkdir -p /kaniko/.docker
# Check if credentials secret is mounted
if [ -f "$(workspaces.docker-credentials.path)/config.json" ]; then
cp "$(workspaces.docker-credentials.path)/config.json" /kaniko/.docker/config.json
echo "Docker config copied from secret"
elif [ -f "$(workspaces.docker-credentials.path)/.dockerconfigjson" ]; then
cp "$(workspaces.docker-credentials.path)/.dockerconfigjson" /kaniko/.docker/config.json
echo "Docker config copied from .dockerconfigjson"
else
echo "Warning: No docker credentials found, builds may fail for private registries"
echo '{}' > /kaniko/.docker/config.json
fi
volumeMounts:
- name: docker-config
mountPath: /kaniko/.docker
resources:
limits:
cpu: 100m
memory: 64Mi
requests:
cpu: 50m
memory: 32Mi
# Step 2: Build each service iteratively
- name: build-services
image: gcr.io/kaniko-project/executor:v1.23.0
script: |
#!/busybox/sh
set -e
SERVICES="$(params.services)"
REGISTRY="$(params.registry)"
REVISION="$(params.git-revision)"
SOURCE_PATH="$(workspaces.source.path)"
BUILT_IMAGES=""
FAILED_SERVICES=""
echo "============================================"
echo "Starting build for services: $SERVICES"
echo "Registry: $REGISTRY"
echo "Tag: $REVISION"
echo "============================================"
# Skip if no services to build
if [ "$SERVICES" = "none" ] || [ -z "$SERVICES" ]; then
echo "No services to build, skipping..."
echo "none" > $(results.built-images.path)
echo "skipped" > $(results.build-status.path)
exit 0
fi
# Convert comma-separated list to space-separated
SERVICES_LIST=$(echo "$SERVICES" | tr ',' ' ')
for SERVICE in $SERVICES_LIST; do
# Trim whitespace
SERVICE=$(echo "$SERVICE" | tr -d ' ')
# Skip infrastructure changes (not buildable)
if [ "$SERVICE" = "infrastructure" ]; then
echo "Skipping infrastructure (not a buildable service)"
continue
fi
echo ""
echo "--------------------------------------------"
echo "Building service: $SERVICE"
echo "--------------------------------------------"
# Determine Dockerfile path based on service type
if [ "$SERVICE" = "frontend" ]; then
DOCKERFILE_PATH="$SOURCE_PATH/frontend/Dockerfile"
CONTEXT_PATH="$SOURCE_PATH/frontend"
elif [ "$SERVICE" = "gateway" ]; then
DOCKERFILE_PATH="$SOURCE_PATH/gateway/Dockerfile"
CONTEXT_PATH="$SOURCE_PATH/gateway"
else
DOCKERFILE_PATH="$SOURCE_PATH/services/$SERVICE/Dockerfile"
CONTEXT_PATH="$SOURCE_PATH"
fi
# Check if Dockerfile exists
if [ ! -f "$DOCKERFILE_PATH" ]; then
echo "Warning: Dockerfile not found at $DOCKERFILE_PATH, skipping $SERVICE"
FAILED_SERVICES="$FAILED_SERVICES $SERVICE"
continue
fi
IMAGE_NAME="$REGISTRY/bakery/$SERVICE:$REVISION"
IMAGE_NAME_LATEST="$REGISTRY/bakery/$SERVICE:latest"
echo "Dockerfile: $DOCKERFILE_PATH"
echo "Context: $CONTEXT_PATH"
echo "Image: $IMAGE_NAME"
# Run Kaniko build
/kaniko/executor \
--dockerfile="$DOCKERFILE_PATH" \
--context="$CONTEXT_PATH" \
--destination="$IMAGE_NAME" \
--destination="$IMAGE_NAME_LATEST" \
--cache=true \
--cache-ttl=24h \
--verbosity=info \
--snapshot-mode=redo \
--use-new-run
BUILD_EXIT_CODE=$?
if [ $BUILD_EXIT_CODE -eq 0 ]; then
echo "Successfully built and pushed: $IMAGE_NAME"
if [ -z "$BUILT_IMAGES" ]; then
BUILT_IMAGES="$IMAGE_NAME"
else
BUILT_IMAGES="$BUILT_IMAGES,$IMAGE_NAME"
fi
else
echo "Failed to build: $SERVICE (exit code: $BUILD_EXIT_CODE)"
FAILED_SERVICES="$FAILED_SERVICES $SERVICE"
fi
done
echo ""
echo "============================================"
echo "Build Summary"
echo "============================================"
echo "Built images: $BUILT_IMAGES"
echo "Failed services: $FAILED_SERVICES"
# Write results
if [ -z "$BUILT_IMAGES" ]; then
echo "none" > $(results.built-images.path)
else
echo "$BUILT_IMAGES" > $(results.built-images.path)
fi
if [ -n "$FAILED_SERVICES" ]; then
echo "partial" > $(results.build-status.path)
echo "Warning: Some services failed to build: $FAILED_SERVICES"
else
echo "success" > $(results.build-status.path)
fi
volumeMounts:
- name: docker-config
mountPath: /kaniko/.docker
securityContext:
runAsUser: 0
resources:
limits:
cpu: 2000m
memory: 4Gi
requests:
cpu: 500m
memory: 1Gi
volumes:
- name: docker-config
emptyDir: {}

View File

@@ -0,0 +1,14 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- git-clone.yaml
- detect-changes.yaml
- run-tests.yaml
- kaniko-build.yaml
- update-gitops.yaml
- pipeline-summary.yaml
# Production deployment tasks
- verify-images.yaml
- pre-deploy-validation.yaml
- prod-deployment-summary.yaml

View File

@@ -0,0 +1,62 @@
# Tekton Pipeline Summary Task for Bakery-IA CI/CD
# This task runs at the end of the pipeline and provides a summary
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: pipeline-summary
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: summary
spec:
params:
- name: changed-services
type: string
description: List of changed services
default: "none"
- name: git-revision
type: string
description: Git revision that was built
default: "unknown"
steps:
- name: summary
image: alpine:3.18
script: |
#!/bin/sh
SERVICES="$(params.changed-services)"
REVISION="$(params.git-revision)"
echo ""
echo "============================================"
echo " Pipeline Execution Summary"
echo "============================================"
echo ""
echo "Git Revision: $REVISION"
echo "Changed Services: $SERVICES"
echo ""
echo "Timestamp: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
echo ""
echo "============================================"
echo ""
if [ "$SERVICES" = "none" ] || [ -z "$SERVICES" ]; then
echo "No services were changed in this commit."
echo "Pipeline completed without building any images."
else
echo "The following services were processed:"
echo "$SERVICES" | tr ',' '\n' | while read service; do
echo " - $service"
done
fi
echo ""
echo "============================================"
resources:
limits:
cpu: 100m
memory: 64Mi
requests:
cpu: 50m
memory: 32Mi

View File

@@ -0,0 +1,76 @@
# Task for pre-deployment validation
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: pre-deploy-validation
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: validation
spec:
workspaces:
- name: source
description: Source code workspace
params:
- name: services
type: string
description: Comma-separated list of services to validate
- name: environment
type: string
description: Target environment (staging/production)
default: "production"
results:
- name: validation-status
description: Status of validation (passed/failed)
steps:
- name: validate
image: registry.k8s.io/kustomize/kustomize:v5.3.0
script: |
#!/bin/sh
set -e
SOURCE_PATH="$(workspaces.source.path)"
SERVICES="$(params.services)"
ENVIRONMENT="$(params.environment)"
echo "============================================"
echo "Pre-Deployment Validation"
echo "============================================"
echo "Environment: $ENVIRONMENT"
echo "Services: $SERVICES"
echo "============================================"
cd "$SOURCE_PATH"
# Validate kustomization can be built
KUSTOMIZE_DIR="infrastructure/environments/$ENVIRONMENT"
if [ -d "$KUSTOMIZE_DIR" ]; then
echo ""
echo "Validating kustomization..."
if kustomize build "$KUSTOMIZE_DIR" > /dev/null 2>&1; then
echo " ✓ Kustomization is valid"
else
echo " ✗ Kustomization validation failed"
echo "failed" > $(results.validation-status.path)
exit 1
fi
fi
# Additional validation checks can be added here
# - Schema validation
# - Policy checks (OPA/Gatekeeper)
# - Security scanning
echo ""
echo "============================================"
echo "All validations passed"
echo "============================================"
echo "passed" > $(results.validation-status.path)
resources:
limits:
cpu: 500m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi

View File

@@ -0,0 +1,57 @@
# Task for production deployment summary
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: prod-deployment-summary
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: summary
spec:
params:
- name: services
type: string
description: List of deployed services
- name: git-revision
type: string
description: Git revision that was deployed
- name: approver
type: string
description: Name of the approver
- name: approval-ticket
type: string
description: Approval ticket number
steps:
- name: summary
image: alpine:3.18
script: |
#!/bin/sh
echo ""
echo "============================================"
echo " Production Deployment Summary"
echo "============================================"
echo ""
echo "Git Revision: $(params.git-revision)"
echo "Services: $(params.services)"
echo "Approved By: $(params.approver)"
echo "Approval Ticket: $(params.approval-ticket)"
echo "Timestamp: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
echo ""
echo "============================================"
echo ""
echo "Deployment to production initiated."
echo "Flux CD will reconcile the changes."
echo ""
echo "Monitor deployment status with:"
echo " kubectl get kustomization -n flux-system"
echo " kubectl get pods -n bakery-ia"
echo ""
echo "============================================"
resources:
limits:
cpu: 100m
memory: 64Mi
requests:
cpu: 50m
memory: 32Mi

View File

@@ -0,0 +1,205 @@
# Tekton Test Task for Bakery-IA CI/CD
# This task runs unit tests and linting for changed services
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: run-tests
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: test
spec:
workspaces:
- name: source
description: Source code workspace
params:
- name: services
type: string
description: Comma-separated list of services to test
- name: skip-lint
type: string
description: Skip linting if "true"
default: "false"
- name: skip-tests
type: string
description: Skip tests if "true"
default: "false"
results:
- name: test-status
description: Overall test status (passed/failed/skipped)
- name: tested-services
description: List of services that were tested
- name: failed-services
description: List of services that failed tests
steps:
- name: run-tests
image: python:3.11-slim
script: |
#!/bin/bash
set -e
SOURCE_PATH="$(workspaces.source.path)"
SERVICES="$(params.services)"
SKIP_LINT="$(params.skip-lint)"
SKIP_TESTS="$(params.skip-tests)"
TESTED_SERVICES=""
FAILED_SERVICES=""
OVERALL_STATUS="passed"
cd "$SOURCE_PATH"
echo "============================================"
echo "Running Tests"
echo "============================================"
echo "Services: $SERVICES"
echo "Skip Lint: $SKIP_LINT"
echo "Skip Tests: $SKIP_TESTS"
echo "============================================"
# Skip if no services to test
if [ "$SERVICES" = "none" ] || [ -z "$SERVICES" ]; then
echo "No services to test, skipping..."
echo "skipped" > $(results.test-status.path)
echo "none" > $(results.tested-services.path)
echo "none" > $(results.failed-services.path)
exit 0
fi
# Install common test dependencies
echo ""
echo "Installing test dependencies..."
pip install --quiet pytest pytest-cov pytest-asyncio ruff mypy 2>/dev/null || true
# Convert comma-separated list to space-separated
SERVICES_LIST=$(echo "$SERVICES" | tr ',' ' ')
for SERVICE in $SERVICES_LIST; do
# Trim whitespace
SERVICE=$(echo "$SERVICE" | tr -d ' ')
# Skip infrastructure changes
if [ "$SERVICE" = "infrastructure" ]; then
echo "Skipping infrastructure (not testable)"
continue
fi
echo ""
echo "--------------------------------------------"
echo "Testing service: $SERVICE"
echo "--------------------------------------------"
# Determine service path
if [ "$SERVICE" = "frontend" ]; then
SERVICE_PATH="$SOURCE_PATH/frontend"
elif [ "$SERVICE" = "gateway" ]; then
SERVICE_PATH="$SOURCE_PATH/gateway"
else
SERVICE_PATH="$SOURCE_PATH/services/$SERVICE"
fi
# Check if service exists
if [ ! -d "$SERVICE_PATH" ]; then
echo "Warning: Service directory not found: $SERVICE_PATH"
continue
fi
cd "$SERVICE_PATH"
SERVICE_FAILED=false
# Install service-specific dependencies if requirements.txt exists
if [ -f "requirements.txt" ]; then
echo "Installing service dependencies..."
pip install --quiet -r requirements.txt 2>/dev/null || true
fi
# Run linting (ruff)
if [ "$SKIP_LINT" != "true" ]; then
echo ""
echo "Running linter (ruff)..."
if [ -d "app" ]; then
ruff check app/ --output-format=text 2>&1 || {
echo "Linting failed for $SERVICE"
SERVICE_FAILED=true
}
fi
fi
# Run tests
if [ "$SKIP_TESTS" != "true" ]; then
echo ""
echo "Running tests (pytest)..."
if [ -d "tests" ]; then
pytest tests/ -v --tb=short 2>&1 || {
echo "Tests failed for $SERVICE"
SERVICE_FAILED=true
}
elif [ -d "app/tests" ]; then
pytest app/tests/ -v --tb=short 2>&1 || {
echo "Tests failed for $SERVICE"
SERVICE_FAILED=true
}
else
echo "No tests directory found, skipping tests"
fi
fi
# Track results
if [ -z "$TESTED_SERVICES" ]; then
TESTED_SERVICES="$SERVICE"
else
TESTED_SERVICES="$TESTED_SERVICES,$SERVICE"
fi
if [ "$SERVICE_FAILED" = true ]; then
OVERALL_STATUS="failed"
if [ -z "$FAILED_SERVICES" ]; then
FAILED_SERVICES="$SERVICE"
else
FAILED_SERVICES="$FAILED_SERVICES,$SERVICE"
fi
fi
cd "$SOURCE_PATH"
done
echo ""
echo "============================================"
echo "Test Summary"
echo "============================================"
echo "Tested services: $TESTED_SERVICES"
echo "Failed services: $FAILED_SERVICES"
echo "Overall status: $OVERALL_STATUS"
# Write results
echo "$OVERALL_STATUS" > $(results.test-status.path)
if [ -z "$TESTED_SERVICES" ]; then
echo "none" > $(results.tested-services.path)
else
echo "$TESTED_SERVICES" > $(results.tested-services.path)
fi
if [ -z "$FAILED_SERVICES" ]; then
echo "none" > $(results.failed-services.path)
else
echo "$FAILED_SERVICES" > $(results.failed-services.path)
fi
# Exit with error if tests failed
if [ "$OVERALL_STATUS" = "failed" ]; then
echo ""
echo "ERROR: Some tests failed!"
exit 1
fi
echo ""
echo "All tests passed!"
resources:
limits:
cpu: 1000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi

View File

@@ -0,0 +1,302 @@
# Tekton Update GitOps Manifests Task for Bakery-IA CI/CD
# This task updates Kubernetes manifests with new image tags using Kustomize
# It uses a safer approach than sed for updating image references
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: update-gitops
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: gitops
spec:
workspaces:
- name: source
description: Source code workspace with Git repository
- name: git-credentials
description: Git credentials for pushing changes
optional: true
params:
- name: services
type: string
description: Comma-separated list of services to update
- name: registry
type: string
description: Container registry URL
- name: git-revision
type: string
description: Git revision for image tag
- name: git-branch
type: string
description: Target branch for GitOps updates
default: "main"
- name: dry-run
type: string
description: If "true", only show what would be changed without committing
default: "false"
results:
- name: updated-services
description: List of services that were updated
- name: commit-sha
description: Git commit SHA of the update (empty if dry-run)
steps:
- name: update-manifests
# Use alpine with curl to install kustomize
image: alpine:3.19
script: |
#!/bin/sh
set -e
# Install kustomize
echo "Installing kustomize..."
wget -q "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" -O - | sh
mv kustomize /usr/local/bin/
echo "Kustomize version: $(kustomize version)"
SOURCE_PATH="$(workspaces.source.path)"
SERVICES="$(params.services)"
REGISTRY="$(params.registry)"
REVISION="$(params.git-revision)"
DRY_RUN="$(params.dry-run)"
UPDATED_SERVICES=""
cd "$SOURCE_PATH"
echo "============================================"
echo "GitOps Manifest Update"
echo "============================================"
echo "Services: $SERVICES"
echo "Registry: $REGISTRY"
echo "Revision: $REVISION"
echo "Dry Run: $DRY_RUN"
echo "============================================"
# Skip if no services to update
if [ "$SERVICES" = "none" ] || [ -z "$SERVICES" ]; then
echo "No services to update, skipping..."
echo "none" > $(results.updated-services.path)
echo "" > $(results.commit-sha.path)
exit 0
fi
# Define the kustomization directory
KUSTOMIZE_DIR="infrastructure/environments/prod"
# Check if kustomization.yaml exists, create if not
if [ ! -f "$KUSTOMIZE_DIR/kustomization.yaml" ]; then
echo "Creating kustomization.yaml in $KUSTOMIZE_DIR"
mkdir -p "$KUSTOMIZE_DIR"
printf '%s\n' \
"apiVersion: kustomize.config.k8s.io/v1beta1" \
"kind: Kustomization" \
"" \
"resources:" \
" - ../base" \
"" \
"images: []" \
> "$KUSTOMIZE_DIR/kustomization.yaml"
fi
# Convert comma-separated list to space-separated
SERVICES_LIST=$(echo "$SERVICES" | tr ',' ' ')
# Build the images section for kustomization
echo ""
echo "Updating image references..."
for SERVICE in $SERVICES_LIST; do
# Trim whitespace
SERVICE=$(echo "$SERVICE" | tr -d ' ')
# Skip infrastructure changes
if [ "$SERVICE" = "infrastructure" ]; then
echo "Skipping infrastructure (not a deployable service)"
continue
fi
echo "Processing: $SERVICE"
# Determine the image name based on service
NEW_IMAGE="$REGISTRY/bakery/$SERVICE:$REVISION"
# Use kustomize to set the image
# This is safer than sed as it understands the YAML structure
cd "$SOURCE_PATH/$KUSTOMIZE_DIR"
# Check if this service has a deployment
SERVICE_DEPLOYMENT=""
if [ "$SERVICE" = "frontend" ]; then
SERVICE_DEPLOYMENT="frontend"
elif [ "$SERVICE" = "gateway" ]; then
SERVICE_DEPLOYMENT="gateway"
else
SERVICE_DEPLOYMENT="$SERVICE-service"
fi
# Update the kustomization with the new image
# Using kustomize edit to safely modify the file
kustomize edit set image "bakery/$SERVICE=$NEW_IMAGE" 2>/dev/null || \
kustomize edit set image "$SERVICE=$NEW_IMAGE" 2>/dev/null || \
echo "Note: Could not set image via kustomize edit, will use alternative method"
# Track updated services
if [ -z "$UPDATED_SERVICES" ]; then
UPDATED_SERVICES="$SERVICE"
else
UPDATED_SERVICES="$UPDATED_SERVICES,$SERVICE"
fi
cd "$SOURCE_PATH"
done
# Alternative: Update images in kustomization.yaml directly if kustomize edit didn't work
# This creates/updates an images section in the kustomization
echo ""
echo "Ensuring image overrides in kustomization.yaml..."
# Create a patch file for image updates
IMAGES_FILE="$KUSTOMIZE_DIR/images.yaml"
printf '%s\n' \
"# Auto-generated by CI/CD pipeline" \
"# Commit: $REVISION" \
"# Updated: $(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
"images:" \
> "$IMAGES_FILE"
for SERVICE in $SERVICES_LIST; do
SERVICE=$(echo "$SERVICE" | tr -d ' ')
if [ "$SERVICE" != "infrastructure" ]; then
printf '%s\n' \
" - name: bakery/$SERVICE" \
" newName: $REGISTRY/bakery/$SERVICE" \
" newTag: \"$REVISION\"" \
>> "$IMAGES_FILE"
fi
done
echo ""
echo "Generated images.yaml:"
cat "$IMAGES_FILE"
# Validate the kustomization
echo ""
echo "Validating kustomization..."
cd "$SOURCE_PATH/$KUSTOMIZE_DIR"
if kustomize build . > /dev/null 2>&1; then
echo "Kustomization is valid"
else
echo "Warning: Kustomization validation failed, but continuing..."
fi
cd "$SOURCE_PATH"
# Write results
echo "$UPDATED_SERVICES" > $(results.updated-services.path)
if [ "$DRY_RUN" = "true" ]; then
echo ""
echo "============================================"
echo "DRY RUN - Changes not committed"
echo "============================================"
echo "Would update services: $UPDATED_SERVICES"
git diff --stat || true
echo "" > $(results.commit-sha.path)
exit 0
fi
echo ""
echo "Committing changes..."
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 256Mi
- name: commit-and-push
image: alpine/git:2.43.0
script: |
#!/bin/sh
set -e
SOURCE_PATH="$(workspaces.source.path)"
SERVICES="$(params.services)"
REVISION="$(params.git-revision)"
BRANCH="$(params.git-branch)"
DRY_RUN="$(params.dry-run)"
cd "$SOURCE_PATH"
if [ "$DRY_RUN" = "true" ]; then
echo "Dry run mode - skipping commit"
echo "" > $(results.commit-sha.path)
exit 0
fi
if [ "$SERVICES" = "none" ] || [ -z "$SERVICES" ]; then
echo "No services to commit"
echo "" > $(results.commit-sha.path)
exit 0
fi
# Check if there are changes to commit
if git diff --quiet && git diff --cached --quiet; then
echo "No changes to commit"
echo "" > $(results.commit-sha.path)
exit 0
fi
# Configure git
git config --global user.name "bakery-ia-ci"
git config --global user.email "ci@bakery-ia.local"
git config --global --add safe.directory "$SOURCE_PATH"
# Setup git credentials if provided
if [ -d "$(workspaces.git-credentials.path)" ]; then
if [ -f "$(workspaces.git-credentials.path)/username" ] && [ -f "$(workspaces.git-credentials.path)/password" ]; then
GIT_USER=$(cat "$(workspaces.git-credentials.path)/username")
GIT_PASS=$(cat "$(workspaces.git-credentials.path)/password")
# Get the remote URL and inject credentials
REMOTE_URL=$(git remote get-url origin)
# Handle both http and https
if echo "$REMOTE_URL" | grep -q "^http"; then
REMOTE_URL=$(echo "$REMOTE_URL" | sed "s|://|://$GIT_USER:$GIT_PASS@|")
git remote set-url origin "$REMOTE_URL"
fi
fi
fi
# Stage changes
git add -A
# Create commit with detailed message
COMMIT_MSG=$(printf 'ci: Update image tags to %s\n\nServices updated: %s\n\nThis commit was automatically generated by the CI/CD pipeline.\nPipeline run triggered by commit: %s' "$REVISION" "$SERVICES" "$REVISION")
git commit -m "$COMMIT_MSG"
# Get the commit SHA
COMMIT_SHA=$(git rev-parse HEAD)
echo "$COMMIT_SHA" > $(results.commit-sha.path)
echo "Created commit: $COMMIT_SHA"
# Push changes
echo "Pushing to origin/$BRANCH..."
git push origin HEAD:"$BRANCH"
echo ""
echo "============================================"
echo "GitOps Update Complete"
echo "============================================"
echo "Commit: $COMMIT_SHA"
echo "Branch: $BRANCH"
echo "Services: $SERVICES"
resources:
limits:
cpu: 200m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi

View File

@@ -0,0 +1,91 @@
# Task to verify images exist in the registry before deploying
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: verify-images
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: validation
spec:
params:
- name: services
type: string
description: Comma-separated list of services to verify
- name: registry
type: string
description: Container registry URL
- name: git-revision
type: string
description: Git revision/tag to verify
results:
- name: verification-status
description: Status of image verification (success/failed)
- name: missing-images
description: List of images that were not found
steps:
- name: verify
image: gcr.io/go-containerregistry/crane:latest
script: |
#!/bin/sh
set -e
SERVICES="$(params.services)"
REGISTRY="$(params.registry)"
REVISION="$(params.git-revision)"
MISSING=""
echo "============================================"
echo "Verifying Images in Registry"
echo "============================================"
echo "Registry: $REGISTRY"
echo "Revision: $REVISION"
echo "Services: $SERVICES"
echo "============================================"
# Convert comma-separated list to space-separated
SERVICES_LIST=$(echo "$SERVICES" | tr ',' ' ')
for SERVICE in $SERVICES_LIST; do
SERVICE=$(echo "$SERVICE" | tr -d ' ')
if [ "$SERVICE" = "infrastructure" ]; then
continue
fi
IMAGE="$REGISTRY/bakery/$SERVICE:$REVISION"
echo ""
echo "Checking: $IMAGE"
if crane manifest "$IMAGE" > /dev/null 2>&1; then
echo " ✓ Found"
else
echo " ✗ NOT FOUND"
if [ -z "$MISSING" ]; then
MISSING="$SERVICE"
else
MISSING="$MISSING,$SERVICE"
fi
fi
done
echo ""
echo "============================================"
if [ -n "$MISSING" ]; then
echo "ERROR: Missing images: $MISSING"
echo "failed" > $(results.verification-status.path)
echo "$MISSING" > $(results.missing-images.path)
exit 1
fi
echo "All images verified successfully"
echo "success" > $(results.verification-status.path)
echo "none" > $(results.missing-images.path)
resources:
limits:
cpu: 200m
memory: 128Mi
requests:
cpu: 100m
memory: 64Mi

View File

@@ -0,0 +1,35 @@
# Tekton EventListener for Bakery-IA CI/CD
# This listener receives webhook events and triggers pipelines
apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
name: bakery-ia-listener
namespace: tekton-pipelines
spec:
serviceAccountName: tekton-triggers-sa
triggers:
- name: bakery-ia-gitea-trigger
bindings:
- ref: bakery-ia-trigger-binding
template:
ref: bakery-ia-trigger-template
# Using CEL interceptor for local development (no TLS/CA bundle required)
# The CEL interceptor is built-in and doesn't need external services
interceptors:
- name: "filter-push-events"
ref:
name: "cel"
params:
# Filter for push events from Gitea or GitHub
- name: "filter"
value: "header.match('X-Gitea-Event', 'push') || header.match('X-GitHub-Event', 'push')"
# Add overlays to standardize the payload
- name: "overlays"
value:
- key: "git_url"
expression: "body.repository.clone_url"
- key: "git_revision"
expression: "body.after"
- key: "git_branch"
expression: "body.ref.split('/')[2]"

View File

@@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
# NOTE: gitlab-interceptor.yaml removed - uses built-in Tekton Triggers interceptor
# The gitlab ClusterInterceptor is provided by Tekton Triggers installation
- event-listener.yaml
- trigger-template.yaml
- trigger-binding.yaml

View File

@@ -0,0 +1,31 @@
# Tekton TriggerBinding for Bakery-IA CI/CD
# This binding extracts parameters from Gitea webhook events
#
# Note: We use CEL overlay extensions for consistent field access
# The EventListener's CEL interceptor creates these extensions:
# - extensions.git_url: Repository clone URL
# - extensions.git_revision: Commit SHA (from body.after)
# - extensions.git_branch: Branch name (extracted from ref)
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
name: bakery-ia-trigger-binding
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: triggers
spec:
params:
# Use CEL overlay extensions for consistent access across Git providers
- name: git-repo-url
value: $(extensions.git_url)
- name: git-revision
value: $(extensions.git_revision)
- name: git-branch
value: $(extensions.git_branch)
# Direct body access for fields not in overlays
- name: git-repo-name
value: $(body.repository.name)
- name: git-repo-full-name
value: $(body.repository.full_name)

View File

@@ -0,0 +1,86 @@
# Tekton TriggerTemplate for Bakery-IA CI/CD
# This template defines how PipelineRuns are created when triggers fire
#
# Registry URL Configuration:
# The registry URL is configured via the 'registry' parameter.
# Default value should match pipeline-config ConfigMap's REGISTRY_URL.
# To change the registry, update BOTH:
# 1. This template's default value
# 2. The pipeline-config ConfigMap
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
name: bakery-ia-trigger-template
namespace: tekton-pipelines
labels:
app.kubernetes.io/name: bakery-ia-cicd
app.kubernetes.io/component: triggers
spec:
params:
- name: git-repo-url
description: The git repository URL
- name: git-revision
description: The git revision/commit hash
- name: git-branch
description: The git branch name
default: "main"
- name: git-repo-name
description: The git repository name
default: "bakery-ia"
- name: git-repo-full-name
description: The full repository name (org/repo)
default: "bakery/bakery-ia"
# Registry URL - keep in sync with pipeline-config ConfigMap
- name: registry-url
description: Container registry URL
default: "gitea.bakery-ia.local:5000"
resourcetemplates:
- apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: bakery-ia-ci-run-
labels:
app.kubernetes.io/name: bakery-ia-cicd
tekton.dev/pipeline: bakery-ia-ci
triggers.tekton.dev/trigger: bakery-ia-gitea-trigger
annotations:
# Track the source commit
bakery-ia.io/git-revision: $(tt.params.git-revision)
bakery-ia.io/git-branch: $(tt.params.git-branch)
spec:
pipelineRef:
name: bakery-ia-ci
serviceAccountName: tekton-pipeline-sa
workspaces:
- name: shared-workspace
volumeClaimTemplate:
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
- name: docker-credentials
secret:
secretName: gitea-registry-credentials
- name: git-credentials
secret:
secretName: gitea-git-credentials
params:
- name: git-url
value: $(tt.params.git-repo-url)
- name: git-revision
value: $(tt.params.git-revision)
- name: git-branch
value: $(tt.params.git-branch)
# Use template parameter for registry URL
- name: registry
value: $(tt.params.registry-url)
- name: skip-tests
value: "false"
- name: dry-run
value: "false"
# Timeout for the entire pipeline run
timeouts:
pipeline: "1h0m0s"
tasks: "45m0s"

View File

@@ -7,7 +7,6 @@ metadata:
app.kubernetes.io/name: bakery-ia app.kubernetes.io/name: bakery-ia
app.kubernetes.io/component: config app.kubernetes.io/component: config
data: data:
# ================================================================
# ENVIRONMENT & BUILD SETTINGS # ENVIRONMENT & BUILD SETTINGS
# ================================================================ # ================================================================
ENVIRONMENT: "development" ENVIRONMENT: "development"
@@ -31,7 +30,7 @@ data:
BUILD_DATE: "2024-01-20T10:00:00Z" BUILD_DATE: "2024-01-20T10:00:00Z"
VCS_REF: "latest" VCS_REF: "latest"
IMAGE_TAG: "latest" IMAGE_TAG: "latest"
DOMAIN: "bakery.yourdomain.com" DOMAIN: "bakewise.ai"
AUTO_RELOAD: "false" AUTO_RELOAD: "false"
PROFILING_ENABLED: "false" PROFILING_ENABLED: "false"
MOCK_EXTERNAL_APIS: "false" MOCK_EXTERNAL_APIS: "false"
@@ -177,13 +176,13 @@ data:
# ================================================================ # ================================================================
# EMAIL CONFIGURATION # EMAIL CONFIGURATION
# ================================================================ # ================================================================
SMTP_HOST: "smtp.gmail.com" SMTP_HOST: "email-smtp.bakery-ia.svc.cluster.local"
SMTP_PORT: "587" SMTP_PORT: "587"
SMTP_TLS: "true" SMTP_TLS: "true"
SMTP_SSL: "false" SMTP_SSL: "false"
DEFAULT_FROM_EMAIL: "noreply@bakeryforecast.es" DEFAULT_FROM_EMAIL: "noreply@bakewise.ai"
DEFAULT_FROM_NAME: "Bakery-Forecast" DEFAULT_FROM_NAME: "Bakery-Forecast"
EMAIL_FROM_ADDRESS: "alerts@bakery.local" EMAIL_FROM_ADDRESS: "alerts@bakewise.ai"
EMAIL_FROM_NAME: "Bakery Alert System" EMAIL_FROM_NAME: "Bakery Alert System"
# ================================================================ # ================================================================
@@ -444,6 +443,13 @@ data:
SIGNOZ_ENDPOINT: "http://signoz.bakery-ia.svc.cluster.local:8080" SIGNOZ_ENDPOINT: "http://signoz.bakery-ia.svc.cluster.local:8080"
SIGNOZ_FRONTEND_URL: "https://monitoring.bakery-ia.local" SIGNOZ_FRONTEND_URL: "https://monitoring.bakery-ia.local"
# ================================================================
# DISTRIBUTION & ROUTING OPTIMIZATION SETTINGS
# ================================================================
VRP_TIME_LIMIT_SECONDS: "30"
VRP_DEFAULT_VEHICLE_CAPACITY_KG: "1000"
VRP_AVERAGE_SPEED_KMH: "30"
# ================================================================ # ================================================================
# REPLENISHMENT PLANNING SETTINGS # REPLENISHMENT PLANNING SETTINGS
# ================================================================ # ================================================================

View File

@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- configmap.yaml
- secrets.yaml

View File

@@ -160,8 +160,12 @@ metadata:
app.kubernetes.io/component: notifications app.kubernetes.io/component: notifications
type: Opaque type: Opaque
data: data:
SMTP_USER: eW91ci1lbWFpbEBnbWFpbC5jb20= # your-email@gmail.com # SMTP credentials for internal Mailu server
SMTP_PASSWORD: eW91ci1hcHAtc3BlY2lmaWMtcGFzc3dvcmQ= # your-app-specific-password # These are used by notification-service to send emails via mailu-smtp
SMTP_USER: cG9zdG1hc3RlckBiYWtld2lzZS5haQ== # postmaster@bakewise.ai
SMTP_PASSWORD: VzJYS2tSdUxpT25ZS2RCWVFTQXJvbjFpeWtFU1M1b2I= # W2XKkRuLiOnYKdBYQSAron1iykESS5ob
# Dovecot admin password for IMAP management
DOVEADM_PASSWORD: WnZhMzNoaVBJc2ZtV3RxUlBWV29taTRYZ2xLTlZPcHY= # Zva33hiPIsfmWtqRPVWomi4XglKNVOpv
--- ---
apiVersion: v1 apiVersion: v1

View File

@@ -0,0 +1,159 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
metadata:
name: bakery-ia-dev
# NOTE: Do NOT set a global namespace here.
# Each resource already has its namespace explicitly defined.
# A global namespace would incorrectly transform cluster-scoped resources
# like cert-manager namespaces.
resources:
- ../../../environments/common/configs
- ../../../platform/infrastructure
- ../../../platform/cert-manager
- ../../../platform/networking/ingress/overlays/dev
- ../../../platform/storage
- ../../../platform/mail/mailu
- ../../../services/databases
- ../../../services/microservices
# NOTE: cicd is NOT included here - it's deployed manually via Tilt triggers
# Run 'tilt trigger tekton-install' followed by 'tilt trigger tekton-pipelines-deploy'
# - ../../../cicd
- dev-certificate.yaml
# Dev-specific patches
patches:
- target:
kind: ConfigMap
name: bakery-config
patch: |-
- op: replace
path: /data/ENVIRONMENT
value: "development"
- op: replace
path: /data/DEBUG
value: "true"
# Suspend nominatim in dev to save resources
- target:
kind: StatefulSet
name: nominatim
patch: |-
- op: replace
path: /spec/replicas
value: 0
# Suspend nominatim-init job in dev (not needed when nominatim is scaled to 0)
- target:
kind: Job
name: nominatim-init
patch: |-
- op: replace
path: /spec/suspend
value: true
# Mailu TLS: Use self-signed dev certificate
- target:
kind: Deployment
name: mailu-front
patch: |-
- op: replace
path: /spec/template/spec/volumes/1/secret/secretName
value: "bakery-dev-tls-cert"
# Mailu Config: Update for dev environment
- target:
kind: ConfigMap
name: mailu-config
patch: |-
- op: replace
path: /data/DOMAIN
value: "bakery-ia.local"
- op: replace
path: /data/HOSTNAMES
value: "mail.bakery-ia.local"
- op: replace
path: /data/RELAY_LOGIN
value: "postmaster@bakery-ia.local"
- op: replace
path: /data/WEBMAIL_ADMIN
value: "admin@bakery-ia.local"
labels:
- includeSelectors: true
pairs:
environment: development
tier: local
# Dev image overrides - use local registry to avoid Docker Hub rate limits
# IMPORTANT: All image names must be lowercase (Docker requirement)
# The prepull-base-images.sh script converts names to lowercase when pushing to local registry
images:
# Database images
- name: postgres
newName: localhost:5000/postgres_17-alpine
newTag: latest
- name: redis
newName: localhost:5000/redis_7.4-alpine
newTag: latest
- name: rabbitmq
newName: localhost:5000/rabbitmq_4.1-management-alpine
newTag: latest
# Utility images
- name: busybox
newName: localhost:5000/busybox_1.36
newTag: latest
- name: curlimages/curl
newName: localhost:5000/curlimages_curl_latest
newTag: latest
- name: bitnami/kubectl
newName: localhost:5000/bitnami_kubectl_latest
newTag: latest
# Alpine variants
- name: alpine
newName: localhost:5000/alpine_3.19
newTag: latest
- name: alpine/git
newName: localhost:5000/alpine_git_2.43.0
newTag: latest
# CI/CD images (cached locally for consistency)
- name: gcr.io/kaniko-project/executor
newName: localhost:5000/gcr.io_kaniko-project_executor_v1.23.0
newTag: latest
- name: gcr.io/go-containerregistry/crane
newName: localhost:5000/gcr.io_go-containerregistry_crane_latest
newTag: latest
- name: registry.k8s.io/kustomize/kustomize
newName: localhost:5000/registry.k8s.io_kustomize_kustomize_v5.3.0
newTag: latest
# Storage images (lowercase - RELEASE becomes release)
- name: minio/minio
newName: localhost:5000/minio_minio_release.2024-11-07t00-52-20z
newTag: latest
- name: minio/mc
newName: localhost:5000/minio_mc_release.2024-11-17t19-35-25z
newTag: latest
# Geocoding
- name: mediagis/nominatim
newName: localhost:5000/mediagis_nominatim_4.4
newTag: latest
# Python base image
- name: python
newName: localhost:5000/python_3.11-slim
newTag: latest
# Mail server (Mailu)
- name: ghcr.io/mailu/nginx
newName: localhost:5000/ghcr.io_mailu_nginx_2024.06
newTag: latest
- name: ghcr.io/mailu/admin
newName: localhost:5000/ghcr.io_mailu_admin_2024.06
newTag: latest
- name: ghcr.io/mailu/postfix
newName: localhost:5000/ghcr.io_mailu_postfix_2024.06
newTag: latest
- name: ghcr.io/mailu/dovecot
newName: localhost:5000/ghcr.io_mailu_dovecot_2024.06
newTag: latest
- name: ghcr.io/mailu/rspamd
newName: localhost:5000/ghcr.io_mailu_rspamd_2024.06
newTag: latest

View File

@@ -4,18 +4,28 @@ kind: Kustomization
metadata: metadata:
name: bakery-ia-prod name: bakery-ia-prod
namespace: bakery-ia # NOTE: Do NOT set a global namespace here.
# Each resource already has its namespace explicitly defined.
# A global namespace would incorrectly transform cluster-scoped resources
# like flux-system and cert-manager namespaces.
resources: resources:
- ../../base - ../../../environments/common/configs
- prod-ingress.yaml - ../../../platform/infrastructure
- ../../../platform/cert-manager
- ../../../platform/networking/ingress/overlays/prod
- ../../../platform/storage
- ../../../platform/mail/mailu
- ../../../services/databases
- ../../../services/microservices
- ../../../cicd
- prod-certificate.yaml
# SigNoz is managed via Helm deployment (see infrastructure/helm/deploy-signoz.sh) # SigNoz is managed via Helm deployment (see infrastructure/helm/deploy-signoz.sh)
# Monitoring is handled by SigNoz (no separate monitoring components needed) # Monitoring is handled by SigNoz (no separate monitoring components needed)
# SigNoz paths are now included in the main ingress (ingress-https.yaml) # SigNoz paths are now included in the main ingress (ingress-https.yaml)
patchesStrategicMerge:
- storage-patch.yaml
labels: labels:
- includeSelectors: true - includeSelectors: true
pairs: pairs:
@@ -159,8 +169,17 @@ patches:
limits: limits:
memory: "1Gi" memory: "1Gi"
cpu: "500m" cpu: "500m"
# Mailu TLS: Use Let's Encrypt production certificate
- target:
kind: Deployment
name: mailu-front
patch: |-
- op: replace
path: /spec/template/spec/volumes/1/secret/secretName
value: "bakery-ia-prod-tls-cert"
images: images:
# Application services
- name: bakery/auth-service - name: bakery/auth-service
newTag: latest newTag: latest
- name: bakery/tenant-service - name: bakery/tenant-service
@@ -193,6 +212,58 @@ images:
newTag: latest newTag: latest
- name: bakery/dashboard - name: bakery/dashboard
newTag: latest newTag: latest
# =============================================================================
# Production Base Images - mapped to production registry
# TODO: Update PROD_REGISTRY_URL to your production registry (e.g., ghcr.io/your-org)
# =============================================================================
# Database images (using canonical Docker Hub - no rate limits in prod with auth)
- name: postgres
newTag: 17-alpine
- name: redis
newTag: 7.4-alpine
- name: rabbitmq
newTag: 4.1-management-alpine
# Utility images
- name: busybox
newTag: "1.36"
- name: curlimages/curl
newTag: latest
- name: bitnami/kubectl
newTag: latest
# Alpine variants
- name: alpine
newTag: "3.19"
- name: alpine/git
newTag: 2.43.0
# CI/CD images (GCR/registry.k8s.io - no rate limits)
- name: gcr.io/kaniko-project/executor
newTag: v1.23.0
- name: gcr.io/go-containerregistry/crane
newTag: latest
- name: registry.k8s.io/kustomize/kustomize
newTag: v5.3.0
# Storage images
- name: minio/minio
newTag: RELEASE.2024-11-07T00-52-20Z
- name: minio/mc
newTag: RELEASE.2024-11-17T19-35-25Z
# Geocoding
- name: mediagis/nominatim
newTag: "4.4"
# Python base image
- name: python
newTag: 3.11-slim
# Mail server (Mailu) - using canonical GHCR names
- name: ghcr.io/mailu/nginx
newTag: "2024.06"
- name: ghcr.io/mailu/admin
newTag: "2024.06"
- name: ghcr.io/mailu/postfix
newTag: "2024.06"
- name: ghcr.io/mailu/dovecot
newTag: "2024.06"
- name: ghcr.io/mailu/rspamd
newTag: "2024.06"
replicas: replicas:
- name: auth-service - name: auth-service

View File

@@ -0,0 +1,48 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: bakery-ia-prod-tls-cert
namespace: bakery-ia
spec:
# Let's Encrypt certificate for production
secretName: bakery-ia-prod-tls-cert
# Certificate duration and renewal
duration: 2160h # 90 days (Let's Encrypt default)
renewBefore: 360h # 15 days before expiry
# Subject configuration
subject:
organizations:
- Bakery IA
# Common name
commonName: bakewise.ai
# DNS names this certificate is valid for
dnsNames:
- bakewise.ai
- www.bakewise.ai
- mail.bakewise.ai
- monitoring.bakewise.ai
- gitea.bakewise.ai
- api.bakewise.ai
# Use Let's Encrypt production issuer
issuerRef:
name: letsencrypt-production
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

View File

@@ -1,299 +0,0 @@
# Bakery IA Kubernetes Configuration
This directory contains Kubernetes manifests for deploying the Bakery IA platform in local development and production environments with HTTPS support using cert-manager and NGINX ingress.
## Quick Start
Deploy the entire platform with these 4 commands:
```bash
# 1. Start Colima with adequate resources
colima start --cpu 6 --memory 12 --disk 120 --runtime docker --profile k8s-local
# 2. Create Kind cluster with permanent localhost access
kind create cluster --config kind-config.yaml
# 3. Install NGINX Ingress Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx --for=condition=ready pod --selector=app.kubernetes.io/component=controller --timeout=300s
# 4. Deploy with Tilt
tilt up
# 🎉 Access at: http://localhost (or see Tilt for individual service ports)
```
> **Note**: The kind-config.yaml already configures port mappings (30080→80, 30443→443) for localhost access, so no additional service patching is needed. The NGINX Ingress for Kind uses NodePort by default on those exact ports.
## Prerequisites
Install the following tools on macOS:
```bash
# Install via Homebrew
brew install colima kind kubectl skaffold
# Verify installations
colima version && kind version && kubectl version --client && skaffold version
```
## Directory Structure
```
infrastructure/kubernetes/
├── base/ # Base Kubernetes resources
│ ├── namespace.yaml # Namespace definition
│ ├── configmap.yaml # Shared configuration
│ ├── secrets.yaml # Base64 encoded secrets
│ ├── ingress-https.yaml # HTTPS ingress rules
│ ├── kustomization.yaml # Base kustomization
│ └── components/ # Individual component manifests
│ ├── cert-manager/ # Certificate management
│ ├── auth/ # Authentication service
│ ├── tenant/ # Tenant management
│ ├── training/ # ML training service
│ ├── forecasting/ # Demand forecasting
│ ├── sales/ # Sales management
│ ├── external/ # External API service
│ ├── notification/ # Notification service
│ ├── inventory/ # Inventory management
│ ├── recipes/ # Recipe management
│ ├── suppliers/ # Supplier management
│ ├── pos/ # Point of sale
│ ├── orders/ # Order management
│ ├── production/ # Production planning
│ ├── alert-processor/ # Alert processing
│ ├── frontend/ # React frontend
│ ├── databases/ # Database deployments
│ └── infrastructure/ # Gateway & monitoring
└── overlays/
└── dev/ # Development environment
├── kustomization.yaml # Dev-specific configuration
└── dev-patches.yaml # Development patches
```
## Access URLs
### Primary Access (Standard Web Ports)
- **Frontend**: https://localhost
- **API Gateway**: https://localhost/api
### Named Host Access (Optional)
Add to `/etc/hosts` for named access:
```bash
echo "127.0.0.1 bakery-ia.local" | sudo tee -a /etc/hosts
echo "127.0.0.1 api.bakery-ia.local" | sudo tee -a /etc/hosts
echo "127.0.0.1 monitoring.bakery-ia.local" | sudo tee -a /etc/hosts
```
Then access via:
- **Frontend**: https://bakery-ia.local
- **API**: https://api.bakery-ia.local
- **Monitoring**: https://monitoring.bakery-ia.local
### Direct Service Access (Development)
- **Frontend**: http://localhost:3000
- **Gateway**: http://localhost:8000
## Development Workflow
### Start Development Environment
```bash
# Start development mode with hot-reload using Tilt
tilt up
# Or start in background
tilt up --stream
```
### Key Features
-**Hot-reload development** - Automatic rebuilds on code changes
-**Permanent localhost access** - No port forwarding needed
-**HTTPS by default** - Local CA certificates for secure development
-**Microservices architecture** - All services deployed together
-**Database management** - PostgreSQL, Redis, and RabbitMQ included
### Monitor and Debug
```bash
# Check all resources
kubectl get all -n bakery-ia
# View logs
kubectl logs -n bakery-ia deployment/auth-service -f
# Check ingress status
kubectl get ingress -n bakery-ia
# Debug certificate issues
kubectl describe certificate bakery-ia-tls-cert -n bakery-ia
```
## Certificate Management
The platform uses cert-manager for automatic HTTPS certificate generation:
- **Local CA**: For development (default)
- **Let's Encrypt Staging**: For testing
- **Let's Encrypt Production**: For production deployments
### Trust Local Certificates
```bash
# Export CA certificate
kubectl get secret local-ca-key-pair -n cert-manager -o jsonpath='{.data.tls\.crt}' | base64 -d > bakery-ia-ca.crt
# Trust in macOS
open bakery-ia-ca.crt
# In Keychain Access, set "bakery-ia-local-ca" to "Always Trust"
```
## Configuration Management
### Secrets
Base64-encoded secrets are stored in `base/secrets.yaml`. For production:
- Use external secret management (HashiCorp Vault, AWS Secrets Manager)
- Never commit real secrets to version control
```bash
# Encode secrets
echo -n "your-secret-value" | base64
# Decode secrets
echo "eW91ci1zZWNyZXQtdmFsdWU=" | base64 -d
```
### Environment Configuration
Development-specific settings are in `overlays/dev/`:
- **Resource limits**: Reduced for local development
- **Image pull policy**: Never (for local images)
- **Debug settings**: Enabled
- **CORS**: Configured for localhost
## Scaling and Resource Management
### Scale Services
```bash
# Scale individual service
kubectl scale -n bakery-ia deployment/auth-service --replicas=3
# Or update kustomization.yaml replicas section
```
### Resource Configuration
Development environment uses minimal resources:
- **Databases**: 64Mi-256Mi memory, 25m-200m CPU
- **Services**: 64Mi-256Mi memory, 25m-200m CPU
- **Training Service**: 256Mi-1Gi memory (ML workloads)
## Troubleshooting
### Common Issues
1. **Images not found**
```bash
# Build images with Skaffold
skaffold build --profile=dev
```
2. **Database corruption after restart**
```bash
# Delete corrupted PVC and restart
kubectl delete pod -n bakery-ia -l app.kubernetes.io/name=inventory-db
kubectl delete pvc -n bakery-ia inventory-db-pvc
```
3. **HTTPS certificate not issued**
```bash
# Check cert-manager logs
kubectl logs -n cert-manager deployment/cert-manager
kubectl describe certificate bakery-ia-tls-cert -n bakery-ia
```
4. **Port conflicts**
```bash
# Check what's using ports 80/443
sudo lsof -i :80 -i :443
```
### Debug Commands
```bash
# Get cluster events
kubectl get events -n bakery-ia --sort-by='.firstTimestamp'
# Resource usage
kubectl top pods -n bakery-ia
kubectl top nodes
# Execute in pod
kubectl exec -n bakery-ia -it <pod-name> -- bash
```
## Cleanup
### Quick Cleanup
```bash
# Stop Skaffold (Ctrl+C or)
skaffold delete --profile=dev
```
### Complete Cleanup
```bash
# Delete everything
kubectl delete namespace bakery-ia
kind delete cluster --name bakery-ia-local
colima stop --profile k8s-local
```
### Restart Sequence
```bash
# Post-restart startup (or use kubernetes_restart.sh script)
colima start --cpu 6 --memory 12 --disk 120 --runtime docker --profile k8s-local
kind create cluster --config kind-config.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx --for=condition=ready pod --selector=app.kubernetes.io/component=controller --timeout=300s
tilt up
```
## Production Deployment
### Production URLs
The production environment uses the following domains:
- **Main Application**: https://bakewise.ai
- Frontend application and all public pages
- API endpoints: https://bakewise.ai/api/v1/...
- **Monitoring Stack**: https://monitoring.bakewise.ai
- Grafana: https://monitoring.bakewise.ai/grafana
- Prometheus: https://monitoring.bakewise.ai/prometheus
- Jaeger: https://monitoring.bakewise.ai/jaeger
- AlertManager: https://monitoring.bakewise.ai/alertmanager
### Production Configuration
The production overlay (`overlays/prod/`) includes:
- **Domain Configuration**: bakewise.ai with Let's Encrypt certificates
- **High Availability**: Multi-replica deployments (2-3 replicas per service)
- **Enhanced Security**: Rate limiting, CORS restrictions, security headers
- **Monitoring**: Full observability stack with Prometheus, Grafana, Jaeger
### Production Considerations
For production deployment:
- **Security**: Implement RBAC, network policies, pod security standards
- **Monitoring**: Deploy Prometheus, Grafana, and alerting
- **Backup**: Database backup strategies
- **High Availability**: Multi-replica deployments with anti-affinity
- **External Secrets**: Use managed secret services
- **TLS**: Production Let's Encrypt certificates
- **CI/CD**: Automated deployment pipelines
- **DNS**: Configure DNS A/CNAME records pointing to your cluster's load balancer
## Next Steps
1. Add comprehensive monitoring and logging
2. Implement automated testing
3. Set up CI/CD pipelines
4. Add health checks and metrics endpoints
5. Implement proper backup strategies

View File

@@ -1,14 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: cert-manager-webhook
namespace: cert-manager
---
# Cert-manager installation using Helm repository
# This will be installed via kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.yaml
# The actual installation will be done via command line, this file documents the resources

View File

@@ -1,78 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: distribution-service-config
data:
# Service settings
SERVICE_NAME: "distribution-service"
APP_NAME: "Bakery Distribution Service"
DESCRIPTION: "Distribution service for enterprise tier bakery management"
VERSION: "1.0.0"
# Database settings
DB_POOL_SIZE: "10"
DB_MAX_OVERFLOW: "20"
DB_POOL_TIMEOUT: "30"
DB_POOL_RECYCLE: "3600"
DB_POOL_PRE_PING: "true"
DB_ECHO: "false"
# Redis settings
REDIS_DB: "7" # Use separate database for distribution service
REDIS_MAX_CONNECTIONS: "50"
REDIS_RETRY_ON_TIMEOUT: "true"
REDIS_SOCKET_KEEPALIVE: "true"
# RabbitMQ settings
RABBITMQ_EXCHANGE: "bakery_events"
RABBITMQ_QUEUE_PREFIX: "distribution"
RABBITMQ_RETRY_ATTEMPTS: "3"
RABBITMQ_RETRY_DELAY: "5"
# Authentication settings
JWT_ALGORITHM: "HS256"
JWT_ACCESS_TOKEN_EXPIRE_MINUTES: "30"
JWT_REFRESH_TOKEN_EXPIRE_DAYS: "7"
ENABLE_SERVICE_AUTH: "true"
# HTTP client settings
HTTP_TIMEOUT: "30"
HTTP_RETRIES: "3"
HTTP_RETRY_DELAY: "1.0"
# CORS settings
CORS_ORIGINS: "http://localhost:3000,http://localhost:3001"
CORS_ALLOW_CREDENTIALS: "true"
CORS_ALLOW_METHODS: "GET,POST,PUT,DELETE,PATCH,OPTIONS"
CORS_ALLOW_HEADERS: "*"
# Rate limiting
RATE_LIMIT_ENABLED: "true"
RATE_LIMIT_REQUESTS: "100"
RATE_LIMIT_WINDOW: "60"
RATE_LIMIT_BURST: "10"
# Monitoring and observability
LOG_LEVEL: "INFO"
PROMETHEUS_ENABLED: "true"
PROMETHEUS_PORT: "9090"
JAEGER_ENABLED: "false"
JAEGER_AGENT_HOST: "jaeger-agent"
JAEGER_AGENT_PORT: "6831"
# Health check settings
HEALTH_CHECK_TIMEOUT: "30"
HEALTH_CHECK_INTERVAL: "30"
# Business rules
MAX_FORECAST_DAYS: "30"
MIN_HISTORICAL_DAYS: "60"
CONFIDENCE_THRESHOLD: "0.8"
# Routing optimization settings
VRP_TIME_LIMIT_SECONDS: "30"
VRP_DEFAULT_VEHICLE_CAPACITY_KG: "1000"
VRP_AVERAGE_SPEED_KMH: "30"
# Service-specific settings
DISTRIBUTION_SERVICE_URL: "http://distribution-service:8000"

View File

@@ -1,134 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: distribution-service
labels:
app: distribution-service
tier: backend
spec:
replicas: 2
selector:
matchLabels:
app: distribution-service
template:
metadata:
labels:
app: distribution-service
tier: backend
spec:
imagePullSecrets:
- name: dockerhub-creds
containers:
- name: distribution-service
image: bakery/distribution-service:latest
imagePullPolicy: Always
ports:
- containerPort: 8000
name: http
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: database-secret
key: url
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: redis-secret
key: url
- name: RABBITMQ_URL
valueFrom:
secretKeyRef:
name: rabbitmq-secret
key: url
- name: JWT_SECRET_KEY
valueFrom:
secretKeyRef:
name: auth-secret
key: jwt-secret
- name: ENVIRONMENT
value: "production"
- name: LOG_LEVEL
value: "INFO"
- name: DB_POOL_SIZE
value: "10"
- name: DB_MAX_OVERFLOW
value: "20"
- name: REDIS_MAX_CONNECTIONS
value: "50"
- name: HTTP_TIMEOUT
value: "30"
- name: HTTP_RETRIES
value: "3"
# OpenTelemetry Configuration
- name: OTEL_COLLECTOR_ENDPOINT
value: "http://signoz-otel-collector.bakery-ia.svc.cluster.local:4318"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
valueFrom:
configMapKeyRef:
name: bakery-config
key: OTEL_EXPORTER_OTLP_ENDPOINT
- name: OTEL_SERVICE_NAME
value: "distribution-service"
- name: ENABLE_TRACING
value: "true"
# Logging Configuration
- name: OTEL_LOGS_EXPORTER
value: "otlp"
- name: OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED
value: "true"
# Metrics Configuration
- name: ENABLE_OTEL_METRICS
value: "true"
- name: ENABLE_SYSTEM_METRICS
value: "true"
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
capabilities:
drop:
- ALL
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
---
apiVersion: v1
kind: Service
metadata:
name: distribution-service
labels:
app: distribution-service
tier: backend
spec:
selector:
app.kubernetes.io/name: distribution-service
ports:
- protocol: TCP
port: 8000
targetPort: 8000
name: http
type: ClusterIP

View File

@@ -1,151 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{SERVICE_NAME}}-service
namespace: bakery-ia
labels:
app.kubernetes.io/name: {{SERVICE_NAME}}-service
app.kubernetes.io/component: microservice
app.kubernetes.io/part-of: bakery-ia
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: {{SERVICE_NAME}}-service
app.kubernetes.io/component: microservice
template:
metadata:
labels:
app.kubernetes.io/name: {{SERVICE_NAME}}-service
app.kubernetes.io/component: microservice
spec:
containers:
- name: {{SERVICE_NAME}}-service
image: bakery/{{SERVICE_NAME}}-service:latest
ports:
- containerPort: 8000
name: http
env:
- name: ENVIRONMENT
valueFrom:
configMapKeyRef:
name: bakery-config
key: ENVIRONMENT
- name: DEBUG
valueFrom:
configMapKeyRef:
name: bakery-config
key: DEBUG
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: bakery-config
key: LOG_LEVEL
- name: {{SERVICE_NAME_UPPER}}_DB_HOST
valueFrom:
configMapKeyRef:
name: bakery-config
key: {{SERVICE_NAME_UPPER}}_DB_HOST
- name: {{SERVICE_NAME_UPPER}}_DB_PORT
valueFrom:
configMapKeyRef:
name: bakery-config
key: DB_PORT
- name: {{SERVICE_NAME_UPPER}}_DB_NAME
valueFrom:
configMapKeyRef:
name: bakery-config
key: {{SERVICE_NAME_UPPER}}_DB_NAME
- name: {{SERVICE_NAME_UPPER}}_DB_USER
valueFrom:
secretKeyRef:
name: database-secrets
key: {{SERVICE_NAME_UPPER}}_DB_USER
- name: {{SERVICE_NAME_UPPER}}_DB_PASSWORD
valueFrom:
secretKeyRef:
name: database-secrets
key: {{SERVICE_NAME_UPPER}}_DB_PASSWORD
- name: REDIS_HOST
valueFrom:
configMapKeyRef:
name: bakery-config
key: REDIS_HOST
- name: REDIS_PORT
valueFrom:
configMapKeyRef:
name: bakery-config
key: REDIS_PORT
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: redis-secrets
key: REDIS_PASSWORD
- name: RABBITMQ_HOST
valueFrom:
configMapKeyRef:
name: bakery-config
key: RABBITMQ_HOST
- name: RABBITMQ_PORT
valueFrom:
configMapKeyRef:
name: bakery-config
key: RABBITMQ_PORT
- name: RABBITMQ_USER
valueFrom:
secretKeyRef:
name: rabbitmq-secrets
key: RABBITMQ_USER
- name: RABBITMQ_PASSWORD
valueFrom:
secretKeyRef:
name: rabbitmq-secrets
key: RABBITMQ_PASSWORD
- name: AUTH_SERVICE_URL
valueFrom:
configMapKeyRef:
name: bakery-config
key: AUTH_SERVICE_URL
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health/live
port: 8000
initialDelaySeconds: 30
timeoutSeconds: 5
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/ready
port: 8000
initialDelaySeconds: 15
timeoutSeconds: 3
periodSeconds: 5
failureThreshold: 5
---
apiVersion: v1
kind: Service
metadata:
name: {{SERVICE_NAME}}-service
namespace: bakery-ia
labels:
app.kubernetes.io/name: {{SERVICE_NAME}}-service
app.kubernetes.io/component: microservice
spec:
type: ClusterIP
ports:
- port: 8000
targetPort: 8000
protocol: TCP
name: http
selector:
app.kubernetes.io/name: {{SERVICE_NAME}}-service
app.kubernetes.io/component: microservice

View File

@@ -1,69 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: bakery-ingress-https
namespace: bakery-ia
labels:
app.kubernetes.io/name: bakery-ia
app.kubernetes.io/component: ingress
annotations:
# Nginx ingress controller annotations
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
# SSE and WebSocket configuration for long-lived connections
nginx.ingress.kubernetes.io/proxy-buffering: "off"
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "3600"
# WebSocket upgrade support
nginx.ingress.kubernetes.io/websocket-services: "gateway-service"
# CORS configuration for HTTPS
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://your-domain.com" # To be overridden in overlays
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-credentials: "true"
# Cert-manager annotations for automatic certificate issuance
# Using issuer appropriate for environment
cert-manager.io/cluster-issuer: "letsencrypt-prod" # To be overridden in dev overlay
spec:
ingressClassName: nginx
tls:
- hosts:
- your-domain.com # To be overridden in overlays
secretName: bakery-tls-cert # To be overridden in overlays
rules:
- host: your-domain.com # To be overridden in overlays
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 3000
- path: /api
pathType: Prefix
backend:
service:
name: gateway-service
port:
number: 8000
- host: api.your-domain.com # To be overridden in overlays
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gateway-service
port:
number: 8000
# Note: SigNoz monitoring is deployed via Helm in the 'signoz' namespace
# SigNoz creates its own Ingress via Helm chart configuration
# Access at: https://monitoring.your-domain.com/ (configured in signoz-values.yaml)
# SignOz ingress is managed separately - no need to configure here

View File

@@ -1,181 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
metadata:
name: bakery-ia-base
resources:
# Base configuration
- namespace.yaml
- configmap.yaml
- secrets.yaml
- ingress-https.yaml
# TLS configuration
- configmaps/postgres-logging-config.yaml
- secrets/postgres-tls-secret.yaml
- secrets/redis-tls-secret.yaml
# Additional configs
- configs/postgres-init-config.yaml
# MinIO Storage (with TLS)
- components/minio/minio-secrets.yaml
- secrets/minio-tls-secret.yaml
- components/minio/minio-pvc.yaml
- components/minio/minio-deployment.yaml
- jobs/minio-bucket-init-job.yaml
# Migration jobs
- migrations/auth-migration-job.yaml
- migrations/tenant-migration-job.yaml
# Note: tenant-seed-pilot-coupon-job.yaml removed - pilot coupon is now seeded
# automatically during tenant-service startup (see app/jobs/startup_seeder.py)
- migrations/training-migration-job.yaml
- migrations/forecasting-migration-job.yaml
- migrations/sales-migration-job.yaml
- migrations/external-migration-job.yaml
- migrations/notification-migration-job.yaml
- migrations/inventory-migration-job.yaml
- migrations/recipes-migration-job.yaml
- migrations/suppliers-migration-job.yaml
- migrations/pos-migration-job.yaml
- migrations/orders-migration-job.yaml
- migrations/production-migration-job.yaml
- migrations/alert-processor-migration-job.yaml
- migrations/demo-session-migration-job.yaml
- migrations/procurement-migration-job.yaml
- migrations/orchestrator-migration-job.yaml
- migrations/ai-insights-migration-job.yaml
- migrations/distribution-migration-job.yaml
- migrations/demo-seed-rbac.yaml
# External data initialization job (v2.0)
- jobs/external-data-init-job.yaml
# CronJobs
- cronjobs/demo-cleanup-cronjob.yaml
- cronjobs/external-data-rotation-cronjob.yaml
# Infrastructure components
- components/databases/redis.yaml
- components/databases/rabbitmq.yaml
- components/infrastructure/gateway-service.yaml
# Distribution service
- components/distribution/distribution-deployment.yaml
- components/distribution/distribution-configmap.yaml
# Nominatim geocoding service
- components/nominatim/nominatim.yaml
- jobs/nominatim-init-job.yaml
# Cert manager cluster issuers
- components/cert-manager/cluster-issuer-staging.yaml
- components/cert-manager/local-ca-issuer.yaml
# Database services
- components/databases/auth-db.yaml
- components/databases/tenant-db.yaml
- components/databases/training-db.yaml
- components/databases/forecasting-db.yaml
- components/databases/sales-db.yaml
- components/databases/external-db.yaml
- components/databases/notification-db.yaml
- components/databases/inventory-db.yaml
- components/databases/recipes-db.yaml
- components/databases/suppliers-db.yaml
- components/databases/pos-db.yaml
- components/databases/orders-db.yaml
- components/databases/production-db.yaml
- components/databases/procurement-db.yaml
- components/databases/orchestrator-db.yaml
- components/databases/alert-processor-db.yaml
- components/databases/ai-insights-db.yaml
- components/databases/distribution-db.yaml
# Demo session components
- components/demo-session/database.yaml
- components/demo-session/rbac.yaml
- components/demo-session/service.yaml
- components/demo-session/deployment.yaml
# Demo cleanup worker (background job processor)
- deployments/demo-cleanup-worker.yaml
# Microservices
- components/auth/auth-service.yaml
- components/tenant/tenant-service.yaml
- components/training/training-service.yaml
- components/forecasting/forecasting-service.yaml
- components/sales/sales-service.yaml
- components/external/external-service.yaml
- components/notification/notification-service.yaml
- components/inventory/inventory-service.yaml
- components/recipes/recipes-service.yaml
- components/suppliers/suppliers-service.yaml
- components/pos/pos-service.yaml
- components/orders/orders-service.yaml
- components/production/production-service.yaml
- components/procurement/procurement-service.yaml
- components/orchestrator/orchestrator-service.yaml
- components/alert-processor/alert-processor.yaml
- components/ai-insights/ai-insights-service.yaml
# Frontend
- components/frontend/frontend-service.yaml
# HorizontalPodAutoscalers (for production autoscaling)
- components/hpa/orders-hpa.yaml
- components/hpa/forecasting-hpa.yaml
- components/hpa/notification-hpa.yaml
labels:
- includeSelectors: true
pairs:
app.kubernetes.io/part-of: bakery-ia
app.kubernetes.io/managed-by: kustomize
images:
- name: bakery/auth-service
newTag: latest
- name: bakery/tenant-service
newTag: latest
- name: bakery/training-service
newTag: latest
- name: bakery/forecasting-service
newTag: latest
- name: bakery/sales-service
newTag: latest
- name: bakery/external-service
newTag: latest
- name: bakery/notification-service
newTag: latest
- name: bakery/inventory-service
newTag: latest
- name: bakery/recipes-service
newTag: latest
- name: bakery/suppliers-service
newTag: latest
- name: bakery/pos-service
newTag: latest
- name: bakery/orders-service
newTag: latest
- name: bakery/production-service
newTag: latest
- name: bakery/procurement-service
newTag: latest
- name: bakery/orchestrator-service
newTag: latest
- name: bakery/alert-processor
newTag: latest
- name: bakery/ai-insights-service
newTag: latest
- name: bakery/demo-session-service
newTag: latest
- name: bakery/gateway
newTag: latest
- name: bakery/dashboard
newTag: latest
- name: bakery/distribution-service
newTag: latest

View File

@@ -1,11 +0,0 @@
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: 2eAEevJmGb+y0bPzYhc4qCpqUa3r5M5Kduch1b4olHE=
- identity: {}

View File

@@ -1,699 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
metadata:
name: bakery-ia-dev
# Note: Removed global namespace to prevent monitoring namespace conflict
# All base resources already have namespace: bakery-ia defined
resources:
- ../../base
- dev-ingress.yaml
# SigNoz is managed via Helm deployment (see Tiltfile signoz-deploy)
# Monitoring is handled by SigNoz (no separate monitoring components needed)
# Dev-Prod Parity: Enable HTTPS with self-signed certificates
- dev-certificate.yaml
# SigNoz paths are now included in the main ingress (ingress-https.yaml)
# Exclude nominatim from dev to save resources
# Using scale to 0 for StatefulSet to prevent pod creation
patches:
# Override specific ConfigMap values for development
- target:
kind: ConfigMap
name: bakery-config
patch: |-
- op: replace
path: /data/ENVIRONMENT
value: "development"
- op: replace
path: /data/DEBUG
value: "true"
- op: replace
path: /data/LOG_LEVEL
value: "DEBUG"
- op: replace
path: /data/AUTO_RELOAD
value: "true"
- op: replace
path: /data/PROFILING_ENABLED
value: "true"
- op: replace
path: /data/MOCK_EXTERNAL_APIS
value: "false"
- op: replace
path: /data/TESTING
value: "false"
- op: replace
path: /data/DOMAIN
value: "localhost"
- op: replace
path: /data/API_DOCS_ENABLED
value: "true"
- op: replace
path: /data/CORS_ORIGINS
value: "http://frontend-service:3000,http://localhost:3000,http://localhost:3001,http://localhost,http://127.0.0.1:3000,http://127.0.0.1:3001,http://bakery-ia.local,https://localhost,https://127.0.0.1"
- op: replace
path: /data/VITE_ENVIRONMENT
value: "development"
- op: replace
path: /data/VITE_API_URL
value: "/api"
- op: replace
path: /data/STRIPE_PUBLISHABLE_KEY
value: "pk_test_your_stripe_publishable_key_here"
- op: replace
path: /data/SQUARE_ENVIRONMENT
value: "sandbox"
- op: replace
path: /data/TOAST_ENVIRONMENT
value: "sandbox"
- op: replace
path: /data/LIGHTSPEED_ENVIRONMENT
value: "sandbox"
- op: replace
path: /data/RATE_LIMIT_ENABLED
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
path: /data/DB_FORCE_RECREATE
value: "false"
- op: add
path: /data/DEVELOPMENT_MODE
value: "true"
- op: add
path: /data/DEBUG_LOGGING
value: "true"
- op: add
path: /data/SKIP_MIGRATION_VERSION_CHECK
value: "false"
- target:
kind: StatefulSet
name: nominatim
patch: |-
- op: replace
path: /spec/replicas
value: 0
# Suspend nominatim-init job in dev (not needed when nominatim is scaled to 0)
- target:
kind: Job
name: nominatim-init
patch: |-
- op: replace
path: /spec/suspend
value: true
- target:
group: apps
version: v1
kind: Deployment
name: auth-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: redis
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: rabbitmq
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "300m"
- target:
group: apps
version: v1
kind: Deployment
name: auth-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "128Mi"
cpu: "50m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: frontend
patch: |-
- op: replace
path: /spec/template/spec/containers/0/imagePullPolicy
value: Never
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "1000m"
- target:
group: apps
version: v1
kind: Deployment
name: gateway
patch: |-
- op: replace
path: /spec/template/spec/containers/0/imagePullPolicy
value: Never
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "128Mi"
cpu: "100m"
- target:
group: apps
version: v1
kind: Deployment
name: alert-processor
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
# Database patches
- target:
group: apps
version: v1
kind: Deployment
name: external-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: forecasting-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: inventory-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: notification-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: orders-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: pos-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: production-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: recipes-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: sales-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: suppliers-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: tenant-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: training-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: ai-insights-db
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
# Service patches
- target:
group: apps
version: v1
kind: Deployment
name: external-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: forecasting-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: inventory-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: notification-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: orders-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: pos-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: production-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: recipes-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: sales-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: suppliers-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: tenant-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "64Mi"
cpu: "25m"
limits:
memory: "256Mi"
cpu: "200m"
- target:
group: apps
version: v1
kind: Deployment
name: training-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "1Gi"
cpu: "500m"
- target:
group: apps
version: v1
kind: Deployment
name: ai-insights-service
patch: |-
- op: replace
path: /spec/template/spec/containers/0/resources
value:
requests:
memory: "128Mi"
cpu: "50m"
limits:
memory: "512Mi"
cpu: "300m"
secretGenerator:
- name: dev-secrets
literals:
- DEV_MODE=true
labels:
- includeSelectors: true
pairs:
environment: development
tier: local
images:
- name: bakery/auth-service
newTag: dev
- name: bakery/tenant-service
newTag: dev
- name: bakery/training-service
newTag: dev
- name: bakery/forecasting-service
newTag: dev
- name: bakery/sales-service
newTag: dev
- name: bakery/external-service
newTag: dev
- name: bakery/notification-service
newTag: dev
- name: bakery/inventory-service
newTag: dev
- name: bakery/recipes-service
newTag: dev
- name: bakery/suppliers-service
newTag: dev
- name: bakery/pos-service
newTag: dev
- name: bakery/orders-service
newTag: dev
- name: bakery/production-service
newTag: dev
- name: bakery/alert-processor
newTag: dev
- name: bakery/ai-insights-service
newTag: dev
- name: bakery/demo-session-service
newTag: dev
- name: bakery/gateway
newTag: dev
- name: bakery/dashboard
newTag: dev
replicas:
# Dev-Prod Parity: Run 2 replicas of critical services
# This helps catch load balancing, session management, and race condition issues
- name: auth-service
count: 2 # Increased from 1 for dev-prod parity
- name: tenant-service
count: 1
- name: training-service
count: 2 # Safe with MinIO storage
- name: forecasting-service
count: 1
- name: sales-service
count: 1
- name: external-service
count: 1
- name: notification-service
count: 1
- name: inventory-service
count: 1
- name: recipes-service
count: 1
- name: suppliers-service
count: 1
- name: pos-service
count: 1
- name: orders-service
count: 1
- name: production-service
count: 1
- name: alert-processor
count: 1
- name: ai-insights-service
count: 1
- name: demo-session-service
count: 1
- name: gateway
count: 2 # Increased from 1 for dev-prod parity
- name: frontend
count: 1

View File

@@ -1,74 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: bakery-ingress-prod
labels:
app.kubernetes.io/name: bakery-ia
app.kubernetes.io/component: ingress
annotations:
# Nginx ingress controller annotations
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
# CORS configuration for production
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://bakewise.ai"
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"
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
# Security headers
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Frame-Options: DENY";
more_set_headers "X-Content-Type-Options: nosniff";
more_set_headers "X-XSS-Protection: 1; mode=block";
more_set_headers "Referrer-Policy: strict-origin-when-cross-origin";
# Rate limiting
nginx.ingress.kubernetes.io/limit-rps: "100"
nginx.ingress.kubernetes.io/limit-connections: "50"
# Cert-manager annotations for automatic certificate issuance
cert-manager.io/cluster-issuer: "letsencrypt-production"
cert-manager.io/acme-challenge-type: http01
spec:
ingressClassName: nginx
tls:
- hosts:
- bakewise.ai
- monitoring.bakewise.ai
secretName: bakery-ia-prod-tls-cert
rules:
- host: bakewise.ai
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 3000
- path: /api/v1
pathType: Prefix
backend:
service:
name: gateway-service
port:
number: 8000
# SigNoz Monitoring on subdomain (deployed via Helm in bakery-ia namespace)
- host: monitoring.bakewise.ai
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: signoz
port:
number: 8080

View File

@@ -1,79 +0,0 @@
# SigNoz Helm Chart Values - Customized for Bakery IA
# https://github.com/SigNoz/charts
# Global settings
global:
storageClass: "standard"
# Frontend configuration
frontend:
service:
type: ClusterIP
port: 3301
ingress:
enabled: true
hosts:
- host: localhost
paths:
- path: /signoz
pathType: Prefix
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
# Query Service configuration
queryService:
replicaCount: 1
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 200m
memory: 512Mi
# AlertManager configuration
alertmanager:
replicaCount: 1
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 100m
memory: 256Mi
# ClickHouse configuration
clickhouse:
persistence:
enabled: true
size: 10Gi
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 1000m
memory: 2Gi
# OpenTelemetry Collector configuration
otelCollector:
enabled: true
config:
exporters:
otlp:
endpoint: "signoz-query-service:8080"
service:
pipelines:
traces:
receivers: [otlp]
exporters: [otlp]
metrics:
receivers: [otlp]
exporters: [otlp]
logs:
receivers: [otlp]
exporters: [otlp]
# Resource optimization for development
# These can be increased for production
development: true

View File

@@ -349,18 +349,20 @@ podDisruptionBudget:
## Monitoring and Alerting ## Monitoring and Alerting
### Email Alerts (Production) ### Email Alerts (Production)
Configure SMTP in production values: Configure SMTP in production values (using Mailu with Mailgun relay):
```yaml ```yaml
signoz: signoz:
env: env:
signoz_smtp_enabled: "true" signoz_smtp_enabled: "true"
signoz_smtp_host: "smtp.gmail.com" signoz_smtp_host: "mailu-smtp.bakery-ia.svc.cluster.local"
signoz_smtp_port: "587" signoz_smtp_port: "587"
signoz_smtp_from: "alerts@bakewise.ai" signoz_smtp_from: "alerts@bakewise.ai"
signoz_smtp_username: "alerts@bakewise.ai" signoz_smtp_username: "alerts@bakewise.ai"
# Set via secret: signoz_smtp_password # Set via secret: signoz_smtp_password
``` ```
**Note**: Signoz now uses the internal Mailu SMTP service, which relays to Mailgun for better deliverability and centralized email management.
### Slack Alerts (Production) ### Slack Alerts (Production)
Configure webhook in Alertmanager: Configure webhook in Alertmanager:
```yaml ```yaml
@@ -373,6 +375,69 @@ alertmanager:
channel: '#alerts-critical' channel: '#alerts-critical'
``` ```
### Mailgun Integration for Alert Emails
Signoz has been configured to use Mailgun for sending alert emails through the Mailu SMTP service. This provides:
**Benefits:**
- Better email deliverability through Mailgun's infrastructure
- Centralized email management via Mailu
- Improved tracking and analytics for alert emails
- Compliance with email sending best practices
**Architecture:**
```
Signoz Alertmanager → Mailu SMTP → Mailgun Relay → Recipients
```
**Configuration Requirements:**
1. **Mailu Configuration** (`infrastructure/platform/mail/mailu/mailu-configmap.yaml`):
```yaml
RELAYHOST: "smtp.mailgun.org:587"
RELAY_LOGIN: "postmaster@bakewise.ai"
```
2. **Mailu Secrets** (`infrastructure/platform/mail/mailu/mailu-secrets.yaml`):
```yaml
RELAY_PASSWORD: "<mailgun-api-key>" # Base64 encoded Mailgun API key
```
3. **DNS Configuration** (required for Mailgun):
```
# MX record
bakewise.ai. IN MX 10 mail.bakewise.ai.
# SPF record (authorize Mailgun)
bakewise.ai. IN TXT "v=spf1 include:mailgun.org ~all"
# DKIM record (provided by Mailgun)
m1._domainkey.bakewise.ai. IN TXT "v=DKIM1; k=rsa; p=<mailgun-public-key>"
# DMARC record
_dmarc.bakewise.ai. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@bakewise.ai"
```
4. **Signoz SMTP Configuration** (already configured in `signoz-values-prod.yaml`):
```yaml
signoz_smtp_host: "mailu-smtp.bakery-ia.svc.cluster.local"
signoz_smtp_port: "587"
signoz_smtp_from: "alerts@bakewise.ai"
```
**Testing the Integration:**
1. Trigger a test alert from Signoz UI
2. Check Mailu logs: `kubectl logs -f mailu-smtp-<pod-id> -n bakery-ia`
3. Check Mailgun dashboard for delivery status
4. Verify email receipt in destination inbox
**Troubleshooting:**
- **SMTP Authentication Failed**: Verify Mailu credentials and Mailgun API key
- **Email Delivery Delays**: Check Mailu queue with `kubectl exec -it mailu-smtp-<pod-id> -n bakery-ia -- mailq`
- **SPF/DKIM Issues**: Verify DNS records and Mailgun domain verification
### Self-Monitoring ### Self-Monitoring
SigNoz monitors itself: SigNoz monitors itself:
```yaml ```yaml

View File

@@ -71,9 +71,9 @@ signoz:
# Only enable if you have a stable OpAMP backend server # Only enable if you have a stable OpAMP backend server
signoz_opamp_server_enabled: "false" signoz_opamp_server_enabled: "false"
# signoz_opamp_server_endpoint: "0.0.0.0:4320" # signoz_opamp_server_endpoint: "0.0.0.0:4320"
# SMTP configuration for email alerts # SMTP configuration for email alerts - now using Mailu as SMTP server
signoz_smtp_enabled: "true" signoz_smtp_enabled: "true"
signoz_smtp_host: "smtp.gmail.com" signoz_smtp_host: "email-smtp.bakery-ia.svc.cluster.local"
signoz_smtp_port: "587" signoz_smtp_port: "587"
signoz_smtp_from: "alerts@bakewise.ai" signoz_smtp_from: "alerts@bakewise.ai"
signoz_smtp_username: "alerts@bakewise.ai" signoz_smtp_username: "alerts@bakewise.ai"
@@ -136,7 +136,7 @@ alertmanager:
config: config:
global: global:
resolve_timeout: 5m resolve_timeout: 5m
smtp_smarthost: 'smtp.gmail.com:587' smtp_smarthost: 'email-smtp.bakery-ia.svc.cluster.local:587'
smtp_from: 'alerts@bakewise.ai' smtp_from: 'alerts@bakewise.ai'
smtp_auth_username: 'alerts@bakewise.ai' smtp_auth_username: 'alerts@bakewise.ai'
smtp_auth_password: '${SMTP_PASSWORD}' smtp_auth_password: '${SMTP_PASSWORD}'

Some files were not shown because too many files have changed in this diff Show More