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
60
Tiltfile
60
Tiltfile
@@ -818,12 +818,54 @@ local_resource(
|
|||||||
if [ "$CURRENT_FORWARD" != "$UNBOUND_IP" ]; then
|
if [ "$CURRENT_FORWARD" != "$UNBOUND_IP" ]; then
|
||||||
echo "Updating CoreDNS to forward to Unbound ($UNBOUND_IP)..."
|
echo "Updating CoreDNS to forward to Unbound ($UNBOUND_IP)..."
|
||||||
|
|
||||||
# Patch CoreDNS ConfigMap
|
# Change to project root to ensure correct file paths
|
||||||
kubectl patch configmap coredns -n kube-system --type merge -p "{
|
cd /Users/urtzialfaro/Documents/bakery-ia
|
||||||
\"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\"
|
# 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
|
# Restart CoreDNS
|
||||||
kubectl rollout restart deployment coredns -n kube-system
|
kubectl rollout restart deployment coredns -n kube-system
|
||||||
@@ -887,6 +929,9 @@ local_resource(
|
|||||||
echo "Environment detected: $ENVIRONMENT"
|
echo "Environment detected: $ENVIRONMENT"
|
||||||
|
|
||||||
# Install Mailu with appropriate values
|
# 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
|
if [ "$ENVIRONMENT" = "dev" ]; then
|
||||||
helm upgrade --install mailu mailu/mailu \
|
helm upgrade --install mailu mailu/mailu \
|
||||||
-n bakery-ia \
|
-n bakery-ia \
|
||||||
@@ -912,6 +957,7 @@ local_resource(
|
|||||||
# =====================================================
|
# =====================================================
|
||||||
echo ""
|
echo ""
|
||||||
echo "Applying Mailu ingress configuration..."
|
echo "Applying Mailu ingress configuration..."
|
||||||
|
cd /Users/urtzialfaro/Documents/bakery-ia
|
||||||
kubectl apply -f infrastructure/platform/mail/mailu-helm/mailu-ingress.yaml
|
kubectl apply -f infrastructure/platform/mail/mailu-helm/mailu-ingress.yaml
|
||||||
echo "Mailu ingress applied for mail.bakery-ia.dev"
|
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 " IMAP: mail.bakery-ia.dev:993 (SSL/TLS)"
|
||||||
echo ""
|
echo ""
|
||||||
echo "To create admin user:"
|
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 ""
|
||||||
echo "To check pod status: kubectl get pods -n bakery-ia | grep mailu"
|
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
|
### 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):**
|
**Gitea (Git Server):**
|
||||||
- URL: http://gitea.bakery-ia.local (development) or http://gitea.bakewise.ai (production)
|
- URL: http://gitea.bakery-ia.local (development) or http://gitea.bakewise.ai (production)
|
||||||
- Admin panel: http://gitea.bakery-ia.local/admin
|
- 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
|
## Features
|
||||||
|
|
||||||
- **Automatic Repository Creation**: When Gitea is installed via Helm, it automatically creates a `bakery-ia` repository owned by the admin user.
|
- **Automatic Admin User**: Admin user is created automatically from Kubernetes secret
|
||||||
- **Pre-configured Settings**: The repository comes with issues, wiki, pull requests, and projects enabled.
|
- **Automatic Repository Creation**: The `bakery-ia` repository is created via a Kubernetes Job after Gitea starts
|
||||||
- **Easy Setup Script**: A script to push your existing code to the new Gitea repository.
|
- **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
|
```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 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
|
# 3. Wait for everything to be ready
|
||||||
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
|
|
||||||
kubectl wait --for=condition=ready pod -n gitea -l app.kubernetes.io/name=gitea --timeout=300s
|
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
|
```bash
|
||||||
# Set the admin password as environment variable
|
# 1. Generate and export secure password
|
||||||
export GITEA_ADMIN_PASSWORD="your-secure-password"
|
export GITEA_ADMIN_PASSWORD=$(openssl rand -base64 32)
|
||||||
|
|
||||||
# Run the setup script
|
# 2. Setup secrets with production flag (requires GITEA_ADMIN_PASSWORD)
|
||||||
./infrastructure/cicd/gitea/setup-gitea-repository.sh
|
./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
|
```yaml
|
||||||
gitea:
|
gitea:
|
||||||
initialRepositories:
|
admin:
|
||||||
- name: bakery-ia
|
username: bakery-admin
|
||||||
description: "Main repository for Bakery IA project - Automatically created by Helm"
|
email: admin@bakery-ia.local
|
||||||
private: false
|
existingSecret: gitea-admin-secret # Secret with username/password keys
|
||||||
auto_init: true
|
passwordMode: keepUpdated # Sync password changes from secret
|
||||||
default_branch: main
|
|
||||||
owner: "{{ .Values.gitea.admin.username }}"
|
|
||||||
enable_issues: true
|
|
||||||
enable_wiki: true
|
|
||||||
enable_pull_requests: true
|
|
||||||
enable_projects: true
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Repository Features
|
The `setup-admin-secret.sh` script creates this secret before Helm install.
|
||||||
|
|
||||||
The automatically created repository includes:
|
### 2. Repository Initialization
|
||||||
- **Issues**: For tracking bugs and feature requests
|
|
||||||
- **Wiki**: For project documentation
|
Since the Gitea Helm chart doesn't support automatic repository creation, we use a Kubernetes Job (`gitea-init-job.yaml`) that:
|
||||||
- **Pull Requests**: For code review workflow
|
|
||||||
- **Projects**: For project management
|
1. Waits for Gitea to be ready
|
||||||
- **Auto Initialization**: Creates an initial README.md file
|
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
|
## 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
|
https://gitea.bakery-ia.local/bakery-admin/bakery-ia.git
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example Tekton Pipeline Configuration
|
Internal cluster URL (for pipelines):
|
||||||
|
```
|
||||||
```yaml
|
http://gitea-http.gitea.svc.cluster.local:3000/bakery-admin/bakery-ia.git
|
||||||
# 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"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### Repository not created
|
### Init Job Failed
|
||||||
|
|
||||||
If the repository is not automatically created:
|
```bash
|
||||||
1. Check Gitea logs: `kubectl logs -n gitea -l app.kubernetes.io/name=gitea`
|
# Check job status
|
||||||
2. Verify the Helm values were applied correctly
|
kubectl get jobs -n gitea
|
||||||
3. Manually create the repository using the setup script
|
|
||||||
|
|
||||||
### Authentication issues
|
# View logs
|
||||||
|
kubectl logs -n gitea job/gitea-init-repo
|
||||||
|
|
||||||
If you have authentication problems when pushing:
|
# Re-run the job
|
||||||
1. Verify the admin password is correct
|
kubectl delete job gitea-init-repo -n gitea
|
||||||
2. Check that the Gitea service is accessible
|
kubectl apply -f infrastructure/cicd/gitea/gitea-init-job.yaml
|
||||||
3. Ensure your kubeconfig has access to the Gitea namespace
|
```
|
||||||
|
|
||||||
## Security Notes
|
### Repository Not Created
|
||||||
|
|
||||||
- Always use a strong password for the Gitea admin user
|
1. Check if Gitea is ready: `kubectl get pods -n gitea`
|
||||||
- Consider using Kubernetes secrets for sensitive data
|
2. Check init job logs: `kubectl logs -n gitea job/gitea-init-repo`
|
||||||
- The setup script uses basic authentication - for production, consider using SSH keys or tokens
|
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
|
## Upgrading
|
||||||
|
|
||||||
To upgrade Gitea while preserving your repositories:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
helm upgrade gitea gitea/gitea -n gitea \
|
helm upgrade gitea gitea/gitea -n gitea \
|
||||||
-f infrastructure/cicd/gitea/values.yaml \
|
-f infrastructure/cicd/gitea/values.yaml
|
||||||
--set gitea.admin.password=your-secure-password
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
#!/bin/bash
|
||||||
# Setup Gitea Admin Secret
|
# Setup Gitea Admin Secret and Initialize Gitea
|
||||||
#
|
#
|
||||||
# This script creates TWO Kubernetes secrets:
|
# This script:
|
||||||
# 1. gitea-admin-secret (gitea namespace) - Used by Gitea Helm chart for admin credentials
|
# 1. Creates 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
|
# 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
|
||||||
# Both secrets use the SAME credentials, ensuring consistency.
|
|
||||||
#
|
#
|
||||||
# Usage:
|
# 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
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
KUBECTL="kubectl"
|
KUBECTL="kubectl"
|
||||||
GITEA_NAMESPACE="gitea"
|
GITEA_NAMESPACE="gitea"
|
||||||
BAKERY_NAMESPACE="bakery-ia"
|
BAKERY_NAMESPACE="bakery-ia"
|
||||||
REGISTRY_HOST="registry.bakery-ia.local"
|
REGISTRY_HOST="registry.bakery-ia.local"
|
||||||
ADMIN_USERNAME="bakery-admin"
|
ADMIN_USERNAME="bakery-admin"
|
||||||
# Static password for consistent dev environment setup
|
# Default password for dev environment only
|
||||||
# This ensures the same credentials work across environment recreations
|
# For PRODUCTION: Always set GITEA_ADMIN_PASSWORD environment variable
|
||||||
STATIC_ADMIN_PASSWORD="pvYUkGWJijqc0QfIZEXw"
|
# Generate secure password with: openssl rand -base64 32
|
||||||
|
DEV_DEFAULT_PASSWORD="pvYUkGWJijqc0QfIZEXw"
|
||||||
|
SECRETS_ONLY=false
|
||||||
|
IS_PRODUCTION=false
|
||||||
|
|
||||||
# Check if running in microk8s
|
# Check if running in microk8s
|
||||||
if command -v microk8s &> /dev/null; then
|
if command -v microk8s &> /dev/null; then
|
||||||
KUBECTL="microk8s kubectl"
|
KUBECTL="microk8s kubectl"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get password from argument, environment variable, or use static default
|
# Parse arguments
|
||||||
if [ -n "$1" ]; then
|
for arg in "$@"; do
|
||||||
ADMIN_PASSWORD="$1"
|
case $arg in
|
||||||
elif [ -n "$GITEA_ADMIN_PASSWORD" ]; then
|
--secrets-only)
|
||||||
ADMIN_PASSWORD="$GITEA_ADMIN_PASSWORD"
|
SECRETS_ONLY=true
|
||||||
else
|
;;
|
||||||
ADMIN_PASSWORD="$STATIC_ADMIN_PASSWORD"
|
--production)
|
||||||
echo "Using static admin password for dev environment consistency"
|
IS_PRODUCTION=true
|
||||||
|
REGISTRY_HOST="registry.bakewise.ai"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ -z "$ADMIN_PASSWORD" ] && [ "$arg" != "--secrets-only" ] && [ "$arg" != "--production" ]; then
|
||||||
|
ADMIN_PASSWORD="$arg"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Get password from argument, environment variable, or use default (dev only)
|
||||||
|
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||||
|
if [ -n "$GITEA_ADMIN_PASSWORD" ]; then
|
||||||
|
ADMIN_PASSWORD="$GITEA_ADMIN_PASSWORD"
|
||||||
|
echo "Using password from GITEA_ADMIN_PASSWORD environment variable"
|
||||||
|
elif [ "$IS_PRODUCTION" = true ]; then
|
||||||
|
echo "ERROR: Production deployment requires GITEA_ADMIN_PASSWORD environment variable"
|
||||||
|
echo "Generate a secure password with: openssl rand -base64 32"
|
||||||
|
echo ""
|
||||||
|
echo "Usage for production:"
|
||||||
|
echo " export GITEA_ADMIN_PASSWORD=\$(openssl rand -base64 32)"
|
||||||
|
echo " ./setup-admin-secret.sh --production"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
ADMIN_PASSWORD="$DEV_DEFAULT_PASSWORD"
|
||||||
|
echo "WARNING: Using default dev password. For production, set GITEA_ADMIN_PASSWORD"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate password strength for production
|
||||||
|
if [ "$IS_PRODUCTION" = true ] && [ ${#ADMIN_PASSWORD} -lt 16 ]; then
|
||||||
|
echo "ERROR: Production password must be at least 16 characters"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create namespaces if they don't exist
|
# Create namespaces if they don't exist
|
||||||
@@ -103,9 +148,15 @@ echo "=========================================="
|
|||||||
echo "Gitea secrets created successfully!"
|
echo "Gitea secrets created successfully!"
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo ""
|
echo ""
|
||||||
echo "Credentials (same for both secrets):"
|
echo "Environment: $([ "$IS_PRODUCTION" = true ] && echo "PRODUCTION" || echo "Development")"
|
||||||
|
echo ""
|
||||||
|
echo "Credentials:"
|
||||||
echo " Username: $ADMIN_USERNAME"
|
echo " Username: $ADMIN_USERNAME"
|
||||||
echo " Password: $ADMIN_PASSWORD"
|
if [ "$IS_PRODUCTION" = true ]; then
|
||||||
|
echo " Password: (stored in secret, not displayed for security)"
|
||||||
|
else
|
||||||
|
echo " Password: $ADMIN_PASSWORD"
|
||||||
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
echo "Secrets created:"
|
echo "Secrets created:"
|
||||||
echo " 1. gitea-admin-secret (namespace: $GITEA_NAMESPACE) - For Gitea Helm chart"
|
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 " External: https://$REGISTRY_HOST"
|
||||||
echo " Internal: $INTERNAL_REGISTRY_HOST"
|
echo " Internal: $INTERNAL_REGISTRY_HOST"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Now install Gitea with:"
|
|
||||||
echo " helm install gitea gitea/gitea -n gitea -f infrastructure/cicd/gitea/values.yaml"
|
# 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
|
# Gitea Helm values configuration for Bakery-IA CI/CD
|
||||||
# This configuration sets up Gitea with registry support and appropriate storage
|
# 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:
|
# Installation:
|
||||||
# helm repo add gitea https://dl.gitea.io/charts
|
# 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
|
# 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.
|
# NOTE: The namespace is determined by the -n flag during helm install, not in this file.
|
||||||
@@ -43,22 +46,6 @@ ingress:
|
|||||||
hosts:
|
hosts:
|
||||||
- gitea.bakery-ia.local
|
- gitea.bakery-ia.local
|
||||||
- registry.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:
|
persistence:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -68,39 +55,44 @@ persistence:
|
|||||||
# For Kind: leave empty or use "standard"
|
# For Kind: leave empty or use "standard"
|
||||||
storageClass: ""
|
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:
|
gitea:
|
||||||
admin:
|
admin:
|
||||||
username: bakery-admin
|
username: bakery-admin
|
||||||
# IMPORTANT: Override this with --set gitea.admin.password=<secure-password>
|
|
||||||
# or use existingSecret
|
|
||||||
password: ""
|
|
||||||
email: admin@bakery-ia.local
|
email: admin@bakery-ia.local
|
||||||
|
# Use existing secret for admin credentials (created by setup-admin-secret.sh)
|
||||||
existingSecret: gitea-admin-secret
|
existingSecret: gitea-admin-secret
|
||||||
|
# keepUpdated ensures password changes in secret are applied
|
||||||
|
passwordMode: keepUpdated
|
||||||
|
|
||||||
config:
|
config:
|
||||||
server:
|
server:
|
||||||
DOMAIN: gitea.bakery-ia.local
|
DOMAIN: gitea.bakery-ia.local
|
||||||
SSH_DOMAIN: gitea.bakery-ia.local
|
SSH_DOMAIN: gitea.bakery-ia.local
|
||||||
|
SSH_PORT: 2222
|
||||||
# Use HTTPS for external access; TLS termination happens at ingress
|
# Use HTTPS for external access; TLS termination happens at ingress
|
||||||
ROOT_URL: https://gitea.bakery-ia.local
|
ROOT_URL: https://gitea.bakery-ia.local
|
||||||
HTTP_PORT: 3000
|
HTTP_PORT: 3000
|
||||||
# Enable package registry
|
|
||||||
PACKAGES_ENABLED: true
|
|
||||||
# Disable built-in HTTPS since ingress handles TLS
|
# Disable built-in HTTPS since ingress handles TLS
|
||||||
PROTOCOL: http
|
PROTOCOL: http
|
||||||
repository:
|
repository:
|
||||||
ENABLE_PUSH_CREATE_USER: true
|
ENABLE_PUSH_CREATE_USER: true
|
||||||
ENABLE_PUSH_CREATE_ORG: true
|
ENABLE_PUSH_CREATE_ORG: true
|
||||||
|
DEFAULT_BRANCH: main
|
||||||
packages:
|
packages:
|
||||||
ENABLED: true
|
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:
|
webhook:
|
||||||
ALLOWED_HOST_LIST: "*"
|
ALLOWED_HOST_LIST: "*"
|
||||||
# Allow internal cluster URLs for Tekton EventListener
|
# Allow internal cluster URLs for Tekton EventListener
|
||||||
@@ -109,21 +101,6 @@ gitea:
|
|||||||
DISABLE_REGISTRATION: false
|
DISABLE_REGISTRATION: false
|
||||||
REQUIRE_SIGNIN_VIEW: 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
|
# Use embedded SQLite for simpler local development
|
||||||
# For production, enable postgresql
|
# For production, enable postgresql
|
||||||
postgresql:
|
postgresql:
|
||||||
|
|||||||
@@ -18,10 +18,30 @@ kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/
|
|||||||
|
|
||||||
Then install the chart:
|
Then install the chart:
|
||||||
|
|
||||||
|
### Development Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
helm repo add tekton-pipelines https://tekton.dev/charts
|
helm install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||||
helm repo update
|
--namespace tekton-pipelines \
|
||||||
helm install tekton-cicd infrastructure/helm/tekton --namespace tekton-pipelines --create-namespace
|
--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
|
## Configuration
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ spec:
|
|||||||
git config --global user.name "bakery-ia-ci"
|
git config --global user.name "bakery-ia-ci"
|
||||||
|
|
||||||
# Clone the main repository (not a separate gitops repo)
|
# 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
|
git clone "$REPO_URL" /tmp/gitops
|
||||||
|
|
||||||
cd /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.
|
# This secret stores Mailgun credentials for outbound email relay.
|
||||||
# Mailu uses Mailgun as an external SMTP relay to send all outbound emails.
|
# Mailu uses Mailgun as an external SMTP relay to send all outbound emails.
|
||||||
#
|
#
|
||||||
|
# ============================================================================
|
||||||
# HOW TO CONFIGURE:
|
# HOW TO CONFIGURE:
|
||||||
|
# ============================================================================
|
||||||
|
#
|
||||||
# 1. Go to https://www.mailgun.com and create an account
|
# 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:
|
# 4. Note your SMTP credentials:
|
||||||
# - SMTP hostname: smtp.mailgun.org
|
# - SMTP hostname: smtp.mailgun.org
|
||||||
# - Port: 587 (TLS)
|
# - Port: 587 (TLS/STARTTLS)
|
||||||
# - Username: usually postmaster@yourdomain.com
|
# - Username: typically postmaster@yourdomain.com
|
||||||
# - Password: your Mailgun SMTP password (NOT API key)
|
# - Password: your Mailgun SMTP password (NOT the API key)
|
||||||
# 5. Base64 encode your password:
|
#
|
||||||
|
# 5. Base64 encode your credentials:
|
||||||
|
# echo -n 'postmaster@bakewise.ai' | base64
|
||||||
# echo -n 'your-mailgun-smtp-password' | 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:
|
# 7. Apply this secret:
|
||||||
# kubectl apply -f mailgun-credentials-secret.yaml -n bakery-ia
|
# kubectl apply -f mailgun-credentials-secret.yaml -n bakery-ia
|
||||||
#
|
#
|
||||||
|
# ============================================================================
|
||||||
# IMPORTANT NOTES:
|
# 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:
|
# 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
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
@@ -39,39 +67,28 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
app: mailu
|
app: mailu
|
||||||
component: external-relay
|
component: external-relay
|
||||||
|
annotations:
|
||||||
|
description: "Mailgun SMTP credentials for Mailu external relay"
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
stringData:
|
||||||
# Base64 encoded Mailgun SMTP password
|
# ============================================================================
|
||||||
# To encode: echo -n 'your-password' | base64
|
# REPLACE THESE VALUES WITH YOUR MAILGUN CREDENTIALS
|
||||||
# To decode: echo 'encoded-value' | base64 -d
|
# ============================================================================
|
||||||
RELAY_PASSWORD: MAILGUN_SMTP_PASSWORD_BASE64
|
#
|
||||||
---
|
# Option 1: Use stringData (plain text - Kubernetes will encode automatically)
|
||||||
# Development environment secret (separate for different Mailgun domain)
|
# This is easier for initial setup but shows credentials in the file
|
||||||
apiVersion: v1
|
#
|
||||||
kind: Secret
|
RELAY_USERNAME: "postmaster@sandboxc1bff891532b4f0c83056a68ae080b4c.mailgun.org"
|
||||||
metadata:
|
RELAY_PASSWORD: "2e47104abadad8eb820d00042ea6d5eb-77c6c375-89c7ea55"
|
||||||
name: mailu-mailgun-credentials-dev
|
#
|
||||||
namespace: bakery-ia
|
# ============================================================================
|
||||||
labels:
|
# ALTERNATIVE: Use pre-encoded values (more secure for version control)
|
||||||
app: mailu
|
# ============================================================================
|
||||||
component: external-relay
|
# Comment out stringData above and uncomment data below:
|
||||||
environment: dev
|
#
|
||||||
type: Opaque
|
# data:
|
||||||
data:
|
# # Base64 encoded values
|
||||||
# Mailgun credentials for bakery-ia.dev domain
|
# # echo -n 'postmaster@bakewise.ai' | base64
|
||||||
RELAY_PASSWORD: MAILGUN_DEV_SMTP_PASSWORD_BASE64
|
# RELAY_USERNAME: cG9zdG1hc3RlckBiYWtld2lzZS5haQ==
|
||||||
---
|
# # echo -n 'your-password' | base64
|
||||||
# Production environment secret
|
# RELAY_PASSWORD: WU9VUl9NQUlMR1VOX1NNVFBfUEFTU1dPUkQ=
|
||||||
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
|
|
||||||
|
|||||||
@@ -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:
|
hostnames:
|
||||||
- "mail.bakery-ia.dev"
|
- "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)
|
# External relay configuration for dev (Mailgun)
|
||||||
# All outbound emails will be relayed through Mailgun SMTP
|
# All outbound emails will be relayed through Mailgun SMTP
|
||||||
# To configure:
|
# To configure:
|
||||||
# 1. Register at mailgun.com and verify your domain (bakery-ia.dev)
|
# 1. Register at mailgun.com and verify your domain (bakery-ia.dev)
|
||||||
# 2. Get your SMTP credentials from Mailgun dashboard
|
# 2. Get your SMTP credentials from Mailgun dashboard
|
||||||
# 3. Update the secret in configs/mailgun-credentials-secret.yaml
|
# 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:
|
externalRelay:
|
||||||
host: "[smtp.mailgun.org]:587"
|
host: "[smtp.mailgun.org]:587"
|
||||||
username: "postmaster@bakery-ia.dev" # Your Mailgun SMTP username (usually postmaster@yourdomain)
|
# Credentials loaded from Kubernetes secret
|
||||||
password: "" # Will be loaded from secret - see configs/mailgun-credentials-secret.yaml
|
secretName: "mailu-mailgun-credentials"
|
||||||
|
usernameKey: "RELAY_USERNAME"
|
||||||
|
passwordKey: "RELAY_PASSWORD"
|
||||||
|
|
||||||
# Environment-specific configurations
|
# Environment-specific configurations
|
||||||
persistence:
|
persistence:
|
||||||
@@ -92,6 +104,13 @@ resources:
|
|||||||
limits:
|
limits:
|
||||||
cpu: "200m"
|
cpu: "200m"
|
||||||
memory: "128Mi"
|
memory: "128Mi"
|
||||||
|
webmail:
|
||||||
|
requests:
|
||||||
|
cpu: "50m"
|
||||||
|
memory: "64Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "200m"
|
||||||
|
memory: "128Mi"
|
||||||
clamav:
|
clamav:
|
||||||
requests:
|
requests:
|
||||||
cpu: "100m"
|
cpu: "100m"
|
||||||
|
|||||||
@@ -21,17 +21,29 @@ domain: "bakewise.ai"
|
|||||||
hostnames:
|
hostnames:
|
||||||
- "mail.bakewise.ai"
|
- "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)
|
# External relay configuration for production (Mailgun)
|
||||||
# All outbound emails will be relayed through Mailgun SMTP
|
# All outbound emails will be relayed through Mailgun SMTP
|
||||||
# To configure:
|
# To configure:
|
||||||
# 1. Register at mailgun.com and verify your domain (bakewise.ai)
|
# 1. Register at mailgun.com and verify your domain (bakewise.ai)
|
||||||
# 2. Get your SMTP credentials from Mailgun dashboard
|
# 2. Get your SMTP credentials from Mailgun dashboard
|
||||||
# 3. Update the secret in configs/mailgun-credentials-secret.yaml
|
# 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:
|
externalRelay:
|
||||||
host: "[smtp.mailgun.org]:587"
|
host: "[smtp.mailgun.org]:587"
|
||||||
username: "postmaster@bakewise.ai" # Your Mailgun SMTP username
|
# Credentials loaded from Kubernetes secret
|
||||||
password: "" # Will be loaded from secret - see configs/mailgun-credentials-secret.yaml
|
secretName: "mailu-mailgun-credentials"
|
||||||
|
usernameKey: "RELAY_USERNAME"
|
||||||
|
passwordKey: "RELAY_PASSWORD"
|
||||||
|
|
||||||
# Environment-specific configurations
|
# Environment-specific configurations
|
||||||
persistence:
|
persistence:
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
# 1. Unbound DNS deployment (for DNSSEC validation)
|
# 1. Unbound DNS deployment (for DNSSEC validation)
|
||||||
# 2. CoreDNS configuration (forward to Unbound)
|
# 2. CoreDNS configuration (forward to Unbound)
|
||||||
# 3. TLS certificate secret creation
|
# 3. TLS certificate secret creation
|
||||||
# 4. Mailu Helm deployment
|
# 4. Admin credentials secret creation
|
||||||
# 5. Admin user creation
|
# 5. Mailu Helm deployment (admin user created automatically via initialAccount)
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# ./deploy-mailu-prod.sh [--domain DOMAIN] [--admin-password PASSWORD]
|
# ./deploy-mailu-prod.sh [--domain DOMAIN] [--admin-password PASSWORD]
|
||||||
@@ -174,9 +174,35 @@ else
|
|||||||
fi
|
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
|
# Add Mailu Helm repository
|
||||||
helm repo add mailu https://mailu.github.io/helm-charts 2>/dev/null || true
|
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" \
|
-f "$MAILU_HELM_DIR/prod/values.yaml" \
|
||||||
--timeout 10m
|
--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)..."
|
echo "This may take 5-10 minutes (ClamAV takes time to initialize)..."
|
||||||
|
|
||||||
@@ -212,24 +238,7 @@ echo ""
|
|||||||
echo "Mailu Pod Status:"
|
echo "Mailu Pod Status:"
|
||||||
kubectl get pods -n "$NAMESPACE" | grep mailu
|
kubectl get pods -n "$NAMESPACE" | grep mailu
|
||||||
|
|
||||||
# =============================================================================
|
print_success "Admin user created automatically via Helm initialAccount"
|
||||||
# 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"
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Summary
|
# Summary
|
||||||
|
|||||||
@@ -25,6 +25,18 @@ timezone: "Etc/UTC"
|
|||||||
# Postmaster configuration
|
# Postmaster configuration
|
||||||
postmaster: "admin"
|
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 configuration
|
||||||
tls:
|
tls:
|
||||||
flavor: "notls" # Disable TLS for development
|
flavor: "notls" # Disable TLS for development
|
||||||
@@ -40,16 +52,18 @@ limits:
|
|||||||
|
|
||||||
# External relay configuration (Mailgun)
|
# External relay configuration (Mailgun)
|
||||||
# Mailu will relay all outbound emails through Mailgun SMTP
|
# 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:
|
externalRelay:
|
||||||
host: "[smtp.mailgun.org]:587"
|
host: "[smtp.mailgun.org]:587"
|
||||||
username: "" # Set in environment-specific values or via secret
|
# Use existing secret for credentials (recommended for security)
|
||||||
password: "" # Set in environment-specific values or via secret
|
secretName: "mailu-mailgun-credentials"
|
||||||
|
usernameKey: "RELAY_USERNAME"
|
||||||
|
passwordKey: "RELAY_PASSWORD"
|
||||||
|
|
||||||
# Webmail configuration
|
# Webmail configuration
|
||||||
webmail:
|
webmail:
|
||||||
enabled: true
|
enabled: true
|
||||||
flavor: "roundcube"
|
type: "roundcube"
|
||||||
|
|
||||||
# Antivirus and antispam configuration
|
# Antivirus and antispam configuration
|
||||||
antivirus:
|
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
|
# Base Image Pre-Pull Script for Bakery-IA
|
||||||
# This script pre-pulls all required base images to reduce Docker Hub usage
|
# 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
|
# Run this script before building services to cache base images locally
|
||||||
|
|
||||||
set -e
|
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
|
# Function to check if required tools are available
|
||||||
check_required_tools() {
|
check_required_tools() {
|
||||||
local missing_tools=()
|
local missing_tools=()
|
||||||
|
|
||||||
# Check for required 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
|
if ! command -v "$tool" &> /dev/null; then
|
||||||
missing_tools+=("$tool")
|
missing_tools+=("$tool")
|
||||||
fi
|
fi
|
||||||
@@ -22,13 +80,13 @@ check_required_tools() {
|
|||||||
echo "Please install them before running this script."
|
echo "Please install them before running this script."
|
||||||
echo ""
|
echo ""
|
||||||
echo "On macOS (with Homebrew):"
|
echo "On macOS (with Homebrew):"
|
||||||
echo " brew install docker curl jq"
|
echo " brew install docker curl jq kubectl"
|
||||||
echo ""
|
echo ""
|
||||||
echo "On Ubuntu/Debian:"
|
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 ""
|
||||||
echo "On CentOS/RHEL:"
|
echo "On CentOS/RHEL:"
|
||||||
echo " sudo yum install docker curl jq"
|
echo " sudo yum install docker curl jq kubectl"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -38,24 +96,78 @@ check_required_tools
|
|||||||
|
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo "Bakery-IA Base Image Pre-Pull Script"
|
echo "Bakery-IA Base Image Pre-Pull Script"
|
||||||
|
echo "Environment: $ENVIRONMENT"
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Docker Hub credentials (use the same as in your Kubernetes setup)
|
# Set defaults based on environment
|
||||||
DOCKER_USERNAME="uals"
|
if [ "$ENVIRONMENT" = "prod" ]; then
|
||||||
DOCKER_PASSWORD="dckr_pat_zzEY5Q58x1S0puraIoKEtbpue3A"
|
# 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
|
||||||
echo "Authenticating with Docker Hub..."
|
if [ -z "$PUSH_IMAGES" ]; then
|
||||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
PUSH_IMAGES=false
|
||||||
echo "✓ Authentication successful"
|
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 ""
|
echo ""
|
||||||
|
|
||||||
# Define all base images used in the project
|
# 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=(
|
BASE_IMAGES=(
|
||||||
# Service base images
|
# Service base images (Python microservices)
|
||||||
"python:3.11-slim"
|
"python:3.11-slim"
|
||||||
|
# Frontend base images (Node.js build + Nginx runtime)
|
||||||
|
"node:18-alpine"
|
||||||
|
"nginx:1.25-alpine"
|
||||||
# Database images
|
# Database images
|
||||||
"postgres:17-alpine"
|
"postgres:17-alpine"
|
||||||
"redis:7.4-alpine"
|
"redis:7.4-alpine"
|
||||||
@@ -85,27 +197,19 @@ BASE_IMAGES=(
|
|||||||
"ghcr.io/mailu/rspamd:2024.06"
|
"ghcr.io/mailu/rspamd:2024.06"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Registry configuration
|
# If using registry, verify it's running
|
||||||
# Read from environment variables (set by Tiltfile or manually)
|
if [ "$PUSH_IMAGES" = true ]; then
|
||||||
# USE_LOCAL_REGISTRY=true to push images to local registry after pulling
|
echo "Checking registry at $REGISTRY..."
|
||||||
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 curl -s http://$REGISTRY/v2/ >/dev/null 2>&1; then
|
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
|
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)"
|
echo "Will only pull images locally (no registry push)"
|
||||||
USE_LOCAL_REGISTRY="false"
|
PUSH_IMAGES=false
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -136,17 +240,24 @@ for image in "${BASE_IMAGES[@]}"; do
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Tag for registry if enabled
|
# Tag for registry if enabled
|
||||||
if [ "$USE_LOCAL_REGISTRY" = "true" ]; then
|
if [ "$PUSH_IMAGES" = true ]; then
|
||||||
# Local registry format: replace /, :, -, and . with _
|
# 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:]')"
|
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"
|
docker tag "$image" "$registry_image"
|
||||||
echo " Tagged as: $registry_image"
|
echo " Tagged as: $registry_image"
|
||||||
|
|
||||||
# Push to registry
|
# Push to registry
|
||||||
if docker push "$registry_image"; then
|
if docker push "$registry_image"; then
|
||||||
echo " ✓ Pushed to local registry"
|
echo " ✓ Pushed to registry"
|
||||||
else
|
else
|
||||||
echo " ⚠ Failed to push to registry (image still available locally)"
|
echo " ⚠ Failed to push to registry (image still available locally)"
|
||||||
fi
|
fi
|
||||||
@@ -168,8 +279,9 @@ if [ ${#FAILED_IMAGES[@]} -gt 0 ]; then
|
|||||||
echo " - Failed: ${#FAILED_IMAGES[@]}"
|
echo " - Failed: ${#FAILED_IMAGES[@]}"
|
||||||
echo " - Failed images: ${FAILED_IMAGES[*]}"
|
echo " - Failed images: ${FAILED_IMAGES[*]}"
|
||||||
fi
|
fi
|
||||||
if [ "$USE_LOCAL_REGISTRY" = "true" ]; then
|
echo " - Environment: $ENVIRONMENT"
|
||||||
echo " - Registry: Local ($REGISTRY)"
|
if [ "$PUSH_IMAGES" = true ]; then
|
||||||
|
echo " - Registry: $REGISTRY"
|
||||||
else
|
else
|
||||||
echo " - Registry: None (local Docker only)"
|
echo " - Registry: None (local Docker only)"
|
||||||
fi
|
fi
|
||||||
@@ -183,3 +295,19 @@ if [ ${#FAILED_IMAGES[@]} -gt 0 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "✓ All images pulled successfully!"
|
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