From 67774accb7b038231f7c227a2b670cc7277c8307 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 May 2025 11:37:38 +0000 Subject: [PATCH 1/2] Initial plan for issue From 696082e6dd7a0f98db55c787c8379495958b1167 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 May 2025 11:47:55 +0000 Subject: [PATCH 2/2] Create Terraform files for Azure Container Apps deployment Co-authored-by: 0GiS0 <175379+0GiS0@users.noreply.github.com> --- .github/workflows/deploy-to-azure.yml | 84 ++++++++++ codemotion-mcp-server/.env.example | 9 + codemotion-mcp-server/Dockerfile | 21 +++ .../src/tools/sessionTool.ts | 12 +- infra/README.md | 98 +++++++++++ infra/acr.tf | 27 +++ infra/container_apps.tf | 156 ++++++++++++++++++ infra/deploy.sh | 85 ++++++++++ infra/main.tf | 24 +++ infra/outputs.tf | 23 +++ infra/variables.tf | 65 ++++++++ 11 files changed, 598 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/deploy-to-azure.yml create mode 100644 codemotion-mcp-server/.env.example create mode 100644 codemotion-mcp-server/Dockerfile create mode 100644 infra/README.md create mode 100644 infra/acr.tf create mode 100644 infra/container_apps.tf create mode 100755 infra/deploy.sh create mode 100644 infra/outputs.tf create mode 100644 infra/variables.tf diff --git a/.github/workflows/deploy-to-azure.yml b/.github/workflows/deploy-to-azure.yml new file mode 100644 index 0000000..eb4f75d --- /dev/null +++ b/.github/workflows/deploy-to-azure.yml @@ -0,0 +1,84 @@ +name: Deploy to Azure Container Apps + +on: + push: + branches: [ main ] + paths: + - 'codemotion-mcp-server/**' + - 'infra/**' + - '.github/workflows/deploy-to-azure.yml' + workflow_dispatch: + +permissions: + contents: read + id-token: write + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_version: 1.0.0 + + - name: Azure Login + uses: azure/login@v1 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: Terraform Init + run: | + cd infra + terraform init + + - name: Terraform Plan + run: | + cd infra + terraform plan -out=tfplan \ + -var="github_token=${{ secrets.GITHUB_TOKEN }}" + + - name: Terraform Apply + run: | + cd infra + terraform apply -auto-approve tfplan + + - name: Get ACR details + id: acr + run: | + cd infra + echo "ACR_LOGIN_SERVER=$(terraform output -raw acr_login_server)" >> $GITHUB_ENV + echo "ACR_USERNAME=$(terraform output -raw acr_admin_username)" >> $GITHUB_ENV + echo "ACR_PASSWORD=$(terraform output -raw acr_admin_password)" >> $GITHUB_ENV + + - name: Build and push image to ACR + uses: azure/docker-login@v1 + with: + login-server: ${{ env.ACR_LOGIN_SERVER }} + username: ${{ env.ACR_USERNAME }} + password: ${{ env.ACR_PASSWORD }} + + - name: Build and push Docker image + run: | + cd codemotion-mcp-server + docker build -t ${{ env.ACR_LOGIN_SERVER }}/codemotion-mcp-server:${{ github.sha }} . + docker push ${{ env.ACR_LOGIN_SERVER }}/codemotion-mcp-server:${{ github.sha }} + docker tag ${{ env.ACR_LOGIN_SERVER }}/codemotion-mcp-server:${{ github.sha }} ${{ env.ACR_LOGIN_SERVER }}/codemotion-mcp-server:latest + docker push ${{ env.ACR_LOGIN_SERVER }}/codemotion-mcp-server:latest + + - name: Update Container App with new image + run: | + RESOURCE_GROUP=$(cd infra && terraform output -raw resource_group_name) + APP_NAME=$(cd infra && terraform output -raw container_app_name) + + az containerapp update \ + --name $APP_NAME \ + --resource-group $RESOURCE_GROUP \ + --container-name mcp-server \ + --image ${{ env.ACR_LOGIN_SERVER }}/codemotion-mcp-server:${{ github.sha }} \ No newline at end of file diff --git a/codemotion-mcp-server/.env.example b/codemotion-mcp-server/.env.example new file mode 100644 index 0000000..9e8f209 --- /dev/null +++ b/codemotion-mcp-server/.env.example @@ -0,0 +1,9 @@ +# GitHub Models API credentials +GITHUB_TOKEN=your_github_token +GITHUB_MODELS_URL=https://api.github.com/models +GITHUB_MODELS_MODEL_FOR_EMBEDDINGS=text-embedding-3-large + +# Qdrant Configuration +QDRANT_HOST=qdrant.internal +QDRANT_PORT=6333 +QDRANT_COLLECTION_NAME=codemotion \ No newline at end of file diff --git a/codemotion-mcp-server/Dockerfile b/codemotion-mcp-server/Dockerfile new file mode 100644 index 0000000..a0e1517 --- /dev/null +++ b/codemotion-mcp-server/Dockerfile @@ -0,0 +1,21 @@ +FROM node:18-alpine + +WORKDIR /app + +# Copy package.json and package-lock.json +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy source code +COPY . . + +# Build TypeScript +RUN npx tsc + +# Expose port +EXPOSE 3000 + +# Command to run the application +CMD ["node", "dist/src/index.js"] \ No newline at end of file diff --git a/codemotion-mcp-server/src/tools/sessionTool.ts b/codemotion-mcp-server/src/tools/sessionTool.ts index bc8857f..2d66d10 100644 --- a/codemotion-mcp-server/src/tools/sessionTool.ts +++ b/codemotion-mcp-server/src/tools/sessionTool.ts @@ -48,12 +48,12 @@ export const registerSessionTool = (server: any): void => { console.log(chalk.blue('Codemotion MCP Server: Vector:', vector)); console.log(chalk.blue('Codemotion MCP Server: Searching for sessions in Qdrant...')); - // Create a Qdrant client - const qdrantClient = new QdrantClient({ - host: 'qdrant', - port: 6333, - https: false, - checkCompatibility: false + // Create a Qdrant client + const qdrantClient = new QdrantClient({ + host: process.env.QDRANT_HOST || 'qdrant', + port: Number(process.env.QDRANT_PORT) || 6333, + https: false, + checkCompatibility: false }); // Search for the sessions in Qdrant diff --git a/infra/README.md b/infra/README.md new file mode 100644 index 0000000..e3ab1b5 --- /dev/null +++ b/infra/README.md @@ -0,0 +1,98 @@ +# Codemotion 2025 Azure Deployment + +This directory contains Terraform code to deploy the Codemotion 2025 MCP Server on Azure Container Apps. + +## Prerequisites + +- [Terraform](https://www.terraform.io/downloads.html) (version >= 1.0) +- [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) +- Docker installed locally for building the container image +- An Azure subscription + +## Setup Steps + +### 1. Login to Azure + +```bash +az login +``` + +### 2. Build and Push the Docker Image + +```bash +# Navigate to the MCP Server directory +cd ../codemotion-mcp-server + +# Build the Docker image +docker build -t codemotion-mcp-server:latest . + +# Log in to Azure Container Registry (after terraform apply) +az acr login --name + +# Tag the image +docker tag codemotion-mcp-server:latest .azurecr.io/codemotion-mcp-server:latest + +# Push the image +docker push .azurecr.io/codemotion-mcp-server:latest +``` + +### 3. Initialize Terraform + +```bash +# Navigate back to the infra directory +cd ../infra + +# Initialize Terraform +terraform init +``` + +### 4. Create a terraform.tfvars File + +Create a `terraform.tfvars` file with your custom values: + +```hcl +resource_group_name = "rg-codemotion-2025" +location = "westeurope" +acr_name = "acrcodemotion2025" +github_token = "your-github-token" +# Add other variables as needed +``` + +### 5. Apply Terraform Configuration + +```bash +terraform apply +``` + +Review the plan and type `yes` to proceed. + +## Accessing the Deployed Application + +After the deployment is complete, you can access your MCP Server at the URL provided in the outputs: + +```bash +terraform output mcp_server_url +``` + +## Clean Up Resources + +To remove all resources created by this Terraform configuration: + +```bash +terraform destroy +``` + +Review the plan and type `yes` to proceed with deletion. + +## Architecture + +This deployment creates: + +1. Azure Resource Group +2. Azure Container Registry (ACR) +3. Log Analytics Workspace +4. Container App Environment +5. Qdrant Container App (for vector search) +6. MCP Server Container App + +The MCP Server connects to Qdrant using the internal DNS name within the Container App Environment. \ No newline at end of file diff --git a/infra/acr.tf b/infra/acr.tf new file mode 100644 index 0000000..067c497 --- /dev/null +++ b/infra/acr.tf @@ -0,0 +1,27 @@ +# Create Azure Container Registry +resource "azurerm_container_registry" "acr" { + name = var.acr_name + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + sku = "Basic" + admin_enabled = true + + tags = { + Environment = "Demo" + Project = "Codemotion2025" + } +} + +# Output for later use in GitHub Actions or other CI/CD +output "acr_login_server" { + value = azurerm_container_registry.acr.login_server +} + +output "acr_admin_username" { + value = azurerm_container_registry.acr.admin_username +} + +output "acr_admin_password" { + value = azurerm_container_registry.acr.admin_password + sensitive = true +} \ No newline at end of file diff --git a/infra/container_apps.tf b/infra/container_apps.tf new file mode 100644 index 0000000..c8a3292 --- /dev/null +++ b/infra/container_apps.tf @@ -0,0 +1,156 @@ +# Create Log Analytics workspace for Container Apps Environment +resource "azurerm_log_analytics_workspace" "law" { + name = "law-${var.container_app_environment_name}" + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + sku = "PerGB2018" + retention_in_days = 30 + + tags = { + Environment = "Demo" + Project = "Codemotion2025" + } +} + +# Create Container Apps Environment +resource "azurerm_container_app_environment" "env" { + name = var.container_app_environment_name + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + log_analytics_workspace_id = azurerm_log_analytics_workspace.law.id + + tags = { + Environment = "Demo" + Project = "Codemotion2025" + } +} + +# Deploy Qdrant as a Container App +resource "azurerm_container_app" "qdrant" { + name = var.qdrant_container_app_name + container_app_environment_id = azurerm_container_app_environment.env.id + resource_group_name = azurerm_resource_group.rg.name + revision_mode = "Single" + + template { + container { + name = "qdrant" + image = "qdrant/qdrant:latest" + cpu = 1.0 + memory = "2Gi" + + env { + name = "QDRANT__SERVICE__HTTP_PORT" + value = "6333" + } + } + + min_replicas = 1 + max_replicas = 1 + } + + ingress { + allow_insecure_connections = false + external_enabled = false + target_port = 6333 + transport = "http" + + traffic_weight { + latest_revision = true + percentage = 100 + } + } + + tags = { + Environment = "Demo" + Project = "Codemotion2025" + } +} + +# Deploy MCP Server as a Container App +resource "azurerm_container_app" "mcp_server" { + name = var.container_app_name + container_app_environment_id = azurerm_container_app_environment.env.id + resource_group_name = azurerm_resource_group.rg.name + revision_mode = "Single" + + registry { + server = azurerm_container_registry.acr.login_server + username = azurerm_container_registry.acr.admin_username + password_secret_name = "registry-password" + } + + secret { + name = "registry-password" + value = azurerm_container_registry.acr.admin_password + } + + secret { + name = "github-token" + value = var.github_token + } + + template { + container { + name = "mcp-server" + image = "${azurerm_container_registry.acr.login_server}/codemotion-mcp-server:${var.image_tag}" + cpu = 0.5 + memory = "1Gi" + + env { + name = "GITHUB_TOKEN" + secret_name = "github-token" + } + + env { + name = "GITHUB_MODELS_URL" + value = var.github_models_url + } + + env { + name = "GITHUB_MODELS_MODEL_FOR_EMBEDDINGS" + value = var.github_models_model_for_embeddings + } + + env { + name = "QDRANT_COLLECTION_NAME" + value = var.qdrant_collection_name + } + + # Configure the app to connect to Qdrant in the same environment + env { + name = "QDRANT_HOST" + value = "${var.qdrant_container_app_name}.internal" + } + + env { + name = "QDRANT_PORT" + value = "6333" + } + } + + min_replicas = 1 + max_replicas = 3 + } + + ingress { + allow_insecure_connections = false + external_enabled = true + target_port = 3000 + transport = "http" + + traffic_weight { + latest_revision = true + percentage = 100 + } + } + + depends_on = [ + azurerm_container_app.qdrant + ] + + tags = { + Environment = "Demo" + Project = "Codemotion2025" + } +} \ No newline at end of file diff --git a/infra/deploy.sh b/infra/deploy.sh new file mode 100755 index 0000000..64a5b2c --- /dev/null +++ b/infra/deploy.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +# Stop on any error +set -e + +# Color output +GREEN="\033[0;32m" +YELLOW="\033[1;33m" +RED="\033[0;31m" +NC="\033[0m" # No Color + +echo -e "${YELLOW}=== Codemotion 2025 Azure Container Apps Deployment ===${NC}" + +# Verify prerequisites +echo -e "\n${YELLOW}Checking prerequisites...${NC}" + +# Check if Azure CLI is installed +if ! command -v az &> /dev/null; then + echo -e "${RED}Azure CLI is not installed. Please install it first.${NC}" + exit 1 +fi + +# Check if logged in to Azure +if ! az account show &> /dev/null; then + echo -e "${YELLOW}Not logged in to Azure. Please log in:${NC}" + az login +fi + +echo -e "${GREEN}Prerequisites met!${NC}" + +# Initialize Terraform +echo -e "\n${YELLOW}Initializing Terraform...${NC}" +terraform init + +# Check if terraform.tfvars exists +if [ ! -f "terraform.tfvars" ]; then + echo -e "${YELLOW}No terraform.tfvars found. Creating a sample one...${NC}" + cat > terraform.tfvars << EOF +resource_group_name = "rg-codemotion-2025" +location = "westeurope" +acr_name = "acrcodemotion2025" +github_token = "your-github-token" +# Add other variables as needed +EOF + echo -e "${YELLOW}Please edit terraform.tfvars with your values before continuing.${NC}" + read -p "Press enter to continue after editing the file..." +fi + +# Apply Terraform configuration +echo -e "\n${YELLOW}Planning Terraform deployment...${NC}" +terraform plan -out=tfplan + +echo -e "\n${YELLOW}Ready to apply Terraform configuration.${NC}" +read -p "Do you want to continue? [y/N] " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + echo -e "\n${YELLOW}Applying Terraform configuration...${NC}" + terraform apply -auto-approve tfplan + + # Get outputs + ACR_LOGIN_SERVER=$(terraform output -raw acr_login_server) + ACR_USERNAME=$(terraform output -raw acr_admin_username) + ACR_PASSWORD=$(terraform output -raw acr_admin_password) + MCP_SERVER_URL=$(terraform output -raw mcp_server_url) + + echo -e "\n${GREEN}Terraform deployment complete!${NC}" + + # Build and push Docker image + echo -e "\n${YELLOW}Building and pushing Docker image...${NC}" + cd ../codemotion-mcp-server + + echo -e "${YELLOW}Building Docker image...${NC}" + docker build -t ${ACR_LOGIN_SERVER}/codemotion-mcp-server:latest . + + echo -e "${YELLOW}Logging in to ACR...${NC}" + echo "$ACR_PASSWORD" | docker login ${ACR_LOGIN_SERVER} -u ${ACR_USERNAME} --password-stdin + + echo -e "${YELLOW}Pushing image to ACR...${NC}" + docker push ${ACR_LOGIN_SERVER}/codemotion-mcp-server:latest + + echo -e "\n${GREEN}Deployment complete!${NC}" + echo -e "\n${GREEN}Your MCP Server is available at:${NC} ${MCP_SERVER_URL}/mcp" +else + echo -e "\n${YELLOW}Deployment cancelled.${NC}" +fi \ No newline at end of file diff --git a/infra/main.tf b/infra/main.tf index e69de29..7cead3a 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -0,0 +1,24 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0" + } + } + required_version = ">= 1.0" +} + +provider "azurerm" { + features {} +} + +# Create resource group +resource "azurerm_resource_group" "rg" { + name = var.resource_group_name + location = var.location + + tags = { + Environment = "Demo" + Project = "Codemotion2025" + } +} diff --git a/infra/outputs.tf b/infra/outputs.tf new file mode 100644 index 0000000..609d845 --- /dev/null +++ b/infra/outputs.tf @@ -0,0 +1,23 @@ +output "resource_group_name" { + value = azurerm_resource_group.rg.name +} + +output "container_app_environment_name" { + value = azurerm_container_app_environment.env.name +} + +output "container_app_name" { + value = azurerm_container_app.mcp_server.name +} + +output "mcp_server_url" { + value = "https://${azurerm_container_app.mcp_server.ingress[0].fqdn}" +} + +output "qdrant_service_name" { + value = azurerm_container_app.qdrant.name +} + +output "deployment_completed" { + value = "The MCP Server has been successfully deployed to Azure Container Apps!" +} \ No newline at end of file diff --git a/infra/variables.tf b/infra/variables.tf new file mode 100644 index 0000000..c822106 --- /dev/null +++ b/infra/variables.tf @@ -0,0 +1,65 @@ +variable "resource_group_name" { + description = "Name of the resource group" + type = string + default = "rg-codemotion-2025" +} + +variable "location" { + description = "Azure region to deploy resources" + type = string + default = "westeurope" +} + +variable "acr_name" { + description = "Name of the Azure Container Registry" + type = string + default = "acrcodemotion2025" +} + +variable "container_app_environment_name" { + description = "Name of the Container App Environment" + type = string + default = "env-codemotion-2025" +} + +variable "container_app_name" { + description = "Name of the Container App" + type = string + default = "app-mcp-server" +} + +variable "qdrant_container_app_name" { + description = "Name of the Qdrant Container App" + type = string + default = "app-qdrant" +} + +variable "github_token" { + description = "GitHub token for authentication with GitHub Models" + type = string + sensitive = true +} + +variable "github_models_url" { + description = "URL for GitHub Models" + type = string + default = "https://api.github.com/models" +} + +variable "github_models_model_for_embeddings" { + description = "Model for embeddings from GitHub Models" + type = string + default = "text-embedding-3-large" +} + +variable "qdrant_collection_name" { + description = "Name of the Qdrant collection" + type = string + default = "codemotion" +} + +variable "image_tag" { + description = "Docker image tag for the MCP server" + type = string + default = "latest" +} \ No newline at end of file