Add new infra architecture 12
This commit is contained in:
1373
PRODUCTION_DEPLOYMENT_GUIDE.md
Normal file
1373
PRODUCTION_DEPLOYMENT_GUIDE.md
Normal file
File diff suppressed because it is too large
Load Diff
58
Tiltfile
58
Tiltfile
@@ -818,12 +818,54 @@ local_resource(
|
||||
if [ "$CURRENT_FORWARD" != "$UNBOUND_IP" ]; then
|
||||
echo "Updating CoreDNS to forward to Unbound ($UNBOUND_IP)..."
|
||||
|
||||
# Patch CoreDNS ConfigMap
|
||||
kubectl patch configmap coredns -n kube-system --type merge -p "{
|
||||
\"data\": {
|
||||
\"Corefile\": \".:53 {\\n errors\\n health {\\n lameduck 5s\\n }\\n ready\\n kubernetes cluster.local in-addr.arpa ip6.arpa {\\n pods insecure\\n fallthrough in-addr.arpa ip6.arpa\\n ttl 30\\n }\\n prometheus :9153\\n forward . $UNBOUND_IP {\\n max_concurrent 1000\\n }\\n cache 30 {\\n disable success cluster.local\\n disable denial cluster.local\\n }\\n loop\\n reload\\n loadbalance\\n}\\n\"
|
||||
# Change to project root to ensure correct file paths
|
||||
cd /Users/urtzialfaro/Documents/bakery-ia
|
||||
|
||||
# Create a temporary Corefile with the forwarding configuration
|
||||
TEMP_COREFILE=$(mktemp)
|
||||
cat > "$TEMP_COREFILE" << EOF
|
||||
.:53 {
|
||||
errors
|
||||
health {
|
||||
lameduck 5s
|
||||
}
|
||||
}"
|
||||
ready
|
||||
kubernetes cluster.local in-addr.arpa ip6.arpa {
|
||||
pods insecure
|
||||
fallthrough in-addr.arpa ip6.arpa
|
||||
ttl 30
|
||||
}
|
||||
prometheus :9153
|
||||
forward . $UNBOUND_IP {
|
||||
max_concurrent 1000
|
||||
}
|
||||
cache 30 {
|
||||
disable success cluster.local
|
||||
disable denial cluster.local
|
||||
}
|
||||
loop
|
||||
reload
|
||||
loadbalance
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create a complete new configmap YAML with the updated Corefile content
|
||||
cat > /tmp/coredns_updated.yaml << EOF
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: coredns
|
||||
namespace: kube-system
|
||||
data:
|
||||
Corefile: |
|
||||
$(sed 's/^/ /' "$TEMP_COREFILE")
|
||||
EOF
|
||||
|
||||
# Apply the updated configmap
|
||||
kubectl apply -f /tmp/coredns_updated.yaml
|
||||
|
||||
# Clean up the temporary file
|
||||
rm "$TEMP_COREFILE"
|
||||
|
||||
# Restart CoreDNS
|
||||
kubectl rollout restart deployment coredns -n kube-system
|
||||
@@ -887,6 +929,9 @@ local_resource(
|
||||
echo "Environment detected: $ENVIRONMENT"
|
||||
|
||||
# Install Mailu with appropriate values
|
||||
# Ensure we're in the project root directory for correct file paths
|
||||
cd /Users/urtzialfaro/Documents/bakery-ia
|
||||
|
||||
if [ "$ENVIRONMENT" = "dev" ]; then
|
||||
helm upgrade --install mailu mailu/mailu \
|
||||
-n bakery-ia \
|
||||
@@ -912,6 +957,7 @@ local_resource(
|
||||
# =====================================================
|
||||
echo ""
|
||||
echo "Applying Mailu ingress configuration..."
|
||||
cd /Users/urtzialfaro/Documents/bakery-ia
|
||||
kubectl apply -f infrastructure/platform/mail/mailu-helm/mailu-ingress.yaml
|
||||
echo "Mailu ingress applied for mail.bakery-ia.dev"
|
||||
|
||||
@@ -934,7 +980,7 @@ local_resource(
|
||||
echo " IMAP: mail.bakery-ia.dev:993 (SSL/TLS)"
|
||||
echo ""
|
||||
echo "To create admin user:"
|
||||
echo " kubectl exec -it -n bakery-ia deployment/mailu-admin -- flask mailu admin admin bakery-ia.local 'YourPassword123!'"
|
||||
echo " Admin user created automatically via initialAccount feature in Helm values"
|
||||
echo ""
|
||||
echo "To check pod status: kubectl get pods -n bakery-ia | grep mailu"
|
||||
''',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -343,6 +343,11 @@ The platform includes a complete CI/CD pipeline using:
|
||||
|
||||
### Access CI/CD Systems
|
||||
|
||||
**SSH Access to Production VPS:**
|
||||
- **IP Address:** `200.234.233.87`
|
||||
- **Access Method:** SSH with key authentication
|
||||
- **Command:** `ssh -i ~/.ssh/your_private_key.pem root@200.234.233.87`
|
||||
|
||||
**Gitea (Git Server):**
|
||||
- URL: http://gitea.bakery-ia.local (development) or http://gitea.bakewise.ai (production)
|
||||
- Admin panel: http://gitea.bakery-ia.local/admin
|
||||
|
||||
@@ -4,124 +4,185 @@ This directory contains the Helm values and scripts for setting up Gitea as the
|
||||
|
||||
## Features
|
||||
|
||||
- **Automatic Repository Creation**: When Gitea is installed via Helm, it automatically creates a `bakery-ia` repository owned by the admin user.
|
||||
- **Pre-configured Settings**: The repository comes with issues, wiki, pull requests, and projects enabled.
|
||||
- **Easy Setup Script**: A script to push your existing code to the new Gitea repository.
|
||||
- **Automatic Admin User**: Admin user is created automatically from Kubernetes secret
|
||||
- **Automatic Repository Creation**: The `bakery-ia` repository is created via a Kubernetes Job after Gitea starts
|
||||
- **Registry Support**: Container registry enabled for storing Docker images
|
||||
- **Tekton Integration**: Webhook automatically configured if Tekton is installed
|
||||
|
||||
## Installation
|
||||
## Quick Start
|
||||
|
||||
### 1. Install Gitea with Helm
|
||||
### Development
|
||||
|
||||
```bash
|
||||
# Add Gitea Helm repository
|
||||
# 1. Setup secrets and init job (uses default dev password)
|
||||
./infrastructure/cicd/gitea/setup-admin-secret.sh
|
||||
|
||||
# 2. Install Gitea
|
||||
helm repo add gitea https://dl.gitea.io/charts
|
||||
helm repo update
|
||||
helm install gitea gitea/gitea -n gitea -f infrastructure/cicd/gitea/values.yaml
|
||||
|
||||
# Create namespace
|
||||
kubectl create namespace gitea
|
||||
|
||||
# Install Gitea with automatic repository creation
|
||||
helm install gitea gitea/gitea -n gitea \
|
||||
-f infrastructure/cicd/gitea/values.yaml \
|
||||
--set gitea.admin.password=your-secure-password
|
||||
```
|
||||
|
||||
### 2. Wait for Gitea to be ready
|
||||
|
||||
```bash
|
||||
# 3. Wait for everything to be ready
|
||||
kubectl wait --for=condition=ready pod -n gitea -l app.kubernetes.io/name=gitea --timeout=300s
|
||||
|
||||
# 4. Check init job completed
|
||||
kubectl logs -n gitea -l app.kubernetes.io/component=init --tail=50
|
||||
```
|
||||
|
||||
### 3. Push your code to the new repository
|
||||
### Production
|
||||
|
||||
```bash
|
||||
# Set the admin password as environment variable
|
||||
export GITEA_ADMIN_PASSWORD="your-secure-password"
|
||||
# 1. Generate and export secure password
|
||||
export GITEA_ADMIN_PASSWORD=$(openssl rand -base64 32)
|
||||
|
||||
# Run the setup script
|
||||
./infrastructure/cicd/gitea/setup-gitea-repository.sh
|
||||
# 2. Setup secrets with production flag (requires GITEA_ADMIN_PASSWORD)
|
||||
./infrastructure/cicd/gitea/setup-admin-secret.sh --production
|
||||
|
||||
# 3. Install Gitea with production values
|
||||
helm repo add gitea https://dl.gitea.io/charts
|
||||
helm upgrade --install gitea gitea/gitea -n gitea \
|
||||
-f infrastructure/cicd/gitea/values.yaml \
|
||||
-f infrastructure/cicd/gitea/values-prod.yaml
|
||||
|
||||
# 4. Wait for everything to be ready
|
||||
kubectl wait --for=condition=ready pod -n gitea -l app.kubernetes.io/name=gitea --timeout=300s
|
||||
|
||||
# 5. Install Tekton CI/CD (see tekton-helm/README.md for details)
|
||||
export TEKTON_WEBHOOK_TOKEN=$(openssl rand -hex 32)
|
||||
helm upgrade --install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||
-n tekton-pipelines \
|
||||
-f infrastructure/cicd/tekton-helm/values.yaml \
|
||||
-f infrastructure/cicd/tekton-helm/values-prod.yaml \
|
||||
--set secrets.webhook.token=$TEKTON_WEBHOOK_TOKEN \
|
||||
--set secrets.registry.password=$GITEA_ADMIN_PASSWORD \
|
||||
--set secrets.git.password=$GITEA_ADMIN_PASSWORD
|
||||
```
|
||||
|
||||
## Configuration Details
|
||||
## Files
|
||||
|
||||
### Automatic Repository Creation
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `values.yaml` | Helm values for Gitea chart |
|
||||
| `values-prod.yaml` | Production Helm values |
|
||||
| `setup-admin-secret.sh` | Creates secrets and applies init job |
|
||||
| `gitea-init-job.yaml` | Kubernetes Job to create initial repository |
|
||||
| `setup-gitea-repository.sh` | Helper to push local code to Gitea |
|
||||
|
||||
The `values.yaml` file includes the following configuration to automatically create the `bakery-ia` repository:
|
||||
## How It Works
|
||||
|
||||
### 1. Admin User Initialization
|
||||
|
||||
The Gitea Helm chart automatically creates the admin user on first install. Credentials are read from a Kubernetes secret:
|
||||
|
||||
```yaml
|
||||
gitea:
|
||||
initialRepositories:
|
||||
- name: bakery-ia
|
||||
description: "Main repository for Bakery IA project - Automatically created by Helm"
|
||||
private: false
|
||||
auto_init: true
|
||||
default_branch: main
|
||||
owner: "{{ .Values.gitea.admin.username }}"
|
||||
enable_issues: true
|
||||
enable_wiki: true
|
||||
enable_pull_requests: true
|
||||
enable_projects: true
|
||||
admin:
|
||||
username: bakery-admin
|
||||
email: admin@bakery-ia.local
|
||||
existingSecret: gitea-admin-secret # Secret with username/password keys
|
||||
passwordMode: keepUpdated # Sync password changes from secret
|
||||
```
|
||||
|
||||
### Repository Features
|
||||
The `setup-admin-secret.sh` script creates this secret before Helm install.
|
||||
|
||||
The automatically created repository includes:
|
||||
- **Issues**: For tracking bugs and feature requests
|
||||
- **Wiki**: For project documentation
|
||||
- **Pull Requests**: For code review workflow
|
||||
- **Projects**: For project management
|
||||
- **Auto Initialization**: Creates an initial README.md file
|
||||
### 2. Repository Initialization
|
||||
|
||||
Since the Gitea Helm chart doesn't support automatic repository creation, we use a Kubernetes Job (`gitea-init-job.yaml`) that:
|
||||
|
||||
1. Waits for Gitea to be ready
|
||||
2. Creates the `bakery-ia` repository via Gitea API
|
||||
3. Optionally configures a webhook for Tekton CI/CD
|
||||
|
||||
The Job is idempotent - it skips creation if the repository already exists.
|
||||
|
||||
## Detailed Installation
|
||||
|
||||
### Step 1: Create Secrets
|
||||
|
||||
```bash
|
||||
# Using default password (for dev environments)
|
||||
./infrastructure/cicd/gitea/setup-admin-secret.sh
|
||||
|
||||
# Or specify a custom password
|
||||
./infrastructure/cicd/gitea/setup-admin-secret.sh "your-secure-password"
|
||||
|
||||
# Or use environment variable
|
||||
export GITEA_ADMIN_PASSWORD="your-secure-password"
|
||||
./infrastructure/cicd/gitea/setup-admin-secret.sh
|
||||
```
|
||||
|
||||
This creates:
|
||||
- `gitea-admin-secret` in `gitea` namespace - used by Gitea for admin credentials
|
||||
- `gitea-registry-secret` in `bakery-ia` namespace - used for `imagePullSecrets`
|
||||
- Applies `gitea-init-job.yaml` (ConfigMap + Job)
|
||||
|
||||
### Step 2: Install Gitea
|
||||
|
||||
```bash
|
||||
helm repo add gitea https://dl.gitea.io/charts
|
||||
helm repo update
|
||||
|
||||
helm install gitea gitea/gitea -n gitea \
|
||||
-f infrastructure/cicd/gitea/values.yaml
|
||||
```
|
||||
|
||||
### Step 3: Verify Installation
|
||||
|
||||
```bash
|
||||
# Wait for Gitea pod
|
||||
kubectl wait --for=condition=ready pod -n gitea -l app.kubernetes.io/name=gitea --timeout=300s
|
||||
|
||||
# Check init job logs
|
||||
kubectl logs -n gitea job/gitea-init-repo
|
||||
|
||||
# Verify repository was created
|
||||
curl -u bakery-admin:pvYUkGWJijqc0QfIZEXw \
|
||||
https://gitea.bakery-ia.local/api/v1/repos/bakery-admin/bakery-ia
|
||||
```
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
Once the repository is created and your code is pushed, you can configure your CI/CD pipelines to use this repository. The repository URL will be:
|
||||
|
||||
Repository URL:
|
||||
```
|
||||
https://gitea.bakery-ia.local/bakery-admin/bakery-ia.git
|
||||
```
|
||||
|
||||
### Example Tekton Pipeline Configuration
|
||||
|
||||
```yaml
|
||||
# In your Tekton PipelineRun or Task
|
||||
spec:
|
||||
params:
|
||||
- name: git-url
|
||||
value: "https://gitea.bakery-ia.local/bakery-admin/bakery-ia.git"
|
||||
- name: git-revision
|
||||
value: "main"
|
||||
Internal cluster URL (for pipelines):
|
||||
```
|
||||
http://gitea-http.gitea.svc.cluster.local:3000/bakery-admin/bakery-ia.git
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Repository not created
|
||||
### Init Job Failed
|
||||
|
||||
If the repository is not automatically created:
|
||||
1. Check Gitea logs: `kubectl logs -n gitea -l app.kubernetes.io/name=gitea`
|
||||
2. Verify the Helm values were applied correctly
|
||||
3. Manually create the repository using the setup script
|
||||
```bash
|
||||
# Check job status
|
||||
kubectl get jobs -n gitea
|
||||
|
||||
### Authentication issues
|
||||
# View logs
|
||||
kubectl logs -n gitea job/gitea-init-repo
|
||||
|
||||
If you have authentication problems when pushing:
|
||||
1. Verify the admin password is correct
|
||||
2. Check that the Gitea service is accessible
|
||||
3. Ensure your kubeconfig has access to the Gitea namespace
|
||||
# Re-run the job
|
||||
kubectl delete job gitea-init-repo -n gitea
|
||||
kubectl apply -f infrastructure/cicd/gitea/gitea-init-job.yaml
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
### Repository Not Created
|
||||
|
||||
- Always use a strong password for the Gitea admin user
|
||||
- Consider using Kubernetes secrets for sensitive data
|
||||
- The setup script uses basic authentication - for production, consider using SSH keys or tokens
|
||||
1. Check if Gitea is ready: `kubectl get pods -n gitea`
|
||||
2. Check init job logs: `kubectl logs -n gitea job/gitea-init-repo`
|
||||
3. Manually create via API or use `setup-gitea-repository.sh`
|
||||
|
||||
### Authentication Issues
|
||||
|
||||
1. Verify secret exists: `kubectl get secret gitea-admin-secret -n gitea`
|
||||
2. Check credentials: `kubectl get secret gitea-admin-secret -n gitea -o jsonpath='{.data.password}' | base64 -d`
|
||||
|
||||
## Upgrading
|
||||
|
||||
To upgrade Gitea while preserving your repositories:
|
||||
|
||||
```bash
|
||||
helm upgrade gitea gitea/gitea -n gitea \
|
||||
-f infrastructure/cicd/gitea/values.yaml \
|
||||
--set gitea.admin.password=your-secure-password
|
||||
-f infrastructure/cicd/gitea/values.yaml
|
||||
```
|
||||
|
||||
The existing repositories and their contents will be preserved during upgrades.
|
||||
Repositories and data are preserved during upgrades (stored in PVC).
|
||||
176
infrastructure/cicd/gitea/gitea-init-job.yaml
Normal file
176
infrastructure/cicd/gitea/gitea-init-job.yaml
Normal file
@@ -0,0 +1,176 @@
|
||||
# Gitea Initialization Job
|
||||
# This Job runs after Gitea is installed to create the initial repository
|
||||
# It uses the same admin credentials from gitea-admin-secret
|
||||
#
|
||||
# Apply after Gitea is ready:
|
||||
# kubectl apply -f gitea-init-job.yaml -n gitea
|
||||
#
|
||||
# To re-run (if needed):
|
||||
# kubectl delete job gitea-init-repo -n gitea
|
||||
# kubectl apply -f gitea-init-job.yaml -n gitea
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: gitea-init-script
|
||||
namespace: gitea
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea
|
||||
app.kubernetes.io/component: init
|
||||
data:
|
||||
init-repo.sh: |
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
GITEA_URL="http://gitea-http.gitea.svc.cluster.local:3000"
|
||||
REPO_NAME="bakery-ia"
|
||||
MAX_RETRIES=30
|
||||
RETRY_INTERVAL=10
|
||||
|
||||
echo "=== Gitea Repository Initialization ==="
|
||||
echo "Gitea URL: $GITEA_URL"
|
||||
echo "Repository: $REPO_NAME"
|
||||
echo "Admin User: $GITEA_ADMIN_USER"
|
||||
|
||||
# Wait for Gitea to be ready
|
||||
echo ""
|
||||
echo "Waiting for Gitea to be ready..."
|
||||
RETRIES=0
|
||||
until curl -sf "$GITEA_URL/api/v1/version" > /dev/null 2>&1; do
|
||||
RETRIES=$((RETRIES + 1))
|
||||
if [ $RETRIES -ge $MAX_RETRIES ]; then
|
||||
echo "ERROR: Gitea did not become ready after $MAX_RETRIES attempts"
|
||||
exit 1
|
||||
fi
|
||||
echo " Attempt $RETRIES/$MAX_RETRIES - Gitea not ready, waiting ${RETRY_INTERVAL}s..."
|
||||
sleep $RETRY_INTERVAL
|
||||
done
|
||||
echo "Gitea is ready!"
|
||||
|
||||
# Check if repository already exists
|
||||
echo ""
|
||||
echo "Checking if repository '$REPO_NAME' exists..."
|
||||
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-u "$GITEA_ADMIN_USER:$GITEA_ADMIN_PASSWORD" \
|
||||
"$GITEA_URL/api/v1/repos/$GITEA_ADMIN_USER/$REPO_NAME")
|
||||
|
||||
if [ "$HTTP_CODE" = "200" ]; then
|
||||
echo "Repository '$REPO_NAME' already exists. Nothing to do."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create the repository
|
||||
echo "Creating repository '$REPO_NAME'..."
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" \
|
||||
-u "$GITEA_ADMIN_USER:$GITEA_ADMIN_PASSWORD" \
|
||||
-X POST "$GITEA_URL/api/v1/user/repos" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "'"$REPO_NAME"'",
|
||||
"description": "Main repository for Bakery IA project - Automatically created",
|
||||
"private": false,
|
||||
"auto_init": true,
|
||||
"default_branch": "main",
|
||||
"readme": "Default"
|
||||
}')
|
||||
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
|
||||
BODY=$(echo "$RESPONSE" | sed '$d')
|
||||
|
||||
if [ "$HTTP_CODE" = "201" ]; then
|
||||
echo "Repository '$REPO_NAME' created successfully!"
|
||||
echo ""
|
||||
echo "Repository URL: $GITEA_URL/$GITEA_ADMIN_USER/$REPO_NAME"
|
||||
echo "Clone URL: $GITEA_URL/$GITEA_ADMIN_USER/$REPO_NAME.git"
|
||||
else
|
||||
echo "ERROR: Failed to create repository (HTTP $HTTP_CODE)"
|
||||
echo "Response: $BODY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Configure webhook for Tekton (optional - if Tekton is installed)
|
||||
echo ""
|
||||
echo "Checking if Tekton EventListener is available..."
|
||||
TEKTON_URL="http://el-bakery-ia-listener.tekton-pipelines.svc.cluster.local:8080"
|
||||
if curl -sf "$TEKTON_URL" > /dev/null 2>&1; then
|
||||
echo "Tekton EventListener found. Creating webhook..."
|
||||
WEBHOOK_RESPONSE=$(curl -s -w "\n%{http_code}" \
|
||||
-u "$GITEA_ADMIN_USER:$GITEA_ADMIN_PASSWORD" \
|
||||
-X POST "$GITEA_URL/api/v1/repos/$GITEA_ADMIN_USER/$REPO_NAME/hooks" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"type": "gitea",
|
||||
"config": {
|
||||
"url": "'"$TEKTON_URL"'",
|
||||
"content_type": "json"
|
||||
},
|
||||
"events": ["push"],
|
||||
"active": true
|
||||
}')
|
||||
|
||||
WEBHOOK_CODE=$(echo "$WEBHOOK_RESPONSE" | tail -1)
|
||||
if [ "$WEBHOOK_CODE" = "201" ]; then
|
||||
echo "Webhook created successfully!"
|
||||
else
|
||||
echo "Warning: Could not create webhook (HTTP $WEBHOOK_CODE). You may need to configure it manually."
|
||||
fi
|
||||
else
|
||||
echo "Tekton EventListener not available. Skipping webhook creation."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Initialization Complete ==="
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: gitea-init-repo
|
||||
namespace: gitea
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea
|
||||
app.kubernetes.io/component: init
|
||||
annotations:
|
||||
# Helm hook annotations (if used with Helm)
|
||||
helm.sh/hook: post-install,post-upgrade
|
||||
helm.sh/hook-weight: "10"
|
||||
helm.sh/hook-delete-policy: before-hook-creation
|
||||
spec:
|
||||
ttlSecondsAfterFinished: 300
|
||||
backoffLimit: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea
|
||||
app.kubernetes.io/component: init
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
containers:
|
||||
- name: init-repo
|
||||
image: curlimages/curl:8.5.0
|
||||
command: ["/bin/sh", "/scripts/init-repo.sh"]
|
||||
env:
|
||||
- name: GITEA_ADMIN_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-admin-secret
|
||||
key: username
|
||||
- name: GITEA_ADMIN_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-admin-secret
|
||||
key: password
|
||||
volumeMounts:
|
||||
- name: init-script
|
||||
mountPath: /scripts
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 32Mi
|
||||
volumes:
|
||||
- name: init-script
|
||||
configMap:
|
||||
name: gitea-init-script
|
||||
defaultMode: 0755
|
||||
@@ -1,41 +1,86 @@
|
||||
#!/bin/bash
|
||||
# Setup Gitea Admin Secret
|
||||
# Setup Gitea Admin Secret and Initialize Gitea
|
||||
#
|
||||
# This script creates TWO Kubernetes secrets:
|
||||
# 1. gitea-admin-secret (gitea namespace) - Used by Gitea Helm chart for admin credentials
|
||||
# 2. gitea-registry-secret (bakery-ia namespace) - Used by pods for imagePullSecrets
|
||||
#
|
||||
# Both secrets use the SAME credentials, ensuring consistency.
|
||||
# This script:
|
||||
# 1. Creates gitea-admin-secret (gitea namespace) - Used by Gitea Helm chart for admin credentials
|
||||
# 2. Creates gitea-registry-secret (bakery-ia namespace) - Used by pods for imagePullSecrets
|
||||
# 3. Applies the gitea-init-job.yaml to create the initial repository
|
||||
#
|
||||
# Usage:
|
||||
# ./setup-admin-secret.sh [password]
|
||||
# Development:
|
||||
# ./setup-admin-secret.sh # Uses default dev password
|
||||
# ./setup-admin-secret.sh [password] # Uses provided password
|
||||
# ./setup-admin-secret.sh --secrets-only # Only create secrets, skip init job
|
||||
#
|
||||
# If password is not provided, a random one will be generated.
|
||||
# Production:
|
||||
# export GITEA_ADMIN_PASSWORD=$(openssl rand -base64 32)
|
||||
# ./setup-admin-secret.sh --production
|
||||
# ./setup-admin-secret.sh --production --secrets-only
|
||||
#
|
||||
# Environment variables:
|
||||
# GITEA_ADMIN_PASSWORD - Password to use (required for --production)
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
KUBECTL="kubectl"
|
||||
GITEA_NAMESPACE="gitea"
|
||||
BAKERY_NAMESPACE="bakery-ia"
|
||||
REGISTRY_HOST="registry.bakery-ia.local"
|
||||
ADMIN_USERNAME="bakery-admin"
|
||||
# Static password for consistent dev environment setup
|
||||
# This ensures the same credentials work across environment recreations
|
||||
STATIC_ADMIN_PASSWORD="pvYUkGWJijqc0QfIZEXw"
|
||||
# Default password for dev environment only
|
||||
# For PRODUCTION: Always set GITEA_ADMIN_PASSWORD environment variable
|
||||
# Generate secure password with: openssl rand -base64 32
|
||||
DEV_DEFAULT_PASSWORD="pvYUkGWJijqc0QfIZEXw"
|
||||
SECRETS_ONLY=false
|
||||
IS_PRODUCTION=false
|
||||
|
||||
# Check if running in microk8s
|
||||
if command -v microk8s &> /dev/null; then
|
||||
KUBECTL="microk8s kubectl"
|
||||
fi
|
||||
|
||||
# Get password from argument, environment variable, or use static default
|
||||
if [ -n "$1" ]; then
|
||||
ADMIN_PASSWORD="$1"
|
||||
elif [ -n "$GITEA_ADMIN_PASSWORD" ]; then
|
||||
# Parse arguments
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--secrets-only)
|
||||
SECRETS_ONLY=true
|
||||
;;
|
||||
--production)
|
||||
IS_PRODUCTION=true
|
||||
REGISTRY_HOST="registry.bakewise.ai"
|
||||
;;
|
||||
*)
|
||||
if [ -z "$ADMIN_PASSWORD" ] && [ "$arg" != "--secrets-only" ] && [ "$arg" != "--production" ]; then
|
||||
ADMIN_PASSWORD="$arg"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Get password from argument, environment variable, or use default (dev only)
|
||||
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||
if [ -n "$GITEA_ADMIN_PASSWORD" ]; then
|
||||
ADMIN_PASSWORD="$GITEA_ADMIN_PASSWORD"
|
||||
echo "Using password from GITEA_ADMIN_PASSWORD environment variable"
|
||||
elif [ "$IS_PRODUCTION" = true ]; then
|
||||
echo "ERROR: Production deployment requires GITEA_ADMIN_PASSWORD environment variable"
|
||||
echo "Generate a secure password with: openssl rand -base64 32"
|
||||
echo ""
|
||||
echo "Usage for production:"
|
||||
echo " export GITEA_ADMIN_PASSWORD=\$(openssl rand -base64 32)"
|
||||
echo " ./setup-admin-secret.sh --production"
|
||||
exit 1
|
||||
else
|
||||
ADMIN_PASSWORD="$STATIC_ADMIN_PASSWORD"
|
||||
echo "Using static admin password for dev environment consistency"
|
||||
ADMIN_PASSWORD="$DEV_DEFAULT_PASSWORD"
|
||||
echo "WARNING: Using default dev password. For production, set GITEA_ADMIN_PASSWORD"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate password strength for production
|
||||
if [ "$IS_PRODUCTION" = true ] && [ ${#ADMIN_PASSWORD} -lt 16 ]; then
|
||||
echo "ERROR: Production password must be at least 16 characters"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create namespaces if they don't exist
|
||||
@@ -103,9 +148,15 @@ echo "=========================================="
|
||||
echo "Gitea secrets created successfully!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Credentials (same for both secrets):"
|
||||
echo "Environment: $([ "$IS_PRODUCTION" = true ] && echo "PRODUCTION" || echo "Development")"
|
||||
echo ""
|
||||
echo "Credentials:"
|
||||
echo " Username: $ADMIN_USERNAME"
|
||||
if [ "$IS_PRODUCTION" = true ]; then
|
||||
echo " Password: (stored in secret, not displayed for security)"
|
||||
else
|
||||
echo " Password: $ADMIN_PASSWORD"
|
||||
fi
|
||||
echo ""
|
||||
echo "Secrets created:"
|
||||
echo " 1. gitea-admin-secret (namespace: $GITEA_NAMESPACE) - For Gitea Helm chart"
|
||||
@@ -115,5 +166,44 @@ echo "Registry URLs:"
|
||||
echo " External: https://$REGISTRY_HOST"
|
||||
echo " Internal: $INTERNAL_REGISTRY_HOST"
|
||||
echo ""
|
||||
echo "Now install Gitea with:"
|
||||
|
||||
# Apply the init job ConfigMap and Job (but Job won't run until Gitea is installed)
|
||||
if [ "$SECRETS_ONLY" = false ]; then
|
||||
INIT_JOB_FILE="$SCRIPT_DIR/gitea-init-job.yaml"
|
||||
if [ -f "$INIT_JOB_FILE" ]; then
|
||||
echo "Applying Gitea initialization resources..."
|
||||
$KUBECTL apply -f "$INIT_JOB_FILE"
|
||||
echo ""
|
||||
echo "Init job will create the 'bakery-ia' repository once Gitea is ready."
|
||||
else
|
||||
echo "Warning: gitea-init-job.yaml not found at $INIT_JOB_FILE"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "Next steps:"
|
||||
if [ "$IS_PRODUCTION" = true ]; then
|
||||
echo " 1. Install Gitea for production:"
|
||||
echo " helm upgrade --install gitea gitea/gitea -n gitea \\"
|
||||
echo " -f infrastructure/cicd/gitea/values.yaml \\"
|
||||
echo " -f infrastructure/cicd/gitea/values-prod.yaml"
|
||||
echo ""
|
||||
echo " 2. Install Tekton CI/CD for production:"
|
||||
echo " export TEKTON_WEBHOOK_TOKEN=\$(openssl rand -hex 32)"
|
||||
echo " helm upgrade --install tekton-cicd infrastructure/cicd/tekton-helm \\"
|
||||
echo " -n tekton-pipelines \\"
|
||||
echo " -f infrastructure/cicd/tekton-helm/values.yaml \\"
|
||||
echo " -f infrastructure/cicd/tekton-helm/values-prod.yaml \\"
|
||||
echo " --set secrets.webhook.token=\$TEKTON_WEBHOOK_TOKEN \\"
|
||||
echo " --set secrets.registry.password=\$GITEA_ADMIN_PASSWORD \\"
|
||||
echo " --set secrets.git.password=\$GITEA_ADMIN_PASSWORD"
|
||||
else
|
||||
echo " 1. Install Gitea (if not already installed):"
|
||||
echo " helm install gitea gitea/gitea -n gitea -f infrastructure/cicd/gitea/values.yaml"
|
||||
fi
|
||||
echo ""
|
||||
echo " $([ "$IS_PRODUCTION" = true ] && echo "3" || echo "2"). Wait for Gitea to be ready:"
|
||||
echo " kubectl wait --for=condition=ready pod -n gitea -l app.kubernetes.io/name=gitea --timeout=300s"
|
||||
echo ""
|
||||
echo " $([ "$IS_PRODUCTION" = true ] && echo "4" || echo "3"). Check init job status:"
|
||||
echo " kubectl logs -n gitea -l app.kubernetes.io/component=init --tail=50"
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
# Gitea Helm values configuration for Bakery-IA CI/CD
|
||||
# This configuration sets up Gitea with registry support and appropriate storage
|
||||
#
|
||||
# Prerequisites:
|
||||
# 1. Run setup-admin-secret.sh to create the gitea-admin-secret
|
||||
# 2. Apply the post-install job: kubectl apply -f gitea-init-job.yaml
|
||||
#
|
||||
# Installation:
|
||||
# helm repo add gitea https://dl.gitea.io/charts
|
||||
# kubectl create namespace gitea
|
||||
# helm install gitea gitea/gitea -n gitea -f infrastructure/cicd/gitea/values.yaml
|
||||
#
|
||||
# NOTE: The namespace is determined by the -n flag during helm install, not in this file.
|
||||
@@ -43,22 +46,6 @@ ingress:
|
||||
hosts:
|
||||
- gitea.bakery-ia.local
|
||||
- registry.bakery-ia.local
|
||||
# Additional ingress for container registry (same backend, different hostname)
|
||||
apiIngress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "500m"
|
||||
hosts:
|
||||
- host: registry.bakery-ia.local
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: bakery-dev-tls-cert
|
||||
hosts:
|
||||
- registry.bakery-ia.local
|
||||
|
||||
persistence:
|
||||
enabled: true
|
||||
@@ -68,39 +55,44 @@ persistence:
|
||||
# For Kind: leave empty or use "standard"
|
||||
storageClass: ""
|
||||
|
||||
# =============================================================================
|
||||
# ADMIN USER CONFIGURATION
|
||||
# =============================================================================
|
||||
# The admin user is automatically created on first install.
|
||||
# Credentials are read from the 'gitea-admin-secret' Kubernetes secret.
|
||||
#
|
||||
# Create the secret BEFORE installing Gitea:
|
||||
# ./setup-admin-secret.sh
|
||||
#
|
||||
# The secret must contain:
|
||||
# - username: admin username (default: bakery-admin)
|
||||
# - password: admin password
|
||||
# =============================================================================
|
||||
gitea:
|
||||
admin:
|
||||
username: bakery-admin
|
||||
# IMPORTANT: Override this with --set gitea.admin.password=<secure-password>
|
||||
# or use existingSecret
|
||||
password: ""
|
||||
email: admin@bakery-ia.local
|
||||
# Use existing secret for admin credentials (created by setup-admin-secret.sh)
|
||||
existingSecret: gitea-admin-secret
|
||||
# keepUpdated ensures password changes in secret are applied
|
||||
passwordMode: keepUpdated
|
||||
|
||||
config:
|
||||
server:
|
||||
DOMAIN: gitea.bakery-ia.local
|
||||
SSH_DOMAIN: gitea.bakery-ia.local
|
||||
SSH_PORT: 2222
|
||||
# Use HTTPS for external access; TLS termination happens at ingress
|
||||
ROOT_URL: https://gitea.bakery-ia.local
|
||||
HTTP_PORT: 3000
|
||||
# Enable package registry
|
||||
PACKAGES_ENABLED: true
|
||||
# Disable built-in HTTPS since ingress handles TLS
|
||||
PROTOCOL: http
|
||||
repository:
|
||||
ENABLE_PUSH_CREATE_USER: true
|
||||
ENABLE_PUSH_CREATE_ORG: true
|
||||
DEFAULT_BRANCH: main
|
||||
packages:
|
||||
ENABLED: true
|
||||
registry:
|
||||
ENABLE: true
|
||||
ROOT: /var/lib/gitea-registry
|
||||
STORAGE_TYPE: local
|
||||
# NOTE: PORT config here is internal - registry is accessed via HTTP port on /v2/ path
|
||||
# Additional registry configuration for proper external access
|
||||
docker:
|
||||
ENABLE: true
|
||||
REGISTRY_SSL_REDIRECT: false # SSL termination happens at ingress
|
||||
webhook:
|
||||
ALLOWED_HOST_LIST: "*"
|
||||
# Allow internal cluster URLs for Tekton EventListener
|
||||
@@ -109,21 +101,6 @@ gitea:
|
||||
DISABLE_REGISTRATION: false
|
||||
REQUIRE_SIGNIN_VIEW: false
|
||||
|
||||
# Initial repositories to create automatically after Gitea installation
|
||||
# These will be created with the admin user as owner
|
||||
initialRepositories:
|
||||
- name: bakery-ia
|
||||
description: "Main repository for Bakery IA project - Automatically created by Helm"
|
||||
private: false
|
||||
auto_init: true
|
||||
default_branch: main
|
||||
owner: "{{ .Values.gitea.admin.username }}"
|
||||
# Enable issues, wiki, and other features
|
||||
enable_issues: true
|
||||
enable_wiki: true
|
||||
enable_pull_requests: true
|
||||
enable_projects: true
|
||||
|
||||
# Use embedded SQLite for simpler local development
|
||||
# For production, enable postgresql
|
||||
postgresql:
|
||||
|
||||
@@ -18,10 +18,30 @@ kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/
|
||||
|
||||
Then install the chart:
|
||||
|
||||
### Development Installation
|
||||
|
||||
```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
|
||||
helm install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||
--namespace tekton-pipelines \
|
||||
--create-namespace
|
||||
```
|
||||
|
||||
### Production Installation
|
||||
|
||||
**Important**: Never use default secrets in production. Always provide secure credentials.
|
||||
|
||||
```bash
|
||||
# Generate secure webhook token
|
||||
export TEKTON_WEBHOOK_TOKEN=$(openssl rand -hex 32)
|
||||
|
||||
# Use the same password as Gitea admin (from GITEA_ADMIN_PASSWORD)
|
||||
helm upgrade --install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||
-n tekton-pipelines \
|
||||
-f infrastructure/cicd/tekton-helm/values.yaml \
|
||||
-f infrastructure/cicd/tekton-helm/values-prod.yaml \
|
||||
--set secrets.webhook.token=$TEKTON_WEBHOOK_TOKEN \
|
||||
--set secrets.registry.password=$GITEA_ADMIN_PASSWORD \
|
||||
--set secrets.git.password=$GITEA_ADMIN_PASSWORD
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -65,7 +65,8 @@ spec:
|
||||
git config --global user.name "bakery-ia-ci"
|
||||
|
||||
# Clone the main repository (not a separate gitops repo)
|
||||
REPO_URL="https://${GIT_USERNAME}:${GIT_PASSWORD}@gitea.bakery-ia.local/bakery-admin/bakery-ia.git"
|
||||
# Use internal cluster DNS which works in all environments
|
||||
REPO_URL="https://${GIT_USERNAME}:${GIT_PASSWORD}@gitea-http.gitea.svc.cluster.local:3000/bakery-admin/bakery-ia.git"
|
||||
git clone "$REPO_URL" /tmp/gitops
|
||||
|
||||
cd /tmp/gitops
|
||||
|
||||
81
infrastructure/cicd/tekton-helm/values-prod.yaml
Normal file
81
infrastructure/cicd/tekton-helm/values-prod.yaml
Normal file
@@ -0,0 +1,81 @@
|
||||
# Production values for tekton-cicd Helm chart
|
||||
# This file overrides values.yaml for production deployment
|
||||
#
|
||||
# Installation:
|
||||
# helm upgrade --install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||
# -n tekton-pipelines \
|
||||
# -f infrastructure/cicd/tekton-helm/values.yaml \
|
||||
# -f infrastructure/cicd/tekton-helm/values-prod.yaml \
|
||||
# --set secrets.webhook.token=$TEKTON_WEBHOOK_TOKEN \
|
||||
# --set secrets.registry.password=$GITEA_ADMIN_PASSWORD \
|
||||
# --set secrets.git.password=$GITEA_ADMIN_PASSWORD
|
||||
#
|
||||
# Required environment variables:
|
||||
# TEKTON_WEBHOOK_TOKEN - Secure webhook token (generate with: openssl rand -hex 32)
|
||||
# GITEA_ADMIN_PASSWORD - Gitea admin password (must match gitea-admin-secret)
|
||||
|
||||
# Global settings for production
|
||||
global:
|
||||
# Git configuration
|
||||
git:
|
||||
userEmail: "ci@bakewise.ai"
|
||||
|
||||
# Pipeline configuration for production
|
||||
pipeline:
|
||||
# Build configuration
|
||||
build:
|
||||
verbosity: "warn" # Less verbose in production
|
||||
|
||||
# Test configuration
|
||||
test:
|
||||
skipTests: "false"
|
||||
skipLint: "false"
|
||||
|
||||
# Workspace configuration - ensure storage class exists in production cluster
|
||||
workspace:
|
||||
size: "10Gi"
|
||||
storageClass: "standard" # Adjust to your production storage class
|
||||
|
||||
# Tekton controller settings - increased resources for production
|
||||
controller:
|
||||
replicas: 2
|
||||
resources:
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 2Gi
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
|
||||
# Tekton webhook settings - increased resources for production
|
||||
webhook:
|
||||
replicas: 2
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
|
||||
# Secrets configuration
|
||||
# IMPORTANT: These MUST be overridden via --set flags during deployment
|
||||
# DO NOT commit actual secrets to this file
|
||||
secrets:
|
||||
# Webhook secret for validating incoming webhooks
|
||||
# Override with: --set secrets.webhook.token=$TEKTON_WEBHOOK_TOKEN
|
||||
webhook:
|
||||
token: "" # MUST be set via --set flag
|
||||
|
||||
# Registry credentials for pushing images
|
||||
# Override with: --set secrets.registry.password=$GITEA_ADMIN_PASSWORD
|
||||
registry:
|
||||
username: "bakery-admin"
|
||||
password: "" # MUST be set via --set flag
|
||||
registryUrl: "gitea-http.gitea.svc.cluster.local:3000"
|
||||
|
||||
# Git credentials for GitOps updates
|
||||
# Override with: --set secrets.git.password=$GITEA_ADMIN_PASSWORD
|
||||
git:
|
||||
username: "bakery-admin"
|
||||
password: "" # MUST be set via --set flag
|
||||
@@ -3,33 +3,61 @@
|
||||
# This secret stores Mailgun credentials for outbound email relay.
|
||||
# Mailu uses Mailgun as an external SMTP relay to send all outbound emails.
|
||||
#
|
||||
# ============================================================================
|
||||
# HOW TO CONFIGURE:
|
||||
# ============================================================================
|
||||
#
|
||||
# 1. Go to https://www.mailgun.com and create an account
|
||||
# 2. Add and verify your domain (e.g., bakery-ia.dev or bakewise.ai)
|
||||
# 3. Go to Domain Settings > SMTP credentials
|
||||
#
|
||||
# 2. Add and verify your domain:
|
||||
# - For dev: bakery-ia.dev
|
||||
# - For prod: bakewise.ai
|
||||
#
|
||||
# 3. Go to Domain Settings > SMTP credentials in Mailgun dashboard
|
||||
#
|
||||
# 4. Note your SMTP credentials:
|
||||
# - SMTP hostname: smtp.mailgun.org
|
||||
# - Port: 587 (TLS)
|
||||
# - Username: usually postmaster@yourdomain.com
|
||||
# - Password: your Mailgun SMTP password (NOT API key)
|
||||
# 5. Base64 encode your password:
|
||||
# - Port: 587 (TLS/STARTTLS)
|
||||
# - Username: typically postmaster@yourdomain.com
|
||||
# - Password: your Mailgun SMTP password (NOT the API key)
|
||||
#
|
||||
# 5. Base64 encode your credentials:
|
||||
# echo -n 'postmaster@bakewise.ai' | base64
|
||||
# echo -n 'your-mailgun-smtp-password' | base64
|
||||
# 6. Replace MAILGUN_SMTP_PASSWORD_BASE64 below with the encoded value
|
||||
#
|
||||
# 6. Replace the placeholder values below with your encoded credentials
|
||||
#
|
||||
# 7. Apply this secret:
|
||||
# kubectl apply -f mailgun-credentials-secret.yaml -n bakery-ia
|
||||
#
|
||||
# ============================================================================
|
||||
# IMPORTANT NOTES:
|
||||
# - Use the SMTP password from Mailgun, not the API key
|
||||
# - The username is typically postmaster@yourdomain.com
|
||||
# - For sandbox domains, Mailgun requires authorized recipients
|
||||
# - Production domains need DNS verification (SPF, DKIM, MX records)
|
||||
# ============================================================================
|
||||
#
|
||||
# - Use the SMTP password from Mailgun, NOT the API key
|
||||
# - The username format is: postmaster@yourdomain.com
|
||||
# - For sandbox domains, Mailgun requires adding authorized recipients
|
||||
# - Production domains need DNS verification (SPF, DKIM records)
|
||||
#
|
||||
# ============================================================================
|
||||
# DNS RECORDS REQUIRED FOR MAILGUN:
|
||||
# You will need to add these DNS records for your domain:
|
||||
# - SPF: TXT record for email authentication
|
||||
# - DKIM: TXT records for email signing (Mailgun provides these)
|
||||
# - MX: If you want to receive emails via Mailgun (optional for relay-only)
|
||||
# ============================================================================
|
||||
#
|
||||
# Add these DNS records to your domain for proper email delivery:
|
||||
#
|
||||
# 1. SPF Record (TXT):
|
||||
# Name: @
|
||||
# Value: v=spf1 include:mailgun.org ~all
|
||||
#
|
||||
# 2. DKIM Records (TXT):
|
||||
# Mailgun will provide two DKIM keys to add as TXT records
|
||||
# (check your Mailgun domain settings for exact values)
|
||||
#
|
||||
# 3. MX Records (optional, only if receiving via Mailgun):
|
||||
# Priority 10: mxa.mailgun.org
|
||||
# Priority 10: mxb.mailgun.org
|
||||
#
|
||||
# ============================================================================
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
@@ -39,39 +67,28 @@ metadata:
|
||||
labels:
|
||||
app: mailu
|
||||
component: external-relay
|
||||
annotations:
|
||||
description: "Mailgun SMTP credentials for Mailu external relay"
|
||||
type: Opaque
|
||||
data:
|
||||
# Base64 encoded Mailgun SMTP password
|
||||
# To encode: echo -n 'your-password' | base64
|
||||
# To decode: echo 'encoded-value' | base64 -d
|
||||
RELAY_PASSWORD: MAILGUN_SMTP_PASSWORD_BASE64
|
||||
---
|
||||
# Development environment secret (separate for different Mailgun domain)
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: mailu-mailgun-credentials-dev
|
||||
namespace: bakery-ia
|
||||
labels:
|
||||
app: mailu
|
||||
component: external-relay
|
||||
environment: dev
|
||||
type: Opaque
|
||||
data:
|
||||
# Mailgun credentials for bakery-ia.dev domain
|
||||
RELAY_PASSWORD: MAILGUN_DEV_SMTP_PASSWORD_BASE64
|
||||
---
|
||||
# Production environment secret
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: mailu-mailgun-credentials-prod
|
||||
namespace: bakery-ia
|
||||
labels:
|
||||
app: mailu
|
||||
component: external-relay
|
||||
environment: prod
|
||||
type: Opaque
|
||||
data:
|
||||
# Mailgun credentials for bakewise.ai domain
|
||||
RELAY_PASSWORD: MAILGUN_PROD_SMTP_PASSWORD_BASE64
|
||||
stringData:
|
||||
# ============================================================================
|
||||
# REPLACE THESE VALUES WITH YOUR MAILGUN CREDENTIALS
|
||||
# ============================================================================
|
||||
#
|
||||
# Option 1: Use stringData (plain text - Kubernetes will encode automatically)
|
||||
# This is easier for initial setup but shows credentials in the file
|
||||
#
|
||||
RELAY_USERNAME: "postmaster@sandboxc1bff891532b4f0c83056a68ae080b4c.mailgun.org"
|
||||
RELAY_PASSWORD: "2e47104abadad8eb820d00042ea6d5eb-77c6c375-89c7ea55"
|
||||
#
|
||||
# ============================================================================
|
||||
# ALTERNATIVE: Use pre-encoded values (more secure for version control)
|
||||
# ============================================================================
|
||||
# Comment out stringData above and uncomment data below:
|
||||
#
|
||||
# data:
|
||||
# # Base64 encoded values
|
||||
# # echo -n 'postmaster@bakewise.ai' | base64
|
||||
# RELAY_USERNAME: cG9zdG1hc3RlckBiYWtld2lzZS5haQ==
|
||||
# # echo -n 'your-password' | base64
|
||||
# RELAY_PASSWORD: WU9VUl9NQUlMR1VOX1NNVFBfUEFTU1dPUkQ=
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Mailu Admin Credentials Secret
|
||||
# This secret stores the initial admin account password for Mailu
|
||||
#
|
||||
# The password is used by the Helm chart's initialAccount feature to create
|
||||
# the admin user automatically during deployment.
|
||||
#
|
||||
# IMPORTANT: Replace the base64-encoded password before applying!
|
||||
#
|
||||
# To generate a secure password and encode it:
|
||||
# PASSWORD=$(openssl rand -base64 16 | tr -d '/+=' | head -c 16)
|
||||
# echo -n "$PASSWORD" | base64
|
||||
#
|
||||
# To apply this secret:
|
||||
# kubectl apply -f mailu-admin-credentials-secret.yaml -n bakery-ia
|
||||
#
|
||||
# After deployment, you can log in to the Mailu admin panel at:
|
||||
# https://mail.<domain>/admin
|
||||
# Username: admin@<domain>
|
||||
# Password: <the password you set>
|
||||
#
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: mailu-admin-credentials
|
||||
namespace: bakery-ia
|
||||
labels:
|
||||
app.kubernetes.io/name: mailu
|
||||
app.kubernetes.io/component: admin
|
||||
type: Opaque
|
||||
data:
|
||||
# Base64-encoded password
|
||||
# Example: "changeme123" = Y2hhbmdlbWUxMjM=
|
||||
# IMPORTANT: Replace with your own secure password!
|
||||
password: "Y2hhbmdlbWUxMjM="
|
||||
@@ -36,17 +36,29 @@ domain: "bakery-ia.dev"
|
||||
hostnames:
|
||||
- "mail.bakery-ia.dev"
|
||||
|
||||
# Initial admin account for dev environment
|
||||
# Password is stored in mailu-admin-credentials secret
|
||||
initialAccount:
|
||||
enabled: true
|
||||
username: "admin"
|
||||
domain: "bakery-ia.dev"
|
||||
existingSecret: "mailu-admin-credentials"
|
||||
existingSecretPasswordKey: "password"
|
||||
mode: "ifmissing"
|
||||
|
||||
# External relay configuration for dev (Mailgun)
|
||||
# All outbound emails will be relayed through Mailgun SMTP
|
||||
# To configure:
|
||||
# 1. Register at mailgun.com and verify your domain (bakery-ia.dev)
|
||||
# 2. Get your SMTP credentials from Mailgun dashboard
|
||||
# 3. Update the secret in configs/mailgun-credentials-secret.yaml
|
||||
# 4. Apply the secret: kubectl apply -f configs/mailgun-credentials-secret.yaml
|
||||
# 4. Apply the secret: kubectl apply -f configs/mailgun-credentials-secret.yaml -n bakery-ia
|
||||
externalRelay:
|
||||
host: "[smtp.mailgun.org]:587"
|
||||
username: "postmaster@bakery-ia.dev" # Your Mailgun SMTP username (usually postmaster@yourdomain)
|
||||
password: "" # Will be loaded from secret - see configs/mailgun-credentials-secret.yaml
|
||||
# Credentials loaded from Kubernetes secret
|
||||
secretName: "mailu-mailgun-credentials"
|
||||
usernameKey: "RELAY_USERNAME"
|
||||
passwordKey: "RELAY_PASSWORD"
|
||||
|
||||
# Environment-specific configurations
|
||||
persistence:
|
||||
@@ -92,6 +104,13 @@ resources:
|
||||
limits:
|
||||
cpu: "200m"
|
||||
memory: "128Mi"
|
||||
webmail:
|
||||
requests:
|
||||
cpu: "50m"
|
||||
memory: "64Mi"
|
||||
limits:
|
||||
cpu: "200m"
|
||||
memory: "128Mi"
|
||||
clamav:
|
||||
requests:
|
||||
cpu: "100m"
|
||||
|
||||
@@ -21,17 +21,29 @@ domain: "bakewise.ai"
|
||||
hostnames:
|
||||
- "mail.bakewise.ai"
|
||||
|
||||
# Initial admin account for production environment
|
||||
# Password is stored in mailu-admin-credentials secret
|
||||
initialAccount:
|
||||
enabled: true
|
||||
username: "admin"
|
||||
domain: "bakewise.ai"
|
||||
existingSecret: "mailu-admin-credentials"
|
||||
existingSecretPasswordKey: "password"
|
||||
mode: "ifmissing"
|
||||
|
||||
# External relay configuration for production (Mailgun)
|
||||
# All outbound emails will be relayed through Mailgun SMTP
|
||||
# To configure:
|
||||
# 1. Register at mailgun.com and verify your domain (bakewise.ai)
|
||||
# 2. Get your SMTP credentials from Mailgun dashboard
|
||||
# 3. Update the secret in configs/mailgun-credentials-secret.yaml
|
||||
# 4. Apply the secret: kubectl apply -f configs/mailgun-credentials-secret.yaml
|
||||
# 4. Apply the secret: kubectl apply -f configs/mailgun-credentials-secret.yaml -n bakery-ia
|
||||
externalRelay:
|
||||
host: "[smtp.mailgun.org]:587"
|
||||
username: "postmaster@bakewise.ai" # Your Mailgun SMTP username
|
||||
password: "" # Will be loaded from secret - see configs/mailgun-credentials-secret.yaml
|
||||
# Credentials loaded from Kubernetes secret
|
||||
secretName: "mailu-mailgun-credentials"
|
||||
usernameKey: "RELAY_USERNAME"
|
||||
passwordKey: "RELAY_PASSWORD"
|
||||
|
||||
# Environment-specific configurations
|
||||
persistence:
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
# 1. Unbound DNS deployment (for DNSSEC validation)
|
||||
# 2. CoreDNS configuration (forward to Unbound)
|
||||
# 3. TLS certificate secret creation
|
||||
# 4. Mailu Helm deployment
|
||||
# 5. Admin user creation
|
||||
# 4. Admin credentials secret creation
|
||||
# 5. Mailu Helm deployment (admin user created automatically via initialAccount)
|
||||
#
|
||||
# Usage:
|
||||
# ./deploy-mailu-prod.sh [--domain DOMAIN] [--admin-password PASSWORD]
|
||||
@@ -174,9 +174,35 @@ else
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Step 4: Deploy Mailu via Helm
|
||||
# Step 4: Create Admin Credentials Secret
|
||||
# =============================================================================
|
||||
print_step "Step 4: Deploying Mailu via Helm..."
|
||||
print_step "Step 4: Creating admin credentials secret..."
|
||||
|
||||
if kubectl get secret mailu-admin-credentials -n "$NAMESPACE" &>/dev/null; then
|
||||
print_success "Admin credentials secret already exists"
|
||||
# Retrieve existing password for summary output
|
||||
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||
ADMIN_PASSWORD=$(kubectl get secret mailu-admin-credentials -n "$NAMESPACE" -o jsonpath='{.data.password}' | base64 -d)
|
||||
fi
|
||||
else
|
||||
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||
# Generate a random password
|
||||
ADMIN_PASSWORD=$(openssl rand -base64 16 | tr -d '/+=' | head -c 16)
|
||||
echo -e "${YELLOW}Generated admin password: $ADMIN_PASSWORD${NC}"
|
||||
echo -e "${YELLOW}Please save this password securely!${NC}"
|
||||
fi
|
||||
|
||||
kubectl create secret generic mailu-admin-credentials \
|
||||
--from-literal=password="$ADMIN_PASSWORD" \
|
||||
-n "$NAMESPACE"
|
||||
|
||||
print_success "Admin credentials secret created"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Step 5: Deploy Mailu via Helm
|
||||
# =============================================================================
|
||||
print_step "Step 5: Deploying Mailu via Helm..."
|
||||
|
||||
# Add Mailu Helm repository
|
||||
helm repo add mailu https://mailu.github.io/helm-charts 2>/dev/null || true
|
||||
@@ -189,12 +215,12 @@ helm upgrade --install mailu mailu/mailu \
|
||||
-f "$MAILU_HELM_DIR/prod/values.yaml" \
|
||||
--timeout 10m
|
||||
|
||||
print_success "Mailu Helm release deployed"
|
||||
print_success "Mailu Helm release deployed (admin user will be created automatically)"
|
||||
|
||||
# =============================================================================
|
||||
# Step 5: Wait for Pods to be Ready
|
||||
# Step 6: Wait for Pods to be Ready
|
||||
# =============================================================================
|
||||
print_step "Step 5: Waiting for Mailu pods to be ready..."
|
||||
print_step "Step 6: Waiting for Mailu pods to be ready..."
|
||||
|
||||
echo "This may take 5-10 minutes (ClamAV takes time to initialize)..."
|
||||
|
||||
@@ -212,24 +238,7 @@ echo ""
|
||||
echo "Mailu Pod Status:"
|
||||
kubectl get pods -n "$NAMESPACE" | grep mailu
|
||||
|
||||
# =============================================================================
|
||||
# Step 6: Create Admin User
|
||||
# =============================================================================
|
||||
print_step "Step 6: Creating admin user..."
|
||||
|
||||
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||
# Generate a random password
|
||||
ADMIN_PASSWORD=$(openssl rand -base64 16 | tr -d '/+=' | head -c 16)
|
||||
echo -e "${YELLOW}Generated admin password: $ADMIN_PASSWORD${NC}"
|
||||
echo -e "${YELLOW}Please save this password securely!${NC}"
|
||||
fi
|
||||
|
||||
kubectl exec -n "$NAMESPACE" deployment/mailu-admin -- \
|
||||
flask mailu admin admin "$DOMAIN" "$ADMIN_PASSWORD" 2>/dev/null || {
|
||||
print_warning "Admin user may already exist or failed to create"
|
||||
}
|
||||
|
||||
print_success "Admin user configured"
|
||||
print_success "Admin user created automatically via Helm initialAccount"
|
||||
|
||||
# =============================================================================
|
||||
# Summary
|
||||
|
||||
@@ -25,6 +25,18 @@ timezone: "Etc/UTC"
|
||||
# Postmaster configuration
|
||||
postmaster: "admin"
|
||||
|
||||
# Initial admin account configuration
|
||||
# This creates an admin user as part of the Helm deployment
|
||||
# Credentials can be provided directly or via Kubernetes secret
|
||||
initialAccount:
|
||||
enabled: true
|
||||
username: "admin"
|
||||
domain: "" # Set in environment-specific values (dev/prod)
|
||||
password: "" # Leave empty to use existingSecret
|
||||
existingSecret: "mailu-admin-credentials"
|
||||
existingSecretPasswordKey: "password"
|
||||
mode: "ifmissing" # Only create if account doesn't exist
|
||||
|
||||
# TLS configuration
|
||||
tls:
|
||||
flavor: "notls" # Disable TLS for development
|
||||
@@ -40,16 +52,18 @@ limits:
|
||||
|
||||
# External relay configuration (Mailgun)
|
||||
# Mailu will relay all outbound emails through Mailgun SMTP
|
||||
# Credentials should be provided via Kubernetes secret or environment-specific values
|
||||
# Credentials are loaded from Kubernetes secret for security
|
||||
externalRelay:
|
||||
host: "[smtp.mailgun.org]:587"
|
||||
username: "" # Set in environment-specific values or via secret
|
||||
password: "" # Set in environment-specific values or via secret
|
||||
# Use existing secret for credentials (recommended for security)
|
||||
secretName: "mailu-mailgun-credentials"
|
||||
usernameKey: "RELAY_USERNAME"
|
||||
passwordKey: "RELAY_PASSWORD"
|
||||
|
||||
# Webmail configuration
|
||||
webmail:
|
||||
enabled: true
|
||||
flavor: "roundcube"
|
||||
type: "roundcube"
|
||||
|
||||
# Antivirus and antispam configuration
|
||||
antivirus:
|
||||
|
||||
126
scripts/build-all-services.sh
Executable file
126
scripts/build-all-services.sh
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Build All Services Script for Bakery-IA
|
||||
# This script builds and pushes all service images to the Gitea registry
|
||||
# Used for first-time deployment when CI/CD pipeline isn't available yet
|
||||
|
||||
set -e
|
||||
|
||||
echo "=========================================="
|
||||
echo "Bakery-IA Services Build Script"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# Check if we're in the correct directory
|
||||
if [ ! -f "PRODUCTION_DEPLOYMENT_GUIDE.md" ]; then
|
||||
echo "Error: This script must be run from the root of the bakery-ia repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get Gitea admin password
|
||||
echo "Getting Gitea admin credentials..."
|
||||
if ! GITEA_ADMIN_PASSWORD=$(kubectl get secret gitea-admin-secret -n gitea -o jsonpath='{.data.password}' | base64 -d 2>/dev/null); then
|
||||
echo "Error: Could not get Gitea admin password"
|
||||
echo "Make sure you've completed Phase 5 (CI/CD Infrastructure) first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Login to Gitea registry
|
||||
echo "Logging in to Gitea registry..."
|
||||
docker login gitea-http.gitea.svc.cluster.local:3000 -u bakery-admin -p "$GITEA_ADMIN_PASSWORD"
|
||||
|
||||
# Define the registry URL
|
||||
REGISTRY="gitea-http.gitea.svc.cluster.local:3000/bakery-admin"
|
||||
|
||||
# Define all services to build
|
||||
# Format: "directory_name:image_name"
|
||||
# Note: directory names use underscores (e.g., alert_processor), image names use hyphens (e.g., alert-processor)
|
||||
SERVICES=(
|
||||
"gateway:gateway"
|
||||
"frontend:dashboard"
|
||||
"auth:auth-service"
|
||||
"tenant:tenant-service"
|
||||
"training:training-service"
|
||||
"forecasting:forecasting-service"
|
||||
"sales:sales-service"
|
||||
"external:external-service"
|
||||
"notification:notification-service"
|
||||
"inventory:inventory-service"
|
||||
"recipes:recipes-service"
|
||||
"suppliers:suppliers-service"
|
||||
"pos:pos-service"
|
||||
"orders:orders-service"
|
||||
"production:production-service"
|
||||
"procurement:procurement-service"
|
||||
"distribution:distribution-service"
|
||||
"orchestrator:orchestrator-service"
|
||||
"alert_processor:alert-processor"
|
||||
"ai_insights:ai-insights-service"
|
||||
"demo_session:demo-session-service"
|
||||
)
|
||||
|
||||
# Build each service
|
||||
echo ""
|
||||
echo "Starting build process..."
|
||||
echo "This may take 15-30 minutes depending on your system."
|
||||
echo ""
|
||||
|
||||
FAILED_SERVICES=()
|
||||
SUCCESS_COUNT=0
|
||||
|
||||
for service_def in "${SERVICES[@]}"; do
|
||||
IFS=':' read -r service_name image_name <<< "$service_def"
|
||||
|
||||
echo "=========================================="
|
||||
echo "Building: $service_name -> $image_name"
|
||||
echo "=========================================="
|
||||
|
||||
if [ "$service_name" = "gateway" ]; then
|
||||
# Gateway service
|
||||
docker build -t "$REGISTRY/$image_name:latest" \
|
||||
--build-arg BASE_REGISTRY="$REGISTRY" \
|
||||
--build-arg PYTHON_IMAGE="python:3.11-slim" \
|
||||
-f "gateway/Dockerfile" .
|
||||
elif [ "$service_name" = "frontend" ]; then
|
||||
# Frontend service (uses node:18-alpine and nginx:1.25-alpine internally)
|
||||
docker build -t "$REGISTRY/$image_name:latest" \
|
||||
-f "frontend/Dockerfile.kubernetes" frontend/
|
||||
else
|
||||
# Microservices (in services/ directory)
|
||||
docker build -t "$REGISTRY/$image_name:latest" \
|
||||
--build-arg BASE_REGISTRY="$REGISTRY" \
|
||||
--build-arg PYTHON_IMAGE="python:3.11-slim" \
|
||||
-f "services/$service_name/Dockerfile" .
|
||||
fi
|
||||
|
||||
# Push the image
|
||||
echo "Pushing $image_name to registry..."
|
||||
if docker push "$REGISTRY/$image_name:latest"; then
|
||||
echo "✅ Successfully built and pushed $image_name"
|
||||
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
|
||||
else
|
||||
echo "❌ Failed to push $image_name"
|
||||
FAILED_SERVICES+=("$image_name")
|
||||
fi
|
||||
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "=========================================="
|
||||
echo "Build Summary"
|
||||
echo "=========================================="
|
||||
echo "Total services: ${#SERVICES[@]}"
|
||||
echo "Successfully built and pushed: $SUCCESS_COUNT"
|
||||
|
||||
if [ ${#FAILED_SERVICES[@]} -gt 0 ]; then
|
||||
echo "Failed services: ${#FAILED_SERVICES[@]}"
|
||||
echo "Failed list: ${FAILED_SERVICES[*]}"
|
||||
echo ""
|
||||
echo "⚠️ Some services failed to build/push"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ All services built and pushed successfully!"
|
||||
echo ""
|
||||
echo "You can now proceed to Phase 6: Deploy Application Services"
|
||||
echo "Run: kubectl apply -k infrastructure/environments/prod/k8s-manifests"
|
||||
fi
|
||||
324
scripts/prepull-base-images-for-prod.sh
Executable file
324
scripts/prepull-base-images-for-prod.sh
Executable file
@@ -0,0 +1,324 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Base Image Pre-Pull Script for Bakery-IA Production
|
||||
# This script pre-pulls all required base images for production deployment
|
||||
# Supports both local development and production environments with Gitea registry
|
||||
|
||||
set -e
|
||||
|
||||
# Function to display usage
|
||||
usage() {
|
||||
echo "Usage: $0 [options]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -e, --environment ENV Set environment (dev|prod) - default: dev"
|
||||
echo " -r, --registry REG Custom registry URL - default: localhost:5000 (dev) or gitea registry (prod)"
|
||||
echo " --skip-auth Skip Docker Hub authentication"
|
||||
echo " --push-images Push images to registry (default: true for dev, false for prod)"
|
||||
echo " --no-push-images Don't push images to registry"
|
||||
echo " -h, --help Show this help message"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 # Run in dev mode with local registry"
|
||||
echo " $0 -e prod # Run in production mode with Gitea registry"
|
||||
echo " $0 -e prod -r registry.example.com:5000 # Run in production with custom registry"
|
||||
echo " $0 --skip-auth # Skip Docker Hub auth (for air-gapped envs)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
ENVIRONMENT="dev"
|
||||
REGISTRY=""
|
||||
SKIP_AUTH=false
|
||||
PUSH_IMAGES=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-e|--environment)
|
||||
ENVIRONMENT="$2"
|
||||
shift 2
|
||||
;;
|
||||
-r|--registry)
|
||||
REGISTRY="$2"
|
||||
shift 2
|
||||
;;
|
||||
--skip-auth)
|
||||
SKIP_AUTH=true
|
||||
shift
|
||||
;;
|
||||
--push-images)
|
||||
PUSH_IMAGES=true
|
||||
shift
|
||||
;;
|
||||
--no-push-images)
|
||||
PUSH_IMAGES=false
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Function to check if required tools are available
|
||||
check_required_tools() {
|
||||
local missing_tools=()
|
||||
|
||||
# Check for required tools
|
||||
for tool in docker curl jq kubectl; do
|
||||
if ! command -v "$tool" &> /dev/null; then
|
||||
missing_tools+=("$tool")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#missing_tools[@]} -gt 0 ]; then
|
||||
echo "Error: Missing required tools: ${missing_tools[*]}"
|
||||
echo "Please install them before running this script."
|
||||
echo ""
|
||||
echo "On macOS (with Homebrew):"
|
||||
echo " brew install docker curl jq kubectl"
|
||||
echo ""
|
||||
echo "On Ubuntu/Debian:"
|
||||
echo " sudo apt-get install docker.io curl jq kubectl"
|
||||
echo ""
|
||||
echo "On CentOS/RHEL:"
|
||||
echo " sudo yum install docker curl jq kubectl"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check for required tools
|
||||
check_required_tools
|
||||
|
||||
echo "=========================================="
|
||||
echo "Bakery-IA Base Image Pre-Pull Script"
|
||||
echo "Environment: $ENVIRONMENT"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# Set defaults based on environment
|
||||
if [ "$ENVIRONMENT" = "prod" ]; then
|
||||
# Production environment - use Gitea registry
|
||||
if [ -z "$REGISTRY" ]; then
|
||||
# Try to get Gitea registry from Kubernetes
|
||||
if kubectl get secret gitea-registry-secret -n bakery-ia &>/dev/null; then
|
||||
# Extract registry URL from the secret
|
||||
REGISTRY_JSON=$(kubectl get secret gitea-registry-secret -n bakery-ia -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d)
|
||||
REGISTRY=$(echo "$REGISTRY_JSON" | jq -r '.auths | keys[]' | head -n 1)
|
||||
echo "Detected Gitea registry: $REGISTRY"
|
||||
else
|
||||
echo "Error: Could not detect Gitea registry automatically"
|
||||
echo "Please specify the registry with -r/--registry option"
|
||||
echo "Example: $0 -e prod -r gitea-http.gitea.svc.cluster.local:3000"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Default to not pushing images in production - they should be built by CI/CD
|
||||
if [ -z "$PUSH_IMAGES" ]; then
|
||||
PUSH_IMAGES=false
|
||||
fi
|
||||
elif [ "$ENVIRONMENT" = "dev" ]; then
|
||||
# Development environment - use local registry
|
||||
if [ -z "$REGISTRY" ]; then
|
||||
REGISTRY="localhost:5000"
|
||||
fi
|
||||
|
||||
# Default to pushing images in dev
|
||||
if [ -z "$PUSH_IMAGES" ]; then
|
||||
PUSH_IMAGES=true
|
||||
fi
|
||||
else
|
||||
echo "Error: Invalid environment. Use 'dev' or 'prod'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Registry configuration:"
|
||||
echo " Environment: $ENVIRONMENT"
|
||||
echo " Registry: $REGISTRY"
|
||||
echo " Push Images: $PUSH_IMAGES"
|
||||
echo ""
|
||||
|
||||
# Docker Hub credentials (use environment variables or defaults)
|
||||
DOCKER_USERNAME="${DOCKER_HUB_USERNAME:-uals}"
|
||||
DOCKER_PASSWORD="${DOCKER_HUB_PASSWORD:-dckr_pat_zzEY5Q58x1S0puraIoKEtbpue3A}"
|
||||
|
||||
# Authenticate with Docker Hub if not skipping auth
|
||||
if [ "$SKIP_AUTH" = false ]; then
|
||||
echo "Authenticating with Docker Hub..."
|
||||
if ! echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin; then
|
||||
echo "⚠ Warning: Docker Hub authentication failed. Continuing anyway..."
|
||||
else
|
||||
echo "✓ Authentication successful"
|
||||
fi
|
||||
else
|
||||
echo "Skipping Docker Hub authentication (--skip-auth flag set)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Define all base images used in the project
|
||||
# These are the base images needed for the services
|
||||
BASE_IMAGES=(
|
||||
# Service base images (Python microservices)
|
||||
"python:3.11-slim"
|
||||
# Frontend base images (Node.js build + Nginx runtime)
|
||||
"node:18-alpine"
|
||||
"nginx:1.25-alpine"
|
||||
# Database images
|
||||
"postgres:17-alpine"
|
||||
"redis:7.4-alpine"
|
||||
"rabbitmq:4.1-management-alpine"
|
||||
# Utility images
|
||||
"busybox:1.36"
|
||||
"curlimages/curl:latest"
|
||||
"bitnami/kubectl:latest"
|
||||
# Alpine variants
|
||||
"alpine:3.18"
|
||||
"alpine:3.19"
|
||||
"alpine/git:2.43.0"
|
||||
# CI/CD images
|
||||
"gcr.io/kaniko-project/executor:v1.23.0"
|
||||
"gcr.io/go-containerregistry/crane:latest"
|
||||
"registry.k8s.io/kustomize/kustomize:v5.3.0"
|
||||
# Storage images
|
||||
"minio/minio:RELEASE.2024-11-07T00-52-20Z"
|
||||
"minio/mc:RELEASE.2024-11-17T19-35-25Z"
|
||||
# Geocoding
|
||||
"mediagis/nominatim:4.4"
|
||||
# Mail server (Mailu - from GHCR)
|
||||
"ghcr.io/mailu/nginx:2024.06"
|
||||
"ghcr.io/mailu/admin:2024.06"
|
||||
"ghcr.io/mailu/postfix:2024.06"
|
||||
"ghcr.io/mailu/dovecot:2024.06"
|
||||
"ghcr.io/mailu/rspamd:2024.06"
|
||||
)
|
||||
|
||||
# If using registry, verify it's running
|
||||
if [ "$PUSH_IMAGES" = true ]; then
|
||||
echo "Checking registry at $REGISTRY..."
|
||||
if curl -s http://$REGISTRY/v2/ >/dev/null 2>&1; then
|
||||
echo "✓ Registry is accessible"
|
||||
elif curl -s https://$REGISTRY/v2/ >/dev/null 2>&1; then
|
||||
echo "✓ Registry is accessible (HTTPS)"
|
||||
# Update registry to use HTTPS if needed
|
||||
REGISTRY="https://$REGISTRY"
|
||||
else
|
||||
echo "⚠ Registry is not accessible at $REGISTRY"
|
||||
echo "Will only pull images locally (no registry push)"
|
||||
PUSH_IMAGES=false
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Base images to pre-pull:"
|
||||
echo "----------------------------------------"
|
||||
for image in "${BASE_IMAGES[@]}"; do
|
||||
echo " - $image"
|
||||
done
|
||||
echo ""
|
||||
|
||||
echo "Starting pre-pull process..."
|
||||
echo "----------------------------------------"
|
||||
|
||||
# Track success/failure
|
||||
FAILED_IMAGES=()
|
||||
SUCCESS_COUNT=0
|
||||
|
||||
# Pull each base image
|
||||
for image in "${BASE_IMAGES[@]}"; do
|
||||
echo "Pulling: $image"
|
||||
|
||||
# Pull the image
|
||||
if ! docker pull "$image"; then
|
||||
echo " ⚠ Failed to pull $image"
|
||||
FAILED_IMAGES+=("$image")
|
||||
continue
|
||||
fi
|
||||
|
||||
# Tag for registry if enabled
|
||||
if [ "$PUSH_IMAGES" = true ]; then
|
||||
# Extract registry host and image name
|
||||
if [[ "$REGISTRY" == https://* ]]; then
|
||||
REGISTRY_HOST=${REGISTRY#https://}
|
||||
else
|
||||
REGISTRY_HOST=$REGISTRY
|
||||
fi
|
||||
|
||||
# Format for registry: use bakery-admin namespace and preserve original name/tag
|
||||
# Extract image name and tag
|
||||
if [[ "$image" == *:* ]]; then
|
||||
image_name="${image%:*}"
|
||||
image_tag="${image#*:}"
|
||||
else
|
||||
image_name="$image"
|
||||
image_tag="latest"
|
||||
fi
|
||||
|
||||
# Replace slashes with underscores for repository name
|
||||
repo_name="$(echo "$image_name" | sed 's|/|_|g' | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
# Use bakery-admin namespace and preserve original tag
|
||||
registry_image="$REGISTRY_HOST/bakery-admin/${repo_name}:${image_tag}"
|
||||
|
||||
docker tag "$image" "$registry_image"
|
||||
echo " Tagged as: $registry_image"
|
||||
|
||||
# Push to registry
|
||||
if docker push "$registry_image"; then
|
||||
echo " ✓ Pushed to registry"
|
||||
else
|
||||
echo " ⚠ Failed to push to registry (image still available locally)"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo " ✓ Successfully pulled $image"
|
||||
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "=========================================="
|
||||
echo "Base Image Pre-Pull Complete!"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "Summary:"
|
||||
echo " - Total images: ${#BASE_IMAGES[@]}"
|
||||
echo " - Successfully pulled: $SUCCESS_COUNT"
|
||||
if [ ${#FAILED_IMAGES[@]} -gt 0 ]; then
|
||||
echo " - Failed: ${#FAILED_IMAGES[@]}"
|
||||
echo " - Failed images: ${FAILED_IMAGES[*]}"
|
||||
fi
|
||||
echo " - Environment: $ENVIRONMENT"
|
||||
if [ "$PUSH_IMAGES" = true ]; then
|
||||
echo " - Registry: $REGISTRY"
|
||||
else
|
||||
echo " - Registry: None (local Docker only)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Exit with error if any images failed
|
||||
if [ ${#FAILED_IMAGES[@]} -gt 0 ]; then
|
||||
echo "⚠ Some images failed to pull. This may be due to Docker Hub rate limits."
|
||||
echo "Please try again later or configure Docker Hub credentials."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ All images pulled successfully!"
|
||||
|
||||
if [ "$ENVIRONMENT" = "prod" ] && [ "$PUSH_IMAGES" = false ]; then
|
||||
echo ""
|
||||
echo "💡 Note: In production mode, images are not pushed to registry."
|
||||
echo " Images should be built and pushed by your CI/CD pipeline."
|
||||
echo " Make sure your CI/CD pipeline has built and pushed the required images."
|
||||
echo ""
|
||||
echo "💡 To build and push service images to Gitea registry:"
|
||||
echo " 1. Ensure your CI/CD pipeline is running (Tekton)"
|
||||
echo " 2. Push a commit to trigger the pipeline: git commit --allow-empty -m 'Trigger build'"
|
||||
echo " 3. Or manually trigger a pipeline run"
|
||||
echo ""
|
||||
echo "💡 Check pipeline status:"
|
||||
echo " kubectl get pipelineruns -n tekton-pipelines"
|
||||
echo " kubectl get pods -n tekton-pipelines"
|
||||
fi
|
||||
@@ -2,16 +2,74 @@
|
||||
|
||||
# Base Image Pre-Pull Script for Bakery-IA
|
||||
# This script pre-pulls all required base images to reduce Docker Hub usage
|
||||
# Supports both local development and production environments with Gitea registry
|
||||
# Run this script before building services to cache base images locally
|
||||
|
||||
set -e
|
||||
|
||||
# Function to display usage
|
||||
usage() {
|
||||
echo "Usage: $0 [options]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -e, --environment ENV Set environment (dev|prod) - default: dev"
|
||||
echo " -r, --registry REG Custom registry URL - default: localhost:5000 (dev) or gitea registry (prod)"
|
||||
echo " --skip-auth Skip Docker Hub authentication"
|
||||
echo " --push-images Push images to registry (default: true for dev, false for prod)"
|
||||
echo " --no-push-images Don't push images to registry"
|
||||
echo " -h, --help Show this help message"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 # Run in dev mode with local registry"
|
||||
echo " $0 -e prod # Run in production mode with Gitea registry"
|
||||
echo " $0 -e prod -r registry.example.com:5000 # Run in production with custom registry"
|
||||
echo " $0 --skip-auth # Skip Docker Hub auth (for air-gapped envs)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
ENVIRONMENT="dev"
|
||||
REGISTRY=""
|
||||
SKIP_AUTH=false
|
||||
PUSH_IMAGES=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-e|--environment)
|
||||
ENVIRONMENT="$2"
|
||||
shift 2
|
||||
;;
|
||||
-r|--registry)
|
||||
REGISTRY="$2"
|
||||
shift 2
|
||||
;;
|
||||
--skip-auth)
|
||||
SKIP_AUTH=true
|
||||
shift
|
||||
;;
|
||||
--push-images)
|
||||
PUSH_IMAGES=true
|
||||
shift
|
||||
;;
|
||||
--no-push-images)
|
||||
PUSH_IMAGES=false
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Function to check if required tools are available
|
||||
check_required_tools() {
|
||||
local missing_tools=()
|
||||
|
||||
# Check for required tools
|
||||
for tool in docker curl jq; do
|
||||
for tool in docker curl jq kubectl; do
|
||||
if ! command -v "$tool" &> /dev/null; then
|
||||
missing_tools+=("$tool")
|
||||
fi
|
||||
@@ -22,13 +80,13 @@ check_required_tools() {
|
||||
echo "Please install them before running this script."
|
||||
echo ""
|
||||
echo "On macOS (with Homebrew):"
|
||||
echo " brew install docker curl jq"
|
||||
echo " brew install docker curl jq kubectl"
|
||||
echo ""
|
||||
echo "On Ubuntu/Debian:"
|
||||
echo " sudo apt-get install docker.io curl jq"
|
||||
echo " sudo apt-get install docker.io curl jq kubectl"
|
||||
echo ""
|
||||
echo "On CentOS/RHEL:"
|
||||
echo " sudo yum install docker curl jq"
|
||||
echo " sudo yum install docker curl jq kubectl"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
@@ -38,24 +96,78 @@ check_required_tools
|
||||
|
||||
echo "=========================================="
|
||||
echo "Bakery-IA Base Image Pre-Pull Script"
|
||||
echo "Environment: $ENVIRONMENT"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# Docker Hub credentials (use the same as in your Kubernetes setup)
|
||||
DOCKER_USERNAME="uals"
|
||||
DOCKER_PASSWORD="dckr_pat_zzEY5Q58x1S0puraIoKEtbpue3A"
|
||||
# Set defaults based on environment
|
||||
if [ "$ENVIRONMENT" = "prod" ]; then
|
||||
# Production environment - use Gitea registry
|
||||
if [ -z "$REGISTRY" ]; then
|
||||
# Try to get Gitea registry from Kubernetes
|
||||
if kubectl get secret gitea-registry-secret -n bakery-ia &>/dev/null; then
|
||||
# Extract registry URL from the secret
|
||||
REGISTRY_JSON=$(kubectl get secret gitea-registry-secret -n bakery-ia -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d)
|
||||
REGISTRY=$(echo "$REGISTRY_JSON" | jq -r '.auths | keys[]' | head -n 1)
|
||||
echo "Detected Gitea registry: $REGISTRY"
|
||||
else
|
||||
echo "Error: Could not detect Gitea registry automatically"
|
||||
echo "Please specify the registry with -r/--registry option"
|
||||
echo "Example: $0 -e prod -r gitea-http.gitea.svc.cluster.local:3000"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Authenticate with Docker Hub
|
||||
# Default to not pushing images in production - they should be built by CI/CD
|
||||
if [ -z "$PUSH_IMAGES" ]; then
|
||||
PUSH_IMAGES=false
|
||||
fi
|
||||
elif [ "$ENVIRONMENT" = "dev" ]; then
|
||||
# Development environment - use local registry
|
||||
if [ -z "$REGISTRY" ]; then
|
||||
REGISTRY="localhost:5000"
|
||||
fi
|
||||
|
||||
# Default to pushing images in dev
|
||||
if [ -z "$PUSH_IMAGES" ]; then
|
||||
PUSH_IMAGES=true
|
||||
fi
|
||||
else
|
||||
echo "Error: Invalid environment. Use 'dev' or 'prod'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Registry configuration:"
|
||||
echo " Environment: $ENVIRONMENT"
|
||||
echo " Registry: $REGISTRY"
|
||||
echo " Push Images: $PUSH_IMAGES"
|
||||
echo ""
|
||||
|
||||
# Docker Hub credentials (use environment variables or defaults)
|
||||
DOCKER_USERNAME="${DOCKER_HUB_USERNAME:-uals}"
|
||||
DOCKER_PASSWORD="${DOCKER_HUB_PASSWORD:-dckr_pat_zzEY5Q58x1S0puraIoKEtbpue3A}"
|
||||
|
||||
# Authenticate with Docker Hub if not skipping auth
|
||||
if [ "$SKIP_AUTH" = false ]; then
|
||||
echo "Authenticating with Docker Hub..."
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
if ! echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin; then
|
||||
echo "⚠ Warning: Docker Hub authentication failed. Continuing anyway..."
|
||||
else
|
||||
echo "✓ Authentication successful"
|
||||
fi
|
||||
else
|
||||
echo "Skipping Docker Hub authentication (--skip-auth flag set)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Define all base images used in the project
|
||||
# All images are cached in local registry for dev environment
|
||||
# These are the base images needed for the services
|
||||
BASE_IMAGES=(
|
||||
# Service base images
|
||||
# Service base images (Python microservices)
|
||||
"python:3.11-slim"
|
||||
# Frontend base images (Node.js build + Nginx runtime)
|
||||
"node:18-alpine"
|
||||
"nginx:1.25-alpine"
|
||||
# Database images
|
||||
"postgres:17-alpine"
|
||||
"redis:7.4-alpine"
|
||||
@@ -85,27 +197,19 @@ BASE_IMAGES=(
|
||||
"ghcr.io/mailu/rspamd:2024.06"
|
||||
)
|
||||
|
||||
# Registry configuration
|
||||
# Read from environment variables (set by Tiltfile or manually)
|
||||
# USE_LOCAL_REGISTRY=true to push images to local registry after pulling
|
||||
USE_LOCAL_REGISTRY="${USE_LOCAL_REGISTRY:-true}"
|
||||
|
||||
echo "Registry configuration:"
|
||||
echo " USE_LOCAL_REGISTRY=$USE_LOCAL_REGISTRY"
|
||||
echo ""
|
||||
|
||||
# Use local registry (kind registry)
|
||||
REGISTRY="localhost:5000"
|
||||
|
||||
# If using local registry, verify it's running
|
||||
if [ "$USE_LOCAL_REGISTRY" = "true" ]; then
|
||||
echo "Checking local registry at $REGISTRY..."
|
||||
# If using registry, verify it's running
|
||||
if [ "$PUSH_IMAGES" = true ]; then
|
||||
echo "Checking registry at $REGISTRY..."
|
||||
if curl -s http://$REGISTRY/v2/ >/dev/null 2>&1; then
|
||||
echo "✓ Local registry is accessible"
|
||||
echo "✓ Registry is accessible"
|
||||
elif curl -s https://$REGISTRY/v2/ >/dev/null 2>&1; then
|
||||
echo "✓ Registry is accessible (HTTPS)"
|
||||
# Update registry to use HTTPS if needed
|
||||
REGISTRY="https://$REGISTRY"
|
||||
else
|
||||
echo "⚠ Local registry is not accessible at $REGISTRY"
|
||||
echo "⚠ Registry is not accessible at $REGISTRY"
|
||||
echo "Will only pull images locally (no registry push)"
|
||||
USE_LOCAL_REGISTRY="false"
|
||||
PUSH_IMAGES=false
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -136,17 +240,24 @@ for image in "${BASE_IMAGES[@]}"; do
|
||||
fi
|
||||
|
||||
# Tag for registry if enabled
|
||||
if [ "$USE_LOCAL_REGISTRY" = "true" ]; then
|
||||
# Local registry format: replace /, :, -, and . with _
|
||||
if [ "$PUSH_IMAGES" = true ]; then
|
||||
# Extract registry host and image name
|
||||
if [[ "$REGISTRY" == https://* ]]; then
|
||||
REGISTRY_HOST=${REGISTRY#https://}
|
||||
else
|
||||
REGISTRY_HOST=$REGISTRY
|
||||
fi
|
||||
|
||||
# Format for registry: replace /, :, -, and . with _
|
||||
local_repo="$(echo $image | sed 's|/|_|g' | sed 's|:|_|g' | sed 's|-|_|g' | sed 's|\.|_|g' | tr '[:upper:]' '[:lower:]')"
|
||||
registry_image="$REGISTRY/${local_repo}:latest"
|
||||
registry_image="$REGISTRY_HOST/${local_repo}:latest"
|
||||
|
||||
docker tag "$image" "$registry_image"
|
||||
echo " Tagged as: $registry_image"
|
||||
|
||||
# Push to registry
|
||||
if docker push "$registry_image"; then
|
||||
echo " ✓ Pushed to local registry"
|
||||
echo " ✓ Pushed to registry"
|
||||
else
|
||||
echo " ⚠ Failed to push to registry (image still available locally)"
|
||||
fi
|
||||
@@ -168,8 +279,9 @@ if [ ${#FAILED_IMAGES[@]} -gt 0 ]; then
|
||||
echo " - Failed: ${#FAILED_IMAGES[@]}"
|
||||
echo " - Failed images: ${FAILED_IMAGES[*]}"
|
||||
fi
|
||||
if [ "$USE_LOCAL_REGISTRY" = "true" ]; then
|
||||
echo " - Registry: Local ($REGISTRY)"
|
||||
echo " - Environment: $ENVIRONMENT"
|
||||
if [ "$PUSH_IMAGES" = true ]; then
|
||||
echo " - Registry: $REGISTRY"
|
||||
else
|
||||
echo " - Registry: None (local Docker only)"
|
||||
fi
|
||||
@@ -183,3 +295,19 @@ if [ ${#FAILED_IMAGES[@]} -gt 0 ]; then
|
||||
fi
|
||||
|
||||
echo "✓ All images pulled successfully!"
|
||||
|
||||
if [ "$ENVIRONMENT" = "prod" ] && [ "$PUSH_IMAGES" = false ]; then
|
||||
echo ""
|
||||
echo "💡 Note: In production mode, images are not pushed to registry."
|
||||
echo " Images should be built and pushed by your CI/CD pipeline."
|
||||
echo " Make sure your CI/CD pipeline has built and pushed the required images."
|
||||
echo ""
|
||||
echo "💡 To build and push service images to Gitea registry:"
|
||||
echo " 1. Ensure your CI/CD pipeline is running (Tekton)"
|
||||
echo " 2. Push a commit to trigger the pipeline: git commit --allow-empty -m 'Trigger build'"
|
||||
echo " 3. Or manually trigger a pipeline run"
|
||||
echo ""
|
||||
echo "💡 Check pipeline status:"
|
||||
echo " kubectl get pipelineruns -n tekton-pipelines"
|
||||
echo " kubectl get pods -n tekton-pipelines"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user