Initial commit - production deployment
This commit is contained in:
298
infrastructure/cicd/README.md
Normal file
298
infrastructure/cicd/README.md
Normal file
@@ -0,0 +1,298 @@
|
||||
# Bakery-IA CI/CD Implementation
|
||||
|
||||
This directory contains the configuration for the production-grade CI/CD system for Bakery-IA using Gitea, Tekton, and Flux CD.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Developer] -->|Push Code| B[Gitea]
|
||||
B -->|Webhook| C[Tekton Pipelines]
|
||||
C -->|Build/Test| D[Gitea Registry]
|
||||
D -->|New Image| E[Flux CD]
|
||||
E -->|kubectl apply| F[MicroK8s Cluster]
|
||||
F -->|Metrics| G[SigNoz]
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
infrastructure/ci-cd/
|
||||
├── gitea/ # Gitea configuration (Git server + registry)
|
||||
│ └── values.yaml # Helm values for Gitea (ingress now in main config)
|
||||
├── tekton/ # Tekton CI/CD pipeline configuration
|
||||
│ ├── tasks/ # Individual pipeline tasks
|
||||
│ │ ├── git-clone.yaml
|
||||
│ │ ├── detect-changes.yaml
|
||||
│ │ ├── kaniko-build.yaml
|
||||
│ │ └── update-gitops.yaml
|
||||
│ ├── pipelines/ # Pipeline definitions
|
||||
│ │ └── ci-pipeline.yaml
|
||||
│ └── triggers/ # Webhook trigger configuration
|
||||
│ ├── trigger-template.yaml
|
||||
│ ├── trigger-binding.yaml
|
||||
│ ├── event-listener.yaml
|
||||
│ └── gitlab-interceptor.yaml
|
||||
├── flux/ # Flux CD GitOps Helm chart configuration
|
||||
│ ├── Chart.yaml # Helm chart definition
|
||||
│ ├── values.yaml # Default configuration values
|
||||
│ ├── templates/ # Kubernetes manifest templates
|
||||
│ │ ├── gitrepository.yaml
|
||||
│ │ ├── kustomization.yaml
|
||||
│ │ └── namespace.yaml
|
||||
│ └── values/ # Additional value files
|
||||
├── monitoring/ # Monitoring configuration
|
||||
│ └── otel-collector.yaml # OpenTelemetry collector
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## Deployment Instructions
|
||||
|
||||
### Phase 1: Infrastructure Setup
|
||||
|
||||
1. **Deploy Gitea**:
|
||||
```bash
|
||||
# Add Helm repo
|
||||
microk8s helm repo add gitea https://dl.gitea.io/charts
|
||||
|
||||
# Create namespace
|
||||
microk8s kubectl create namespace gitea
|
||||
|
||||
# Install Gitea
|
||||
microk8s helm install gitea gitea/gitea \
|
||||
-n gitea \
|
||||
-f infrastructure/ci-cd/gitea/values.yaml
|
||||
|
||||
# Note: Gitea ingress is now included in the main ingress configuration
|
||||
# No separate ingress needs to be applied
|
||||
```
|
||||
|
||||
2. **Deploy Tekton**:
|
||||
```bash
|
||||
# Create namespace
|
||||
microk8s kubectl create namespace tekton-pipelines
|
||||
|
||||
# Install Tekton Pipelines
|
||||
microk8s kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
|
||||
|
||||
# Install Tekton Triggers
|
||||
microk8s kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml
|
||||
|
||||
# Apply Tekton configurations
|
||||
microk8s kubectl apply -f infrastructure/ci-cd/tekton/tasks/
|
||||
microk8s kubectl apply -f infrastructure/ci-cd/tekton/pipelines/
|
||||
microk8s kubectl apply -f infrastructure/ci-cd/tekton/triggers/
|
||||
```
|
||||
|
||||
3. **Deploy Flux CD** (already enabled in MicroK8s):
|
||||
```bash
|
||||
# Verify Flux installation
|
||||
microk8s kubectl get pods -n flux-system
|
||||
|
||||
# Apply Flux configurations using kustomize
|
||||
microk8s kubectl apply -k infrastructure/ci-cd/flux/
|
||||
```
|
||||
|
||||
### Phase 2: Configuration
|
||||
|
||||
1. **Set up Gitea webhook**:
|
||||
- Go to your Gitea repository settings
|
||||
- Add webhook with URL: `http://tekton-triggers.tekton-pipelines.svc.cluster.local:8080`
|
||||
- Use the secret from `gitea-webhook-secret`
|
||||
|
||||
2. **Configure registry credentials**:
|
||||
```bash
|
||||
# Create registry credentials secret
|
||||
microk8s kubectl create secret docker-registry gitea-registry-credentials \
|
||||
-n tekton-pipelines \
|
||||
--docker-server=gitea.bakery-ia.local:5000 \
|
||||
--docker-username=your-username \
|
||||
--docker-password=your-password
|
||||
```
|
||||
|
||||
3. **Configure Git credentials for Flux**:
|
||||
```bash
|
||||
# Create Git credentials secret
|
||||
microk8s kubectl create secret generic gitea-credentials \
|
||||
-n flux-system \
|
||||
--from-literal=username=your-username \
|
||||
--from-literal=password=your-password
|
||||
```
|
||||
|
||||
### Phase 3: Monitoring
|
||||
|
||||
```bash
|
||||
# Apply OpenTelemetry configuration
|
||||
microk8s kubectl apply -f infrastructure/ci-cd/monitoring/otel-collector.yaml
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Triggering a Pipeline
|
||||
|
||||
1. **Manual trigger**:
|
||||
```bash
|
||||
# Create a PipelineRun manually
|
||||
microk8s kubectl create -f - <<EOF
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: PipelineRun
|
||||
metadata:
|
||||
name: manual-ci-run
|
||||
namespace: tekton-pipelines
|
||||
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: "http://gitea.bakery-ia.local/bakery-admin/bakery-ia.git"
|
||||
- name: git-revision
|
||||
value: "main"
|
||||
EOF
|
||||
```
|
||||
|
||||
2. **Automatic trigger**: Push code to the repository and the webhook will trigger the pipeline automatically.
|
||||
|
||||
### Monitoring Pipeline Runs
|
||||
|
||||
```bash
|
||||
# List all PipelineRuns
|
||||
microk8s kubectl get pipelineruns -n tekton-pipelines
|
||||
|
||||
# View logs for a specific PipelineRun
|
||||
microk8s kubectl logs -n tekton-pipelines <pipelinerun-pod> -c <step-name>
|
||||
|
||||
# View Tekton dashboard
|
||||
microk8s kubectl port-forward -n tekton-pipelines svc/tekton-dashboard 9097:9097
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Pipeline not triggering**:
|
||||
- Check Gitea webhook logs
|
||||
- Verify EventListener pods are running
|
||||
- Check TriggerBinding configuration
|
||||
|
||||
2. **Build failures**:
|
||||
- Check Kaniko logs for build errors
|
||||
- Verify Dockerfile paths are correct
|
||||
- Ensure registry credentials are valid
|
||||
|
||||
3. **Flux not applying changes**:
|
||||
- Check GitRepository status
|
||||
- Verify Kustomization reconciliation
|
||||
- Check Flux logs for errors
|
||||
|
||||
### Debugging Commands
|
||||
|
||||
```bash
|
||||
# Check Tekton controller logs
|
||||
microk8s kubectl logs -n tekton-pipelines -l app=tekton-pipelines-controller
|
||||
|
||||
# Check Flux reconciliation
|
||||
microk8s kubectl get kustomizations -n flux-system -o yaml
|
||||
|
||||
# Check Gitea webhook delivery
|
||||
microk8s kubectl logs -n tekton-pipelines -l app=tekton-triggers-controller
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. **Secrets Management**:
|
||||
- Use Kubernetes secrets for sensitive data
|
||||
- Rotate credentials regularly
|
||||
- Use RBAC for namespace isolation
|
||||
|
||||
2. **Network Security**:
|
||||
- Configure network policies
|
||||
- Use internal DNS names
|
||||
- Restrict ingress access
|
||||
|
||||
3. **Registry Security**:
|
||||
- Enable image scanning
|
||||
- Use image signing
|
||||
- Implement cleanup policies
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Upgrading Components
|
||||
|
||||
```bash
|
||||
# Upgrade Tekton
|
||||
microk8s kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
|
||||
|
||||
# Upgrade Flux
|
||||
microk8s helm upgrade fluxcd fluxcd/flux2 -n flux-system
|
||||
|
||||
# Upgrade Gitea
|
||||
microk8s helm upgrade gitea gitea/gitea -n gitea -f infrastructure/ci-cd/gitea/values.yaml
|
||||
```
|
||||
|
||||
### Backup Procedures
|
||||
|
||||
```bash
|
||||
# Backup Gitea
|
||||
microk8s kubectl exec -n gitea gitea-0 -- gitea dump -c /data/gitea/conf/app.ini
|
||||
|
||||
# Backup Flux configurations
|
||||
microk8s kubectl get all -n flux-system -o yaml > flux-backup.yaml
|
||||
|
||||
# Backup Tekton configurations
|
||||
microk8s kubectl get all -n tekton-pipelines -o yaml > tekton-backup.yaml
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
1. **Resource Management**:
|
||||
- Set appropriate resource limits
|
||||
- Limit concurrent builds
|
||||
- Use node selectors for build pods
|
||||
|
||||
2. **Caching**:
|
||||
- Configure Kaniko cache
|
||||
- Use persistent volumes for dependencies
|
||||
- Cache Docker layers
|
||||
|
||||
3. **Parallelization**:
|
||||
- Build independent services in parallel
|
||||
- Use matrix builds for different architectures
|
||||
- Optimize task dependencies
|
||||
|
||||
## Integration with Existing System
|
||||
|
||||
The CI/CD system integrates with:
|
||||
- **SigNoz**: For monitoring and observability
|
||||
- **MicroK8s**: For cluster management
|
||||
- **Existing Kubernetes manifests**: In `infrastructure/kubernetes/`
|
||||
- **Current services**: All 19 microservices in `services/`
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. **Phase 1**: Set up infrastructure (Gitea, Tekton, Flux)
|
||||
2. **Phase 2**: Configure pipelines and triggers
|
||||
3. **Phase 3**: Test with non-critical services
|
||||
4. **Phase 4**: Gradual rollout to all services
|
||||
5. **Phase 5**: Decommission old deployment methods
|
||||
|
||||
## Support
|
||||
|
||||
For issues with the CI/CD system:
|
||||
- Check logs and monitoring first
|
||||
- Review the troubleshooting section
|
||||
- Consult the original implementation plan
|
||||
- Refer to component documentation:
|
||||
- [Tekton Documentation](https://tekton.dev/docs/)
|
||||
- [Flux CD Documentation](https://fluxcd.io/docs/)
|
||||
- [Gitea Documentation](https://docs.gitea.io/)
|
||||
6
infrastructure/cicd/flux/Chart.yaml
Normal file
6
infrastructure/cicd/flux/Chart.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: flux-cd
|
||||
description: A Helm chart for deploying Flux CD GitOps toolkit for Bakery-IA
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "2.2.3"
|
||||
15
infrastructure/cicd/flux/templates/gitrepository.yaml
Normal file
15
infrastructure/cicd/flux/templates/gitrepository.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
{{- if .Values.gitRepository }}
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: {{ .Values.gitRepository.name }}
|
||||
namespace: {{ .Values.gitRepository.namespace }}
|
||||
spec:
|
||||
interval: {{ .Values.gitRepository.interval }}
|
||||
url: {{ .Values.gitRepository.url }}
|
||||
ref:
|
||||
branch: {{ .Values.gitRepository.ref.branch }}
|
||||
secretRef:
|
||||
name: {{ .Values.gitRepository.secretRef.name }}
|
||||
timeout: {{ .Values.gitRepository.timeout }}
|
||||
{{- end }}
|
||||
43
infrastructure/cicd/flux/templates/kustomization.yaml
Normal file
43
infrastructure/cicd/flux/templates/kustomization.yaml
Normal file
@@ -0,0 +1,43 @@
|
||||
{{- if .Values.kustomization }}
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: {{ .Values.kustomization.name }}
|
||||
namespace: {{ .Values.kustomization.namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia
|
||||
app.kubernetes.io/component: flux
|
||||
spec:
|
||||
# Wait for GitRepository to be ready before reconciling
|
||||
dependsOn: []
|
||||
interval: {{ .Values.kustomization.interval }}
|
||||
path: {{ .Values.kustomization.path }}
|
||||
prune: {{ .Values.kustomization.prune }}
|
||||
sourceRef:
|
||||
kind: {{ .Values.kustomization.sourceRef.kind }}
|
||||
name: {{ .Values.kustomization.sourceRef.name }}
|
||||
targetNamespace: {{ .Values.kustomization.targetNamespace }}
|
||||
timeout: {{ .Values.kustomization.timeout }}
|
||||
retryInterval: {{ .Values.kustomization.retryInterval }}
|
||||
wait: {{ .Values.kustomization.wait }}
|
||||
{{- if .Values.kustomization.healthChecks }}
|
||||
healthChecks:
|
||||
{{- range .Values.kustomization.healthChecks }}
|
||||
- apiVersion: {{ .apiVersion }}
|
||||
kind: {{ .kind }}
|
||||
name: {{ .name }}
|
||||
namespace: {{ .namespace }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.kustomization.postBuild }}
|
||||
postBuild:
|
||||
substituteFrom:
|
||||
{{- range .Values.kustomization.postBuild.substituteFrom }}
|
||||
- kind: {{ .kind }}
|
||||
name: {{ .name }}
|
||||
{{- if .optional }}
|
||||
optional: {{ .optional }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
9
infrastructure/cicd/flux/templates/namespace.yaml
Normal file
9
infrastructure/cicd/flux/templates/namespace.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
{{- if .Values.createNamespace | default false }}
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: {{ .Values.gitRepository.namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: flux
|
||||
kubernetes.io/metadata.name: {{ .Values.gitRepository.namespace }}
|
||||
{{- end }}
|
||||
73
infrastructure/cicd/flux/values.yaml
Normal file
73
infrastructure/cicd/flux/values.yaml
Normal file
@@ -0,0 +1,73 @@
|
||||
# Default values for flux-cd
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
gitRepository:
|
||||
name: bakery-ia
|
||||
namespace: flux-system
|
||||
interval: 1m
|
||||
url: http://gitea-http.gitea.svc.cluster.local:3000/bakery-admin/bakery-ia.git
|
||||
ref:
|
||||
branch: main
|
||||
secretRef:
|
||||
name: gitea-credentials
|
||||
timeout: 60s
|
||||
|
||||
kustomization:
|
||||
name: bakery-ia-prod
|
||||
namespace: flux-system
|
||||
interval: 5m
|
||||
path: ./infrastructure/environments/prod
|
||||
prune: true
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: bakery-ia
|
||||
targetNamespace: bakery-ia
|
||||
timeout: 10m
|
||||
retryInterval: 1m
|
||||
wait: true
|
||||
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
|
||||
postBuild:
|
||||
substituteFrom:
|
||||
- kind: ConfigMap
|
||||
name: bakery-ia-config
|
||||
optional: true
|
||||
- kind: Secret
|
||||
name: bakery-ia-secrets
|
||||
optional: true
|
||||
151
infrastructure/cicd/gitea/IMPLEMENTATION_SUMMARY.md
Normal file
151
infrastructure/cicd/gitea/IMPLEMENTATION_SUMMARY.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Gitea Automatic Repository Creation - Implementation Summary
|
||||
|
||||
## Overview
|
||||
|
||||
This implementation adds automatic repository creation to the Gitea Helm chart configuration for the Bakery-IA project. When Gitea is installed or upgraded via Helm, it will automatically create a `bakery-ia` repository with the specified configuration.
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. Updated Helm Values (`values.yaml`)
|
||||
|
||||
Added the `initialRepositories` configuration under the `gitea:` section:
|
||||
|
||||
```yaml
|
||||
# Initial repositories to create automatically after Gitea installation
|
||||
# These will be created with the admin user as owner
|
||||
gitea:
|
||||
initialRepositories:
|
||||
- name: bakery-ia
|
||||
description: "Main repository for Bakery IA project - Automatically created by Helm"
|
||||
private: false
|
||||
auto_init: true
|
||||
default_branch: main
|
||||
owner: "{{ .Values.gitea.admin.username }}"
|
||||
# Enable issues, wiki, and other features
|
||||
enable_issues: true
|
||||
enable_wiki: true
|
||||
enable_pull_requests: true
|
||||
enable_projects: true
|
||||
```
|
||||
|
||||
### 2. Created Setup Script (`setup-gitea-repository.sh`)
|
||||
|
||||
A comprehensive bash script that:
|
||||
- Checks if Gitea is accessible
|
||||
- Verifies if the repository exists (creates it if not)
|
||||
- Configures the local Git repository
|
||||
- Pushes the existing code to the new Gitea repository
|
||||
|
||||
### 3. Created Test Script (`test-repository-creation.sh`)
|
||||
|
||||
A test script that verifies:
|
||||
- Gitea accessibility
|
||||
- Repository existence
|
||||
- Repository configuration (issues, wiki, pull requests)
|
||||
- Provides detailed repository information
|
||||
|
||||
### 4. Created Documentation
|
||||
|
||||
- **README.md**: Complete guide on installation, usage, and troubleshooting
|
||||
- **IMPLEMENTATION_SUMMARY.md**: This file, summarizing the implementation
|
||||
|
||||
## How It Works
|
||||
|
||||
### Automatic Repository Creation Flow
|
||||
|
||||
1. **Helm Installation**: When `helm install` or `helm upgrade` is executed with the updated values
|
||||
2. **Gitea Initialization**: Gitea starts and creates the admin user
|
||||
3. **Repository Creation**: Gitea processes the `initialRepositories` configuration and creates the specified repositories
|
||||
4. **Completion**: The repository is ready for use immediately after Gitea is fully initialized
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Automatic**: No manual intervention required after Helm installation
|
||||
- **Idempotent**: Safe to run multiple times (won't duplicate repositories)
|
||||
- **Configurable**: All repository settings are defined in Helm values
|
||||
- **Integrated**: Uses native Gitea Helm chart features
|
||||
|
||||
## Usage
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Install Gitea with automatic repository creation
|
||||
helm install gitea gitea/gitea -n gitea \
|
||||
-f infrastructure/cicd/gitea/values.yaml \
|
||||
--set gitea.admin.password=your-secure-password
|
||||
```
|
||||
|
||||
### Push Existing Code
|
||||
|
||||
```bash
|
||||
export GITEA_ADMIN_PASSWORD="your-secure-password"
|
||||
./infrastructure/cicd/gitea/setup-gitea-repository.sh
|
||||
```
|
||||
|
||||
### Verify Repository
|
||||
|
||||
```bash
|
||||
export GITEA_ADMIN_PASSWORD="your-secure-password"
|
||||
./infrastructure/cicd/gitea/test-repository-creation.sh
|
||||
```
|
||||
|
||||
## Repository Configuration
|
||||
|
||||
The automatically created repository includes:
|
||||
|
||||
| Feature | Enabled | Description |
|
||||
|---------|---------|-------------|
|
||||
| Name | bakery-ia | Main project repository |
|
||||
| Description | Main repository for Bakery IA project | Clear identification |
|
||||
| Visibility | Public | Accessible without authentication |
|
||||
| Auto Init | Yes | Creates initial README.md |
|
||||
| Default Branch | main | Standard branch naming |
|
||||
| Issues | Yes | Bug and feature tracking |
|
||||
| Wiki | Yes | Project documentation |
|
||||
| Pull Requests | Yes | Code review workflow |
|
||||
| Projects | Yes | Project management |
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
The repository is ready for immediate CI/CD integration:
|
||||
|
||||
- **Repository URL**: `https://gitea.bakery-ia.local/bakery-admin/bakery-ia.git`
|
||||
- **Clone URL**: `https://gitea.bakery-ia.local/bakery-admin/bakery-ia.git`
|
||||
- **SSH URL**: `git@gitea.bakery-ia.local:bakery-admin/bakery-ia.git`
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Automation**: Eliminates manual repository creation step
|
||||
2. **Consistency**: Ensures all environments have the same repository structure
|
||||
3. **Reliability**: Uses Helm's declarative configuration management
|
||||
4. **Documentation**: Clear repository purpose and features
|
||||
5. **CI/CD Ready**: Repository is immediately available for pipeline configuration
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Repository Not Created
|
||||
|
||||
1. **Check Helm Values**: Ensure the `initialRepositories` section is correctly formatted
|
||||
2. **Verify Gitea Logs**: `kubectl logs -n gitea -l app.kubernetes.io/name=gitea`
|
||||
3. **Manual Creation**: Use the setup script to create the repository manually
|
||||
|
||||
### Authentication Issues
|
||||
|
||||
1. **Verify Password**: Ensure `GITEA_ADMIN_PASSWORD` is correct
|
||||
2. **Check Accessibility**: Confirm Gitea service is running and accessible
|
||||
3. **Network Configuration**: Verify ingress and DNS settings
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential improvements for future iterations:
|
||||
|
||||
1. **Multiple Repositories**: Add more repositories for different components
|
||||
2. **Webhooks**: Automatically configure webhooks for CI/CD triggers
|
||||
3. **Teams and Permissions**: Set up teams and access controls
|
||||
4. **Template Repositories**: Create repository templates with standard files
|
||||
5. **Backup Configuration**: Add automatic backup configuration
|
||||
|
||||
## Conclusion
|
||||
|
||||
This implementation provides a robust, automated solution for Gitea repository creation in the Bakery-IA project. It leverages Helm's native capabilities to ensure consistent, reliable repository setup across all environments.
|
||||
188
infrastructure/cicd/gitea/README.md
Normal file
188
infrastructure/cicd/gitea/README.md
Normal file
@@ -0,0 +1,188 @@
|
||||
# Gitea Configuration for Bakery-IA CI/CD
|
||||
|
||||
This directory contains the Helm values and scripts for setting up Gitea as the Git server for the Bakery-IA project.
|
||||
|
||||
## Features
|
||||
|
||||
- **Automatic Admin User**: Admin user is created automatically from Kubernetes secret
|
||||
- **Automatic Repository Creation**: The `bakery-ia` repository is created via a Kubernetes Job after Gitea starts
|
||||
- **Registry Support**: Container registry enabled for storing Docker images
|
||||
- **Tekton Integration**: Webhook automatically configured if Tekton is installed
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
# 1. Setup secrets and init job (uses default dev password)
|
||||
./infrastructure/cicd/gitea/setup-admin-secret.sh
|
||||
|
||||
# 2. Install Gitea
|
||||
helm repo add gitea https://dl.gitea.io/charts
|
||||
helm install gitea gitea/gitea -n gitea -f infrastructure/cicd/gitea/values.yaml
|
||||
|
||||
# 3. Wait for everything to be ready
|
||||
kubectl wait --for=condition=ready pod -n gitea -l app.kubernetes.io/name=gitea --timeout=300s
|
||||
|
||||
# 4. Check init job completed
|
||||
kubectl logs -n gitea -l app.kubernetes.io/component=init --tail=50
|
||||
```
|
||||
|
||||
### Production
|
||||
|
||||
```bash
|
||||
# 1. Generate and export secure password
|
||||
export GITEA_ADMIN_PASSWORD=$(openssl rand -base64 32)
|
||||
|
||||
# 2. Setup secrets with production flag (requires GITEA_ADMIN_PASSWORD)
|
||||
./infrastructure/cicd/gitea/setup-admin-secret.sh --production
|
||||
|
||||
# 3. Install Gitea with production values
|
||||
helm repo add gitea https://dl.gitea.io/charts
|
||||
helm upgrade --install gitea gitea/gitea -n gitea \
|
||||
-f infrastructure/cicd/gitea/values.yaml \
|
||||
-f infrastructure/cicd/gitea/values-prod.yaml
|
||||
|
||||
# 4. Wait for everything to be ready
|
||||
kubectl wait --for=condition=ready pod -n gitea -l app.kubernetes.io/name=gitea --timeout=300s
|
||||
|
||||
# 5. Install Tekton CI/CD (see tekton-helm/README.md for details)
|
||||
export TEKTON_WEBHOOK_TOKEN=$(openssl rand -hex 32)
|
||||
helm upgrade --install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||
-n tekton-pipelines \
|
||||
-f infrastructure/cicd/tekton-helm/values.yaml \
|
||||
-f infrastructure/cicd/tekton-helm/values-prod.yaml \
|
||||
--set secrets.webhook.token=$TEKTON_WEBHOOK_TOKEN \
|
||||
--set secrets.registry.password=$GITEA_ADMIN_PASSWORD \
|
||||
--set secrets.git.password=$GITEA_ADMIN_PASSWORD
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `values.yaml` | Helm values for Gitea chart |
|
||||
| `values-prod.yaml` | Production Helm values |
|
||||
| `setup-admin-secret.sh` | Creates secrets and applies init job |
|
||||
| `gitea-init-job.yaml` | Kubernetes Job to create initial repository |
|
||||
| `setup-gitea-repository.sh` | Helper to push local code to Gitea |
|
||||
|
||||
## How It Works
|
||||
|
||||
### 1. Admin User Initialization
|
||||
|
||||
The Gitea Helm chart automatically creates the admin user on first install. Credentials are read from a Kubernetes secret:
|
||||
|
||||
```yaml
|
||||
gitea:
|
||||
admin:
|
||||
username: bakery-admin
|
||||
email: admin@bakery-ia.local
|
||||
existingSecret: gitea-admin-secret # Secret with username/password keys
|
||||
passwordMode: keepUpdated # Sync password changes from secret
|
||||
```
|
||||
|
||||
The `setup-admin-secret.sh` script creates this secret before Helm install.
|
||||
|
||||
### 2. Repository Initialization
|
||||
|
||||
Since the Gitea Helm chart doesn't support automatic repository creation, we use a Kubernetes Job (`gitea-init-job.yaml`) that:
|
||||
|
||||
1. Waits for Gitea to be ready
|
||||
2. Creates the `bakery-ia` repository via Gitea API
|
||||
3. Optionally configures a webhook for Tekton CI/CD
|
||||
|
||||
The Job is idempotent - it skips creation if the repository already exists.
|
||||
|
||||
## Detailed Installation
|
||||
|
||||
### Step 1: Create Secrets
|
||||
|
||||
```bash
|
||||
# Using default password (for dev environments)
|
||||
./infrastructure/cicd/gitea/setup-admin-secret.sh
|
||||
|
||||
# Or specify a custom password
|
||||
./infrastructure/cicd/gitea/setup-admin-secret.sh "your-secure-password"
|
||||
|
||||
# Or use environment variable
|
||||
export GITEA_ADMIN_PASSWORD="your-secure-password"
|
||||
./infrastructure/cicd/gitea/setup-admin-secret.sh
|
||||
```
|
||||
|
||||
This creates:
|
||||
- `gitea-admin-secret` in `gitea` namespace - used by Gitea for admin credentials
|
||||
- `gitea-registry-secret` in `bakery-ia` namespace - used for `imagePullSecrets`
|
||||
- Applies `gitea-init-job.yaml` (ConfigMap + Job)
|
||||
|
||||
### Step 2: Install Gitea
|
||||
|
||||
```bash
|
||||
helm repo add gitea https://dl.gitea.io/charts
|
||||
helm repo update
|
||||
|
||||
helm install gitea gitea/gitea -n gitea \
|
||||
-f infrastructure/cicd/gitea/values.yaml
|
||||
```
|
||||
|
||||
### Step 3: Verify Installation
|
||||
|
||||
```bash
|
||||
# Wait for Gitea pod
|
||||
kubectl wait --for=condition=ready pod -n gitea -l app.kubernetes.io/name=gitea --timeout=300s
|
||||
|
||||
# Check init job logs
|
||||
kubectl logs -n gitea job/gitea-init-repo
|
||||
|
||||
# Verify repository was created
|
||||
curl -u bakery-admin:pvYUkGWJijqc0QfIZEXw \
|
||||
https://gitea.bakery-ia.local/api/v1/repos/bakery-admin/bakery-ia
|
||||
```
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
Repository URL:
|
||||
```
|
||||
https://gitea.bakery-ia.local/bakery-admin/bakery-ia.git
|
||||
```
|
||||
|
||||
Internal cluster URL (for pipelines):
|
||||
```
|
||||
http://gitea-http.gitea.svc.cluster.local:3000/bakery-admin/bakery-ia.git
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Init Job Failed
|
||||
|
||||
```bash
|
||||
# Check job status
|
||||
kubectl get jobs -n gitea
|
||||
|
||||
# View logs
|
||||
kubectl logs -n gitea job/gitea-init-repo
|
||||
|
||||
# Re-run the job
|
||||
kubectl delete job gitea-init-repo -n gitea
|
||||
kubectl apply -f infrastructure/cicd/gitea/gitea-init-job.yaml
|
||||
```
|
||||
|
||||
### Repository Not Created
|
||||
|
||||
1. Check if Gitea is ready: `kubectl get pods -n gitea`
|
||||
2. Check init job logs: `kubectl logs -n gitea job/gitea-init-repo`
|
||||
3. Manually create via API or use `setup-gitea-repository.sh`
|
||||
|
||||
### Authentication Issues
|
||||
|
||||
1. Verify secret exists: `kubectl get secret gitea-admin-secret -n gitea`
|
||||
2. Check credentials: `kubectl get secret gitea-admin-secret -n gitea -o jsonpath='{.data.password}' | base64 -d`
|
||||
|
||||
## Upgrading
|
||||
|
||||
```bash
|
||||
helm upgrade gitea gitea/gitea -n gitea \
|
||||
-f infrastructure/cicd/gitea/values.yaml
|
||||
```
|
||||
|
||||
Repositories and data are preserved during upgrades (stored in PVC).
|
||||
176
infrastructure/cicd/gitea/gitea-init-job.yaml
Normal file
176
infrastructure/cicd/gitea/gitea-init-job.yaml
Normal file
@@ -0,0 +1,176 @@
|
||||
# Gitea Initialization Job
|
||||
# This Job runs after Gitea is installed to create the initial repository
|
||||
# It uses the same admin credentials from gitea-admin-secret
|
||||
#
|
||||
# Apply after Gitea is ready:
|
||||
# kubectl apply -f gitea-init-job.yaml -n gitea
|
||||
#
|
||||
# To re-run (if needed):
|
||||
# kubectl delete job gitea-init-repo -n gitea
|
||||
# kubectl apply -f gitea-init-job.yaml -n gitea
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: gitea-init-script
|
||||
namespace: gitea
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea
|
||||
app.kubernetes.io/component: init
|
||||
data:
|
||||
init-repo.sh: |
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
GITEA_URL="http://gitea-http.gitea.svc.cluster.local:3000"
|
||||
REPO_NAME="bakery-ia"
|
||||
MAX_RETRIES=30
|
||||
RETRY_INTERVAL=10
|
||||
|
||||
echo "=== Gitea Repository Initialization ==="
|
||||
echo "Gitea URL: $GITEA_URL"
|
||||
echo "Repository: $REPO_NAME"
|
||||
echo "Admin User: $GITEA_ADMIN_USER"
|
||||
|
||||
# Wait for Gitea to be ready
|
||||
echo ""
|
||||
echo "Waiting for Gitea to be ready..."
|
||||
RETRIES=0
|
||||
until curl -sf "$GITEA_URL/api/v1/version" > /dev/null 2>&1; do
|
||||
RETRIES=$((RETRIES + 1))
|
||||
if [ $RETRIES -ge $MAX_RETRIES ]; then
|
||||
echo "ERROR: Gitea did not become ready after $MAX_RETRIES attempts"
|
||||
exit 1
|
||||
fi
|
||||
echo " Attempt $RETRIES/$MAX_RETRIES - Gitea not ready, waiting ${RETRY_INTERVAL}s..."
|
||||
sleep $RETRY_INTERVAL
|
||||
done
|
||||
echo "Gitea is ready!"
|
||||
|
||||
# Check if repository already exists
|
||||
echo ""
|
||||
echo "Checking if repository '$REPO_NAME' exists..."
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-u "$GITEA_ADMIN_USER:$GITEA_ADMIN_PASSWORD" \
|
||||
"$GITEA_URL/api/v1/repos/$GITEA_ADMIN_USER/$REPO_NAME")
|
||||
|
||||
if [ "$HTTP_CODE" = "200" ]; then
|
||||
echo "Repository '$REPO_NAME' already exists. Nothing to do."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create the repository
|
||||
echo "Creating repository '$REPO_NAME'..."
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" \
|
||||
-u "$GITEA_ADMIN_USER:$GITEA_ADMIN_PASSWORD" \
|
||||
-X POST "$GITEA_URL/api/v1/user/repos" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "'"$REPO_NAME"'",
|
||||
"description": "Main repository for Bakery IA project - Automatically created",
|
||||
"private": false,
|
||||
"auto_init": true,
|
||||
"default_branch": "main",
|
||||
"readme": "Default"
|
||||
}')
|
||||
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
|
||||
BODY=$(echo "$RESPONSE" | sed '$d')
|
||||
|
||||
if [ "$HTTP_CODE" = "201" ]; then
|
||||
echo "Repository '$REPO_NAME' created successfully!"
|
||||
echo ""
|
||||
echo "Repository URL: $GITEA_URL/$GITEA_ADMIN_USER/$REPO_NAME"
|
||||
echo "Clone URL: $GITEA_URL/$GITEA_ADMIN_USER/$REPO_NAME.git"
|
||||
else
|
||||
echo "ERROR: Failed to create repository (HTTP $HTTP_CODE)"
|
||||
echo "Response: $BODY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Configure webhook for Tekton (optional - if Tekton is installed)
|
||||
echo ""
|
||||
echo "Checking if Tekton EventListener is available..."
|
||||
TEKTON_URL="http://el-bakery-ia-listener.tekton-pipelines.svc.cluster.local:8080"
|
||||
if curl -sf "$TEKTON_URL" > /dev/null 2>&1; then
|
||||
echo "Tekton EventListener found. Creating webhook..."
|
||||
WEBHOOK_RESPONSE=$(curl -s -w "\n%{http_code}" \
|
||||
-u "$GITEA_ADMIN_USER:$GITEA_ADMIN_PASSWORD" \
|
||||
-X POST "$GITEA_URL/api/v1/repos/$GITEA_ADMIN_USER/$REPO_NAME/hooks" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"type": "gitea",
|
||||
"config": {
|
||||
"url": "'"$TEKTON_URL"'",
|
||||
"content_type": "json"
|
||||
},
|
||||
"events": ["push"],
|
||||
"active": true
|
||||
}')
|
||||
|
||||
WEBHOOK_CODE=$(echo "$WEBHOOK_RESPONSE" | tail -1)
|
||||
if [ "$WEBHOOK_CODE" = "201" ]; then
|
||||
echo "Webhook created successfully!"
|
||||
else
|
||||
echo "Warning: Could not create webhook (HTTP $WEBHOOK_CODE). You may need to configure it manually."
|
||||
fi
|
||||
else
|
||||
echo "Tekton EventListener not available. Skipping webhook creation."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Initialization Complete ==="
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: gitea-init-repo
|
||||
namespace: gitea
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea
|
||||
app.kubernetes.io/component: init
|
||||
annotations:
|
||||
# Helm hook annotations (if used with Helm)
|
||||
helm.sh/hook: post-install,post-upgrade
|
||||
helm.sh/hook-weight: "10"
|
||||
helm.sh/hook-delete-policy: before-hook-creation
|
||||
spec:
|
||||
ttlSecondsAfterFinished: 300
|
||||
backoffLimit: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea
|
||||
app.kubernetes.io/component: init
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
containers:
|
||||
- name: init-repo
|
||||
image: curlimages/curl:8.5.0
|
||||
command: ["/bin/sh", "/scripts/init-repo.sh"]
|
||||
env:
|
||||
- name: GITEA_ADMIN_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-admin-secret
|
||||
key: username
|
||||
- name: GITEA_ADMIN_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-admin-secret
|
||||
key: password
|
||||
volumeMounts:
|
||||
- name: init-script
|
||||
mountPath: /scripts
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 32Mi
|
||||
volumes:
|
||||
- name: init-script
|
||||
configMap:
|
||||
name: gitea-init-script
|
||||
defaultMode: 0755
|
||||
209
infrastructure/cicd/gitea/setup-admin-secret.sh
Executable file
209
infrastructure/cicd/gitea/setup-admin-secret.sh
Executable file
@@ -0,0 +1,209 @@
|
||||
#!/bin/bash
|
||||
# Setup Gitea Admin Secret and Initialize Gitea
|
||||
#
|
||||
# This script:
|
||||
# 1. Creates gitea-admin-secret (gitea namespace) - Used by Gitea Helm chart for admin credentials
|
||||
# 2. Creates gitea-registry-secret (bakery-ia namespace) - Used by pods for imagePullSecrets
|
||||
# 3. Applies the gitea-init-job.yaml to create the initial repository
|
||||
#
|
||||
# Usage:
|
||||
# Development:
|
||||
# ./setup-admin-secret.sh # Uses default dev password
|
||||
# ./setup-admin-secret.sh [password] # Uses provided password
|
||||
# ./setup-admin-secret.sh --secrets-only # Only create secrets, skip init job
|
||||
#
|
||||
# Production:
|
||||
# export GITEA_ADMIN_PASSWORD=$(openssl rand -base64 32)
|
||||
# ./setup-admin-secret.sh --production
|
||||
# ./setup-admin-secret.sh --production --secrets-only
|
||||
#
|
||||
# Environment variables:
|
||||
# GITEA_ADMIN_PASSWORD - Password to use (required for --production)
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
KUBECTL="kubectl"
|
||||
GITEA_NAMESPACE="gitea"
|
||||
BAKERY_NAMESPACE="bakery-ia"
|
||||
REGISTRY_HOST="registry.bakery-ia.local"
|
||||
ADMIN_USERNAME="bakery-admin"
|
||||
# Default password for dev environment only
|
||||
# For PRODUCTION: Always set GITEA_ADMIN_PASSWORD environment variable
|
||||
# Generate secure password with: openssl rand -base64 32
|
||||
DEV_DEFAULT_PASSWORD="pvYUkGWJijqc0QfIZEXw"
|
||||
SECRETS_ONLY=false
|
||||
IS_PRODUCTION=false
|
||||
|
||||
# Check if running in microk8s
|
||||
if command -v microk8s &> /dev/null; then
|
||||
KUBECTL="microk8s kubectl"
|
||||
fi
|
||||
|
||||
# Parse arguments
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--secrets-only)
|
||||
SECRETS_ONLY=true
|
||||
;;
|
||||
--production)
|
||||
IS_PRODUCTION=true
|
||||
REGISTRY_HOST="registry.bakewise.ai"
|
||||
;;
|
||||
*)
|
||||
if [ -z "$ADMIN_PASSWORD" ] && [ "$arg" != "--secrets-only" ] && [ "$arg" != "--production" ]; then
|
||||
ADMIN_PASSWORD="$arg"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Get password from argument, environment variable, or use default (dev only)
|
||||
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||
if [ -n "$GITEA_ADMIN_PASSWORD" ]; then
|
||||
ADMIN_PASSWORD="$GITEA_ADMIN_PASSWORD"
|
||||
echo "Using password from GITEA_ADMIN_PASSWORD environment variable"
|
||||
elif [ "$IS_PRODUCTION" = true ]; then
|
||||
echo "ERROR: Production deployment requires GITEA_ADMIN_PASSWORD environment variable"
|
||||
echo "Generate a secure password with: openssl rand -base64 32"
|
||||
echo ""
|
||||
echo "Usage for production:"
|
||||
echo " export GITEA_ADMIN_PASSWORD=\$(openssl rand -base64 32)"
|
||||
echo " ./setup-admin-secret.sh --production"
|
||||
exit 1
|
||||
else
|
||||
ADMIN_PASSWORD="$DEV_DEFAULT_PASSWORD"
|
||||
echo "WARNING: Using default dev password. For production, set GITEA_ADMIN_PASSWORD"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate password strength for production
|
||||
if [ "$IS_PRODUCTION" = true ] && [ ${#ADMIN_PASSWORD} -lt 16 ]; then
|
||||
echo "ERROR: Production password must be at least 16 characters"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create namespaces if they don't exist
|
||||
$KUBECTL create namespace "$GITEA_NAMESPACE" --dry-run=client -o yaml | $KUBECTL apply -f -
|
||||
$KUBECTL create namespace "$BAKERY_NAMESPACE" --dry-run=client -o yaml | $KUBECTL apply -f -
|
||||
|
||||
# 1. Create gitea-admin-secret for Gitea Helm chart
|
||||
echo "Creating gitea-admin-secret in $GITEA_NAMESPACE namespace..."
|
||||
$KUBECTL create secret generic gitea-admin-secret \
|
||||
--namespace "$GITEA_NAMESPACE" \
|
||||
--from-literal=username="$ADMIN_USERNAME" \
|
||||
--from-literal=password="$ADMIN_PASSWORD" \
|
||||
--dry-run=client -o yaml | $KUBECTL apply -f -
|
||||
|
||||
# 2. Create gitea-registry-secret for imagePullSecrets
|
||||
echo "Creating gitea-registry-secret in $BAKERY_NAMESPACE namespace..."
|
||||
|
||||
# Create Docker config JSON for registry authentication
|
||||
# Include both external (ingress) and internal (cluster) registry URLs
|
||||
AUTH_BASE64=$(echo -n "${ADMIN_USERNAME}:${ADMIN_PASSWORD}" | base64)
|
||||
INTERNAL_REGISTRY_HOST="gitea-http.gitea.svc.cluster.local:3000"
|
||||
DOCKER_CONFIG_JSON=$(cat <<EOF
|
||||
{
|
||||
"auths": {
|
||||
"${REGISTRY_HOST}": {
|
||||
"username": "${ADMIN_USERNAME}",
|
||||
"password": "${ADMIN_PASSWORD}",
|
||||
"auth": "${AUTH_BASE64}"
|
||||
},
|
||||
"${INTERNAL_REGISTRY_HOST}": {
|
||||
"username": "${ADMIN_USERNAME}",
|
||||
"password": "${ADMIN_PASSWORD}",
|
||||
"auth": "${AUTH_BASE64}"
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
# Base64 encode the entire config (use -w0 on Linux, no flag needed on macOS)
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
DOCKER_CONFIG_BASE64=$(echo -n "$DOCKER_CONFIG_JSON" | base64)
|
||||
else
|
||||
DOCKER_CONFIG_BASE64=$(echo -n "$DOCKER_CONFIG_JSON" | base64 -w0)
|
||||
fi
|
||||
|
||||
# Create the registry secret
|
||||
cat <<EOF | $KUBECTL apply -f -
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-registry-secret
|
||||
namespace: ${BAKERY_NAMESPACE}
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia
|
||||
app.kubernetes.io/component: registry
|
||||
app.kubernetes.io/managed-by: setup-admin-secret
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
data:
|
||||
.dockerconfigjson: ${DOCKER_CONFIG_BASE64}
|
||||
EOF
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "Gitea secrets created successfully!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Environment: $([ "$IS_PRODUCTION" = true ] && echo "PRODUCTION" || echo "Development")"
|
||||
echo ""
|
||||
echo "Credentials:"
|
||||
echo " Username: $ADMIN_USERNAME"
|
||||
if [ "$IS_PRODUCTION" = true ]; then
|
||||
echo " Password: (stored in secret, not displayed for security)"
|
||||
else
|
||||
echo " Password: $ADMIN_PASSWORD"
|
||||
fi
|
||||
echo ""
|
||||
echo "Secrets created:"
|
||||
echo " 1. gitea-admin-secret (namespace: $GITEA_NAMESPACE) - For Gitea Helm chart"
|
||||
echo " 2. gitea-registry-secret (namespace: $BAKERY_NAMESPACE) - For imagePullSecrets"
|
||||
echo ""
|
||||
echo "Registry URLs:"
|
||||
echo " External: https://$REGISTRY_HOST"
|
||||
echo " Internal: $INTERNAL_REGISTRY_HOST"
|
||||
echo ""
|
||||
|
||||
# Apply the init job ConfigMap and Job (but Job won't run until Gitea is installed)
|
||||
if [ "$SECRETS_ONLY" = false ]; then
|
||||
INIT_JOB_FILE="$SCRIPT_DIR/gitea-init-job.yaml"
|
||||
if [ -f "$INIT_JOB_FILE" ]; then
|
||||
echo "Applying Gitea initialization resources..."
|
||||
$KUBECTL apply -f "$INIT_JOB_FILE"
|
||||
echo ""
|
||||
echo "Init job will create the 'bakery-ia' repository once Gitea is ready."
|
||||
else
|
||||
echo "Warning: gitea-init-job.yaml not found at $INIT_JOB_FILE"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "Next steps:"
|
||||
if [ "$IS_PRODUCTION" = true ]; then
|
||||
echo " 1. Install Gitea for production:"
|
||||
echo " helm upgrade --install gitea gitea/gitea -n gitea \\"
|
||||
echo " -f infrastructure/cicd/gitea/values.yaml \\"
|
||||
echo " -f infrastructure/cicd/gitea/values-prod.yaml"
|
||||
echo ""
|
||||
echo " 2. Install Tekton CI/CD for production:"
|
||||
echo " export TEKTON_WEBHOOK_TOKEN=\$(openssl rand -hex 32)"
|
||||
echo " helm upgrade --install tekton-cicd infrastructure/cicd/tekton-helm \\"
|
||||
echo " -n tekton-pipelines \\"
|
||||
echo " -f infrastructure/cicd/tekton-helm/values.yaml \\"
|
||||
echo " -f infrastructure/cicd/tekton-helm/values-prod.yaml \\"
|
||||
echo " --set secrets.webhook.token=\$TEKTON_WEBHOOK_TOKEN \\"
|
||||
echo " --set secrets.registry.password=\$GITEA_ADMIN_PASSWORD \\"
|
||||
echo " --set secrets.git.password=\$GITEA_ADMIN_PASSWORD"
|
||||
else
|
||||
echo " 1. Install Gitea (if not already installed):"
|
||||
echo " helm install gitea gitea/gitea -n gitea -f infrastructure/cicd/gitea/values.yaml"
|
||||
fi
|
||||
echo ""
|
||||
echo " $([ "$IS_PRODUCTION" = true ] && echo "3" || echo "2"). Wait for Gitea to be ready:"
|
||||
echo " kubectl wait --for=condition=ready pod -n gitea -l app.kubernetes.io/name=gitea --timeout=300s"
|
||||
echo ""
|
||||
echo " $([ "$IS_PRODUCTION" = true ] && echo "4" || echo "3"). Check init job status:"
|
||||
echo " kubectl logs -n gitea -l app.kubernetes.io/component=init --tail=50"
|
||||
119
infrastructure/cicd/gitea/setup-gitea-repository.sh
Executable file
119
infrastructure/cicd/gitea/setup-gitea-repository.sh
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/bin/bash
|
||||
# Script to setup and push code to the automatically created Gitea repository
|
||||
# This script should be run after Gitea is installed and the repository is created
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== Gitea Repository Setup Script ==="
|
||||
echo "This script will configure the bakery-ia repository in Gitea"
|
||||
echo
|
||||
|
||||
# Configuration - update these values as needed
|
||||
GITEA_URL="https://gitea.bakery-ia.local"
|
||||
GITEA_ADMIN_USER="bakery-admin"
|
||||
REPO_NAME="bakery-ia"
|
||||
LOCAL_DIR="/Users/urtzialfaro/Documents/bakery-ia"
|
||||
|
||||
# Check if Gitea admin password is set
|
||||
if [ -z "$GITEA_ADMIN_PASSWORD" ]; then
|
||||
echo "Error: GITEA_ADMIN_PASSWORD environment variable is not set"
|
||||
echo "Please set it to the admin password you used during Gitea installation"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Checking if Gitea is accessible..."
|
||||
if ! curl -s -o /dev/null -w "%{http_code}" "$GITEA_URL" | grep -q "200"; then
|
||||
echo "Error: Cannot access Gitea at $GITEA_URL"
|
||||
echo "Please ensure Gitea is running and accessible"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ Gitea is accessible"
|
||||
|
||||
echo "Checking if repository $REPO_NAME exists..."
|
||||
REPO_CHECK=$(curl -s -w "%{http_code}" -u "$GITEA_ADMIN_USER:$GITEA_ADMIN_PASSWORD" \
|
||||
"$GITEA_URL/api/v1/repos/$GITEA_ADMIN_USER/$REPO_NAME" | tail -1)
|
||||
|
||||
if [ "$REPO_CHECK" != "200" ]; then
|
||||
echo "Repository $REPO_NAME does not exist or is not accessible"
|
||||
echo "Attempting to create it..."
|
||||
|
||||
CREATE_RESPONSE=$(curl -s -w "%{http_code}" -u "$GITEA_ADMIN_USER:$GITEA_ADMIN_PASSWORD" \
|
||||
-X POST "$GITEA_URL/api/v1/user/repos" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "'"$REPO_NAME"'",
|
||||
"description": "Main repository for Bakery IA project",
|
||||
"private": false,
|
||||
"auto_init": true,
|
||||
"default_branch": "main"
|
||||
}')
|
||||
|
||||
HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -1)
|
||||
RESPONSE_BODY=$(echo "$CREATE_RESPONSE" | sed '$d')
|
||||
|
||||
if [ "$HTTP_CODE" != "201" ]; then
|
||||
echo "Error creating repository: HTTP $HTTP_CODE"
|
||||
echo "Response: $RESPONSE_BODY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ Repository $REPO_NAME created successfully"
|
||||
else
|
||||
echo "✓ Repository $REPO_NAME already exists"
|
||||
fi
|
||||
|
||||
echo "Configuring Git repository..."
|
||||
cd "$LOCAL_DIR"
|
||||
|
||||
# Check if this is already a git repository
|
||||
if [ ! -d ".git" ]; then
|
||||
echo "Initializing Git repository..."
|
||||
git init
|
||||
git branch -M main
|
||||
else
|
||||
echo "Git repository already initialized"
|
||||
fi
|
||||
|
||||
# Configure Git user if not already set
|
||||
if [ -z "$(git config user.name)" ]; then
|
||||
git config user.name "$GITEA_ADMIN_USER"
|
||||
git config user.email "admin@bakery-ia.local"
|
||||
echo "✓ Configured Git user: $GITEA_ADMIN_USER"
|
||||
fi
|
||||
|
||||
# Set the remote URL
|
||||
GIT_REMOTE_URL="$GITEA_URL/$GITEA_ADMIN_USER/$REPO_NAME.git"
|
||||
|
||||
if git remote | grep -q "origin"; then
|
||||
CURRENT_REMOTE=$(git remote get-url origin)
|
||||
if [ "$CURRENT_REMOTE" != "$GIT_REMOTE_URL" ]; then
|
||||
echo "Updating remote origin to: $GIT_REMOTE_URL"
|
||||
git remote set-url origin "$GIT_REMOTE_URL"
|
||||
else
|
||||
echo "Remote origin is already set correctly"
|
||||
fi
|
||||
else
|
||||
echo "Setting remote origin to: $GIT_REMOTE_URL"
|
||||
git remote add origin "$GIT_REMOTE_URL"
|
||||
fi
|
||||
|
||||
echo "Checking if there are changes to commit..."
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo "Committing changes..."
|
||||
git add .
|
||||
git commit -m "Initial commit - Bakery IA project setup"
|
||||
echo "✓ Changes committed"
|
||||
else
|
||||
echo "No changes to commit"
|
||||
fi
|
||||
|
||||
echo "Pushing to Gitea repository..."
|
||||
git push --set-upstream origin main
|
||||
|
||||
echo "✓ Code pushed successfully to Gitea!"
|
||||
|
||||
echo "Repository URL: $GIT_REMOTE_URL"
|
||||
echo "You can now configure your CI/CD pipelines to use this repository."
|
||||
|
||||
echo "=== Setup Complete ==="
|
||||
84
infrastructure/cicd/gitea/test-repository-creation.sh
Executable file
84
infrastructure/cicd/gitea/test-repository-creation.sh
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
# Test script to verify that the Gitea repository was created successfully
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== Gitea Repository Creation Test ==="
|
||||
echo
|
||||
|
||||
# Configuration - update these values as needed
|
||||
GITEA_URL="https://gitea.bakery-ia.local"
|
||||
GITEA_ADMIN_USER="bakery-admin"
|
||||
REPO_NAME="bakery-ia"
|
||||
|
||||
# Check if Gitea admin password is set
|
||||
if [ -z "$GITEA_ADMIN_PASSWORD" ]; then
|
||||
echo "Error: GITEA_ADMIN_PASSWORD environment variable is not set"
|
||||
echo "Please set it to the admin password you used during Gitea installation"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Testing Gitea accessibility..."
|
||||
if ! curl -s -o /dev/null -w "%{http_code}" "$GITEA_URL" | grep -q "200"; then
|
||||
echo "❌ Error: Cannot access Gitea at $GITEA_URL"
|
||||
echo "Please ensure Gitea is running and accessible"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Gitea is accessible"
|
||||
|
||||
echo "Testing repository existence..."
|
||||
REPO_CHECK=$(curl -s -w "%{http_code}" -u "$GITEA_ADMIN_USER:$GITEA_ADMIN_PASSWORD" \
|
||||
"$GITEA_URL/api/v1/repos/$GITEA_ADMIN_USER/$REPO_NAME" | tail -1)
|
||||
|
||||
if [ "$REPO_CHECK" == "200" ]; then
|
||||
echo "✅ Repository '$REPO_NAME' exists"
|
||||
|
||||
# Get repository details
|
||||
REPO_DETAILS=$(curl -s -u "$GITEA_ADMIN_USER:$GITEA_ADMIN_PASSWORD" \
|
||||
"$GITEA_URL/api/v1/repos/$GITEA_ADMIN_USER/$REPO_NAME")
|
||||
|
||||
REPO_DESCRIPTION=$(echo "$REPO_DETAILS" | jq -r '.description')
|
||||
REPO_PRIVATE=$(echo "$REPO_DETAILS" | jq -r '.private')
|
||||
REPO_DEFAULT_BRANCH=$(echo "$REPO_DETAILS" | jq -r '.default_branch')
|
||||
|
||||
echo "Repository Details:"
|
||||
echo " - Name: $REPO_NAME"
|
||||
echo " - Description: $REPO_DESCRIPTION"
|
||||
echo " - Private: $REPO_PRIVATE"
|
||||
echo " - Default Branch: $REPO_DEFAULT_BRANCH"
|
||||
echo " - URL: $GITEA_URL/$GITEA_ADMIN_USER/$REPO_NAME"
|
||||
echo " - Clone URL: $GITEA_URL/$GITEA_ADMIN_USER/$REPO_NAME.git"
|
||||
|
||||
# Test if repository has issues enabled
|
||||
if echo "$REPO_DETAILS" | jq -e '.has_issues == true' > /dev/null; then
|
||||
echo "✅ Issues are enabled"
|
||||
else
|
||||
echo "❌ Issues are not enabled"
|
||||
fi
|
||||
|
||||
# Test if repository has wiki enabled
|
||||
if echo "$REPO_DETAILS" | jq -e '.has_wiki == true' > /dev/null; then
|
||||
echo "✅ Wiki is enabled"
|
||||
else
|
||||
echo "❌ Wiki is not enabled"
|
||||
fi
|
||||
|
||||
# Test if repository has pull requests enabled
|
||||
if echo "$REPO_DETAILS" | jq -e '.has_pull_requests == true' > /dev/null; then
|
||||
echo "✅ Pull requests are enabled"
|
||||
else
|
||||
echo "❌ Pull requests are not enabled"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "✅ All tests passed! Repository is ready for use."
|
||||
|
||||
else
|
||||
echo "❌ Repository '$REPO_NAME' does not exist"
|
||||
echo "Expected HTTP 200, got: $REPO_CHECK"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=== Test Complete ==="
|
||||
65
infrastructure/cicd/gitea/values-prod.yaml
Normal file
65
infrastructure/cicd/gitea/values-prod.yaml
Normal file
@@ -0,0 +1,65 @@
|
||||
# Gitea Helm values for Production environment
|
||||
# This file overrides values.yaml for production deployment
|
||||
#
|
||||
# Installation:
|
||||
# helm upgrade --install gitea gitea/gitea -n gitea \
|
||||
# -f infrastructure/cicd/gitea/values.yaml \
|
||||
# -f infrastructure/cicd/gitea/values-prod.yaml
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "500m"
|
||||
nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-production"
|
||||
hosts:
|
||||
- host: gitea.bakewise.ai
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: gitea-tls-cert
|
||||
hosts:
|
||||
- gitea.bakewise.ai
|
||||
apiIngress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "500m"
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-production"
|
||||
hosts:
|
||||
- host: registry.bakewise.ai
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: registry-tls-cert
|
||||
hosts:
|
||||
- registry.bakewise.ai
|
||||
|
||||
gitea:
|
||||
admin:
|
||||
email: admin@bakewise.ai
|
||||
config:
|
||||
server:
|
||||
DOMAIN: gitea.bakewise.ai
|
||||
SSH_DOMAIN: gitea.bakewise.ai
|
||||
ROOT_URL: https://gitea.bakewise.ai
|
||||
|
||||
# Production resources - adjust based on expected load
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
|
||||
# Larger storage for production
|
||||
persistence:
|
||||
size: 50Gi
|
||||
132
infrastructure/cicd/gitea/values.yaml
Normal file
132
infrastructure/cicd/gitea/values.yaml
Normal file
@@ -0,0 +1,132 @@
|
||||
# Gitea Helm values configuration for Bakery-IA CI/CD
|
||||
# This configuration sets up Gitea with registry support and appropriate storage
|
||||
#
|
||||
# Prerequisites:
|
||||
# 1. Run setup-admin-secret.sh to create the gitea-admin-secret
|
||||
# 2. Apply the post-install job: kubectl apply -f gitea-init-job.yaml
|
||||
#
|
||||
# Installation:
|
||||
# helm repo add gitea https://dl.gitea.io/charts
|
||||
# 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.
|
||||
|
||||
# Use regular Gitea image instead of rootless to ensure registry functionality
|
||||
# Rootless images don't support container registry due to security restrictions
|
||||
image:
|
||||
rootless: false
|
||||
|
||||
service:
|
||||
http:
|
||||
type: ClusterIP
|
||||
port: 3000
|
||||
ssh:
|
||||
type: ClusterIP
|
||||
port: 2222
|
||||
# NOTE: Gitea's container registry is served on port 3000 (same as HTTP) under /v2/
|
||||
# The registry.PORT in gitea config is NOT used for external access
|
||||
# Registry authentication and API is handled by the main HTTP service
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "500m"
|
||||
nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
|
||||
hosts:
|
||||
- host: gitea.bakery-ia.local
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: bakery-dev-tls-cert
|
||||
hosts:
|
||||
- gitea.bakery-ia.local
|
||||
- registry.bakery-ia.local
|
||||
|
||||
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: ""
|
||||
|
||||
# =============================================================================
|
||||
# ADMIN USER CONFIGURATION
|
||||
# =============================================================================
|
||||
# The admin user is automatically created on first install.
|
||||
# Credentials are read from the 'gitea-admin-secret' Kubernetes secret.
|
||||
#
|
||||
# Create the secret BEFORE installing Gitea:
|
||||
# ./setup-admin-secret.sh
|
||||
#
|
||||
# The secret must contain:
|
||||
# - username: admin username (default: bakery-admin)
|
||||
# - password: admin password
|
||||
# =============================================================================
|
||||
gitea:
|
||||
admin:
|
||||
username: bakery-admin
|
||||
email: admin@bakery-ia.local
|
||||
# Use existing secret for admin credentials (created by setup-admin-secret.sh)
|
||||
existingSecret: gitea-admin-secret
|
||||
# keepUpdated ensures password changes in secret are applied
|
||||
passwordMode: keepUpdated
|
||||
|
||||
config:
|
||||
server:
|
||||
DOMAIN: gitea.bakery-ia.local
|
||||
SSH_DOMAIN: gitea.bakery-ia.local
|
||||
SSH_PORT: 2222
|
||||
# Use HTTPS for external access; TLS termination happens at ingress
|
||||
ROOT_URL: https://gitea.bakery-ia.local
|
||||
HTTP_PORT: 3000
|
||||
# Disable built-in HTTPS since ingress handles TLS
|
||||
PROTOCOL: http
|
||||
repository:
|
||||
ENABLE_PUSH_CREATE_USER: true
|
||||
ENABLE_PUSH_CREATE_ORG: true
|
||||
DEFAULT_BRANCH: main
|
||||
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
|
||||
|
||||
|
||||
15
infrastructure/cicd/tekton-helm/Chart.yaml
Normal file
15
infrastructure/cicd/tekton-helm/Chart.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
apiVersion: v2
|
||||
name: tekton-cicd
|
||||
description: Tekton CI/CD infrastructure for Bakery-IA
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "0.57.0"
|
||||
maintainers:
|
||||
- name: Bakery-IA Team
|
||||
email: team@bakery-ia.local
|
||||
annotations:
|
||||
category: Infrastructure
|
||||
app.kubernetes.io/name: tekton-cicd
|
||||
app.kubernetes.io/instance: tekton-cicd
|
||||
app.kubernetes.io/version: "0.57.0"
|
||||
app.kubernetes.io/part-of: bakery-ia
|
||||
145
infrastructure/cicd/tekton-helm/GITEA_SECRET_INTEGRATION.md
Normal file
145
infrastructure/cicd/tekton-helm/GITEA_SECRET_INTEGRATION.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# Gitea Admin Secret Integration for Tekton
|
||||
|
||||
This document explains how Tekton CI/CD integrates with the existing Gitea admin secret to ensure credential consistency across the system.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Gitea Admin Secret] --> B[Tekton Registry Credentials]
|
||||
A --> C[Tekton Git Credentials]
|
||||
A --> D[Flux Git Credentials]
|
||||
B --> E[Kaniko Build Task]
|
||||
C --> F[GitOps Update Task]
|
||||
D --> G[Flux GitRepository]
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
The system uses Helm's `lookup` function to reference the existing `gitea-admin-secret` from the Gitea namespace, ensuring that:
|
||||
|
||||
1. **Single Source of Truth**: All CI/CD components use the same credentials as Gitea
|
||||
2. **Automatic Synchronization**: When Gitea admin password changes, all CI/CD components automatically use the new credentials
|
||||
3. **Reduced Maintenance**: No need to manually update credentials in multiple places
|
||||
|
||||
## Secret Reference Flow
|
||||
|
||||
```
|
||||
Gitea Namespace: gitea-admin-secret
|
||||
└── username: bakery-admin
|
||||
└── password: [secure-password]
|
||||
|
||||
Tekton Namespace:
|
||||
├── gitea-registry-credentials (dockerconfigjson)
|
||||
│ └── references gitea-admin-secret.password
|
||||
│
|
||||
├── gitea-git-credentials (opaque)
|
||||
│ └── references gitea-admin-secret.password
|
||||
│
|
||||
└── gitea-credentials (opaque) [flux-system namespace]
|
||||
└── references gitea-admin-secret.password
|
||||
```
|
||||
|
||||
## Deployment Requirements
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. **Gitea must be installed first**: The `gitea-admin-secret` must exist before deploying Tekton
|
||||
2. **Same username**: All components use `bakery-admin` as the username
|
||||
3. **Namespace access**: Tekton service account needs read access to Gitea namespace secrets
|
||||
|
||||
### Installation Steps
|
||||
|
||||
1. **Install Gitea with admin secret**:
|
||||
```bash
|
||||
# Run the setup script to create gitea-admin-secret
|
||||
./infrastructure/cicd/gitea/setup-admin-secret.sh your-secure-password
|
||||
|
||||
# Install Gitea Helm chart
|
||||
helm install gitea gitea/gitea -n gitea -f infrastructure/cicd/gitea/values.yaml
|
||||
```
|
||||
|
||||
2. **Install Tekton with secret references**:
|
||||
```bash
|
||||
# Install Tekton - it will automatically reference the Gitea admin secret
|
||||
helm install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||
--namespace tekton-pipelines \
|
||||
--set secrets.webhook.token="your-webhook-token"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Secret not found error**:
|
||||
- Ensure Gitea is installed before Tekton
|
||||
- Verify the `gitea-admin-secret` exists in the `gitea` namespace
|
||||
- Check that Tekton service account has RBAC permissions to read Gitea secrets
|
||||
|
||||
2. **Authentication failures**:
|
||||
- Verify the Gitea admin password is correct
|
||||
- Ensure the username is `bakery-admin` (matching the Gitea admin)
|
||||
- Check that the password hasn't been manually changed in Gitea UI
|
||||
|
||||
### Debugging Commands
|
||||
|
||||
```bash
|
||||
# Check if gitea-admin-secret exists
|
||||
kubectl get secret gitea-admin-secret -n gitea
|
||||
|
||||
# Verify Tekton secrets were created correctly
|
||||
kubectl get secret gitea-registry-credentials -n tekton-pipelines -o yaml
|
||||
kubectl get secret gitea-git-credentials -n tekton-pipelines -o yaml
|
||||
kubectl get secret gitea-credentials -n flux-system -o yaml
|
||||
|
||||
# Check RBAC permissions
|
||||
kubectl get role,rolebinding,clusterrole,clusterrolebinding -n tekton-pipelines
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Benefits
|
||||
|
||||
1. **Reduced attack surface**: Fewer secrets to manage and rotate
|
||||
2. **Automatic rotation**: Changing Gitea admin password automatically updates all CI/CD components
|
||||
3. **Consistent access control**: Single point for credential management
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Use strong passwords**: Generate secure random passwords for Gitea admin
|
||||
2. **Rotate regularly**: Change the Gitea admin password periodically
|
||||
3. **Limit access**: Restrict who can read the `gitea-admin-secret`
|
||||
4. **Audit logs**: Monitor access to the admin secret
|
||||
|
||||
## Manual Override
|
||||
|
||||
If you need to use different credentials for specific components, you can override the values:
|
||||
|
||||
```bash
|
||||
helm install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||
--namespace tekton-pipelines \
|
||||
--set secrets.webhook.token="your-webhook-token" \
|
||||
--set secrets.registry.password="custom-registry-password" \
|
||||
--set secrets.git.password="custom-git-password"
|
||||
```
|
||||
|
||||
However, this is **not recommended** as it breaks the single source of truth principle.
|
||||
|
||||
## Helm Template Details
|
||||
|
||||
The integration uses Helm's `lookup` function with `b64dec` to decode the base64-encoded password:
|
||||
|
||||
```yaml
|
||||
password: {{ .Values.secrets.git.password | default (lookup "v1" "Secret" "gitea" "gitea-admin-secret").data.password | b64dec | quote }}
|
||||
```
|
||||
|
||||
This means:
|
||||
1. Look up the `gitea-admin-secret` in the `gitea` namespace
|
||||
2. Get the `password` field from the secret's `data` section
|
||||
3. Base64 decode it (Kubernetes stores secret data as base64)
|
||||
4. Use it as the password value
|
||||
5. If `.Values.secrets.git.password` is provided, use that instead (for manual override)
|
||||
|
||||
## Conclusion
|
||||
|
||||
This integration provides a robust, secure way to manage credentials across the CI/CD pipeline while maintaining consistency with Gitea's admin credentials.
|
||||
83
infrastructure/cicd/tekton-helm/README.md
Normal file
83
infrastructure/cicd/tekton-helm/README.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Tekton CI/CD Helm Chart
|
||||
|
||||
This Helm chart deploys the Tekton CI/CD infrastructure for the Bakery-IA project.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.20+
|
||||
- Tekton Pipelines installed (v0.57.0 or later)
|
||||
- Helm 3.0+
|
||||
|
||||
## Installation
|
||||
|
||||
Before installing this chart, Tekton Pipelines must be installed separately:
|
||||
|
||||
```bash
|
||||
kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
|
||||
```
|
||||
|
||||
Then install the chart:
|
||||
|
||||
### Development Installation
|
||||
|
||||
```bash
|
||||
helm install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||
--namespace tekton-pipelines \
|
||||
--create-namespace
|
||||
```
|
||||
|
||||
### Production Installation
|
||||
|
||||
**Important**: Never use default secrets in production. Always provide secure credentials.
|
||||
|
||||
```bash
|
||||
# Generate secure webhook token
|
||||
export TEKTON_WEBHOOK_TOKEN=$(openssl rand -hex 32)
|
||||
|
||||
# Use the same password as Gitea admin (from GITEA_ADMIN_PASSWORD)
|
||||
helm upgrade --install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||
-n tekton-pipelines \
|
||||
-f infrastructure/cicd/tekton-helm/values.yaml \
|
||||
-f infrastructure/cicd/tekton-helm/values-prod.yaml \
|
||||
--set secrets.webhook.token=$TEKTON_WEBHOOK_TOKEN \
|
||||
--set secrets.registry.password=$GITEA_ADMIN_PASSWORD \
|
||||
--set secrets.git.password=$GITEA_ADMIN_PASSWORD
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The following table lists the configurable parameters of the tekton-cicd chart and their default values.
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `global.registry.url` | Container registry URL | `"gitea.bakery-ia.local:5000"` |
|
||||
| `global.git.branch` | Git branch name | `"main"` |
|
||||
| `global.git.userName` | Git user name | `"bakery-ia-ci"` |
|
||||
| `global.git.userEmail` | Git user email | `"ci@bakery-ia.local"` |
|
||||
| `pipeline.build.cacheTTL` | Build cache TTL | `"24h"` |
|
||||
| `pipeline.build.verbosity` | Build verbosity level | `"info"` |
|
||||
| `pipeline.test.skipTests` | Skip tests flag | `"false"` |
|
||||
| `pipeline.test.skipLint` | Skip lint flag | `"false"` |
|
||||
| `pipeline.deployment.namespace` | Deployment namespace | `"bakery-ia"` |
|
||||
| `pipeline.deployment.fluxNamespace` | Flux namespace | `"flux-system"` |
|
||||
| `pipeline.workspace.size` | Workspace size | `"5Gi"` |
|
||||
| `pipeline.workspace.storageClass` | Workspace storage class | `"standard"` |
|
||||
| `secrets.webhook.token` | Webhook validation token | `"example-webhook-token-do-not-use-in-production"` |
|
||||
| `secrets.registry.username` | Registry username | `"example-user"` |
|
||||
| `secrets.registry.password` | Registry password | `"example-password"` |
|
||||
| `secrets.registry.registryUrl` | Registry URL | `"gitea.bakery-ia.local:5000"` |
|
||||
| `secrets.git.username` | Git username | `"example-user"` |
|
||||
| `secrets.git.password` | Git password | `"example-password"` |
|
||||
| `namespace` | Namespace for Tekton resources | `"tekton-pipelines"` |
|
||||
|
||||
## Uninstallation
|
||||
|
||||
To uninstall/delete the `tekton-cicd` release:
|
||||
|
||||
```bash
|
||||
helm delete tekton-cicd --namespace tekton-pipelines
|
||||
```
|
||||
|
||||
## Values
|
||||
|
||||
For a detailed list of configurable values, see the `values.yaml` file.
|
||||
22
infrastructure/cicd/tekton-helm/templates/NOTES.txt
Normal file
22
infrastructure/cicd/tekton-helm/templates/NOTES.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
Thank you for installing {{ .Chart.Name }}.
|
||||
|
||||
This chart deploys the Tekton CI/CD infrastructure for Bakery-IA.
|
||||
|
||||
IMPORTANT: Tekton Pipelines must be installed separately before deploying this chart.
|
||||
|
||||
To install Tekton Pipelines, run:
|
||||
kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
|
||||
|
||||
To verify Tekton is running:
|
||||
kubectl get pods -n tekton-pipelines
|
||||
|
||||
After Tekton is installed, this chart will deploy:
|
||||
- ConfigMaps with pipeline configuration
|
||||
- RBAC resources for triggers and pipelines
|
||||
- Secrets for registry and Git credentials
|
||||
- Tasks, Pipelines, and Triggers for CI/CD
|
||||
|
||||
To check the status of deployed resources:
|
||||
kubectl get all -n {{ .Release.Namespace }}
|
||||
|
||||
For more information about Tekton, visit: https://tekton.dev/
|
||||
80
infrastructure/cicd/tekton-helm/templates/clusterroles.yaml
Normal file
80
infrastructure/cicd/tekton-helm/templates/clusterroles.yaml
Normal file
@@ -0,0 +1,80 @@
|
||||
# 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: {{ .Values.labels.app.name }}
|
||||
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"]
|
||||
# Ability to list cluster-scoped trigger resources (needed for Tekton Triggers controller)
|
||||
- apiGroups: ["triggers.tekton.dev"]
|
||||
resources: ["clustertriggerbindings", "clusterinterceptors"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
# 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: {{ .Values.labels.app.name }}
|
||||
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"]
|
||||
---
|
||||
# Role for EventListener to access triggers resources
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: tekton-triggers-eventlistener-role
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
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"]
|
||||
32
infrastructure/cicd/tekton-helm/templates/configmap.yaml
Normal file
32
infrastructure/cicd/tekton-helm/templates/configmap.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: pipeline-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: config
|
||||
data:
|
||||
# Container Registry Configuration
|
||||
REGISTRY_URL: "{{ .Values.global.registry.url }}"
|
||||
|
||||
# Git Configuration
|
||||
GIT_BRANCH: "{{ .Values.global.git.branch }}"
|
||||
GIT_USER_NAME: "{{ .Values.global.git.userName }}"
|
||||
GIT_USER_EMAIL: "{{ .Values.global.git.userEmail }}"
|
||||
|
||||
# Build Configuration
|
||||
BUILD_CACHE_TTL: "{{ .Values.pipeline.build.cacheTTL }}"
|
||||
BUILD_VERBOSITY: "{{ .Values.pipeline.build.verbosity }}"
|
||||
|
||||
# Test Configuration
|
||||
SKIP_TESTS: "{{ .Values.pipeline.test.skipTests }}"
|
||||
SKIP_LINT: "{{ .Values.pipeline.test.skipLint }}"
|
||||
|
||||
# Deployment Configuration
|
||||
DEPLOY_NAMESPACE: "{{ .Values.pipeline.deployment.namespace }}"
|
||||
FLUX_NAMESPACE: "{{ .Values.pipeline.deployment.fluxNamespace }}"
|
||||
|
||||
# Workspace Configuration
|
||||
WORKSPACE_SIZE: "{{ .Values.pipeline.workspace.size }}"
|
||||
WORKSPACE_STORAGE_CLASS: "{{ .Values.pipeline.workspace.storageClass }}"
|
||||
@@ -0,0 +1,32 @@
|
||||
# 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-event-listener
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: triggers
|
||||
spec:
|
||||
serviceAccountName: {{ .Values.serviceAccounts.triggers.name }}
|
||||
triggers:
|
||||
- name: bakery-ia-gitea-trigger
|
||||
interceptors:
|
||||
- ref:
|
||||
name: "cel"
|
||||
params:
|
||||
- name: "filter"
|
||||
value: "has(body.repository) && body.ref.contains('main')"
|
||||
- ref:
|
||||
name: "bitbucket"
|
||||
params:
|
||||
- name: "secretRef"
|
||||
value:
|
||||
secretName: gitea-webhook-secret
|
||||
secretKey: secretToken
|
||||
bindings:
|
||||
- ref: bakery-ia-trigger-binding
|
||||
template:
|
||||
ref: bakery-ia-trigger-template
|
||||
9
infrastructure/cicd/tekton-helm/templates/namespace.yaml
Normal file
9
infrastructure/cicd/tekton-helm/templates/namespace.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
{{- if .Values.namespace }}
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: {{ .Values.namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: {{ .Values.labels.app.component }}
|
||||
{{- end }}
|
||||
164
infrastructure/cicd/tekton-helm/templates/pipeline-ci.yaml
Normal file
164
infrastructure/cicd/tekton-helm/templates/pipeline-ci.yaml
Normal file
@@ -0,0 +1,164 @@
|
||||
# Main CI Pipeline for Bakery-IA
|
||||
# This pipeline orchestrates the build, test, and deploy process
|
||||
# Includes: fetch -> detect changes -> test -> build -> update gitops
|
||||
# Supports environment-configurable base images for dev/prod flexibility
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Pipeline
|
||||
metadata:
|
||||
name: bakery-ia-ci
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
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 for pushing built images
|
||||
- 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"
|
||||
# Base image configuration for environment-specific builds
|
||||
- name: base-registry
|
||||
type: string
|
||||
description: "Base image registry URL (e.g., docker.io for prod, localhost:5000 for dev)"
|
||||
default: "{{ .Values.pipeline.build.baseRegistry }}"
|
||||
- name: python-image
|
||||
type: string
|
||||
description: "Python base image name and tag (e.g., python:3.11-slim for prod)"
|
||||
default: "{{ .Values.pipeline.build.pythonImage }}"
|
||||
|
||||
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)
|
||||
# Environment-configurable base images
|
||||
- name: base-registry
|
||||
value: $(params.base-registry)
|
||||
- name: python-image
|
||||
value: $(params.python-image)
|
||||
|
||||
# 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)
|
||||
51
infrastructure/cicd/tekton-helm/templates/rolebindings.yaml
Normal file
51
infrastructure/cicd/tekton-helm/templates/rolebindings.yaml
Normal file
@@ -0,0 +1,51 @@
|
||||
# ClusterRoleBinding for Tekton Triggers
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: tekton-triggers-binding
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: triggers
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ .Values.serviceAccounts.triggers.name }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: tekton-triggers-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
# ClusterRoleBinding for Pipeline execution
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: tekton-pipeline-binding
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: pipeline
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ .Values.serviceAccounts.pipeline.name }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: tekton-pipeline-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
---
|
||||
# RoleBinding for EventListener
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: tekton-triggers-eventlistener-binding
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: triggers
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ .Values.serviceAccounts.triggers.name }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: tekton-triggers-eventlistener-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
87
infrastructure/cicd/tekton-helm/templates/secrets.yaml
Normal file
87
infrastructure/cicd/tekton-helm/templates/secrets.yaml
Normal file
@@ -0,0 +1,87 @@
|
||||
# Secret for Gitea webhook validation
|
||||
# Used by EventListener to validate incoming webhooks
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-webhook-secret
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: triggers
|
||||
annotations:
|
||||
note: "Webhook secret for validating incoming webhooks"
|
||||
type: Opaque
|
||||
stringData:
|
||||
secretToken: {{ .Values.secrets.webhook.token | quote }}
|
||||
---
|
||||
# Secret for Gitea container registry credentials
|
||||
# Used by Kaniko to push images to Gitea registry
|
||||
# References the existing gitea-admin-secret for consistency
|
||||
{{- $giteaSecret := (lookup "v1" "Secret" "gitea" "gitea-admin-secret") }}
|
||||
{{- $giteaPassword := "" }}
|
||||
{{- if and $giteaSecret $giteaSecret.data (index $giteaSecret.data "password") }}
|
||||
{{- $giteaPassword = index $giteaSecret.data "password" | b64dec }}
|
||||
{{- end }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-registry-credentials
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: build
|
||||
annotations:
|
||||
note: "Registry credentials for pushing images - references gitea-admin-secret"
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
stringData:
|
||||
{{- $registryPassword := .Values.secrets.registry.password | default $giteaPassword | default "PLACEHOLDER_PASSWORD" }}
|
||||
{{- if and .Values.secrets.registry.registryUrl .Values.secrets.registry.username }}
|
||||
.dockerconfigjson: |
|
||||
{
|
||||
"auths": {
|
||||
{{ .Values.secrets.registry.registryUrl | quote }}: {
|
||||
"username": {{ .Values.secrets.registry.username | quote }},
|
||||
"password": {{ $registryPassword | quote }}
|
||||
}
|
||||
}
|
||||
}
|
||||
{{- else }}
|
||||
.dockerconfigjson: '{"auths":{}}'
|
||||
{{- end }}
|
||||
---
|
||||
# Secret for Git credentials (used by pipeline to push GitOps updates)
|
||||
# References the existing gitea-admin-secret for consistency
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-git-credentials
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: gitops
|
||||
annotations:
|
||||
note: "Git credentials for GitOps updates - references gitea-admin-secret"
|
||||
type: Opaque
|
||||
stringData:
|
||||
{{- $gitPassword := .Values.secrets.git.password | default $giteaPassword | default "PLACEHOLDER_PASSWORD" }}
|
||||
username: {{ .Values.secrets.git.username | quote }}
|
||||
password: {{ $gitPassword | quote }}
|
||||
---
|
||||
# Secret for Flux GitRepository access
|
||||
# Used by Flux to pull from Gitea repository
|
||||
# References the existing gitea-admin-secret for consistency
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-credentials
|
||||
namespace: {{ .Values.pipeline.deployment.fluxNamespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: flux
|
||||
annotations:
|
||||
note: "Credentials for Flux GitRepository access - references gitea-admin-secret"
|
||||
type: Opaque
|
||||
stringData:
|
||||
{{- $fluxPassword := .Values.secrets.git.password | default $giteaPassword | default "PLACEHOLDER_PASSWORD" }}
|
||||
username: {{ .Values.secrets.git.username | quote }}
|
||||
password: {{ $fluxPassword | quote }}
|
||||
@@ -0,0 +1,19 @@
|
||||
# ServiceAccount for Tekton Triggers EventListener
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ .Values.serviceAccounts.triggers.name }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: triggers
|
||||
---
|
||||
# ServiceAccount for Pipeline execution
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ .Values.serviceAccounts.pipeline.name }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: pipeline
|
||||
@@ -0,0 +1,87 @@
|
||||
# Tekton Task to Detect Changed Services
|
||||
# This task analyzes git changes to determine which services need to be built
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: detect-changed-services
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: detection
|
||||
spec:
|
||||
workspaces:
|
||||
- name: source
|
||||
description: Workspace containing the source code
|
||||
results:
|
||||
- name: changed-services
|
||||
description: Comma-separated list of changed services
|
||||
steps:
|
||||
- name: detect-changes
|
||||
image: alpine/git
|
||||
script: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd $(workspaces.source.path)
|
||||
|
||||
# Get the list of changed files
|
||||
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git diff --name-only $(git rev-parse --abbrev-ref HEAD)@{upstream} HEAD 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$CHANGED_FILES" ]; then
|
||||
# No changes detected, assume all services need building
|
||||
echo "No git changes detected, building all services"
|
||||
echo "all" > $(results.changed-services.path)
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Initialize an array to collect changed services
|
||||
declare -a changed_services=()
|
||||
|
||||
# Check for changes in services/ directory
|
||||
while IFS= read -r service_dir; do
|
||||
if [ -n "$service_dir" ]; then
|
||||
service_name=$(basename "$service_dir")
|
||||
if [[ ! " ${changed_services[@]} " =~ " ${service_name} " ]]; then
|
||||
changed_services+=("$service_name")
|
||||
fi
|
||||
fi
|
||||
done < <(echo "$CHANGED_FILES" | grep '^services/' | cut -d'/' -f2 | sort -u)
|
||||
|
||||
# Check for changes in gateway/ directory
|
||||
if echo "$CHANGED_FILES" | grep -q '^gateway/'; then
|
||||
if [[ ! " ${changed_services[@]} " =~ " gateway " ]]; then
|
||||
changed_services+=("gateway")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for changes in frontend/ directory
|
||||
if echo "$CHANGED_FILES" | grep -q '^frontend/'; then
|
||||
if [[ ! " ${changed_services[@]} " =~ " frontend " ]]; then
|
||||
changed_services+=("frontend")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for changes in shared/ directory (might affect multiple services)
|
||||
if echo "$CHANGED_FILES" | grep -q '^shared/'; then
|
||||
if [[ ! " ${changed_services[@]} " =~ " shared " ]]; then
|
||||
changed_services+=("shared")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Convert array to comma-separated string
|
||||
CHANGED_SERVICES=""
|
||||
for service in "${changed_services[@]}"; do
|
||||
if [ -z "$CHANGED_SERVICES" ]; then
|
||||
CHANGED_SERVICES="$service"
|
||||
else
|
||||
CHANGED_SERVICES="$CHANGED_SERVICES,$service"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$CHANGED_SERVICES" ]; then
|
||||
# Changes are in infrastructure or other non-service files
|
||||
echo "infrastructure" > $(results.changed-services.path)
|
||||
else
|
||||
echo "$CHANGED_SERVICES" > $(results.changed-services.path)
|
||||
fi
|
||||
@@ -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: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
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
|
||||
103
infrastructure/cicd/tekton-helm/templates/task-kaniko-build.yaml
Normal file
103
infrastructure/cicd/tekton-helm/templates/task-kaniko-build.yaml
Normal file
@@ -0,0 +1,103 @@
|
||||
# Tekton Kaniko Build Task for Bakery-IA CI/CD
|
||||
# This task builds and pushes container images using Kaniko
|
||||
# Supports environment-configurable base images via build-args
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: kaniko-build
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: build
|
||||
spec:
|
||||
workspaces:
|
||||
- name: source
|
||||
description: Workspace containing the source code
|
||||
- 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 for pushing built images
|
||||
- name: git-revision
|
||||
type: string
|
||||
description: Git revision to tag images with
|
||||
- name: base-registry
|
||||
type: string
|
||||
description: Base image registry URL (e.g., docker.io, ghcr.io/org)
|
||||
default: "gitea-http.gitea.svc.cluster.local:3000/bakery-admin"
|
||||
- name: python-image
|
||||
type: string
|
||||
description: Python base image name and tag
|
||||
default: "python_3.11-slim"
|
||||
results:
|
||||
- name: build-status
|
||||
description: Status of the build operation
|
||||
steps:
|
||||
- name: build-and-push
|
||||
image: gcr.io/kaniko-project/executor:v1.15.0
|
||||
env:
|
||||
- name: DOCKER_CONFIG
|
||||
value: /tekton/home/.docker
|
||||
script: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "==================================================================="
|
||||
echo "Kaniko Build Configuration"
|
||||
echo "==================================================================="
|
||||
echo "Target Registry: $(params.registry)"
|
||||
echo "Base Registry: $(params.base-registry)"
|
||||
echo "Python Image: $(params.python-image)"
|
||||
echo "Git Revision: $(params.git-revision)"
|
||||
echo "==================================================================="
|
||||
|
||||
# Split services parameter by comma
|
||||
IFS=',' read -ra SERVICES <<< "$(params.services)"
|
||||
|
||||
# Build each service
|
||||
for service in "${SERVICES[@]}"; do
|
||||
service=$(echo "$service" | xargs) # Trim whitespace
|
||||
if [ -n "$service" ] && [ "$service" != "none" ]; then
|
||||
echo ""
|
||||
echo "Building service: $service"
|
||||
echo "-------------------------------------------------------------------"
|
||||
|
||||
# Determine Dockerfile path (services vs gateway vs frontend)
|
||||
if [ "$service" = "gateway" ]; then
|
||||
DOCKERFILE_PATH="$(workspaces.source.path)/gateway/Dockerfile"
|
||||
elif [ "$service" = "frontend" ]; then
|
||||
DOCKERFILE_PATH="$(workspaces.source.path)/frontend/Dockerfile.kubernetes"
|
||||
else
|
||||
DOCKERFILE_PATH="$(workspaces.source.path)/services/$service/Dockerfile"
|
||||
fi
|
||||
|
||||
/kaniko/executor \
|
||||
--dockerfile="$DOCKERFILE_PATH" \
|
||||
--destination="$(params.registry)/$service:$(params.git-revision)" \
|
||||
--context="$(workspaces.source.path)" \
|
||||
--build-arg="BASE_REGISTRY=$(params.base-registry)" \
|
||||
--build-arg="PYTHON_IMAGE=$(params.python-image)" \
|
||||
--cache=true \
|
||||
--cache-repo="$(params.registry)/cache"
|
||||
|
||||
echo "Successfully built: $(params.registry)/$service:$(params.git-revision)"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "==================================================================="
|
||||
echo "Build completed successfully!"
|
||||
echo "==================================================================="
|
||||
echo "success" > $(results.build-status.path)
|
||||
resources:
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
@@ -0,0 +1,33 @@
|
||||
# Tekton Task for Pipeline Summary
|
||||
# This task generates a summary of the pipeline execution
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: pipeline-summary
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: summary
|
||||
spec:
|
||||
params:
|
||||
- name: changed-services
|
||||
type: string
|
||||
description: Services that were changed
|
||||
- name: git-revision
|
||||
type: string
|
||||
description: Git revision being processed
|
||||
steps:
|
||||
- name: generate-summary
|
||||
image: alpine
|
||||
script: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "=== Bakery-IA CI Pipeline Summary ==="
|
||||
echo "Git Revision: $(params.git-revision)"
|
||||
echo "Changed Services: $(params.changed-services)"
|
||||
echo "Pipeline completed successfully"
|
||||
|
||||
# Log summary to stdout for visibility
|
||||
echo "Summary generated"
|
||||
@@ -0,0 +1,86 @@
|
||||
# Tekton Run Tests Task for Bakery-IA CI/CD
|
||||
# This task runs tests on the source code
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: run-tests
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: test
|
||||
spec:
|
||||
workspaces:
|
||||
- name: source
|
||||
description: Workspace containing the source code
|
||||
params:
|
||||
- name: services
|
||||
type: string
|
||||
description: Comma-separated list of services to test
|
||||
- name: skip-tests
|
||||
type: string
|
||||
description: Skip tests if "true"
|
||||
default: "false"
|
||||
steps:
|
||||
- name: run-unit-tests
|
||||
image: gitea-http.gitea.svc.cluster.local:3000/bakery-admin/python_3.11-slim:latest
|
||||
workingDir: $(workspaces.source.path)
|
||||
script: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "============================================"
|
||||
echo "Running Unit Tests"
|
||||
echo "Services: $(params.services)"
|
||||
echo "Skip tests: $(params.skip-tests)"
|
||||
echo "============================================"
|
||||
|
||||
if [ "$(params.skip-tests)" = "true" ]; then
|
||||
echo "Skipping tests as requested"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Install dependencies if requirements file exists
|
||||
if [ -f "requirements.txt" ]; then
|
||||
pip install --no-cache-dir -r requirements.txt
|
||||
fi
|
||||
|
||||
# Run unit tests
|
||||
python -m pytest tests/unit/ -v
|
||||
|
||||
echo "Unit tests completed successfully"
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 2Gi
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
- name: run-integration-tests
|
||||
image: gitea-http.gitea.svc.cluster.local:3000/bakery-admin/python_3.11-slim:latest
|
||||
workingDir: $(workspaces.source.path)
|
||||
script: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "============================================"
|
||||
echo "Running Integration Tests"
|
||||
echo "Services: $(params.services)"
|
||||
echo "============================================"
|
||||
|
||||
if [ "$(params.skip-tests)" = "true" ]; then
|
||||
echo "Skipping integration tests as requested"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Run integration tests
|
||||
python -m pytest tests/integration/ -v
|
||||
|
||||
echo "Integration tests completed successfully"
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 2Gi
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
@@ -0,0 +1,153 @@
|
||||
# Tekton Update GitOps Task for Bakery-IA CI/CD
|
||||
# This task updates GitOps manifests with new image tags
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: update-gitops
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: gitops
|
||||
spec:
|
||||
workspaces:
|
||||
- name: source
|
||||
description: Workspace containing the source code
|
||||
- name: git-credentials
|
||||
description: Git credentials for pushing changes
|
||||
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 to tag images with
|
||||
- name: git-branch
|
||||
type: string
|
||||
description: Git branch to push changes to
|
||||
- name: dry-run
|
||||
type: string
|
||||
description: Dry run mode - don't push changes
|
||||
default: "false"
|
||||
steps:
|
||||
- name: update-manifests
|
||||
image: alpine/git:2.43.0
|
||||
workingDir: $(workspaces.source.path)
|
||||
env:
|
||||
- name: GIT_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-git-credentials
|
||||
key: username
|
||||
- name: GIT_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-git-credentials
|
||||
key: password
|
||||
script: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "============================================"
|
||||
echo "Updating GitOps Manifests"
|
||||
echo "Services: $(params.services)"
|
||||
echo "Registry: $(params.registry)"
|
||||
echo "Revision: $(params.git-revision)"
|
||||
echo "Branch: $(params.git-branch)"
|
||||
echo "Dry run: $(params.dry-run)"
|
||||
echo "============================================"
|
||||
|
||||
# Configure git
|
||||
git config --global user.email "ci@bakery-ia.local"
|
||||
git config --global user.name "bakery-ia-ci"
|
||||
|
||||
# Clone the main repository (not a separate gitops repo)
|
||||
# Use internal cluster DNS which works in all environments
|
||||
REPO_URL="https://${GIT_USERNAME}:${GIT_PASSWORD}@gitea-http.gitea.svc.cluster.local:3000/bakery-admin/bakery-ia.git"
|
||||
git clone "$REPO_URL" /tmp/gitops
|
||||
|
||||
cd /tmp/gitops
|
||||
|
||||
# Switch to target branch
|
||||
git checkout "$(params.git-branch)" || git checkout -b "$(params.git-branch)"
|
||||
|
||||
# Update image tags in Kubernetes manifests
|
||||
for service in $(echo "$(params.services)" | tr ',' '\n'); do
|
||||
service=$(echo "$service" | xargs) # Trim whitespace
|
||||
if [ -n "$service" ] && [ "$service" != "none" ] && [ "$service" != "infrastructure" ] && [ "$service" != "shared" ]; then
|
||||
echo "Updating manifest for service: $service"
|
||||
|
||||
# Format service name for directory (convert from kebab-case to snake_case if needed)
|
||||
# Handle special cases like demo-session -> demo_session, alert-processor -> alert_processor, etc.
|
||||
formatted_service=$(echo "$service" | sed 's/-/_/g')
|
||||
|
||||
# For gateway and frontend, they have different directory structures
|
||||
if [ "$service" = "gateway" ]; then
|
||||
MANIFEST_PATH="infrastructure/platform/gateway/gateway-service.yaml"
|
||||
IMAGE_NAME="gateway" # gateway image name is just "gateway"
|
||||
elif [ "$service" = "frontend" ]; then
|
||||
MANIFEST_PATH="infrastructure/services/microservices/frontend/frontend-service.yaml"
|
||||
IMAGE_NAME="dashboard" # frontend service uses "dashboard" as image name
|
||||
else
|
||||
# For microservices, look in the microservices directory
|
||||
# Convert service name to directory format (kebab-case)
|
||||
service_dir=$(echo "$service" | sed 's/_/-/g')
|
||||
|
||||
# Check for different possible manifest file names
|
||||
if [ -f "infrastructure/services/microservices/$service_dir/deployment.yaml" ]; then
|
||||
MANIFEST_PATH="infrastructure/services/microservices/$service_dir/deployment.yaml"
|
||||
elif [ -f "infrastructure/services/microservices/$service_dir/${formatted_service}-service.yaml" ]; then
|
||||
MANIFEST_PATH="infrastructure/services/microservices/$service_dir/${formatted_service}-service.yaml"
|
||||
elif [ -f "infrastructure/services/microservices/$service_dir/${service_dir}-service.yaml" ]; then
|
||||
MANIFEST_PATH="infrastructure/services/microservices/$service_dir/${service_dir}-service.yaml"
|
||||
else
|
||||
# Default to the standard naming pattern
|
||||
MANIFEST_PATH="infrastructure/services/microservices/$service_dir/${formatted_service}-service.yaml"
|
||||
fi
|
||||
|
||||
# For most services, the image name follows the pattern service-name-service
|
||||
IMAGE_NAME="${service_dir}-service"
|
||||
fi
|
||||
|
||||
# Update the image tag in the deployment YAML
|
||||
if [ -f "$MANIFEST_PATH" ]; then
|
||||
# Update image reference from bakery/image_name:tag to registry/image_name:git_revision
|
||||
# Handle various image name formats that might exist in the manifests
|
||||
sed -i "s|image: bakery/${IMAGE_NAME}:.*|image: $(params.registry)/${IMAGE_NAME}:$(params.git-revision)|g" "$MANIFEST_PATH"
|
||||
# Also handle the case where the image name might be formatted differently
|
||||
sed -i "s|image: bakery/${service}:.*|image: $(params.registry)/${service}:$(params.git-revision)|g" "$MANIFEST_PATH"
|
||||
sed -i "s|image: bakery/${formatted_service}:.*|image: $(params.registry)/${formatted_service}:$(params.git-revision)|g" "$MANIFEST_PATH"
|
||||
|
||||
echo "Updated image in: $MANIFEST_PATH for image: bakery/${IMAGE_NAME}:* -> $(params.registry)/${IMAGE_NAME}:$(params.git-revision)"
|
||||
else
|
||||
echo "Warning: Manifest file not found: $MANIFEST_PATH"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Commit and push changes (unless dry-run)
|
||||
if [ "$(params.dry-run)" != "true" ]; then
|
||||
git add .
|
||||
git status
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "Update images for services: $(params.services) [skip ci]"
|
||||
git push origin "$(params.git-branch)"
|
||||
echo "GitOps manifests updated successfully"
|
||||
else
|
||||
echo "No changes to commit"
|
||||
fi
|
||||
else
|
||||
echo "Dry run mode - changes not pushed"
|
||||
git status
|
||||
git diff
|
||||
fi
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
@@ -0,0 +1,23 @@
|
||||
# Tekton TriggerBinding for Bakery-IA CI/CD
|
||||
# This binding extracts parameters from incoming webhook payloads
|
||||
|
||||
apiVersion: triggers.tekton.dev/v1beta1
|
||||
kind: TriggerBinding
|
||||
metadata:
|
||||
name: bakery-ia-trigger-binding
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: triggers
|
||||
spec:
|
||||
params:
|
||||
- name: git-repo-url
|
||||
value: "{{"{{ .payload.repository.clone_url }}"}}"
|
||||
- name: git-revision
|
||||
value: "{{"{{ .payload.after }}"}}"
|
||||
- name: git-branch
|
||||
value: "{{"{{ .payload.ref }}" | replace "refs/heads/" "" | replace "refs/tags/" "" }}"
|
||||
- name: git-repo-name
|
||||
value: "{{"{{ .payload.repository.name }}"}}"
|
||||
- name: git-repo-full-name
|
||||
value: "{{"{{ .payload.repository.full_name }}"}}"
|
||||
@@ -0,0 +1,79 @@
|
||||
# Tekton TriggerTemplate for Bakery-IA CI/CD
|
||||
# This template defines how PipelineRuns are created when triggers fire
|
||||
|
||||
apiVersion: triggers.tekton.dev/v1beta1
|
||||
kind: TriggerTemplate
|
||||
metadata:
|
||||
name: bakery-ia-trigger-template
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
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-admin/bakery-ia"
|
||||
# Registry URL - keep in sync with pipeline-config ConfigMap
|
||||
- name: registry-url
|
||||
description: Container registry URL
|
||||
default: {{ .Values.global.registry.url | quote }}
|
||||
resourcetemplates:
|
||||
- apiVersion: tekton.dev/v1beta1
|
||||
kind: PipelineRun
|
||||
metadata:
|
||||
generateName: bakery-ia-ci-run-
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
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: {{ .Values.serviceAccounts.pipeline.name }}
|
||||
workspaces:
|
||||
- name: shared-workspace
|
||||
volumeClaimTemplate:
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.pipeline.workspace.size }}
|
||||
- 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"
|
||||
81
infrastructure/cicd/tekton-helm/values-prod.yaml
Normal file
81
infrastructure/cicd/tekton-helm/values-prod.yaml
Normal file
@@ -0,0 +1,81 @@
|
||||
# Production values for tekton-cicd Helm chart
|
||||
# This file overrides values.yaml for production deployment
|
||||
#
|
||||
# Installation:
|
||||
# helm upgrade --install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||
# -n tekton-pipelines \
|
||||
# -f infrastructure/cicd/tekton-helm/values.yaml \
|
||||
# -f infrastructure/cicd/tekton-helm/values-prod.yaml \
|
||||
# --set secrets.webhook.token=$TEKTON_WEBHOOK_TOKEN \
|
||||
# --set secrets.registry.password=$GITEA_ADMIN_PASSWORD \
|
||||
# --set secrets.git.password=$GITEA_ADMIN_PASSWORD
|
||||
#
|
||||
# Required environment variables:
|
||||
# TEKTON_WEBHOOK_TOKEN - Secure webhook token (generate with: openssl rand -hex 32)
|
||||
# GITEA_ADMIN_PASSWORD - Gitea admin password (must match gitea-admin-secret)
|
||||
|
||||
# Global settings for production
|
||||
global:
|
||||
# Git configuration
|
||||
git:
|
||||
userEmail: "ci@bakewise.ai"
|
||||
|
||||
# Pipeline configuration for production
|
||||
pipeline:
|
||||
# Build configuration
|
||||
build:
|
||||
verbosity: "warn" # Less verbose in production
|
||||
|
||||
# Test configuration
|
||||
test:
|
||||
skipTests: "false"
|
||||
skipLint: "false"
|
||||
|
||||
# Workspace configuration - ensure storage class exists in production cluster
|
||||
workspace:
|
||||
size: "10Gi"
|
||||
storageClass: "standard" # Adjust to your production storage class
|
||||
|
||||
# Tekton controller settings - increased resources for production
|
||||
controller:
|
||||
replicas: 2
|
||||
resources:
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 2Gi
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
|
||||
# Tekton webhook settings - increased resources for production
|
||||
webhook:
|
||||
replicas: 2
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
|
||||
# Secrets configuration
|
||||
# IMPORTANT: These MUST be overridden via --set flags during deployment
|
||||
# DO NOT commit actual secrets to this file
|
||||
secrets:
|
||||
# Webhook secret for validating incoming webhooks
|
||||
# Override with: --set secrets.webhook.token=$TEKTON_WEBHOOK_TOKEN
|
||||
webhook:
|
||||
token: "" # MUST be set via --set flag
|
||||
|
||||
# Registry credentials for pushing images
|
||||
# Override with: --set secrets.registry.password=$GITEA_ADMIN_PASSWORD
|
||||
registry:
|
||||
username: "bakery-admin"
|
||||
password: "" # MUST be set via --set flag
|
||||
registryUrl: "gitea-http.gitea.svc.cluster.local:3000"
|
||||
|
||||
# Git credentials for GitOps updates
|
||||
# Override with: --set secrets.git.password=$GITEA_ADMIN_PASSWORD
|
||||
git:
|
||||
username: "bakery-admin"
|
||||
password: "" # MUST be set via --set flag
|
||||
99
infrastructure/cicd/tekton-helm/values.yaml
Normal file
99
infrastructure/cicd/tekton-helm/values.yaml
Normal file
@@ -0,0 +1,99 @@
|
||||
# Default values for tekton-cicd Helm chart
|
||||
# This file contains configurable values for the CI/CD pipeline
|
||||
|
||||
# Global settings
|
||||
global:
|
||||
# Registry configuration
|
||||
registry:
|
||||
url: "gitea-http.gitea.svc.cluster.local:3000/bakery-admin"
|
||||
|
||||
# Git configuration
|
||||
git:
|
||||
branch: "main"
|
||||
userName: "bakery-ia-ci"
|
||||
userEmail: "ci@bakery-ia.local"
|
||||
|
||||
# Pipeline configuration
|
||||
pipeline:
|
||||
# Build configuration
|
||||
build:
|
||||
cacheTTL: "24h"
|
||||
verbosity: "info"
|
||||
# Base image registry configuration
|
||||
# For dev: localhost:5000 with python_3.11-slim
|
||||
# For prod: gitea registry with python_3.11-slim
|
||||
baseRegistry: "gitea-http.gitea.svc.cluster.local:3000/bakery-admin"
|
||||
pythonImage: "python_3.11-slim"
|
||||
|
||||
# Test configuration
|
||||
test:
|
||||
skipTests: "false"
|
||||
skipLint: "false"
|
||||
|
||||
# Deployment configuration
|
||||
deployment:
|
||||
namespace: "bakery-ia"
|
||||
fluxNamespace: "flux-system"
|
||||
|
||||
# Workspace configuration
|
||||
workspace:
|
||||
size: "5Gi"
|
||||
storageClass: "standard"
|
||||
|
||||
# Tekton controller settings
|
||||
controller:
|
||||
replicas: 1
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
|
||||
# Tekton webhook settings
|
||||
webhook:
|
||||
replicas: 1
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
|
||||
# Namespace for Tekton resources
|
||||
# Set to empty/false to skip namespace creation (namespace is created by Tekton installation)
|
||||
namespace: ""
|
||||
|
||||
# Secrets configuration
|
||||
secrets:
|
||||
# Webhook secret for validating incoming webhooks
|
||||
webhook:
|
||||
token: "secure-webhook-token-replace-with-actual-value"
|
||||
|
||||
# Registry credentials for pushing images
|
||||
# Uses the same credentials as Gitea admin for consistency
|
||||
registry:
|
||||
username: "bakery-admin"
|
||||
password: "" # Will be populated from gitea-admin-secret
|
||||
registryUrl: "gitea-http.gitea.svc.cluster.local:3000"
|
||||
|
||||
# Git credentials for GitOps updates
|
||||
# Uses the same credentials as Gitea admin for consistency
|
||||
git:
|
||||
username: "bakery-admin"
|
||||
password: "" # Will be populated from gitea-admin-secret
|
||||
|
||||
# Service accounts
|
||||
serviceAccounts:
|
||||
triggers:
|
||||
name: "tekton-triggers-sa"
|
||||
pipeline:
|
||||
name: "tekton-pipeline-sa"
|
||||
|
||||
# Labels to apply to resources
|
||||
labels:
|
||||
app:
|
||||
name: "bakery-ia-cicd"
|
||||
component: "tekton"
|
||||
Reference in New Issue
Block a user