Skip to main content
Glama
deploy.yml12.1 kB
name: Build and Deploy to AKS on: push: branches: [ main, master ] tags: [ 'v*' ] pull_request: branches: [ main, master ] workflow_dispatch: inputs: environment: description: 'Deployment environment' required: true default: 'staging' type: choice options: - staging - production permissions: contents: read security-events: write actions: read id-token: write env: REGISTRY: ${{ secrets.ACR_LOGIN_SERVER }} IMAGE_NAME: fabric-analytics-mcp AZURE_RESOURCE_GROUP: ${{ secrets.AZURE_RESOURCE_GROUP }} AKS_CLUSTER_NAME: ${{ secrets.AKS_CLUSTER_NAME }} jobs: test: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci - name: Run linting run: npm run lint --if-present - name: Build TypeScript run: npm run build - name: Run tests run: npm test --if-present - name: Validate configuration run: | echo "Skipping validation in test environment - no server is running" echo "Validation will be performed during actual deployment to staging/production" security-scan: runs-on: ubuntu-latest if: github.event_name != 'pull_request' permissions: security-events: write actions: read contents: read id-token: write # Required for SARIF upload steps: - name: Checkout code uses: actions/checkout@v4 - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: scan-type: 'fs' scan-ref: '.' format: 'sarif' output: 'trivy-results.sarif' - name: Upload Trivy scan results to GitHub Security tab uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: 'trivy-results.sarif' docker-build-test: needs: [test] runs-on: ubuntu-latest if: github.event_name != 'pull_request' && secrets.ACR_USERNAME == '' steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build Docker image (test only) uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64 push: false tags: fabric-analytics-mcp:test cache-from: type=gha cache-to: type=gha,mode=max build-args: | BUILD_DATE=${{ github.event.head_commit.timestamp }} VERSION=test COMMIT_SHA=${{ github.sha }} - name: Docker build completed run: | echo "✅ Docker image built successfully" echo "📝 Note: Image was not pushed because Azure Container Registry is not configured" echo "🔧 To enable image pushing, configure these repository secrets:" echo " - ACR_LOGIN_SERVER" echo " - ACR_USERNAME" echo " - ACR_PASSWORD" build-and-push: needs: [test] runs-on: ubuntu-latest if: github.event_name != 'pull_request' && secrets.ACR_USERNAME != '' outputs: image-tag: ${{ steps.meta.outputs.tags }} image-digest: ${{ steps.build.outputs.digest }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Check Azure Container Registry secrets run: | echo "Checking Azure Container Registry configuration..." if [ -z "${{ secrets.ACR_LOGIN_SERVER }}" ] || [ -z "${{ secrets.ACR_USERNAME }}" ] || [ -z "${{ secrets.ACR_PASSWORD }}" ]; then echo "❌ Azure Container Registry secrets are not configured" echo "Required secrets: ACR_LOGIN_SERVER, ACR_USERNAME, ACR_PASSWORD" echo "Please configure these secrets in the repository settings to enable container builds" exit 1 else echo "✅ Azure Container Registry secrets are configured" fi - name: Setup Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to Azure Container Registry uses: azure/docker-login@v1 with: login-server: ${{ secrets.ACR_LOGIN_SERVER }} username: ${{ secrets.ACR_USERNAME }} password: ${{ secrets.ACR_PASSWORD }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=sha,prefix={{branch}}- type=raw,value=latest,enable={{is_default_branch}} - name: Build and push Docker image id: build uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max build-args: | BUILD_DATE=${{ github.event.head_commit.timestamp }} VERSION=${{ steps.meta.outputs.version }} COMMIT_SHA=${{ github.sha }} - name: Sign container image uses: sigstore/cosign-installer@v3 if: github.event_name != 'pull_request' with: cosign-release: 'v2.1.1' - name: Sign the published Docker image if: github.event_name != 'pull_request' env: COSIGN_EXPERIMENTAL: 1 run: echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign --yes {}@${{ steps.build.outputs.digest }} deploy-staging: needs: [build-and-push, security-scan] runs-on: ubuntu-latest if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.event.inputs.environment == 'staging') && secrets.ACR_USERNAME != '' environment: staging steps: - name: Checkout code uses: actions/checkout@v4 - name: Azure Login uses: azure/login@v1 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - name: Set up kubectl uses: azure/setup-kubectl@v3 with: version: 'v1.28.0' - name: Get AKS credentials run: | az aks get-credentials \ --resource-group ${{ env.AZURE_RESOURCE_GROUP }} \ --name ${{ env.AKS_CLUSTER_NAME }}-staging \ --overwrite-existing - name: Create namespace if not exists run: | kubectl create namespace fabric-mcp-staging --dry-run=client -o yaml | kubectl apply -f - - name: Deploy to staging run: | # Update image in deployment IMAGE_TAG="${{ needs.build-and-push.outputs.image-tag }}" sed -i "s|your-acr-registry.azurecr.io/fabric-analytics-mcp:latest|${IMAGE_TAG}|g" k8s/deployment.yaml # Apply Kubernetes manifests kubectl apply -f k8s/namespace.yaml kubectl apply -f k8s/rbac.yaml kubectl apply -f k8s/configmap.yaml kubectl apply -f k8s/deployment.yaml kubectl apply -f k8s/service.yaml kubectl apply -f k8s/hpa.yaml # Wait for rollout kubectl rollout status deployment/fabric-analytics-mcp -n fabric-mcp-staging --timeout=300s - name: Verify deployment run: | kubectl get pods -n fabric-mcp-staging kubectl get services -n fabric-mcp-staging # Health check EXTERNAL_IP=$(kubectl get service fabric-analytics-mcp-service -n fabric-mcp-staging -o jsonpath='{.status.loadBalancer.ingress[0].ip}') if [ -n "$EXTERNAL_IP" ]; then curl -f "http://$EXTERNAL_IP/health" || echo "Health check failed" fi - name: Run deployment validation run: | chmod +x scripts/validate-deployment.sh EXTERNAL_IP=$(kubectl get service fabric-analytics-mcp-service -n fabric-mcp-staging -o jsonpath='{.status.loadBalancer.ingress[0].ip}') if [ -n "$EXTERNAL_IP" ]; then ./scripts/validate-deployment.sh --url "http://$EXTERNAL_IP" --skip-auth fi deploy-production: needs: [build-and-push, security-scan, deploy-staging] runs-on: ubuntu-latest if: (startsWith(github.ref, 'refs/tags/v') || github.event.inputs.environment == 'production') && secrets.ACR_USERNAME != '' environment: production steps: - name: Checkout code uses: actions/checkout@v4 - name: Azure Login uses: azure/login@v1 with: creds: ${{ secrets.AZURE_CREDENTIALS_PROD }} - name: Set up kubectl uses: azure/setup-kubectl@v3 with: version: 'v1.28.0' - name: Get AKS credentials run: | az aks get-credentials \ --resource-group ${{ secrets.AZURE_RESOURCE_GROUP_PROD }} \ --name ${{ secrets.AKS_CLUSTER_NAME_PROD }} \ --overwrite-existing - name: Deploy to production run: | # Update image in deployment IMAGE_TAG="${{ needs.build-and-push.outputs.image-tag }}" sed -i "s|your-acr-registry.azurecr.io/fabric-analytics-mcp:latest|${IMAGE_TAG}|g" k8s/deployment.yaml # Apply Kubernetes manifests kubectl apply -f k8s/namespace.yaml kubectl apply -f k8s/rbac.yaml kubectl apply -f k8s/configmap.yaml kubectl apply -f k8s/deployment.yaml kubectl apply -f k8s/service.yaml kubectl apply -f k8s/hpa.yaml kubectl apply -f k8s/ingress.yaml # Wait for rollout kubectl rollout status deployment/fabric-analytics-mcp -n fabric-mcp --timeout=600s - name: Verify production deployment run: | kubectl get pods -n fabric-mcp kubectl get services -n fabric-mcp kubectl get ingress -n fabric-mcp # Extended health check EXTERNAL_IP=$(kubectl get service fabric-analytics-mcp-service -n fabric-mcp -o jsonpath='{.status.loadBalancer.ingress[0].ip}') if [ -n "$EXTERNAL_IP" ]; then for i in {1..5}; do if curl -f "http://$EXTERNAL_IP/health"; then echo "Health check passed" break else echo "Health check attempt $i failed, retrying..." sleep 10 fi done fi - name: Create GitHub Release if: startsWith(github.ref, 'refs/tags/v') uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ github.ref }} release_name: Release ${{ github.ref }} body: | ## Changes in this Release - Container image: `${{ needs.build-and-push.outputs.image-tag }}` - Image digest: `${{ needs.build-and-push.outputs.image-digest }}` ## Deployment This release has been automatically deployed to production AKS cluster. ## Verification Health endpoint: `https://your-domain.com/health` Metrics endpoint: `https://your-domain.com/metrics` draft: false prerelease: false cleanup: needs: [deploy-production] runs-on: ubuntu-latest if: always() steps: - name: Cleanup old images uses: azure/login@v1 with: creds: ${{ secrets.AZURE_CREDENTIALS }} continue-on-error: true - name: Remove old container images run: | # Keep only the last 10 images az acr repository show-tags \ --name ${{ secrets.ACR_NAME }} \ --repository ${{ env.IMAGE_NAME }} \ --output table \ --orderby time_desc \ --top 20 | tail -n +11 | while read tag; do if [ "$tag" != "latest" ] && [ "$tag" != "main" ]; then az acr repository delete \ --name ${{ secrets.ACR_NAME }} \ --image ${{ env.IMAGE_NAME }}:$tag \ --yes || true fi done continue-on-error: true

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/santhoshravindran7/Fabric-Analytics-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server