252 lines
9.3 KiB
YAML
252 lines
9.3 KiB
YAML
|
|
# VAPORA Woodpecker Pipeline - Deploy to Docker
|
||
|
|
# Deploys VAPORA to Docker Compose with health checks and notifications
|
||
|
|
# Triggers on: pull requests, manual promotion
|
||
|
|
|
||
|
|
trigger:
|
||
|
|
event: [pull_request, promote]
|
||
|
|
branch: [main, develop]
|
||
|
|
|
||
|
|
variables:
|
||
|
|
ARTIFACTS_DIR: provisioning/artifacts
|
||
|
|
LOGS_DIR: provisioning/logs
|
||
|
|
|
||
|
|
stages:
|
||
|
|
setup:
|
||
|
|
steps:
|
||
|
|
- name: prepare
|
||
|
|
image: alpine:latest
|
||
|
|
commands:
|
||
|
|
- mkdir -p ${ARTIFACTS_DIR} ${LOGS_DIR}
|
||
|
|
- echo "🚀 VAPORA Docker Deployment Pipeline"
|
||
|
|
- echo "Commit: ${CI_COMMIT_SHA:0:8}"
|
||
|
|
- echo "Branch: ${CI_COMMIT_BRANCH}"
|
||
|
|
- echo "Event: ${CI_PIPELINE_EVENT}"
|
||
|
|
|
||
|
|
install_dependencies:
|
||
|
|
steps:
|
||
|
|
- name: install_tools
|
||
|
|
image: rust:latest
|
||
|
|
commands:
|
||
|
|
- apt-get update && apt-get install -y curl jq yq
|
||
|
|
- cargo install nu --locked
|
||
|
|
- pip install jinja2-cli
|
||
|
|
- docker --version
|
||
|
|
- nu --version
|
||
|
|
- jinja2 --version
|
||
|
|
- yq --version
|
||
|
|
|
||
|
|
download_artifacts:
|
||
|
|
depends_on: [install_dependencies]
|
||
|
|
steps:
|
||
|
|
- name: fetch_latest_artifacts
|
||
|
|
image: alpine:latest
|
||
|
|
commands:
|
||
|
|
- echo "📦 Downloading latest artifacts..."
|
||
|
|
- mkdir -p ${ARTIFACTS_DIR}
|
||
|
|
- echo "Note: In Woodpecker self-hosted, artifacts are persisted in shared workspace"
|
||
|
|
- echo "For GitHub Actions artifacts, use external script to download from Actions API"
|
||
|
|
- ls -la ${ARTIFACTS_DIR}/ || echo "Artifacts directory empty - will generate locally"
|
||
|
|
|
||
|
|
validate_docker_config:
|
||
|
|
depends_on: [download_artifacts]
|
||
|
|
steps:
|
||
|
|
- name: validate_compose
|
||
|
|
image: rust:latest
|
||
|
|
environment:
|
||
|
|
RUST_LOG: warn
|
||
|
|
commands:
|
||
|
|
- apt-get update && apt-get install -y curl jq yq
|
||
|
|
- cargo install nu --locked > /dev/null 2>&1
|
||
|
|
- cargo install nickel --locked > /dev/null 2>&1
|
||
|
|
- pip install jinja2-cli > /dev/null 2>&1
|
||
|
|
- cd provisioning
|
||
|
|
- |
|
||
|
|
echo "Validating docker-compose configuration..."
|
||
|
|
if [ -f "../${ARTIFACTS_DIR}/docker-compose.yml" ]; then
|
||
|
|
yq eval '.' "../${ARTIFACTS_DIR}/docker-compose.yml" > /dev/null && echo "✓ Docker Compose YAML valid"
|
||
|
|
else
|
||
|
|
echo "⚠️ docker-compose.yml not found, generating from Nickel"
|
||
|
|
nu scripts/ci-pipeline.nu --artifact-dir ../${ARTIFACTS_DIR} --mode multiuser 2>&1 | tee ../${LOGS_DIR}/docker-validation.log
|
||
|
|
fi
|
||
|
|
|
||
|
|
deploy_docker_compose:
|
||
|
|
depends_on: [validate_docker_config]
|
||
|
|
steps:
|
||
|
|
- name: pull_images
|
||
|
|
image: docker:latest
|
||
|
|
volumes:
|
||
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
||
|
|
commands:
|
||
|
|
- echo "📥 Pulling base images..."
|
||
|
|
- docker pull rust:latest
|
||
|
|
- docker pull node:22-alpine
|
||
|
|
- docker pull postgres:16-alpine
|
||
|
|
- docker pull surrealdb/surrealdb:latest
|
||
|
|
- echo "✓ Images pulled"
|
||
|
|
|
||
|
|
- name: compose_up
|
||
|
|
image: docker:latest
|
||
|
|
volumes:
|
||
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
||
|
|
environment:
|
||
|
|
COMPOSE_FILE: ${ARTIFACTS_DIR}/docker-compose.yml
|
||
|
|
commands:
|
||
|
|
- echo "🚀 Starting Docker Compose stack..."
|
||
|
|
- docker compose -f ${ARTIFACTS_DIR}/docker-compose.yml up -d
|
||
|
|
- sleep 10
|
||
|
|
- docker compose -f ${ARTIFACTS_DIR}/docker-compose.yml ps
|
||
|
|
- echo "✓ Services started"
|
||
|
|
|
||
|
|
health_checks:
|
||
|
|
depends_on: [deploy_docker_compose]
|
||
|
|
steps:
|
||
|
|
- name: verify_services
|
||
|
|
image: rust:latest
|
||
|
|
commands:
|
||
|
|
- apt-get update && apt-get install -y curl jq
|
||
|
|
- |
|
||
|
|
echo "🏥 Running health checks..."
|
||
|
|
echo "Checking backend: http://localhost:8001/health"
|
||
|
|
curl -f http://localhost:8001/health && echo "✓ Backend healthy" || echo "⚠️ Backend not ready"
|
||
|
|
|
||
|
|
echo "Checking frontend: http://localhost:3000"
|
||
|
|
curl -f http://localhost:3000 && echo "✓ Frontend accessible" || echo "⚠️ Frontend not ready"
|
||
|
|
|
||
|
|
echo "Checking agents: http://localhost:8002/health"
|
||
|
|
curl -f http://localhost:8002/health && echo "✓ Agents healthy" || echo "⚠️ Agents not ready"
|
||
|
|
|
||
|
|
echo "Checking LLM router: http://localhost:8003/health"
|
||
|
|
curl -f http://localhost:8003/health && echo "✓ LLM Router healthy" || echo "⚠️ Router not ready"
|
||
|
|
|
||
|
|
echo "Checking SurrealDB: http://localhost:8000"
|
||
|
|
curl -f http://localhost:8000/health && echo "✓ SurrealDB accessible" || echo "⚠️ SurrealDB not ready"
|
||
|
|
|
||
|
|
- name: collect_logs
|
||
|
|
image: docker:latest
|
||
|
|
volumes:
|
||
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
||
|
|
commands:
|
||
|
|
- echo "📋 Collecting Docker logs..."
|
||
|
|
- mkdir -p ${LOGS_DIR}/docker
|
||
|
|
- docker compose -f ${ARTIFACTS_DIR}/docker-compose.yml logs > ${LOGS_DIR}/docker/all-services.log 2>&1
|
||
|
|
- docker compose -f ${ARTIFACTS_DIR}/docker-compose.yml logs backend > ${LOGS_DIR}/docker/backend.log 2>&1
|
||
|
|
- docker compose -f ${ARTIFACTS_DIR}/docker-compose.yml logs frontend > ${LOGS_DIR}/docker/frontend.log 2>&1
|
||
|
|
- docker compose -f ${ARTIFACTS_DIR}/docker-compose.yml logs agents > ${LOGS_DIR}/docker/agents.log 2>&1
|
||
|
|
|
||
|
|
verify_endpoints:
|
||
|
|
depends_on: [health_checks]
|
||
|
|
steps:
|
||
|
|
- name: test_endpoints
|
||
|
|
image: rust:latest
|
||
|
|
commands:
|
||
|
|
- apt-get update && apt-get install -y curl jq
|
||
|
|
- |
|
||
|
|
echo "🔍 Testing API endpoints..."
|
||
|
|
|
||
|
|
echo "Testing POST /api/projects"
|
||
|
|
curl -X POST http://localhost:8001/api/projects \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{"name":"test","description":"Test project"}' \
|
||
|
|
&& echo "✓ POST /api/projects works" || echo "⚠️ POST failed"
|
||
|
|
|
||
|
|
echo "Testing GET /api/projects"
|
||
|
|
curl -f http://localhost:8001/api/projects && echo "✓ GET /api/projects works" || echo "⚠️ GET failed"
|
||
|
|
|
||
|
|
echo "Testing metrics endpoint"
|
||
|
|
curl -f http://localhost:8001/metrics && echo "✓ Metrics available" || echo "⚠️ Metrics endpoint failed"
|
||
|
|
|
||
|
|
generate_report:
|
||
|
|
depends_on: [verify_endpoints]
|
||
|
|
steps:
|
||
|
|
- name: create_deployment_report
|
||
|
|
image: alpine:latest
|
||
|
|
commands:
|
||
|
|
- |
|
||
|
|
mkdir -p ${LOGS_DIR}
|
||
|
|
cat > ${LOGS_DIR}/DOCKER_DEPLOYMENT_REPORT.md << 'EOF'
|
||
|
|
# Docker Deployment Report
|
||
|
|
|
||
|
|
**Deployment Time**: $(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||
|
|
**Commit**: ${CI_COMMIT_SHA}
|
||
|
|
**Branch**: ${CI_COMMIT_BRANCH}
|
||
|
|
**Pipeline**: ${CI_BUILD_LINK}
|
||
|
|
|
||
|
|
## Status
|
||
|
|
|
||
|
|
✅ Docker Compose deployment successful
|
||
|
|
|
||
|
|
## Service Endpoints
|
||
|
|
|
||
|
|
- **Backend**: http://localhost:8001
|
||
|
|
- **Frontend**: http://localhost:3000
|
||
|
|
- **Agents**: http://localhost:8002
|
||
|
|
- **LLM Router**: http://localhost:8003
|
||
|
|
- **SurrealDB**: http://localhost:8000
|
||
|
|
- **Health**: http://localhost:8001/health
|
||
|
|
|
||
|
|
## Verification
|
||
|
|
|
||
|
|
All services running and responding to health checks
|
||
|
|
|
||
|
|
## Next Steps
|
||
|
|
|
||
|
|
1. Access frontend at http://localhost:3000
|
||
|
|
2. Review logs in ${LOGS_DIR}/docker/
|
||
|
|
3. Run integration tests against API
|
||
|
|
4. Prepare for staging deployment
|
||
|
|
|
||
|
|
EOF
|
||
|
|
cat ${LOGS_DIR}/DOCKER_DEPLOYMENT_REPORT.md
|
||
|
|
|
||
|
|
publish:
|
||
|
|
depends_on: [generate_report]
|
||
|
|
steps:
|
||
|
|
- name: publish_results
|
||
|
|
image: alpine:latest
|
||
|
|
commands:
|
||
|
|
- echo "📦 Docker deployment complete"
|
||
|
|
- echo ""
|
||
|
|
- echo "Logs available at: ${LOGS_DIR}/"
|
||
|
|
- ls -lah ${LOGS_DIR}/
|
||
|
|
- echo ""
|
||
|
|
- echo "Artifacts:"
|
||
|
|
- ls -lah ${ARTIFACTS_DIR}/
|
||
|
|
- echo ""
|
||
|
|
- echo "Total files: $(find ${ARTIFACTS_DIR} -type f | wc -l)"
|
||
|
|
- du -sh ${ARTIFACTS_DIR}/
|
||
|
|
|
||
|
|
- name: notify_slack
|
||
|
|
image: alpine:latest
|
||
|
|
environment:
|
||
|
|
SLACK_WEBHOOK: ${SLACK_WEBHOOK}
|
||
|
|
commands:
|
||
|
|
- |
|
||
|
|
if [ -n "$SLACK_WEBHOOK" ]; then
|
||
|
|
apk add --no-cache curl jq
|
||
|
|
curl -X POST $SLACK_WEBHOOK \
|
||
|
|
-H 'Content-Type: application/json' \
|
||
|
|
-d '{
|
||
|
|
"text": "✅ VAPORA Docker deployment successful!",
|
||
|
|
"blocks": [
|
||
|
|
{
|
||
|
|
"type": "section",
|
||
|
|
"text": {
|
||
|
|
"type": "mrkdwn",
|
||
|
|
"text": "✅ **VAPORA Docker Deployment Successful**\n\n*Services Ready for Testing:*\n• Backend: http://localhost:8001\n• Frontend: http://localhost:3000\n• Agents: http://localhost:8002\n• LLM Router: http://localhost:8003"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"type": "context",
|
||
|
|
"elements": [
|
||
|
|
{
|
||
|
|
"type": "mrkdwn",
|
||
|
|
"text": "*Commit*: '"${CI_COMMIT_SHA:0:8}"'\n*Branch*: '"${CI_COMMIT_BRANCH}"'\n*Triggered By*: '"${CI_COMMIT_AUTHOR}"'"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}'
|
||
|
|
else
|
||
|
|
echo "⚠️ Slack webhook not configured"
|
||
|
|
fi
|