Add new infra architecture 3
This commit is contained in:
@@ -33,9 +33,14 @@ infrastructure/ci-cd/
|
||||
│ ├── trigger-binding.yaml
|
||||
│ ├── event-listener.yaml
|
||||
│ └── gitlab-interceptor.yaml
|
||||
├── flux/ # Flux CD GitOps configuration
|
||||
│ ├── git-repository.yaml # Git repository source
|
||||
│ └── kustomization.yaml # Deployment kustomization
|
||||
├── 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
|
||||
|
||||
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"
|
||||
@@ -1,16 +0,0 @@
|
||||
# Flux GitRepository for Bakery-IA
|
||||
# This resource tells Flux where to find the Git repository
|
||||
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: bakery-ia
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 1m
|
||||
url: http://gitea.bakery-ia.local/bakery/bakery-ia.git
|
||||
ref:
|
||||
branch: main
|
||||
secretRef:
|
||||
name: gitea-credentials
|
||||
timeout: 60s
|
||||
@@ -1,25 +0,0 @@
|
||||
# Kustomize build configuration for Flux resources
|
||||
# This file is used to build and apply the Flux resources
|
||||
#
|
||||
# IMPORTANT: Apply resources in this order:
|
||||
# 1. Install Flux CD first: flux install
|
||||
# 2. Apply this kustomization: kubectl apply -k infrastructure/cicd/flux/
|
||||
#
|
||||
# The GitRepository must be ready before the Flux Kustomization can reconcile.
|
||||
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
# Resources to apply in order (namespace and secrets first, then sources, then kustomizations)
|
||||
resources:
|
||||
- namespace.yaml
|
||||
- git-repository.yaml
|
||||
- flux-kustomization.yaml
|
||||
|
||||
# Common labels for all resources
|
||||
commonLabels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: flux
|
||||
app.kubernetes.io/managed-by: kustomize
|
||||
|
||||
# Note: Do NOT set namespace here as resources already have explicit namespaces
|
||||
@@ -1,15 +0,0 @@
|
||||
# Flux System Namespace
|
||||
# This namespace is required for Flux CD components
|
||||
# It should be created before any Flux resources are applied
|
||||
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: flux-system
|
||||
labels:
|
||||
app.kubernetes.io/name: flux
|
||||
app.kubernetes.io/component: system
|
||||
kubernetes.io/metadata.name: flux-system
|
||||
pod-security.kubernetes.io/enforce: restricted
|
||||
pod-security.kubernetes.io/audit: restricted
|
||||
pod-security.kubernetes.io/warn: restricted
|
||||
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 }}
|
||||
7
infrastructure/cicd/flux/templates/namespace.yaml
Normal file
7
infrastructure/cicd/flux/templates/namespace.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: {{ .Values.gitRepository.namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: flux
|
||||
kubernetes.io/metadata.name: {{ .Values.gitRepository.namespace }}
|
||||
@@ -1,22 +1,21 @@
|
||||
# Flux Kustomization for Bakery-IA Production Deployment
|
||||
# This resource tells Flux how to deploy the application
|
||||
#
|
||||
# Prerequisites:
|
||||
# 1. Flux CD must be installed: flux install
|
||||
# 2. GitRepository 'bakery-ia' must be created and ready
|
||||
# 3. Secret 'gitea-credentials' must exist in flux-system namespace
|
||||
# Default values for flux-cd
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
gitRepository:
|
||||
name: bakery-ia
|
||||
namespace: flux-system
|
||||
interval: 1m
|
||||
url: http://gitea.bakery-ia.local/bakery/bakery-ia.git
|
||||
ref:
|
||||
branch: main
|
||||
secretRef:
|
||||
name: gitea-credentials
|
||||
timeout: 60s
|
||||
|
||||
kustomization:
|
||||
name: bakery-ia-prod
|
||||
namespace: flux-system
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia
|
||||
app.kubernetes.io/component: flux
|
||||
spec:
|
||||
# Wait for GitRepository to be ready before reconciling
|
||||
dependsOn: []
|
||||
interval: 5m
|
||||
path: ./infrastructure/environments/prod
|
||||
prune: true
|
||||
@@ -27,7 +26,6 @@ spec:
|
||||
timeout: 10m
|
||||
retryInterval: 1m
|
||||
wait: true
|
||||
# Health checks for critical services
|
||||
healthChecks:
|
||||
# Core Infrastructure
|
||||
- apiVersion: apps/v1
|
||||
@@ -65,7 +63,6 @@ spec:
|
||||
kind: Deployment
|
||||
name: notification-service
|
||||
namespace: bakery-ia
|
||||
# Post-build variable substitution
|
||||
postBuild:
|
||||
substituteFrom:
|
||||
- kind: ConfigMap
|
||||
@@ -16,6 +16,9 @@ service:
|
||||
type: ClusterIP
|
||||
port: 2222
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 10Gi
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- tekton/
|
||||
- ../../namespaces/flux-system.yaml
|
||||
# Tekton is now managed via Helm, so we don't include it directly here
|
||||
# The Tekton Helm chart is deployed separately via Tilt
|
||||
|
||||
# Gitea is managed via Helm, so we don't include it directly here
|
||||
# The Gitea Helm chart is deployed separately and referenced in the ingress
|
||||
# Flux configuration is a Flux Kustomization resource, not a kustomize config
|
||||
# Flux is now managed via Helm chart located in this directory, so we don't include it directly here
|
||||
|
||||
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
|
||||
63
infrastructure/cicd/tekton-helm/README.md
Normal file
63
infrastructure/cicd/tekton-helm/README.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
helm repo add tekton-pipelines https://tekton.dev/charts
|
||||
helm repo update
|
||||
helm install tekton-cicd infrastructure/helm/tekton --namespace tekton-pipelines --create-namespace
|
||||
```
|
||||
|
||||
## 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 {{ .Values.namespace }}
|
||||
|
||||
For more information about Tekton, visit: https://tekton.dev/
|
||||
@@ -1,36 +1,10 @@
|
||||
# Tekton RBAC Configuration for Bakery-IA CI/CD
|
||||
# This file defines ServiceAccounts, Roles, and RoleBindings for Tekton
|
||||
|
||||
---
|
||||
# ServiceAccount for Tekton Triggers EventListener
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: tekton-triggers-sa
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: triggers
|
||||
|
||||
---
|
||||
# ServiceAccount for Pipeline execution
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: tekton-pipeline-sa
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: pipeline
|
||||
|
||||
---
|
||||
# ClusterRole for Tekton Triggers to create PipelineRuns
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: tekton-triggers-role
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: triggers
|
||||
rules:
|
||||
# Ability to create PipelineRuns from triggers
|
||||
@@ -57,25 +31,6 @@ rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["events"]
|
||||
verbs: ["create", "patch"]
|
||||
|
||||
---
|
||||
# ClusterRoleBinding for Tekton Triggers
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: tekton-triggers-binding
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: triggers
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: tekton-triggers-sa
|
||||
namespace: tekton-pipelines
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: tekton-triggers-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
---
|
||||
# ClusterRole for Pipeline execution (needed for git operations and deployments)
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
@@ -83,7 +38,7 @@ kind: ClusterRole
|
||||
metadata:
|
||||
name: tekton-pipeline-role
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: pipeline
|
||||
rules:
|
||||
# Ability to read/update deployments for GitOps
|
||||
@@ -102,34 +57,15 @@ rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods", "pods/log"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
|
||||
---
|
||||
# ClusterRoleBinding for Pipeline execution
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: tekton-pipeline-binding
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: pipeline
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: tekton-pipeline-sa
|
||||
namespace: tekton-pipelines
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: tekton-pipeline-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
---
|
||||
# Role for EventListener to access triggers resources
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: tekton-triggers-eventlistener-role
|
||||
namespace: tekton-pipelines
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: triggers
|
||||
rules:
|
||||
- apiGroups: ["triggers.tekton.dev"]
|
||||
@@ -137,23 +73,4 @@ rules:
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["configmaps", "secrets"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
|
||||
---
|
||||
# RoleBinding for EventListener
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: tekton-triggers-eventlistener-binding
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: triggers
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: tekton-triggers-sa
|
||||
namespace: tekton-pipelines
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: tekton-triggers-eventlistener-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
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: {{ .Values.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,33 @@
|
||||
# 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: {{ .Values.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
|
||||
replicas: 1
|
||||
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 }}
|
||||
@@ -6,9 +6,9 @@ apiVersion: tekton.dev/v1beta1
|
||||
kind: Pipeline
|
||||
metadata:
|
||||
name: bakery-ia-ci
|
||||
namespace: tekton-pipelines
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: pipeline
|
||||
spec:
|
||||
workspaces:
|
||||
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: {{ .Values.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: {{ .Values.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: {{ .Values.namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: triggers
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ .Values.serviceAccounts.triggers.name }}
|
||||
namespace: {{ .Values.namespace }}
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: tekton-triggers-eventlistener-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
72
infrastructure/cicd/tekton-helm/templates/secrets.yaml
Normal file
72
infrastructure/cicd/tekton-helm/templates/secrets.yaml
Normal file
@@ -0,0 +1,72 @@
|
||||
# Secret for Gitea webhook validation
|
||||
# Used by EventListener to validate incoming webhooks
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-webhook-secret
|
||||
namespace: {{ .Values.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
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-registry-credentials
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: build
|
||||
annotations:
|
||||
note: "Registry credentials for pushing images"
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
stringData:
|
||||
.dockerconfigjson: |
|
||||
{
|
||||
"auths": {
|
||||
{{ .Values.secrets.registry.registryUrl | quote }}: {
|
||||
"username": {{ .Values.secrets.registry.username | quote }},
|
||||
"password": {{ .Values.secrets.registry.password | quote }}
|
||||
}
|
||||
}
|
||||
}
|
||||
---
|
||||
# Secret for Git credentials (used by pipeline to push GitOps updates)
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-git-credentials
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: gitops
|
||||
annotations:
|
||||
note: "Git credentials for GitOps updates"
|
||||
type: Opaque
|
||||
stringData:
|
||||
username: {{ .Values.secrets.git.username | quote }}
|
||||
password: {{ .Values.secrets.git.password | quote }}
|
||||
---
|
||||
# Secret for Flux GitRepository access
|
||||
# Used by Flux to pull from Gitea repository
|
||||
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"
|
||||
type: Opaque
|
||||
stringData:
|
||||
username: {{ .Values.secrets.git.username | quote }}
|
||||
password: {{ .Values.secrets.git.password | quote }}
|
||||
@@ -0,0 +1,19 @@
|
||||
# ServiceAccount for Tekton Triggers EventListener
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ .Values.serviceAccounts.triggers.name }}
|
||||
namespace: {{ .Values.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: {{ .Values.namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: pipeline
|
||||
@@ -5,9 +5,9 @@ apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: git-clone
|
||||
namespace: tekton-pipelines
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: source
|
||||
spec:
|
||||
workspaces:
|
||||
@@ -0,0 +1,51 @@
|
||||
# Tekton Kaniko Build Task for Bakery-IA CI/CD
|
||||
# This task builds and pushes container images using Kaniko
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: kaniko-build
|
||||
namespace: {{ .Values.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
|
||||
- name: git-revision
|
||||
type: string
|
||||
description: Git revision to tag images with
|
||||
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
|
||||
command:
|
||||
- /kaniko/executor
|
||||
args:
|
||||
- --dockerfile=$(workspaces.source.path)/Dockerfile
|
||||
- --destination=$(params.registry)/$(params.service):$(params.git-revision)
|
||||
- --context=$(workspaces.source.path)
|
||||
- --cache=true
|
||||
- --cache-repo=$(params.registry)/cache
|
||||
resources:
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
@@ -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: {{ .Values.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: python:3.11-slim
|
||||
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: python:3.11-slim
|
||||
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,104 @@
|
||||
# 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: {{ .Values.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 GitOps repository
|
||||
REPO_URL="https://${GIT_USERNAME}:${GIT_PASSWORD}@gitea.bakery-ia.local/bakery/bakery-ia-gitops.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
|
||||
echo "Updating manifest for service: $service"
|
||||
|
||||
# Find and update the image tag in the deployment YAML
|
||||
if [ -f "deployments/${service}-deployment.yaml" ]; then
|
||||
sed -i "s|image: bakery/${service}:.*|image: $(params.registry)/bakery/${service}:$(params.git-revision)|g" "deployments/${service}-deployment.yaml"
|
||||
fi
|
||||
done
|
||||
|
||||
# Commit and push changes (unless dry-run)
|
||||
if [ "$(params.dry-run)" != "true" ]; then
|
||||
git add .
|
||||
git commit -m "Update images for services: $(params.services) [skip ci]"
|
||||
git push origin "$(params.git-branch)"
|
||||
|
||||
echo "GitOps manifests updated successfully"
|
||||
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: {{ .Values.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 }}"}}"
|
||||
@@ -1,20 +1,13 @@
|
||||
# Tekton TriggerTemplate for Bakery-IA CI/CD
|
||||
# This template defines how PipelineRuns are created when triggers fire
|
||||
#
|
||||
# Registry URL Configuration:
|
||||
# The registry URL is configured via the 'registry' parameter.
|
||||
# Default value should match pipeline-config ConfigMap's REGISTRY_URL.
|
||||
# To change the registry, update BOTH:
|
||||
# 1. This template's default value
|
||||
# 2. The pipeline-config ConfigMap
|
||||
|
||||
apiVersion: triggers.tekton.dev/v1beta1
|
||||
kind: TriggerTemplate
|
||||
metadata:
|
||||
name: bakery-ia-trigger-template
|
||||
namespace: tekton-pipelines
|
||||
namespace: {{ .Values.namespace }}
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: triggers
|
||||
spec:
|
||||
params:
|
||||
@@ -34,14 +27,14 @@ spec:
|
||||
# Registry URL - keep in sync with pipeline-config ConfigMap
|
||||
- name: registry-url
|
||||
description: Container registry URL
|
||||
default: "gitea.bakery-ia.local:5000"
|
||||
default: {{ .Values.global.registry.url | quote }}
|
||||
resourcetemplates:
|
||||
- apiVersion: tekton.dev/v1beta1
|
||||
kind: PipelineRun
|
||||
metadata:
|
||||
generateName: bakery-ia-ci-run-
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
tekton.dev/pipeline: bakery-ia-ci
|
||||
triggers.tekton.dev/trigger: bakery-ia-gitea-trigger
|
||||
annotations:
|
||||
@@ -51,7 +44,7 @@ spec:
|
||||
spec:
|
||||
pipelineRef:
|
||||
name: bakery-ia-ci
|
||||
serviceAccountName: tekton-pipeline-sa
|
||||
serviceAccountName: {{ .Values.serviceAccounts.pipeline.name }}
|
||||
workspaces:
|
||||
- name: shared-workspace
|
||||
volumeClaimTemplate:
|
||||
@@ -59,7 +52,7 @@ spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
storage: {{ .Values.pipeline.workspace.size }}
|
||||
- name: docker-credentials
|
||||
secret:
|
||||
secretName: gitea-registry-credentials
|
||||
@@ -83,4 +76,4 @@ spec:
|
||||
# Timeout for the entire pipeline run
|
||||
timeouts:
|
||||
pipeline: "1h0m0s"
|
||||
tasks: "45m0s"
|
||||
tasks: "45m0s"
|
||||
24
infrastructure/cicd/tekton-helm/values-test.yaml
Normal file
24
infrastructure/cicd/tekton-helm/values-test.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
# Test values for Tekton Helm chart
|
||||
# This file overrides default values for testing purposes
|
||||
|
||||
# Use a test namespace
|
||||
namespace: "tekton-test"
|
||||
|
||||
# Test registry URL
|
||||
global:
|
||||
registry:
|
||||
url: "localhost:5000"
|
||||
|
||||
# Test secrets
|
||||
secrets:
|
||||
webhook:
|
||||
token: "test-webhook-token"
|
||||
|
||||
registry:
|
||||
username: "test-user"
|
||||
password: "test-password"
|
||||
registryUrl: "localhost:5000"
|
||||
|
||||
git:
|
||||
username: "test-git-user"
|
||||
password: "test-git-password"
|
||||
91
infrastructure/cicd/tekton-helm/values.yaml
Normal file
91
infrastructure/cicd/tekton-helm/values.yaml
Normal file
@@ -0,0 +1,91 @@
|
||||
# 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.bakery-ia.local:5000"
|
||||
|
||||
# Git configuration
|
||||
git:
|
||||
branch: "main"
|
||||
userName: "bakery-ia-ci"
|
||||
userEmail: "ci@bakery-ia.local"
|
||||
|
||||
# Pipeline configuration
|
||||
pipeline:
|
||||
# Build configuration
|
||||
build:
|
||||
cacheTTL: "24h"
|
||||
verbosity: "info"
|
||||
|
||||
# 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
|
||||
namespace: "tekton-pipelines"
|
||||
|
||||
# Secrets configuration
|
||||
secrets:
|
||||
# Webhook secret for validating incoming webhooks
|
||||
webhook:
|
||||
token: "example-webhook-token-do-not-use-in-production"
|
||||
|
||||
# Registry credentials for pushing images
|
||||
registry:
|
||||
username: "example-user"
|
||||
password: "example-password"
|
||||
registryUrl: "gitea.bakery-ia.local:5000"
|
||||
|
||||
# Git credentials for GitOps updates
|
||||
git:
|
||||
username: "example-user"
|
||||
password: "example-password"
|
||||
|
||||
# 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"
|
||||
@@ -1,222 +0,0 @@
|
||||
# Workspace and PipelineRun Cleanup for Bakery-IA CI/CD
|
||||
# This CronJob cleans up old PipelineRuns and PVCs to prevent storage exhaustion
|
||||
|
||||
---
|
||||
# ServiceAccount for cleanup job
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: tekton-cleanup-sa
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: cleanup
|
||||
|
||||
---
|
||||
# ClusterRole for cleanup operations
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: tekton-cleanup-role
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: cleanup
|
||||
rules:
|
||||
- apiGroups: ["tekton.dev"]
|
||||
resources: ["pipelineruns", "taskruns"]
|
||||
verbs: ["get", "list", "delete"]
|
||||
- apiGroups: [""]
|
||||
resources: ["persistentvolumeclaims"]
|
||||
verbs: ["get", "list", "delete"]
|
||||
- apiGroups: [""]
|
||||
resources: ["pods"]
|
||||
verbs: ["get", "list", "delete"]
|
||||
|
||||
---
|
||||
# ClusterRoleBinding for cleanup
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: tekton-cleanup-binding
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: cleanup
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: tekton-cleanup-sa
|
||||
namespace: tekton-pipelines
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: tekton-cleanup-role
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
---
|
||||
# CronJob to clean up old PipelineRuns
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: tekton-pipelinerun-cleanup
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: cleanup
|
||||
spec:
|
||||
# Run every 6 hours
|
||||
schedule: "0 */6 * * *"
|
||||
concurrencyPolicy: Forbid
|
||||
successfulJobsHistoryLimit: 3
|
||||
failedJobsHistoryLimit: 3
|
||||
jobTemplate:
|
||||
spec:
|
||||
ttlSecondsAfterFinished: 3600
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: cleanup
|
||||
spec:
|
||||
serviceAccountName: tekton-cleanup-sa
|
||||
restartPolicy: OnFailure
|
||||
containers:
|
||||
- name: cleanup
|
||||
image: bitnami/kubectl:latest
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "============================================"
|
||||
echo "Tekton Cleanup Job"
|
||||
echo "Timestamp: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
echo "============================================"
|
||||
|
||||
# Configuration
|
||||
NAMESPACE="tekton-pipelines"
|
||||
MAX_AGE_HOURS=24
|
||||
KEEP_RECENT=10
|
||||
|
||||
echo ""
|
||||
echo "Configuration:"
|
||||
echo " Namespace: $NAMESPACE"
|
||||
echo " Max Age: ${MAX_AGE_HOURS} hours"
|
||||
echo " Keep Recent: $KEEP_RECENT"
|
||||
echo ""
|
||||
|
||||
# Get current timestamp
|
||||
CURRENT_TIME=$(date +%s)
|
||||
|
||||
# Clean up completed PipelineRuns older than MAX_AGE_HOURS
|
||||
echo "Cleaning up old PipelineRuns..."
|
||||
|
||||
# Get all completed PipelineRuns
|
||||
COMPLETED_RUNS=$(kubectl get pipelineruns -n "$NAMESPACE" \
|
||||
--no-headers \
|
||||
-o custom-columns=NAME:.metadata.name,STATUS:.status.conditions[0].reason,AGE:.metadata.creationTimestamp \
|
||||
2>/dev/null | grep -E "Succeeded|Failed" || true)
|
||||
|
||||
DELETED_COUNT=0
|
||||
|
||||
echo "$COMPLETED_RUNS" | while read -r line; do
|
||||
if [ -z "$line" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
RUN_NAME=$(echo "$line" | awk '{print $1}')
|
||||
RUN_TIME=$(echo "$line" | awk '{print $3}')
|
||||
|
||||
if [ -z "$RUN_NAME" ] || [ -z "$RUN_TIME" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Convert timestamp to seconds
|
||||
RUN_TIMESTAMP=$(date -d "$RUN_TIME" +%s 2>/dev/null || echo "0")
|
||||
|
||||
if [ "$RUN_TIMESTAMP" = "0" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Calculate age in hours
|
||||
AGE_SECONDS=$((CURRENT_TIME - RUN_TIMESTAMP))
|
||||
AGE_HOURS=$((AGE_SECONDS / 3600))
|
||||
|
||||
if [ "$AGE_HOURS" -gt "$MAX_AGE_HOURS" ]; then
|
||||
echo "Deleting PipelineRun: $RUN_NAME (age: ${AGE_HOURS}h)"
|
||||
kubectl delete pipelinerun "$RUN_NAME" -n "$NAMESPACE" --ignore-not-found=true
|
||||
DELETED_COUNT=$((DELETED_COUNT + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Deleted $DELETED_COUNT old PipelineRuns"
|
||||
|
||||
# Clean up orphaned PVCs (PVCs without associated PipelineRuns)
|
||||
echo ""
|
||||
echo "Cleaning up orphaned PVCs..."
|
||||
|
||||
ORPHANED_PVCS=$(kubectl get pvc -n "$NAMESPACE" \
|
||||
-l tekton.dev/pipelineRun \
|
||||
--no-headers \
|
||||
-o custom-columns=NAME:.metadata.name,PIPELINERUN:.metadata.labels.tekton\\.dev/pipelineRun \
|
||||
2>/dev/null || true)
|
||||
|
||||
echo "$ORPHANED_PVCS" | while read -r line; do
|
||||
if [ -z "$line" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
PVC_NAME=$(echo "$line" | awk '{print $1}')
|
||||
PR_NAME=$(echo "$line" | awk '{print $2}')
|
||||
|
||||
if [ -z "$PVC_NAME" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if associated PipelineRun exists
|
||||
if ! kubectl get pipelinerun "$PR_NAME" -n "$NAMESPACE" > /dev/null 2>&1; then
|
||||
echo "Deleting orphaned PVC: $PVC_NAME (PipelineRun $PR_NAME not found)"
|
||||
kubectl delete pvc "$PVC_NAME" -n "$NAMESPACE" --ignore-not-found=true
|
||||
fi
|
||||
done
|
||||
|
||||
# Clean up completed/failed pods older than 1 hour
|
||||
echo ""
|
||||
echo "Cleaning up old completed pods..."
|
||||
|
||||
kubectl delete pods -n "$NAMESPACE" \
|
||||
--field-selector=status.phase=Succeeded \
|
||||
--ignore-not-found=true 2>/dev/null || true
|
||||
|
||||
kubectl delete pods -n "$NAMESPACE" \
|
||||
--field-selector=status.phase=Failed \
|
||||
--ignore-not-found=true 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo "Cleanup complete"
|
||||
echo "============================================"
|
||||
resources:
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
|
||||
---
|
||||
# ConfigMap for cleanup configuration
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cleanup-config
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: cleanup
|
||||
data:
|
||||
# Maximum age of completed PipelineRuns to keep (in hours)
|
||||
MAX_AGE_HOURS: "24"
|
||||
# Number of recent PipelineRuns to keep regardless of age
|
||||
KEEP_RECENT: "10"
|
||||
# Cleanup schedule (cron format)
|
||||
CLEANUP_SCHEDULE: "0 */6 * * *"
|
||||
@@ -1,5 +0,0 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- cleanup.yaml
|
||||
@@ -1,5 +0,0 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- pipeline-config.yaml
|
||||
@@ -1,41 +0,0 @@
|
||||
# CI/CD Pipeline Configuration for Bakery-IA
|
||||
# This ConfigMap contains configurable values for the CI/CD pipeline
|
||||
#
|
||||
# IMPORTANT: When changing REGISTRY_URL, also update:
|
||||
# - infrastructure/cicd/tekton/triggers/trigger-template.yaml (registry-url default)
|
||||
# - infrastructure/cicd/tekton/secrets/secrets.yaml (registry credentials)
|
||||
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: pipeline-config
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: config
|
||||
data:
|
||||
# Container Registry Configuration
|
||||
# Change this to your actual registry URL
|
||||
# Also update trigger-template.yaml and secrets when changing this!
|
||||
REGISTRY_URL: "gitea.bakery-ia.local:5000"
|
||||
|
||||
# Git Configuration
|
||||
GIT_BRANCH: "main"
|
||||
GIT_USER_NAME: "bakery-ia-ci"
|
||||
GIT_USER_EMAIL: "ci@bakery-ia.local"
|
||||
|
||||
# Build Configuration
|
||||
BUILD_CACHE_TTL: "24h"
|
||||
BUILD_VERBOSITY: "info"
|
||||
|
||||
# Test Configuration
|
||||
SKIP_TESTS: "false"
|
||||
SKIP_LINT: "false"
|
||||
|
||||
# Deployment Configuration
|
||||
DEPLOY_NAMESPACE: "bakery-ia"
|
||||
FLUX_NAMESPACE: "flux-system"
|
||||
|
||||
# Workspace Configuration
|
||||
WORKSPACE_SIZE: "5Gi"
|
||||
WORKSPACE_STORAGE_CLASS: "standard"
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- rbac/
|
||||
- secrets/
|
||||
- configs/
|
||||
- tasks/
|
||||
- triggers/
|
||||
- pipelines/
|
||||
- cleanup/
|
||||
@@ -1,6 +0,0 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- ci-pipeline.yaml
|
||||
- prod-deploy-pipeline.yaml
|
||||
@@ -1,118 +0,0 @@
|
||||
# Production Deployment Pipeline for Bakery-IA
|
||||
# This pipeline handles production deployments with manual approval gate
|
||||
# It should be triggered after the CI pipeline succeeds
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Pipeline
|
||||
metadata:
|
||||
name: bakery-ia-prod-deploy
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: pipeline
|
||||
app.kubernetes.io/environment: production
|
||||
spec:
|
||||
workspaces:
|
||||
- name: shared-workspace
|
||||
description: Shared workspace for source code
|
||||
- name: git-credentials
|
||||
description: Git credentials for pushing GitOps updates
|
||||
optional: true
|
||||
params:
|
||||
- name: git-url
|
||||
type: string
|
||||
description: Repository URL
|
||||
- name: git-revision
|
||||
type: string
|
||||
description: Git revision/commit hash to deploy
|
||||
- name: services
|
||||
type: string
|
||||
description: Comma-separated list of services to deploy
|
||||
- name: registry
|
||||
type: string
|
||||
description: Container registry URL
|
||||
- name: approver
|
||||
type: string
|
||||
description: Name of the person who approved this deployment
|
||||
default: "automated"
|
||||
- name: approval-ticket
|
||||
type: string
|
||||
description: Ticket/issue number for deployment approval
|
||||
default: "N/A"
|
||||
|
||||
tasks:
|
||||
# Stage 1: Fetch source code
|
||||
- name: fetch-source
|
||||
taskRef:
|
||||
name: git-clone
|
||||
workspaces:
|
||||
- name: output
|
||||
workspace: shared-workspace
|
||||
params:
|
||||
- name: url
|
||||
value: $(params.git-url)
|
||||
- name: revision
|
||||
value: $(params.git-revision)
|
||||
|
||||
# Stage 2: Verify images exist in registry
|
||||
- name: verify-images
|
||||
runAfter: [fetch-source]
|
||||
taskRef:
|
||||
name: verify-images
|
||||
params:
|
||||
- name: services
|
||||
value: $(params.services)
|
||||
- name: registry
|
||||
value: $(params.registry)
|
||||
- name: git-revision
|
||||
value: $(params.git-revision)
|
||||
|
||||
# Stage 3: Pre-deployment validation
|
||||
- name: pre-deploy-validation
|
||||
runAfter: [verify-images]
|
||||
taskRef:
|
||||
name: pre-deploy-validation
|
||||
workspaces:
|
||||
- name: source
|
||||
workspace: shared-workspace
|
||||
params:
|
||||
- name: services
|
||||
value: $(params.services)
|
||||
- name: environment
|
||||
value: "production"
|
||||
|
||||
# Stage 4: Update production manifests
|
||||
- name: update-prod-manifests
|
||||
runAfter: [pre-deploy-validation]
|
||||
taskRef:
|
||||
name: update-gitops
|
||||
workspaces:
|
||||
- name: source
|
||||
workspace: shared-workspace
|
||||
- name: git-credentials
|
||||
workspace: git-credentials
|
||||
params:
|
||||
- name: services
|
||||
value: $(params.services)
|
||||
- name: registry
|
||||
value: $(params.registry)
|
||||
- name: git-revision
|
||||
value: $(params.git-revision)
|
||||
- name: git-branch
|
||||
value: "main"
|
||||
- name: dry-run
|
||||
value: "false"
|
||||
|
||||
finally:
|
||||
- name: deployment-summary
|
||||
taskRef:
|
||||
name: prod-deployment-summary
|
||||
params:
|
||||
- name: services
|
||||
value: $(params.services)
|
||||
- name: git-revision
|
||||
value: $(params.git-revision)
|
||||
- name: approver
|
||||
value: $(params.approver)
|
||||
- name: approval-ticket
|
||||
value: $(params.approval-ticket)
|
||||
@@ -1,6 +0,0 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- rbac.yaml
|
||||
- resource-quota.yaml
|
||||
@@ -1,64 +0,0 @@
|
||||
# ResourceQuota for Tekton Pipelines Namespace
|
||||
# Prevents resource exhaustion from runaway pipeline runs
|
||||
#
|
||||
# This quota limits:
|
||||
# - Total CPU and memory that can be requested/used
|
||||
# - Number of concurrent pods
|
||||
# - Number of PVCs for workspaces
|
||||
|
||||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: tekton-pipelines-quota
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: quota
|
||||
spec:
|
||||
hard:
|
||||
# Limit total CPU
|
||||
requests.cpu: "8"
|
||||
limits.cpu: "16"
|
||||
# Limit total memory
|
||||
requests.memory: "16Gi"
|
||||
limits.memory: "32Gi"
|
||||
# Limit number of pods (controls concurrent pipeline tasks)
|
||||
pods: "20"
|
||||
# Limit PVCs (controls workspace storage)
|
||||
persistentvolumeclaims: "10"
|
||||
# Limit storage
|
||||
requests.storage: "50Gi"
|
||||
|
||||
---
|
||||
# LimitRange to set defaults and limits for individual pods
|
||||
# Ensures every pod has resource requests/limits
|
||||
apiVersion: v1
|
||||
kind: LimitRange
|
||||
metadata:
|
||||
name: tekton-pipelines-limits
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: quota
|
||||
spec:
|
||||
limits:
|
||||
# Default limits for containers
|
||||
- type: Container
|
||||
default:
|
||||
cpu: "1"
|
||||
memory: "1Gi"
|
||||
defaultRequest:
|
||||
cpu: "100m"
|
||||
memory: "256Mi"
|
||||
max:
|
||||
cpu: "4"
|
||||
memory: "8Gi"
|
||||
min:
|
||||
cpu: "50m"
|
||||
memory: "64Mi"
|
||||
# Limits for PVCs
|
||||
- type: PersistentVolumeClaim
|
||||
max:
|
||||
storage: "10Gi"
|
||||
min:
|
||||
storage: "1Gi"
|
||||
@@ -1,4 +0,0 @@
|
||||
# Ignore generated secrets
|
||||
.webhook-secret
|
||||
*-actual.yaml
|
||||
sealed-secrets.yaml
|
||||
@@ -1,167 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Generate CI/CD Secrets for Bakery-IA
|
||||
#
|
||||
# This script creates Kubernetes secrets required for the CI/CD pipeline.
|
||||
# Run this script once during initial setup.
|
||||
#
|
||||
# Usage:
|
||||
# ./generate-secrets.sh [options]
|
||||
#
|
||||
# Options:
|
||||
# --registry-url Container registry URL (default: gitea.bakery-ia.local:5000)
|
||||
# --gitea-user Gitea username (will prompt if not provided)
|
||||
# --gitea-password Gitea password (will prompt if not provided)
|
||||
# --dry-run Print commands without executing
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Default values
|
||||
REGISTRY_URL="${REGISTRY_URL:-gitea.bakery-ia.local:5000}"
|
||||
DRY_RUN=false
|
||||
KUBECTL="kubectl"
|
||||
|
||||
# Check if running in microk8s
|
||||
if command -v microk8s &> /dev/null; then
|
||||
KUBECTL="microk8s kubectl"
|
||||
fi
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--registry-url)
|
||||
REGISTRY_URL="$2"
|
||||
shift 2
|
||||
;;
|
||||
--gitea-user)
|
||||
GITEA_USERNAME="$2"
|
||||
shift 2
|
||||
;;
|
||||
--gitea-password)
|
||||
GITEA_PASSWORD="$2"
|
||||
shift 2
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Unknown option: $1${NC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "=========================================="
|
||||
echo " Bakery-IA CI/CD Secrets Generator"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# Prompt for credentials if not provided
|
||||
if [ -z "$GITEA_USERNAME" ]; then
|
||||
read -p "Enter Gitea username: " GITEA_USERNAME
|
||||
fi
|
||||
|
||||
if [ -z "$GITEA_PASSWORD" ]; then
|
||||
read -s -p "Enter Gitea password: " GITEA_PASSWORD
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Generate webhook secret
|
||||
WEBHOOK_SECRET=$(openssl rand -hex 32)
|
||||
|
||||
echo ""
|
||||
echo -e "${YELLOW}Configuration:${NC}"
|
||||
echo " Registry URL: $REGISTRY_URL"
|
||||
echo " Gitea User: $GITEA_USERNAME"
|
||||
echo " Webhook Secret: ${WEBHOOK_SECRET:0:8}..."
|
||||
echo ""
|
||||
|
||||
# Function to create secret
|
||||
create_secret() {
|
||||
local cmd="$1"
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
echo -e "${YELLOW}[DRY-RUN]${NC} $cmd"
|
||||
else
|
||||
eval "$cmd"
|
||||
fi
|
||||
}
|
||||
|
||||
# Ensure namespaces exist
|
||||
echo -e "${GREEN}Creating namespaces if they don't exist...${NC}"
|
||||
create_secret "$KUBECTL create namespace tekton-pipelines --dry-run=client -o yaml | $KUBECTL apply -f -"
|
||||
create_secret "$KUBECTL create namespace flux-system --dry-run=client -o yaml | $KUBECTL apply -f -"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}Creating secrets...${NC}"
|
||||
|
||||
# 1. Webhook Secret
|
||||
echo " Creating gitea-webhook-secret..."
|
||||
create_secret "$KUBECTL create secret generic gitea-webhook-secret \
|
||||
--namespace tekton-pipelines \
|
||||
--from-literal=secretToken='$WEBHOOK_SECRET' \
|
||||
--dry-run=client -o yaml | $KUBECTL apply -f -"
|
||||
|
||||
# 2. Registry Credentials (docker-registry type)
|
||||
echo " Creating gitea-registry-credentials..."
|
||||
create_secret "$KUBECTL create secret docker-registry gitea-registry-credentials \
|
||||
--namespace tekton-pipelines \
|
||||
--docker-server='$REGISTRY_URL' \
|
||||
--docker-username='$GITEA_USERNAME' \
|
||||
--docker-password='$GITEA_PASSWORD' \
|
||||
--dry-run=client -o yaml | $KUBECTL apply -f -"
|
||||
|
||||
# 3. Git Credentials for Tekton
|
||||
echo " Creating gitea-git-credentials..."
|
||||
create_secret "$KUBECTL create secret generic gitea-git-credentials \
|
||||
--namespace tekton-pipelines \
|
||||
--from-literal=username='$GITEA_USERNAME' \
|
||||
--from-literal=password='$GITEA_PASSWORD' \
|
||||
--dry-run=client -o yaml | $KUBECTL apply -f -"
|
||||
|
||||
# 4. Flux Git Credentials
|
||||
echo " Creating gitea-credentials for Flux..."
|
||||
create_secret "$KUBECTL create secret generic gitea-credentials \
|
||||
--namespace flux-system \
|
||||
--from-literal=username='$GITEA_USERNAME' \
|
||||
--from-literal=password='$GITEA_PASSWORD' \
|
||||
--dry-run=client -o yaml | $KUBECTL apply -f -"
|
||||
|
||||
# Label all secrets
|
||||
echo ""
|
||||
echo -e "${GREEN}Adding labels to secrets...${NC}"
|
||||
for ns in tekton-pipelines flux-system; do
|
||||
for secret in gitea-webhook-secret gitea-registry-credentials gitea-git-credentials gitea-credentials; do
|
||||
if $KUBECTL get secret "$secret" -n "$ns" &> /dev/null; then
|
||||
create_secret "$KUBECTL label secret $secret -n $ns app.kubernetes.io/name=bakery-ia-cicd --overwrite 2>/dev/null || true"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo -e "${GREEN}Secrets created successfully!${NC}"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo -e "${YELLOW}IMPORTANT:${NC} Save this webhook secret for Gitea webhook configuration:"
|
||||
echo ""
|
||||
echo " Webhook Secret: $WEBHOOK_SECRET"
|
||||
echo ""
|
||||
echo "Configure this in Gitea:"
|
||||
echo " 1. Go to Repository Settings > Webhooks"
|
||||
echo " 2. Add webhook with URL: http://el-bakery-ia-listener.tekton-pipelines.svc.cluster.local:8080"
|
||||
echo " 3. Set Secret to the webhook secret above"
|
||||
echo " 4. Select events: Push"
|
||||
echo ""
|
||||
|
||||
# Save webhook secret to a file for reference (gitignored)
|
||||
if [ "$DRY_RUN" = false ]; then
|
||||
echo "$WEBHOOK_SECRET" > "$(dirname "$0")/.webhook-secret"
|
||||
chmod 600 "$(dirname "$0")/.webhook-secret"
|
||||
echo "Webhook secret saved to .webhook-secret (gitignored)"
|
||||
fi
|
||||
@@ -1,19 +0,0 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- secrets.yaml
|
||||
|
||||
# Note: In production, use sealed-secrets or external-secrets-operator
|
||||
# to manage secrets securely. The secrets.yaml file contains placeholder
|
||||
# values that must be replaced before deployment.
|
||||
#
|
||||
# Example using sealed-secrets:
|
||||
# 1. Install sealed-secrets controller
|
||||
# 2. Create SealedSecret resources instead of plain Secrets
|
||||
# 3. Commit the SealedSecret manifests to Git (safe to commit)
|
||||
#
|
||||
# Example using external-secrets-operator:
|
||||
# 1. Install external-secrets-operator
|
||||
# 2. Configure a SecretStore (AWS Secrets Manager, HashiCorp Vault, etc.)
|
||||
# 3. Create ExternalSecret resources that reference the SecretStore
|
||||
@@ -1,79 +0,0 @@
|
||||
# CI/CD Secrets Template for Tekton Pipelines
|
||||
#
|
||||
# DO NOT commit this file with actual credentials!
|
||||
# Use the generate-secrets.sh script to create secrets safely.
|
||||
#
|
||||
# For production, use one of these approaches:
|
||||
# 1. Sealed Secrets: kubeseal < secrets.yaml > sealed-secrets.yaml
|
||||
# 2. External Secrets Operator: Configure with your secret store
|
||||
# 3. Manual creation: kubectl create secret ... (see generate-secrets.sh)
|
||||
|
||||
---
|
||||
# Secret for Gitea webhook validation
|
||||
# Used by EventListener to validate incoming webhooks
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-webhook-secret
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: triggers
|
||||
type: Opaque
|
||||
stringData:
|
||||
# Generate with: openssl rand -hex 32
|
||||
secretToken: "${WEBHOOK_SECRET_TOKEN}"
|
||||
|
||||
---
|
||||
# Secret for Gitea container registry credentials
|
||||
# Used by Kaniko to push images to Gitea registry
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-registry-credentials
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: build
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
stringData:
|
||||
.dockerconfigjson: |
|
||||
{
|
||||
"auths": {
|
||||
"${REGISTRY_URL}": {
|
||||
"username": "${GITEA_USERNAME}",
|
||||
"password": "${GITEA_PASSWORD}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
---
|
||||
# Secret for Git credentials (used by pipeline to push GitOps updates)
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-git-credentials
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: gitops
|
||||
type: Opaque
|
||||
stringData:
|
||||
username: "${GITEA_USERNAME}"
|
||||
password: "${GITEA_PASSWORD}"
|
||||
|
||||
---
|
||||
# Secret for Flux GitRepository access
|
||||
# Used by Flux to pull from Gitea repository
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-credentials
|
||||
namespace: flux-system
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: flux
|
||||
type: Opaque
|
||||
stringData:
|
||||
username: "${GITEA_USERNAME}"
|
||||
password: "${GITEA_PASSWORD}"
|
||||
@@ -1,98 +0,0 @@
|
||||
# CI/CD Secrets for Tekton Pipelines
|
||||
#
|
||||
# WARNING: This file contains EXAMPLE values only!
|
||||
# DO NOT use these values in production.
|
||||
#
|
||||
# To create actual secrets, use ONE of these methods:
|
||||
#
|
||||
# Method 1 (Recommended): Use the generate-secrets.sh script
|
||||
# ./generate-secrets.sh --gitea-user <username> --gitea-password <password>
|
||||
#
|
||||
# Method 2: Create secrets manually with kubectl
|
||||
# kubectl create secret generic gitea-webhook-secret \
|
||||
# --namespace tekton-pipelines \
|
||||
# --from-literal=secretToken="$(openssl rand -hex 32)"
|
||||
#
|
||||
# Method 3: Use Sealed Secrets for GitOps
|
||||
# kubeseal < secrets-template.yaml > sealed-secrets.yaml
|
||||
#
|
||||
# Method 4: Use External Secrets Operator
|
||||
# Configure ESO to pull from your secret store (Vault, AWS SM, etc.)
|
||||
|
||||
---
|
||||
# Example Secret for Gitea webhook validation
|
||||
# Used by EventListener to validate incoming webhooks
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-webhook-secret
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: triggers
|
||||
annotations:
|
||||
note: "EXAMPLE - Replace with actual secret using generate-secrets.sh"
|
||||
type: Opaque
|
||||
stringData:
|
||||
# Generate with: openssl rand -hex 32
|
||||
secretToken: "example-webhook-token-do-not-use-in-production"
|
||||
|
||||
---
|
||||
# Example Secret for Gitea container registry credentials
|
||||
# Used by Kaniko to push images to Gitea registry
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-registry-credentials
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: build
|
||||
annotations:
|
||||
note: "EXAMPLE - Replace with actual secret using generate-secrets.sh"
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
stringData:
|
||||
.dockerconfigjson: |
|
||||
{
|
||||
"auths": {
|
||||
"gitea.bakery-ia.local:5000": {
|
||||
"username": "example-user",
|
||||
"password": "example-password"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
---
|
||||
# Example Secret for Git credentials (used by pipeline to push GitOps updates)
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-git-credentials
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: gitops
|
||||
annotations:
|
||||
note: "EXAMPLE - Replace with actual secret using generate-secrets.sh"
|
||||
type: Opaque
|
||||
stringData:
|
||||
username: "example-user"
|
||||
password: "example-password"
|
||||
|
||||
---
|
||||
# Example Secret for Flux GitRepository access
|
||||
# Used by Flux to pull from Gitea repository
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-credentials
|
||||
namespace: flux-system
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: flux
|
||||
annotations:
|
||||
note: "EXAMPLE - Replace with actual secret using generate-secrets.sh"
|
||||
type: Opaque
|
||||
stringData:
|
||||
username: "example-user"
|
||||
password: "example-password"
|
||||
@@ -1,154 +0,0 @@
|
||||
# Tekton Detect Changed Services Task for Bakery-IA CI/CD
|
||||
# This task identifies which services have changed in the repository
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: detect-changed-services
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: detect
|
||||
spec:
|
||||
workspaces:
|
||||
- name: source
|
||||
description: Source code workspace
|
||||
params:
|
||||
- name: base-ref
|
||||
type: string
|
||||
description: Base reference for comparison (default HEAD~1)
|
||||
default: "HEAD~1"
|
||||
results:
|
||||
- name: changed-services
|
||||
description: Comma-separated list of changed services
|
||||
- name: changed-files-count
|
||||
description: Number of files changed
|
||||
steps:
|
||||
- name: detect
|
||||
image: alpine/git:2.43.0
|
||||
script: |
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
SOURCE_PATH="$(workspaces.source.path)"
|
||||
BASE_REF="$(params.base-ref)"
|
||||
|
||||
cd "$SOURCE_PATH"
|
||||
|
||||
echo "============================================"
|
||||
echo "Detect Changed Services"
|
||||
echo "============================================"
|
||||
echo "Base ref: $BASE_REF"
|
||||
echo "============================================"
|
||||
|
||||
# Get list of changed files compared to base reference
|
||||
echo ""
|
||||
echo "Detecting changed files..."
|
||||
|
||||
# Try to get diff, fall back to listing all files if this is the first commit
|
||||
CHANGED_FILES=$(git diff --name-only "$BASE_REF" HEAD 2>/dev/null || git ls-tree -r HEAD --name-only)
|
||||
|
||||
FILE_COUNT=$(echo "$CHANGED_FILES" | grep -c "." || echo "0")
|
||||
echo "Found $FILE_COUNT changed files"
|
||||
echo "$FILE_COUNT" > $(results.changed-files-count.path)
|
||||
|
||||
if [ "$FILE_COUNT" = "0" ]; then
|
||||
echo "No files changed"
|
||||
echo "none" > $(results.changed-services.path)
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Changed files:"
|
||||
echo "$CHANGED_FILES" | head -20
|
||||
if [ "$FILE_COUNT" -gt 20 ]; then
|
||||
echo "... and $((FILE_COUNT - 20)) more files"
|
||||
fi
|
||||
|
||||
# Map files to services using simple shell (no bash arrays)
|
||||
echo ""
|
||||
echo "Mapping files to services..."
|
||||
|
||||
CHANGED_SERVICES=""
|
||||
|
||||
# Process each file
|
||||
echo "$CHANGED_FILES" | while read -r file; do
|
||||
if [ -z "$file" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check services directory
|
||||
if echo "$file" | grep -q "^services/"; then
|
||||
SERVICE=$(echo "$file" | cut -d'/' -f2)
|
||||
if [ -n "$SERVICE" ] && ! echo "$CHANGED_SERVICES" | grep -q "$SERVICE"; then
|
||||
if [ -z "$CHANGED_SERVICES" ]; then
|
||||
CHANGED_SERVICES="$SERVICE"
|
||||
else
|
||||
CHANGED_SERVICES="$CHANGED_SERVICES,$SERVICE"
|
||||
fi
|
||||
echo "$CHANGED_SERVICES" > /tmp/services.txt
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check frontend
|
||||
if echo "$file" | grep -q "^frontend/"; then
|
||||
if ! echo "$CHANGED_SERVICES" | grep -q "frontend"; then
|
||||
if [ -z "$CHANGED_SERVICES" ]; then
|
||||
CHANGED_SERVICES="frontend"
|
||||
else
|
||||
CHANGED_SERVICES="$CHANGED_SERVICES,frontend"
|
||||
fi
|
||||
echo "$CHANGED_SERVICES" > /tmp/services.txt
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check gateway
|
||||
if echo "$file" | grep -q "^gateway/"; then
|
||||
if ! echo "$CHANGED_SERVICES" | grep -q "gateway"; then
|
||||
if [ -z "$CHANGED_SERVICES" ]; then
|
||||
CHANGED_SERVICES="gateway"
|
||||
else
|
||||
CHANGED_SERVICES="$CHANGED_SERVICES,gateway"
|
||||
fi
|
||||
echo "$CHANGED_SERVICES" > /tmp/services.txt
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check infrastructure
|
||||
if echo "$file" | grep -q "^infrastructure/"; then
|
||||
if ! echo "$CHANGED_SERVICES" | grep -q "infrastructure"; then
|
||||
if [ -z "$CHANGED_SERVICES" ]; then
|
||||
CHANGED_SERVICES="infrastructure"
|
||||
else
|
||||
CHANGED_SERVICES="$CHANGED_SERVICES,infrastructure"
|
||||
fi
|
||||
echo "$CHANGED_SERVICES" > /tmp/services.txt
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Read the accumulated services
|
||||
if [ -f /tmp/services.txt ]; then
|
||||
CHANGED_SERVICES=$(cat /tmp/services.txt)
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
|
||||
# Output result
|
||||
if [ -z "$CHANGED_SERVICES" ]; then
|
||||
echo "No service changes detected"
|
||||
echo "none" > $(results.changed-services.path)
|
||||
else
|
||||
echo "Detected changes in services: $CHANGED_SERVICES"
|
||||
echo "$CHANGED_SERVICES" > $(results.changed-services.path)
|
||||
fi
|
||||
|
||||
echo "============================================"
|
||||
resources:
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
@@ -1,200 +0,0 @@
|
||||
# Tekton Kaniko Build Task for Bakery-IA CI/CD
|
||||
# This task builds and pushes container images using Kaniko
|
||||
# Supports building multiple services from a comma-separated list
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: kaniko-build
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: build
|
||||
spec:
|
||||
workspaces:
|
||||
- name: source
|
||||
description: Source code workspace
|
||||
- name: docker-credentials
|
||||
description: Docker registry credentials
|
||||
params:
|
||||
- name: services
|
||||
type: string
|
||||
description: Comma-separated list of services to build
|
||||
- name: registry
|
||||
type: string
|
||||
description: Container registry URL
|
||||
- name: git-revision
|
||||
type: string
|
||||
description: Git revision for image tag
|
||||
default: "latest"
|
||||
results:
|
||||
- name: built-images
|
||||
description: List of successfully built images
|
||||
- name: build-status
|
||||
description: Overall build status (success/failure)
|
||||
steps:
|
||||
# Step 1: Setup docker credentials
|
||||
- name: setup-docker-config
|
||||
image: alpine:3.18
|
||||
script: |
|
||||
#!/bin/sh
|
||||
set -e
|
||||
echo "Setting up Docker credentials..."
|
||||
mkdir -p /kaniko/.docker
|
||||
|
||||
# Check if credentials secret is mounted
|
||||
if [ -f "$(workspaces.docker-credentials.path)/config.json" ]; then
|
||||
cp "$(workspaces.docker-credentials.path)/config.json" /kaniko/.docker/config.json
|
||||
echo "Docker config copied from secret"
|
||||
elif [ -f "$(workspaces.docker-credentials.path)/.dockerconfigjson" ]; then
|
||||
cp "$(workspaces.docker-credentials.path)/.dockerconfigjson" /kaniko/.docker/config.json
|
||||
echo "Docker config copied from .dockerconfigjson"
|
||||
else
|
||||
echo "Warning: No docker credentials found, builds may fail for private registries"
|
||||
echo '{}' > /kaniko/.docker/config.json
|
||||
fi
|
||||
volumeMounts:
|
||||
- name: docker-config
|
||||
mountPath: /kaniko/.docker
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 32Mi
|
||||
|
||||
# Step 2: Build each service iteratively
|
||||
- name: build-services
|
||||
image: gcr.io/kaniko-project/executor:v1.23.0
|
||||
script: |
|
||||
#!/busybox/sh
|
||||
set -e
|
||||
|
||||
SERVICES="$(params.services)"
|
||||
REGISTRY="$(params.registry)"
|
||||
REVISION="$(params.git-revision)"
|
||||
SOURCE_PATH="$(workspaces.source.path)"
|
||||
BUILT_IMAGES=""
|
||||
FAILED_SERVICES=""
|
||||
|
||||
echo "============================================"
|
||||
echo "Starting build for services: $SERVICES"
|
||||
echo "Registry: $REGISTRY"
|
||||
echo "Tag: $REVISION"
|
||||
echo "============================================"
|
||||
|
||||
# Skip if no services to build
|
||||
if [ "$SERVICES" = "none" ] || [ -z "$SERVICES" ]; then
|
||||
echo "No services to build, skipping..."
|
||||
echo "none" > $(results.built-images.path)
|
||||
echo "skipped" > $(results.build-status.path)
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Convert comma-separated list to space-separated
|
||||
SERVICES_LIST=$(echo "$SERVICES" | tr ',' ' ')
|
||||
|
||||
for SERVICE in $SERVICES_LIST; do
|
||||
# Trim whitespace
|
||||
SERVICE=$(echo "$SERVICE" | tr -d ' ')
|
||||
|
||||
# Skip infrastructure changes (not buildable)
|
||||
if [ "$SERVICE" = "infrastructure" ]; then
|
||||
echo "Skipping infrastructure (not a buildable service)"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "--------------------------------------------"
|
||||
echo "Building service: $SERVICE"
|
||||
echo "--------------------------------------------"
|
||||
|
||||
# Determine Dockerfile path based on service type
|
||||
if [ "$SERVICE" = "frontend" ]; then
|
||||
DOCKERFILE_PATH="$SOURCE_PATH/frontend/Dockerfile"
|
||||
CONTEXT_PATH="$SOURCE_PATH/frontend"
|
||||
elif [ "$SERVICE" = "gateway" ]; then
|
||||
DOCKERFILE_PATH="$SOURCE_PATH/gateway/Dockerfile"
|
||||
CONTEXT_PATH="$SOURCE_PATH/gateway"
|
||||
else
|
||||
DOCKERFILE_PATH="$SOURCE_PATH/services/$SERVICE/Dockerfile"
|
||||
CONTEXT_PATH="$SOURCE_PATH"
|
||||
fi
|
||||
|
||||
# Check if Dockerfile exists
|
||||
if [ ! -f "$DOCKERFILE_PATH" ]; then
|
||||
echo "Warning: Dockerfile not found at $DOCKERFILE_PATH, skipping $SERVICE"
|
||||
FAILED_SERVICES="$FAILED_SERVICES $SERVICE"
|
||||
continue
|
||||
fi
|
||||
|
||||
IMAGE_NAME="$REGISTRY/bakery/$SERVICE:$REVISION"
|
||||
IMAGE_NAME_LATEST="$REGISTRY/bakery/$SERVICE:latest"
|
||||
|
||||
echo "Dockerfile: $DOCKERFILE_PATH"
|
||||
echo "Context: $CONTEXT_PATH"
|
||||
echo "Image: $IMAGE_NAME"
|
||||
|
||||
# Run Kaniko build
|
||||
/kaniko/executor \
|
||||
--dockerfile="$DOCKERFILE_PATH" \
|
||||
--context="$CONTEXT_PATH" \
|
||||
--destination="$IMAGE_NAME" \
|
||||
--destination="$IMAGE_NAME_LATEST" \
|
||||
--cache=true \
|
||||
--cache-ttl=24h \
|
||||
--verbosity=info \
|
||||
--snapshot-mode=redo \
|
||||
--use-new-run
|
||||
|
||||
BUILD_EXIT_CODE=$?
|
||||
|
||||
if [ $BUILD_EXIT_CODE -eq 0 ]; then
|
||||
echo "Successfully built and pushed: $IMAGE_NAME"
|
||||
if [ -z "$BUILT_IMAGES" ]; then
|
||||
BUILT_IMAGES="$IMAGE_NAME"
|
||||
else
|
||||
BUILT_IMAGES="$BUILT_IMAGES,$IMAGE_NAME"
|
||||
fi
|
||||
else
|
||||
echo "Failed to build: $SERVICE (exit code: $BUILD_EXIT_CODE)"
|
||||
FAILED_SERVICES="$FAILED_SERVICES $SERVICE"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo "Build Summary"
|
||||
echo "============================================"
|
||||
echo "Built images: $BUILT_IMAGES"
|
||||
echo "Failed services: $FAILED_SERVICES"
|
||||
|
||||
# Write results
|
||||
if [ -z "$BUILT_IMAGES" ]; then
|
||||
echo "none" > $(results.built-images.path)
|
||||
else
|
||||
echo "$BUILT_IMAGES" > $(results.built-images.path)
|
||||
fi
|
||||
|
||||
if [ -n "$FAILED_SERVICES" ]; then
|
||||
echo "partial" > $(results.build-status.path)
|
||||
echo "Warning: Some services failed to build: $FAILED_SERVICES"
|
||||
else
|
||||
echo "success" > $(results.build-status.path)
|
||||
fi
|
||||
volumeMounts:
|
||||
- name: docker-config
|
||||
mountPath: /kaniko/.docker
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
resources:
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
volumes:
|
||||
- name: docker-config
|
||||
emptyDir: {}
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- git-clone.yaml
|
||||
- detect-changes.yaml
|
||||
- run-tests.yaml
|
||||
- kaniko-build.yaml
|
||||
- update-gitops.yaml
|
||||
- pipeline-summary.yaml
|
||||
# Production deployment tasks
|
||||
- verify-images.yaml
|
||||
- pre-deploy-validation.yaml
|
||||
- prod-deployment-summary.yaml
|
||||
@@ -1,62 +0,0 @@
|
||||
# Tekton Pipeline Summary Task for Bakery-IA CI/CD
|
||||
# This task runs at the end of the pipeline and provides a summary
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: pipeline-summary
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: summary
|
||||
spec:
|
||||
params:
|
||||
- name: changed-services
|
||||
type: string
|
||||
description: List of changed services
|
||||
default: "none"
|
||||
- name: git-revision
|
||||
type: string
|
||||
description: Git revision that was built
|
||||
default: "unknown"
|
||||
steps:
|
||||
- name: summary
|
||||
image: alpine:3.18
|
||||
script: |
|
||||
#!/bin/sh
|
||||
|
||||
SERVICES="$(params.changed-services)"
|
||||
REVISION="$(params.git-revision)"
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " Pipeline Execution Summary"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "Git Revision: $REVISION"
|
||||
echo "Changed Services: $SERVICES"
|
||||
echo ""
|
||||
echo "Timestamp: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo ""
|
||||
|
||||
if [ "$SERVICES" = "none" ] || [ -z "$SERVICES" ]; then
|
||||
echo "No services were changed in this commit."
|
||||
echo "Pipeline completed without building any images."
|
||||
else
|
||||
echo "The following services were processed:"
|
||||
echo "$SERVICES" | tr ',' '\n' | while read service; do
|
||||
echo " - $service"
|
||||
done
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 32Mi
|
||||
@@ -1,76 +0,0 @@
|
||||
# Task for pre-deployment validation
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: pre-deploy-validation
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: validation
|
||||
spec:
|
||||
workspaces:
|
||||
- name: source
|
||||
description: Source code workspace
|
||||
params:
|
||||
- name: services
|
||||
type: string
|
||||
description: Comma-separated list of services to validate
|
||||
- name: environment
|
||||
type: string
|
||||
description: Target environment (staging/production)
|
||||
default: "production"
|
||||
results:
|
||||
- name: validation-status
|
||||
description: Status of validation (passed/failed)
|
||||
steps:
|
||||
- name: validate
|
||||
image: registry.k8s.io/kustomize/kustomize:v5.3.0
|
||||
script: |
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
SOURCE_PATH="$(workspaces.source.path)"
|
||||
SERVICES="$(params.services)"
|
||||
ENVIRONMENT="$(params.environment)"
|
||||
|
||||
echo "============================================"
|
||||
echo "Pre-Deployment Validation"
|
||||
echo "============================================"
|
||||
echo "Environment: $ENVIRONMENT"
|
||||
echo "Services: $SERVICES"
|
||||
echo "============================================"
|
||||
|
||||
cd "$SOURCE_PATH"
|
||||
|
||||
# Validate kustomization can be built
|
||||
KUSTOMIZE_DIR="infrastructure/environments/$ENVIRONMENT"
|
||||
|
||||
if [ -d "$KUSTOMIZE_DIR" ]; then
|
||||
echo ""
|
||||
echo "Validating kustomization..."
|
||||
if kustomize build "$KUSTOMIZE_DIR" > /dev/null 2>&1; then
|
||||
echo " ✓ Kustomization is valid"
|
||||
else
|
||||
echo " ✗ Kustomization validation failed"
|
||||
echo "failed" > $(results.validation-status.path)
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Additional validation checks can be added here
|
||||
# - Schema validation
|
||||
# - Policy checks (OPA/Gatekeeper)
|
||||
# - Security scanning
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo "All validations passed"
|
||||
echo "============================================"
|
||||
echo "passed" > $(results.validation-status.path)
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 256Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
@@ -1,57 +0,0 @@
|
||||
# Task for production deployment summary
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: prod-deployment-summary
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: summary
|
||||
spec:
|
||||
params:
|
||||
- name: services
|
||||
type: string
|
||||
description: List of deployed services
|
||||
- name: git-revision
|
||||
type: string
|
||||
description: Git revision that was deployed
|
||||
- name: approver
|
||||
type: string
|
||||
description: Name of the approver
|
||||
- name: approval-ticket
|
||||
type: string
|
||||
description: Approval ticket number
|
||||
steps:
|
||||
- name: summary
|
||||
image: alpine:3.18
|
||||
script: |
|
||||
#!/bin/sh
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " Production Deployment Summary"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "Git Revision: $(params.git-revision)"
|
||||
echo "Services: $(params.services)"
|
||||
echo "Approved By: $(params.approver)"
|
||||
echo "Approval Ticket: $(params.approval-ticket)"
|
||||
echo "Timestamp: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "Deployment to production initiated."
|
||||
echo "Flux CD will reconcile the changes."
|
||||
echo ""
|
||||
echo "Monitor deployment status with:"
|
||||
echo " kubectl get kustomization -n flux-system"
|
||||
echo " kubectl get pods -n bakery-ia"
|
||||
echo ""
|
||||
echo "============================================"
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 32Mi
|
||||
@@ -1,205 +0,0 @@
|
||||
# Tekton Test Task for Bakery-IA CI/CD
|
||||
# This task runs unit tests and linting for changed services
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: run-tests
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: test
|
||||
spec:
|
||||
workspaces:
|
||||
- name: source
|
||||
description: Source code workspace
|
||||
params:
|
||||
- name: services
|
||||
type: string
|
||||
description: Comma-separated list of services to test
|
||||
- name: skip-lint
|
||||
type: string
|
||||
description: Skip linting if "true"
|
||||
default: "false"
|
||||
- name: skip-tests
|
||||
type: string
|
||||
description: Skip tests if "true"
|
||||
default: "false"
|
||||
results:
|
||||
- name: test-status
|
||||
description: Overall test status (passed/failed/skipped)
|
||||
- name: tested-services
|
||||
description: List of services that were tested
|
||||
- name: failed-services
|
||||
description: List of services that failed tests
|
||||
steps:
|
||||
- name: run-tests
|
||||
image: python:3.11-slim
|
||||
script: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SOURCE_PATH="$(workspaces.source.path)"
|
||||
SERVICES="$(params.services)"
|
||||
SKIP_LINT="$(params.skip-lint)"
|
||||
SKIP_TESTS="$(params.skip-tests)"
|
||||
|
||||
TESTED_SERVICES=""
|
||||
FAILED_SERVICES=""
|
||||
OVERALL_STATUS="passed"
|
||||
|
||||
cd "$SOURCE_PATH"
|
||||
|
||||
echo "============================================"
|
||||
echo "Running Tests"
|
||||
echo "============================================"
|
||||
echo "Services: $SERVICES"
|
||||
echo "Skip Lint: $SKIP_LINT"
|
||||
echo "Skip Tests: $SKIP_TESTS"
|
||||
echo "============================================"
|
||||
|
||||
# Skip if no services to test
|
||||
if [ "$SERVICES" = "none" ] || [ -z "$SERVICES" ]; then
|
||||
echo "No services to test, skipping..."
|
||||
echo "skipped" > $(results.test-status.path)
|
||||
echo "none" > $(results.tested-services.path)
|
||||
echo "none" > $(results.failed-services.path)
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Install common test dependencies
|
||||
echo ""
|
||||
echo "Installing test dependencies..."
|
||||
pip install --quiet pytest pytest-cov pytest-asyncio ruff mypy 2>/dev/null || true
|
||||
|
||||
# Convert comma-separated list to space-separated
|
||||
SERVICES_LIST=$(echo "$SERVICES" | tr ',' ' ')
|
||||
|
||||
for SERVICE in $SERVICES_LIST; do
|
||||
# Trim whitespace
|
||||
SERVICE=$(echo "$SERVICE" | tr -d ' ')
|
||||
|
||||
# Skip infrastructure changes
|
||||
if [ "$SERVICE" = "infrastructure" ]; then
|
||||
echo "Skipping infrastructure (not testable)"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "--------------------------------------------"
|
||||
echo "Testing service: $SERVICE"
|
||||
echo "--------------------------------------------"
|
||||
|
||||
# Determine service path
|
||||
if [ "$SERVICE" = "frontend" ]; then
|
||||
SERVICE_PATH="$SOURCE_PATH/frontend"
|
||||
elif [ "$SERVICE" = "gateway" ]; then
|
||||
SERVICE_PATH="$SOURCE_PATH/gateway"
|
||||
else
|
||||
SERVICE_PATH="$SOURCE_PATH/services/$SERVICE"
|
||||
fi
|
||||
|
||||
# Check if service exists
|
||||
if [ ! -d "$SERVICE_PATH" ]; then
|
||||
echo "Warning: Service directory not found: $SERVICE_PATH"
|
||||
continue
|
||||
fi
|
||||
|
||||
cd "$SERVICE_PATH"
|
||||
SERVICE_FAILED=false
|
||||
|
||||
# Install service-specific dependencies if requirements.txt exists
|
||||
if [ -f "requirements.txt" ]; then
|
||||
echo "Installing service dependencies..."
|
||||
pip install --quiet -r requirements.txt 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Run linting (ruff)
|
||||
if [ "$SKIP_LINT" != "true" ]; then
|
||||
echo ""
|
||||
echo "Running linter (ruff)..."
|
||||
if [ -d "app" ]; then
|
||||
ruff check app/ --output-format=text 2>&1 || {
|
||||
echo "Linting failed for $SERVICE"
|
||||
SERVICE_FAILED=true
|
||||
}
|
||||
fi
|
||||
fi
|
||||
|
||||
# Run tests
|
||||
if [ "$SKIP_TESTS" != "true" ]; then
|
||||
echo ""
|
||||
echo "Running tests (pytest)..."
|
||||
if [ -d "tests" ]; then
|
||||
pytest tests/ -v --tb=short 2>&1 || {
|
||||
echo "Tests failed for $SERVICE"
|
||||
SERVICE_FAILED=true
|
||||
}
|
||||
elif [ -d "app/tests" ]; then
|
||||
pytest app/tests/ -v --tb=short 2>&1 || {
|
||||
echo "Tests failed for $SERVICE"
|
||||
SERVICE_FAILED=true
|
||||
}
|
||||
else
|
||||
echo "No tests directory found, skipping tests"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Track results
|
||||
if [ -z "$TESTED_SERVICES" ]; then
|
||||
TESTED_SERVICES="$SERVICE"
|
||||
else
|
||||
TESTED_SERVICES="$TESTED_SERVICES,$SERVICE"
|
||||
fi
|
||||
|
||||
if [ "$SERVICE_FAILED" = true ]; then
|
||||
OVERALL_STATUS="failed"
|
||||
if [ -z "$FAILED_SERVICES" ]; then
|
||||
FAILED_SERVICES="$SERVICE"
|
||||
else
|
||||
FAILED_SERVICES="$FAILED_SERVICES,$SERVICE"
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "$SOURCE_PATH"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo "Test Summary"
|
||||
echo "============================================"
|
||||
echo "Tested services: $TESTED_SERVICES"
|
||||
echo "Failed services: $FAILED_SERVICES"
|
||||
echo "Overall status: $OVERALL_STATUS"
|
||||
|
||||
# Write results
|
||||
echo "$OVERALL_STATUS" > $(results.test-status.path)
|
||||
|
||||
if [ -z "$TESTED_SERVICES" ]; then
|
||||
echo "none" > $(results.tested-services.path)
|
||||
else
|
||||
echo "$TESTED_SERVICES" > $(results.tested-services.path)
|
||||
fi
|
||||
|
||||
if [ -z "$FAILED_SERVICES" ]; then
|
||||
echo "none" > $(results.failed-services.path)
|
||||
else
|
||||
echo "$FAILED_SERVICES" > $(results.failed-services.path)
|
||||
fi
|
||||
|
||||
# Exit with error if tests failed
|
||||
if [ "$OVERALL_STATUS" = "failed" ]; then
|
||||
echo ""
|
||||
echo "ERROR: Some tests failed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "All tests passed!"
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 2Gi
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
@@ -1,302 +0,0 @@
|
||||
# Tekton Update GitOps Manifests Task for Bakery-IA CI/CD
|
||||
# This task updates Kubernetes manifests with new image tags using Kustomize
|
||||
# It uses a safer approach than sed for updating image references
|
||||
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: update-gitops
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: gitops
|
||||
spec:
|
||||
workspaces:
|
||||
- name: source
|
||||
description: Source code workspace with Git repository
|
||||
- name: git-credentials
|
||||
description: Git credentials for pushing changes
|
||||
optional: true
|
||||
params:
|
||||
- name: services
|
||||
type: string
|
||||
description: Comma-separated list of services to update
|
||||
- name: registry
|
||||
type: string
|
||||
description: Container registry URL
|
||||
- name: git-revision
|
||||
type: string
|
||||
description: Git revision for image tag
|
||||
- name: git-branch
|
||||
type: string
|
||||
description: Target branch for GitOps updates
|
||||
default: "main"
|
||||
- name: dry-run
|
||||
type: string
|
||||
description: If "true", only show what would be changed without committing
|
||||
default: "false"
|
||||
results:
|
||||
- name: updated-services
|
||||
description: List of services that were updated
|
||||
- name: commit-sha
|
||||
description: Git commit SHA of the update (empty if dry-run)
|
||||
steps:
|
||||
- name: update-manifests
|
||||
# Use alpine with curl to install kustomize
|
||||
image: alpine:3.19
|
||||
script: |
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Install kustomize
|
||||
echo "Installing kustomize..."
|
||||
wget -q "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" -O - | sh
|
||||
mv kustomize /usr/local/bin/
|
||||
echo "Kustomize version: $(kustomize version)"
|
||||
|
||||
SOURCE_PATH="$(workspaces.source.path)"
|
||||
SERVICES="$(params.services)"
|
||||
REGISTRY="$(params.registry)"
|
||||
REVISION="$(params.git-revision)"
|
||||
DRY_RUN="$(params.dry-run)"
|
||||
UPDATED_SERVICES=""
|
||||
|
||||
cd "$SOURCE_PATH"
|
||||
|
||||
echo "============================================"
|
||||
echo "GitOps Manifest Update"
|
||||
echo "============================================"
|
||||
echo "Services: $SERVICES"
|
||||
echo "Registry: $REGISTRY"
|
||||
echo "Revision: $REVISION"
|
||||
echo "Dry Run: $DRY_RUN"
|
||||
echo "============================================"
|
||||
|
||||
# Skip if no services to update
|
||||
if [ "$SERVICES" = "none" ] || [ -z "$SERVICES" ]; then
|
||||
echo "No services to update, skipping..."
|
||||
echo "none" > $(results.updated-services.path)
|
||||
echo "" > $(results.commit-sha.path)
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Define the kustomization directory
|
||||
KUSTOMIZE_DIR="infrastructure/environments/prod"
|
||||
|
||||
# Check if kustomization.yaml exists, create if not
|
||||
if [ ! -f "$KUSTOMIZE_DIR/kustomization.yaml" ]; then
|
||||
echo "Creating kustomization.yaml in $KUSTOMIZE_DIR"
|
||||
mkdir -p "$KUSTOMIZE_DIR"
|
||||
printf '%s\n' \
|
||||
"apiVersion: kustomize.config.k8s.io/v1beta1" \
|
||||
"kind: Kustomization" \
|
||||
"" \
|
||||
"resources:" \
|
||||
" - ../base" \
|
||||
"" \
|
||||
"images: []" \
|
||||
> "$KUSTOMIZE_DIR/kustomization.yaml"
|
||||
fi
|
||||
|
||||
# Convert comma-separated list to space-separated
|
||||
SERVICES_LIST=$(echo "$SERVICES" | tr ',' ' ')
|
||||
|
||||
# Build the images section for kustomization
|
||||
echo ""
|
||||
echo "Updating image references..."
|
||||
|
||||
for SERVICE in $SERVICES_LIST; do
|
||||
# Trim whitespace
|
||||
SERVICE=$(echo "$SERVICE" | tr -d ' ')
|
||||
|
||||
# Skip infrastructure changes
|
||||
if [ "$SERVICE" = "infrastructure" ]; then
|
||||
echo "Skipping infrastructure (not a deployable service)"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "Processing: $SERVICE"
|
||||
|
||||
# Determine the image name based on service
|
||||
NEW_IMAGE="$REGISTRY/bakery/$SERVICE:$REVISION"
|
||||
|
||||
# Use kustomize to set the image
|
||||
# This is safer than sed as it understands the YAML structure
|
||||
cd "$SOURCE_PATH/$KUSTOMIZE_DIR"
|
||||
|
||||
# Check if this service has a deployment
|
||||
SERVICE_DEPLOYMENT=""
|
||||
if [ "$SERVICE" = "frontend" ]; then
|
||||
SERVICE_DEPLOYMENT="frontend"
|
||||
elif [ "$SERVICE" = "gateway" ]; then
|
||||
SERVICE_DEPLOYMENT="gateway"
|
||||
else
|
||||
SERVICE_DEPLOYMENT="$SERVICE-service"
|
||||
fi
|
||||
|
||||
# Update the kustomization with the new image
|
||||
# Using kustomize edit to safely modify the file
|
||||
kustomize edit set image "bakery/$SERVICE=$NEW_IMAGE" 2>/dev/null || \
|
||||
kustomize edit set image "$SERVICE=$NEW_IMAGE" 2>/dev/null || \
|
||||
echo "Note: Could not set image via kustomize edit, will use alternative method"
|
||||
|
||||
# Track updated services
|
||||
if [ -z "$UPDATED_SERVICES" ]; then
|
||||
UPDATED_SERVICES="$SERVICE"
|
||||
else
|
||||
UPDATED_SERVICES="$UPDATED_SERVICES,$SERVICE"
|
||||
fi
|
||||
|
||||
cd "$SOURCE_PATH"
|
||||
done
|
||||
|
||||
# Alternative: Update images in kustomization.yaml directly if kustomize edit didn't work
|
||||
# This creates/updates an images section in the kustomization
|
||||
echo ""
|
||||
echo "Ensuring image overrides in kustomization.yaml..."
|
||||
|
||||
# Create a patch file for image updates
|
||||
IMAGES_FILE="$KUSTOMIZE_DIR/images.yaml"
|
||||
printf '%s\n' \
|
||||
"# Auto-generated by CI/CD pipeline" \
|
||||
"# Commit: $REVISION" \
|
||||
"# Updated: $(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
|
||||
"images:" \
|
||||
> "$IMAGES_FILE"
|
||||
|
||||
for SERVICE in $SERVICES_LIST; do
|
||||
SERVICE=$(echo "$SERVICE" | tr -d ' ')
|
||||
if [ "$SERVICE" != "infrastructure" ]; then
|
||||
printf '%s\n' \
|
||||
" - name: bakery/$SERVICE" \
|
||||
" newName: $REGISTRY/bakery/$SERVICE" \
|
||||
" newTag: \"$REVISION\"" \
|
||||
>> "$IMAGES_FILE"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Generated images.yaml:"
|
||||
cat "$IMAGES_FILE"
|
||||
|
||||
# Validate the kustomization
|
||||
echo ""
|
||||
echo "Validating kustomization..."
|
||||
cd "$SOURCE_PATH/$KUSTOMIZE_DIR"
|
||||
if kustomize build . > /dev/null 2>&1; then
|
||||
echo "Kustomization is valid"
|
||||
else
|
||||
echo "Warning: Kustomization validation failed, but continuing..."
|
||||
fi
|
||||
cd "$SOURCE_PATH"
|
||||
|
||||
# Write results
|
||||
echo "$UPDATED_SERVICES" > $(results.updated-services.path)
|
||||
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo "DRY RUN - Changes not committed"
|
||||
echo "============================================"
|
||||
echo "Would update services: $UPDATED_SERVICES"
|
||||
git diff --stat || true
|
||||
echo "" > $(results.commit-sha.path)
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Committing changes..."
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
|
||||
- name: commit-and-push
|
||||
image: alpine/git:2.43.0
|
||||
script: |
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
SOURCE_PATH="$(workspaces.source.path)"
|
||||
SERVICES="$(params.services)"
|
||||
REVISION="$(params.git-revision)"
|
||||
BRANCH="$(params.git-branch)"
|
||||
DRY_RUN="$(params.dry-run)"
|
||||
|
||||
cd "$SOURCE_PATH"
|
||||
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
echo "Dry run mode - skipping commit"
|
||||
echo "" > $(results.commit-sha.path)
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$SERVICES" = "none" ] || [ -z "$SERVICES" ]; then
|
||||
echo "No services to commit"
|
||||
echo "" > $(results.commit-sha.path)
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if there are changes to commit
|
||||
if git diff --quiet && git diff --cached --quiet; then
|
||||
echo "No changes to commit"
|
||||
echo "" > $(results.commit-sha.path)
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Configure git
|
||||
git config --global user.name "bakery-ia-ci"
|
||||
git config --global user.email "ci@bakery-ia.local"
|
||||
git config --global --add safe.directory "$SOURCE_PATH"
|
||||
|
||||
# Setup git credentials if provided
|
||||
if [ -d "$(workspaces.git-credentials.path)" ]; then
|
||||
if [ -f "$(workspaces.git-credentials.path)/username" ] && [ -f "$(workspaces.git-credentials.path)/password" ]; then
|
||||
GIT_USER=$(cat "$(workspaces.git-credentials.path)/username")
|
||||
GIT_PASS=$(cat "$(workspaces.git-credentials.path)/password")
|
||||
|
||||
# Get the remote URL and inject credentials
|
||||
REMOTE_URL=$(git remote get-url origin)
|
||||
# Handle both http and https
|
||||
if echo "$REMOTE_URL" | grep -q "^http"; then
|
||||
REMOTE_URL=$(echo "$REMOTE_URL" | sed "s|://|://$GIT_USER:$GIT_PASS@|")
|
||||
git remote set-url origin "$REMOTE_URL"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Stage changes
|
||||
git add -A
|
||||
|
||||
# Create commit with detailed message
|
||||
COMMIT_MSG=$(printf 'ci: Update image tags to %s\n\nServices updated: %s\n\nThis commit was automatically generated by the CI/CD pipeline.\nPipeline run triggered by commit: %s' "$REVISION" "$SERVICES" "$REVISION")
|
||||
|
||||
git commit -m "$COMMIT_MSG"
|
||||
|
||||
# Get the commit SHA
|
||||
COMMIT_SHA=$(git rev-parse HEAD)
|
||||
echo "$COMMIT_SHA" > $(results.commit-sha.path)
|
||||
|
||||
echo "Created commit: $COMMIT_SHA"
|
||||
|
||||
# Push changes
|
||||
echo "Pushing to origin/$BRANCH..."
|
||||
git push origin HEAD:"$BRANCH"
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo "GitOps Update Complete"
|
||||
echo "============================================"
|
||||
echo "Commit: $COMMIT_SHA"
|
||||
echo "Branch: $BRANCH"
|
||||
echo "Services: $SERVICES"
|
||||
resources:
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
@@ -1,91 +0,0 @@
|
||||
# Task to verify images exist in the registry before deploying
|
||||
apiVersion: tekton.dev/v1beta1
|
||||
kind: Task
|
||||
metadata:
|
||||
name: verify-images
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: validation
|
||||
spec:
|
||||
params:
|
||||
- name: services
|
||||
type: string
|
||||
description: Comma-separated list of services to verify
|
||||
- name: registry
|
||||
type: string
|
||||
description: Container registry URL
|
||||
- name: git-revision
|
||||
type: string
|
||||
description: Git revision/tag to verify
|
||||
results:
|
||||
- name: verification-status
|
||||
description: Status of image verification (success/failed)
|
||||
- name: missing-images
|
||||
description: List of images that were not found
|
||||
steps:
|
||||
- name: verify
|
||||
image: gcr.io/go-containerregistry/crane:latest
|
||||
script: |
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
SERVICES="$(params.services)"
|
||||
REGISTRY="$(params.registry)"
|
||||
REVISION="$(params.git-revision)"
|
||||
MISSING=""
|
||||
|
||||
echo "============================================"
|
||||
echo "Verifying Images in Registry"
|
||||
echo "============================================"
|
||||
echo "Registry: $REGISTRY"
|
||||
echo "Revision: $REVISION"
|
||||
echo "Services: $SERVICES"
|
||||
echo "============================================"
|
||||
|
||||
# Convert comma-separated list to space-separated
|
||||
SERVICES_LIST=$(echo "$SERVICES" | tr ',' ' ')
|
||||
|
||||
for SERVICE in $SERVICES_LIST; do
|
||||
SERVICE=$(echo "$SERVICE" | tr -d ' ')
|
||||
|
||||
if [ "$SERVICE" = "infrastructure" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
IMAGE="$REGISTRY/bakery/$SERVICE:$REVISION"
|
||||
echo ""
|
||||
echo "Checking: $IMAGE"
|
||||
|
||||
if crane manifest "$IMAGE" > /dev/null 2>&1; then
|
||||
echo " ✓ Found"
|
||||
else
|
||||
echo " ✗ NOT FOUND"
|
||||
if [ -z "$MISSING" ]; then
|
||||
MISSING="$SERVICE"
|
||||
else
|
||||
MISSING="$MISSING,$SERVICE"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
|
||||
if [ -n "$MISSING" ]; then
|
||||
echo "ERROR: Missing images: $MISSING"
|
||||
echo "failed" > $(results.verification-status.path)
|
||||
echo "$MISSING" > $(results.missing-images.path)
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "All images verified successfully"
|
||||
echo "success" > $(results.verification-status.path)
|
||||
echo "none" > $(results.missing-images.path)
|
||||
resources:
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
@@ -1,35 +0,0 @@
|
||||
# Tekton EventListener for Bakery-IA CI/CD
|
||||
# This listener receives webhook events and triggers pipelines
|
||||
|
||||
apiVersion: triggers.tekton.dev/v1beta1
|
||||
kind: EventListener
|
||||
metadata:
|
||||
name: bakery-ia-listener
|
||||
namespace: tekton-pipelines
|
||||
spec:
|
||||
serviceAccountName: tekton-triggers-sa
|
||||
triggers:
|
||||
- name: bakery-ia-gitea-trigger
|
||||
bindings:
|
||||
- ref: bakery-ia-trigger-binding
|
||||
template:
|
||||
ref: bakery-ia-trigger-template
|
||||
# Using CEL interceptor for local development (no TLS/CA bundle required)
|
||||
# The CEL interceptor is built-in and doesn't need external services
|
||||
interceptors:
|
||||
- name: "filter-push-events"
|
||||
ref:
|
||||
name: "cel"
|
||||
params:
|
||||
# Filter for push events from Gitea or GitHub
|
||||
- name: "filter"
|
||||
value: "header.match('X-Gitea-Event', 'push') || header.match('X-GitHub-Event', 'push')"
|
||||
# Add overlays to standardize the payload
|
||||
- name: "overlays"
|
||||
value:
|
||||
- key: "git_url"
|
||||
expression: "body.repository.clone_url"
|
||||
- key: "git_revision"
|
||||
expression: "body.after"
|
||||
- key: "git_branch"
|
||||
expression: "body.ref.split('/')[2]"
|
||||
@@ -1,9 +0,0 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
# NOTE: gitlab-interceptor.yaml removed - uses built-in Tekton Triggers interceptor
|
||||
# The gitlab ClusterInterceptor is provided by Tekton Triggers installation
|
||||
- event-listener.yaml
|
||||
- trigger-template.yaml
|
||||
- trigger-binding.yaml
|
||||
@@ -1,31 +0,0 @@
|
||||
# Tekton TriggerBinding for Bakery-IA CI/CD
|
||||
# This binding extracts parameters from Gitea webhook events
|
||||
#
|
||||
# Note: We use CEL overlay extensions for consistent field access
|
||||
# The EventListener's CEL interceptor creates these extensions:
|
||||
# - extensions.git_url: Repository clone URL
|
||||
# - extensions.git_revision: Commit SHA (from body.after)
|
||||
# - extensions.git_branch: Branch name (extracted from ref)
|
||||
|
||||
apiVersion: triggers.tekton.dev/v1beta1
|
||||
kind: TriggerBinding
|
||||
metadata:
|
||||
name: bakery-ia-trigger-binding
|
||||
namespace: tekton-pipelines
|
||||
labels:
|
||||
app.kubernetes.io/name: bakery-ia-cicd
|
||||
app.kubernetes.io/component: triggers
|
||||
spec:
|
||||
params:
|
||||
# Use CEL overlay extensions for consistent access across Git providers
|
||||
- name: git-repo-url
|
||||
value: $(extensions.git_url)
|
||||
- name: git-revision
|
||||
value: $(extensions.git_revision)
|
||||
- name: git-branch
|
||||
value: $(extensions.git_branch)
|
||||
# Direct body access for fields not in overlays
|
||||
- name: git-repo-name
|
||||
value: $(body.repository.name)
|
||||
- name: git-repo-full-name
|
||||
value: $(body.repository.full_name)
|
||||
Reference in New Issue
Block a user