# Woodpecker CI Setup Guide for VAPORA Comprehensive guide for setting up and using Woodpecker CI/CD pipelines for VAPORA provisioning. ## Overview Woodpecker is a self-hosted, container-based CI/CD platform compatible with Docker Compose and Kubernetes. This guide covers VAPORA's 5 production-ready Woodpecker pipelines as an alternative to GitHub Actions. ### Key Features - **Self-Hosted**: Deploy on your own infrastructure (Docker, Kubernetes, VMs) - **Container-Based**: Runs pipeline steps in isolated Docker containers - **YAML Pipelines**: Simple YAML syntax for defining workflows - **Flexible Triggers**: Git webhooks, cron schedules, manual promotions - **Secret Management**: Built-in secret storage with environment variable injection - **Artifact Handling**: Workspace persistence across stages - **Multi-Pipeline Support**: Run multiple pipelines in parallel ### VAPORA Woodpecker Pipelines | Pipeline | Purpose | Trigger | Duration | |----------|---------|---------|----------| | **validate-and-build.yml** | Validate configs, generate artifacts | Push, PR, manual | ~5 min | | **deploy-docker.yml** | Deploy to Docker Compose | Manual, after validation | ~3 min | | **deploy-kubernetes.yml** | Deploy to Kubernetes | Manual with dry-run | ~5-10 min | | **health-check.yml** | Continuous monitoring | Cron (15min, 6hr), manual | ~5 min | | **rollback.yml** | Safe rollback with verification | Manual only | ~3-5 min | --- ## Prerequisites ### Infrastructure Requirements **Minimum**: - Linux server (Ubuntu 20.04+, Debian 11+, CentOS 8+) - Docker 20.10+ installed and running - 2 CPU cores, 4GB RAM, 20GB disk **Recommended for Production**: - Kubernetes cluster (v1.24+) - 4+ CPU cores, 8GB+ RAM, 50GB+ disk - Separate storage for workspace/artifacts - SSL/TLS for Woodpecker UI ### Prerequisites to Install ```bash # Ubuntu/Debian sudo apt-get update sudo apt-get install -y docker.io docker-compose git curl wget jq # Start Docker daemon sudo systemctl start docker sudo systemctl enable docker # Add current user to docker group (after logout/login required) sudo usermod -aG docker $USER ``` ### Git Repository - GitLab, GitHub, Gitea, or Gogs repository - Repository webhook URL accessible from Woodpecker server - OAuth token for repository access (for most Git services) --- ## Installation ### Option 1: Docker Compose Installation (Recommended for Testing) ```bash # Create Woodpecker directory mkdir -p ~/woodpecker && cd ~/woodpecker # Create docker-compose.yml cat > docker-compose.yml << 'EOF' version: '3.8' services: woodpecker-server: image: woodpeckerci/woodpecker-server:latest ports: - "80:8000" - "443:443" environment: - WOODPECKER_ADMIN_USER=admin - WOODPECKER_ADMIN_PASSWORD=admin123 - WOODPECKER_GITHUB_SERVER=https://github.com - WOODPECKER_GITHUB_CLIENT_ID= - WOODPECKER_GITHUB_CLIENT_SECRET= - WOODPECKER_RPC_SECRET= - WOODPECKER_LOG_LEVEL=info volumes: - woodpecker-data:/var/lib/woodpecker restart: always woodpecker-agent: image: woodpeckerci/woodpecker-agent:latest environment: - WOODPECKER_SERVER=http://woodpecker-server:9000 - WOODPECKER_AGENT_SECRET= - WOODPECKER_LOG_LEVEL=info volumes: - /var/run/docker.sock:/var/run/docker.sock restart: always depends_on: - woodpecker-server volumes: woodpecker-data: EOF # Generate RPC secret RPC_SECRET=$(head -c 32 /dev/urandom | base64) echo "RPC_SECRET=$RPC_SECRET" # Start services docker-compose up -d # Logs docker-compose logs -f ``` ### Option 2: Kubernetes Deployment Create `woodpecker-deployment.yaml`: ```yaml apiVersion: v1 kind: Namespace metadata: name: woodpecker --- apiVersion: apps/v1 kind: Deployment metadata: name: woodpecker-server namespace: woodpecker spec: replicas: 1 selector: matchLabels: app: woodpecker-server template: metadata: labels: app: woodpecker-server spec: containers: - name: server image: woodpeckerci/woodpecker-server:latest ports: - containerPort: 8000 - containerPort: 9000 env: - name: WOODPECKER_ADMIN_USER value: "admin" - name: WOODPECKER_ADMIN_PASSWORD valueFrom: secretKeyRef: name: woodpecker-secrets key: admin-password - name: WOODPECKER_RPC_SECRET valueFrom: secretKeyRef: name: woodpecker-secrets key: rpc-secret - name: WOODPECKER_GITHUB_CLIENT_ID valueFrom: secretKeyRef: name: woodpecker-secrets key: github-client-id - name: WOODPECKER_GITHUB_CLIENT_SECRET valueFrom: secretKeyRef: name: woodpecker-secrets key: github-client-secret volumeMounts: - name: woodpecker-data mountPath: /var/lib/woodpecker volumes: - name: woodpecker-data persistentVolumeClaim: claimName: woodpecker-pvc --- apiVersion: v1 kind: Service metadata: name: woodpecker-server namespace: woodpecker spec: selector: app: woodpecker-server ports: - name: ui port: 8000 targetPort: 8000 - name: rpc port: 9000 targetPort: 9000 type: LoadBalancer ``` Deploy: ```bash # Create secrets kubectl create secret generic woodpecker-secrets \ -n woodpecker \ --from-literal=admin-password=YOUR_PASSWORD \ --from-literal=rpc-secret=$(head -c 32 /dev/urandom | base64) \ --from-literal=github-client-id=YOUR_CLIENT_ID \ --from-literal=github-client-secret=YOUR_CLIENT_SECRET # Apply deployment kubectl apply -f woodpecker-deployment.yaml # Check status kubectl get pods -n woodpecker kubectl port-forward -n woodpecker svc/woodpecker-server 8000:8000 ``` --- ## GitHub Integration Setup ### Step 1: Create GitHub OAuth App 1. Go to GitHub → Settings → Developer settings → OAuth Apps 2. Click "New OAuth App" 3. Fill in: - **Application name**: `VAPORA Woodpecker` - **Homepage URL**: `https://woodpecker.your-domain.com` - **Authorization callback URL**: `https://woodpecker.your-domain.com/authorize` 4. Copy `Client ID` and `Client Secret` ### Step 2: Configure Woodpecker For Docker Compose: ```bash # Update docker-compose.yml environment variables WOODPECKER_GITHUB_CLIENT_ID=your_client_id_here WOODPECKER_GITHUB_CLIENT_SECRET=your_client_secret_here WOODPECKER_RPC_SECRET=$(head -c 32 /dev/urandom | base64) ``` For Kubernetes: ```bash kubectl patch secret woodpecker-secrets -n woodpecker \ --type=merge \ -p '{"data":{"github-client-id":"'$(echo -n YOUR_CLIENT_ID | base64)'","github-client-secret":"'$(echo -n YOUR_CLIENT_SECRET | base64)'"}}' ``` ### Step 3: Repository Setup 1. Access Woodpecker UI: `http://localhost:8000` (or your domain) 2. Login with admin credentials 3. Go to Admin → Repositories 4. Authorize your VAPORA repository 5. Enable webhooks by visiting `http://your-github.com/settings/hooks` --- ## Secret Management ### Adding Secrets #### Via Woodpecker UI 1. Go to repository → Settings → Secrets 2. Click "Add secret" 3. Name: `SECRET_NAME` 4. Value: Your secret value 5. Save #### Via CLI ```bash # Install woodpecker-cli go install github.com/woodpeckerci/woodpecker/cmd/woodpecker-cli@latest # Login woodpecker-cli login -s http://woodpecker-server:8000 \ -u admin \ -p admin_password # Add secret woodpecker-cli secret add \ -r owner/repo \ -n KUBE_CONFIG_STAGING \ -v "$(cat ~/.kube/config | base64)" ``` ### Required VAPORA Secrets ```bash # Kubernetes kubeconfigs (base64 encoded) KUBE_CONFIG_STAGING # Staging cluster kubeconfig KUBE_CONFIG_PRODUCTION # Production cluster kubeconfig # Optional: Slack notifications SLACK_WEBHOOK # General notifications webhook SLACK_WEBHOOK_ALERTS # Critical alerts webhook # Optional: Docker registry DOCKER_USERNAME # Docker Hub username DOCKER_PASSWORD # Docker Hub access token ``` ### Encoding Kubeconfig ```bash # Get kubeconfig and encode as base64 cat ~/.kube/config | base64 > kube_config_base64.txt # Use the output in Woodpecker secret UI cat kube_config_base64.txt # Verify locally before adding to Woodpecker echo "$(cat kube_config_base64.txt)" | base64 -d | kubectl cluster-info ``` --- ## Pipeline Triggers ### Automatic Triggers Pipelines trigger automatically when: ```yaml # On push to main/develop branches (if provisioning files change) trigger: event: [push] branch: [main, develop] paths: include: - provisioning/schemas/** - provisioning/scripts/** # On pull requests trigger: event: [pull_request] branch: [main, develop] ``` ### Manual Triggers (Promotions) Manually trigger from UI: 1. Go to repository → Active builds 2. Find a completed build 3. Click "Promote" 4. Select pipeline: `deploy-docker`, `deploy-kubernetes`, etc. 5. Set deployment parameters: - Mode: `solo`, `multiuser`, `enterprise` - Environment: `staging`, `production` - Dry-run: `true`/`false` 6. Click "Promote" ### Scheduled Triggers (Cron) Health check pipeline runs on schedule: ```yaml trigger: cron: - "*/15 * * * *" # Every 15 minutes - "0 */6 * * *" # Every 6 hours ``` --- ## Deployment Workflows ### Workflow 1: Local Development ``` Developer pushes to feature branch ↓ [Validate & Build] runs automatically ↓ Review artifacts in workspace ↓ [Deploy to Docker] manually for local testing ↓ Test with docker compose ↓ Create PR ``` ### Workflow 2: Staging Deployment ``` Merge PR to develop ↓ [Validate & Build] runs automatically ↓ Download artifacts from workspace ↓ Manually run [Deploy to Kubernetes] - Mode: multiuser - Environment: staging - Dry-run: true ↓ Review dry-run output ↓ Run again with dry-run: false ↓ [Health Check] verifies deployment ↓ Staging live ``` ### Workflow 3: Production Deployment ``` Code review approved ↓ Merge to main ↓ [Validate & Build] runs automatically ↓ Manually run [Deploy to Kubernetes] - Mode: enterprise - Environment: production - Dry-run: true ↓ Carefully review changes ↓ Run with dry-run: false ↓ [Health Check] monitoring (auto every 6 hours) ↓ Production deployment complete ``` ### Workflow 4: Emergency Rollback ``` Production issue detected ↓ [Health Check] alerts in Slack ↓ Manually run [Rollback Deployment] - Environment: production ↓ Services restored ↓ Investigate root cause ``` --- ## Configuration Environment Variables ### For validate-and-build.yml ```bash ARTIFACTS_DIR=provisioning/artifacts # Output directory for configs LOG_DIR=provisioning/logs # Output directory for logs ``` ### For deploy-docker.yml ```bash ARTIFACTS_DIR=provisioning/artifacts LOGS_DIR=provisioning/logs ``` ### For deploy-kubernetes.yml ```bash ARTIFACTS_DIR=provisioning/artifacts LOGS_DIR=provisioning/logs VAPORA_NAMESPACE=vapora # Kubernetes namespace ``` ### For health-check.yml ```bash LOGS_DIR=provisioning/logs VAPORA_NAMESPACE=vapora ``` --- ## Monitoring & Logs ### Via Woodpecker UI 1. Go to repository → Active/Previous builds 2. Click a build to see full pipeline execution 3. Click a stage to see detailed logs 4. Download logs or artifacts ### Via CLI ```bash # List recent builds woodpecker-cli build list -r owner/repo # View build details woodpecker-cli build view -r owner/repo -b # Watch build in real-time woodpecker-cli build watch -r owner/repo -b # Get build logs woodpecker-cli build logs -r owner/repo -b ``` ### Logs Location All logs stored in workspace: ```bash provisioning/logs/ ├── validate-solo.log ├── validate-multiuser.log ├── validate-enterprise.log ├── build.log ├── docker/ │ ├── backend.log │ ├── frontend.log │ └── all-services.log ├── kubernetes/ │ ├── backend.log │ ├── agents.log │ ├── llm-router.log │ └── events.log └── health-checks/ ├── docker-endpoints.log ├── k8s-deployments.log └── HEALTH_REPORT.md ``` --- ## Slack Integration ### Setup Webhook 1. Go to Slack workspace → Apps → Custom Integrations 2. Create Incoming Webhook 3. Select channel: `#deployments` 4. Copy Webhook URL 5. Add to Woodpecker secret: `SLACK_WEBHOOK` ### Slack Messages **Build Success**: ``` ✅ VAPORA Artifact Build Complete Artifacts ready for deployment ``` **Docker Deploy Success**: ``` ✅ VAPORA Docker deployment successful! Mode: multiuser | Environment: staging ``` **Kubernetes Deploy Success**: ``` ✅ VAPORA Kubernetes deployment successful! Mode: enterprise | Environment: production ``` **Health Check Alert**: ``` ❌ VAPORA Health Check Failed Target: kubernetes ``` **Rollback Alert**: ``` 🔙 VAPORA Rollback Executed Environment: production Verify service health immediately ``` --- ## Troubleshooting ### Pipeline Not Triggering **Problem**: Push doesn't trigger validate-and-build **Solution**: 1. Check repository is authorized in Woodpecker 2. Verify webhook exists in GitHub settings 3. Check file paths in `trigger.paths.include` match your changes 4. Enable debug logging: `WOODPECKER_LOG_LEVEL=debug` ### Secret Not Found **Problem**: `Secret not found` error in logs **Solution**: 1. Verify secret exists in repository settings 2. Check exact spelling (case-sensitive) 3. Ensure secret value is not empty 4. Test secret value locally before adding ### Kubeconfig Decode Error **Problem**: `base64: invalid input` during kubectl setup **Solution**: ```bash # Test locally first echo "$(cat kube_config_base64.txt)" | base64 -d | kubectl cluster-info # If it fails, re-encode cat ~/.kube/config | base64 | pbcopy # macOS # Update secret in Woodpecker UI ``` ### Docker Connection Failed **Problem**: `Cannot connect to Docker daemon` in deploy-docker stage **Solution**: 1. Ensure Docker socket mounted in agent: `-v /var/run/docker.sock:/var/run/docker.sock` 2. Verify Docker daemon running: `docker ps` 3. Check volume permissions: `sudo chmod 666 /var/run/docker.sock` ### Deployment Hangs **Problem**: Pipeline stage times out waiting for rollout **Solution**: 1. Check pod logs: `kubectl logs -n vapora ` 2. Describe pod: `kubectl describe pod -n vapora ` 3. Increase timeout in pipeline stage 4. Check resource requests/limits 5. Verify cluster has sufficient resources ### Workspace Persistence Issues **Problem**: Files from one stage not available in next stage **Solution**: 1. Create file in correct location (workspace root or subdirectory) 2. Use absolute paths: `${LOGS_DIR}/output.log` 3. Check artifact uploads in "publish" stages 4. Verify docker volumes: `docker volume ls` --- ## Advanced Configuration ### Multi-Agent Setup For distributed build execution: ```yaml # Agent 1 (Docker builds) environment: - WOODPECKER_FILTER_LABELS=type:docker # Agent 2 (Kubernetes operations) environment: - WOODPECKER_FILTER_LABELS=type:kubernetes # Agent 3 (Health checks) environment: - WOODPECKER_FILTER_LABELS=type:monitoring ``` ### Pipeline Concurrency Control Limit concurrent executions: ```yaml concurrency: limit: 2 # Max 2 concurrent builds timeout_minutes: 60 # Timeout after 60 minutes ``` ### Conditional Stage Execution Run stage only if conditions met: ```yaml when: evaluate: 'return build.Deploy_Environment == "production"' ``` --- ## Comparison: Woodpecker vs GitHub Actions | Feature | Woodpecker | GitHub Actions | |---------|-----------|---| | **Hosting** | Self-hosted | GitHub-hosted | | **YAML Format** | Similar | Familiar | | **Manual Dispatch** | Promotion UI | workflow_dispatch | | **Scheduled Workflows** | Cron syntax | schedule syntax | | **Artifact Storage** | Workspace persistence | upload-artifact action | | **PR Comments** | Limited | ✓ Native | | **Slack Integration** | Via webhooks | Actions | | **Secret Management** | Built-in UI | Built-in | | **Free for Public** | Self-hosted cost | ✓ Free | | **Concurrency Control** | ✓ Advanced | ✓ Concurrency groups | | **Deployment Safety** | Dry-run support | Deployment protection | ### When to Use Woodpecker - ✓ You want full control over CI/CD infrastructure - ✓ You need to run on-premise for compliance - ✓ You prefer self-hosted solutions - ✓ You have multiple repositories needing unified CI/CD - ✓ You want to avoid vendor lock-in ### When to Use GitHub Actions - ✓ You want GitHub-hosted runners (no infrastructure) - ✓ You prefer tight GitHub integration - ✓ You want PR comments and GitHub UI integration - ✓ You're already using GitHub workflow syntax --- ## First Deployment with Woodpecker ### Step 1: Enable Woodpecker for Repository 1. Access Woodpecker UI 2. Click "Administration" → "Repositories" 3. Find VAPORA repository 4. Click to enable 5. Grant webhook access ### Step 2: Create Test Branch ```bash git checkout -b test/woodpecker-setup echo "# Woodpecker Test" >> README.md git add README.md git commit -m "test: trigger Woodpecker" git push origin test/woodpecker-setup ``` ### Step 3: Monitor Pipeline 1. Go to Woodpecker → repository 2. See "Validate & Build" trigger automatically 3. Monitor pipeline execution 4. Check logs for each stage ### Step 4: Download Artifacts 1. In completed build, find "Files" section 2. Access workspace artifacts: - `provisioning/artifacts/` - Generated configs - `provisioning/logs/` - Pipeline logs ### Step 5: Test Docker Deployment 1. Download artifacts 2. Go to Woodpecker → repository 3. Click "Promote" on validated build 4. Select "deploy-docker" 5. Set: - Mode: `multiuser` - Environment: `staging` - Dry-run: `true` 6. Monitor deployment ### Step 6: Create Pull Request ```bash git push origin test/woodpecker-setup # Create PR on GitHub ``` --- ## Security Best Practices ✅ **Do**: - Use environment-specific kubeconfigs - Rotate secrets regularly - Run health checks after deployments - Enable dry-run by default - Keep logs for audit trail - Use RBAC in Kubernetes - Monitor Slack alerts - Test on staging first ❌ **Don't**: - Commit secrets to repository - Deploy directly to production without testing - Disable dry-run validation - Skip health checks - Use same credentials for all environments - Share Woodpecker admin credentials - Keep old pipelines around - Ignore Slack alerts --- ## Support & Resources - **Woodpecker Docs**: https://woodpecker-ci.org/docs/intro - **VAPORA Docs**: See `./../docs/` directory - **GitHub Actions Guide**: `./../.github/GITHUB_ACTIONS_GUIDE.md` - **Nushell Scripts**: `provisioning/scripts/*.nu` --- ## Files Created ``` .woodpecker/ ├── validate-and-build.yml (410 lines) ├── deploy-docker.yml (340 lines) ├── deploy-kubernetes.yml (380 lines) ├── health-check.yml (290 lines) ├── rollback.yml (330 lines) └── SETUP.md (This file) Total: 5 pipelines + comprehensive documentation ``` --- ## Next Steps 1. ✅ Install and configure Woodpecker server 2. → Integrate with GitHub repository 3. → Add secrets for Kubernetes kubeconfigs 4. → Configure Slack webhooks (optional) 5. → Run first validation pipeline 6. → Test Docker deployment 7. → Test Kubernetes deployment 8. → Configure health checks 9. → Document team runbooks 10. → Deploy to production --- **Generated**: 2026-01-12 **Status**: Production-ready **Pipelines**: 5 (validate-and-build, deploy-docker, deploy-kubernetes, health-check, rollback) **Documentation**: Complete