iflow-mcp_xamhans-mcp-course 0.1.0
Add your description here
Requires Python: >=3.11

# Google Cloud Build & Deploy Guide

A step-by-step guide for students to build Docker images and deploy them to Google Cloud Run.

## Prerequisites

- Docker installed on your machine
- A Google Cloud account
- A project with Docker files ready to deploy

---

## Step 1: Setup Google Cloud Project

### Create a new project (if needed)

```bash
# Template
gcloud projects create <PROJECT_ID> --name="<PROJECT_NAME>"

# Example
gcloud projects create technova-mcp-server --name="Technova MCP Server"
```

### Set your project as active

```bash
# Template
gcloud config set project <PROJECT_ID>

# Example
gcloud config set project technova-mcp-server
```

---

## Step 2: Install Google Cloud CLI

### For macOS (using Homebrew)

```bash
brew install google-cloud-sdk
```

### For Windows

Download from: https://cloud.google.com/sdk/docs/install

### For Linux

```bash
curl https://sdk.cloud.google.com | bash
exec -l $SHELL
```

---

## Step 3: Authenticate with Google Cloud

```bash
gcloud auth login
```

This opens your browser to sign in with your Google account.

---

## Step 4: Build Your Docker Image

### Build your Docker image locally

```bash
# Template
docker build -t <IMAGE_NAME> .

# Example important we need to specify platform

docker build --platform linux/amd64 -t technova-mcp-server .

```

### Verify your image was built

```bash
docker images
```

---

## Step 5: Enable Required APIs

### Enable Artifact Registry API

```bash
# Template
gcloud services enable artifactregistry.googleapis.com --project=<PROJECT_ID>

# Example
gcloud services enable artifactregistry.googleapis.com --project=technova-mcp-server
```

### Enable Cloud Run API

```bash
# Template
gcloud services enable run.googleapis.com --project=<PROJECT_ID>

# Example
gcloud services enable run.googleapis.com --project=technova-mcp-server
```

---

## Step 6: Create Artifact Registry Repository

```bash
# Template
gcloud artifacts repositories create <REPO_NAME> \
  --repository-format=docker \
  --location=<REGION> \
  --project=<PROJECT_ID>

# Example
gcloud artifacts repositories create technova-repo \
  --repository-format=docker \
  --location=us-central1 \
  --project=technova-mcp-server
```

---

## Step 7: Configure Docker Authentication

```bash
# Template
gcloud auth configure-docker <REGION>-docker.pkg.dev

# Example
gcloud auth configure-docker us-central1-docker.pkg.dev
```

---

## Step 8: Set Up IAM Permissions

### Grant yourself editor permissions

```bash
# Template
gcloud projects add-iam-policy-binding <PROJECT_ID> \
  --member="user:<YOUR_EMAIL>" \
  --role="roles/editor"

# Example
gcloud projects add-iam-policy-binding technova-mcp-server \
  --member="user:muellerjohannes93@gmail.com" \
  --role="roles/editor"
```

### Grant Artifact Registry writer permissions

```bash
# Template
gcloud projects add-iam-policy-binding <PROJECT_ID> \
  --member="user:<YOUR_EMAIL>" \
  --role="roles/artifactregistry.writer"

# Example
gcloud projects add-iam-policy-binding technova-mcp-server \
  --member="user:muellerjohannes93@gmail.com" \
  --role="roles/artifactregistry.writer"
```

---

## Step 9: Tag and Push Image to Artifact Registry

### Tag your image

```bash
# Template
docker tag <LOCAL_IMAGE_NAME> \
  <REGION>-docker.pkg.dev/<PROJECT_ID>/<REPO_NAME>/<IMAGE_NAME>:<TAG>

# Example
docker tag technova-mcp-server \
  us-central1-docker.pkg.dev/technova-mcp-server/technova-repo/technova-mcp-server:latest
```

### Push image to registry

```bash
# Template
docker push <REGION>-docker.pkg.dev/<PROJECT_ID>/<REPO_NAME>/<IMAGE_NAME>:<TAG>

# Example
docker push \
  us-central1-docker.pkg.dev/technova-mcp-server/technova-repo/technova-mcp-server:latest
```

---

## Step 10: Deploy to Cloud Run

### Deploy using the pushed image

```bash
# Template
gcloud run deploy <SERVICE_NAME> \
  --image <REGION>-docker.pkg.dev/<PROJECT_ID>/<REPO_NAME>/<IMAGE_NAME>:<TAG> \
  --region <REGION> \
  --project <PROJECT_ID> \
  --allow-unauthenticated \
  --memory <MEMORY_SIZE> \
  --platform managed \
  --port <PORT>

# Example
gcloud run deploy technova-mcp-server \
  --image us-central1-docker.pkg.dev/technova-mcp-server/technova-repo/technova-mcp-server:latest \
  --region us-central1 \
  --project technova-mcp-server \
  --allow-unauthenticated \
  --memory 1Gi \
  --platform managed \
  --port 8080
```

**Note**: This example uses the consistent project ID `technova-mcp-server` throughout.\_ID> \
 --allow-unauthenticated \
 --memory <MEMORY_SIZE> \
 --platform managed \
 --port <PORT>

# Example

gcloud run deploy technova-mcp-server \
 --image us-central1-docker.pkg.dev/technova-mcp-server/technova-repo/technova-mcp-server:latest \
 --region us-central1 \
 --project technova-mcp-server \
 --allow-unauthenticated \
 --memory 1Gi \
 --platform managed \
 --port 8080

````

### ⭐ Recommended: Deploy directly from source (Cloud Build handles everything)
```bash
# Template
gcloud run deploy <SERVICE_NAME> \
  --source . \
  --port <PORT> \
  --memory <MEMORY_SIZE> \
  --allow-unauthenticated \
  --region <REGION> \
  --project <PROJECT_ID>

# Working example (from successful deployment)
gcloud run deploy technova-mcp-server \
  --source . \
  --port 8080 \
  --memory 1Gi \
  --allow-unauthenticated \
  --region us-central1 \
  --project technova-mcp-server
````

**Why this method works better:**

- Cloud Run automatically builds your Docker image using Cloud Build
- No manual Docker registry setup needed
- Handles dependencies and build process automatically
- Less prone to port configuration errors

---

## Common Values Reference

| Parameter       | Common Values                             | Description         |
| --------------- | ----------------------------------------- | ------------------- |
| `<REGION>`      | `us-central1`, `us-east1`, `europe-west1` | Geographic location |
| `<MEMORY_SIZE>` | `512Mi`, `1Gi`, `2Gi`, `4Gi`              | Memory allocation   |
| `<PORT>`        | `8080`, `3000`, `5000`                    | Application port    |
| `<TAG>`         | `latest`, `v1.0`, `dev`                   | Image version tag   |

---

## Verification Steps

### Check your deployment

```bash
gcloud run services list --project=<PROJECT_ID>
```

### Get service URL

```bash
gcloud run services describe <SERVICE_NAME> \
  --region=<REGION> \
  --project=<PROJECT_ID> \
  --format="value(status.url)"
```

### View logs

```bash
gcloud logs tail --project=<PROJECT_ID>
```

---

## Troubleshooting

### Common Issues

**Authentication Error**: Run `gcloud auth login` again

**Permission Denied**: Check IAM permissions in Step 8

**Image Not Found**: Verify image was pushed successfully with `gcloud artifacts docker images list --repository=<REPO_NAME> --location=<REGION>`

### 🔥 Container Failed to Start (Port Issues)

**Error Message**: `The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable`

**Root Cause**: Your application isn't listening on the correct port that Cloud Run expects.

#### Solution Steps:

**1. Check your application code**
Your app must listen on the port specified by the `PORT` environment variable:

```javascript
// Node.js/Express example
const port = process.env.PORT || 8080;
app.listen(port, '0.0.0.0', () => {
  console.log(`Server running on port ${port}`);
});
```

```python
# Python/Flask example
import os
from flask import Flask

app = Flask(__name__)

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 8080))
    app.run(host='0.0.0.0', port=port)
```

**2. Test locally with PORT environment variable**

```bash
# Test locally to ensure your app respects PORT env var
PORT=8080 docker run -p 8080:8080 -e PORT=8080 technova-mcp-server

# Test if accessible
curl http://localhost:8080
```

**3. Check your Dockerfile**
Ensure your Dockerfile doesn't hardcode a different port:

```dockerfile
# ❌ Bad - hardcoded port
EXPOSE 3000
CMD ["node", "server.js"]

# ✅ Good - uses environment variable
EXPOSE 8080
CMD ["node", "server.js"]
```

**4. Deploy with increased timeout**

```bash
gcloud run deploy technova-mcp-server \
  --image us-central1-docker.pkg.dev/technova-mcp-server/technova-repo/technova-mcp-server:latest \
  --region us-central1 \
  --project technova-mcp-server \
  --allow-unauthenticated \
  --memory 1Gi \
  --port 8080 \
  --timeout 300 \
  --cpu 1
```

**5. Check logs for more details**

```bash
gcloud logs tail --project=technova-mcp-server
```

#### Debug Checklist:

- [ ] App listens on `process.env.PORT` or equivalent
- [ ] App binds to `0.0.0.0`, not `localhost` or `127.0.0.1`
- [ ] Dockerfile exposes the correct port
- [ ] No firewall or security groups blocking the port
- [ ] App starts within Cloud Run's timeout (default 240 seconds)

---

## Debugging Your Deployment

### Get detailed logs

```bash
# Follow logs in real-time
gcloud logs tail --project=technova-mcp-server

# Get specific revision logs
gcloud logging read "resource.type=cloud_run_revision AND resource.labels.service_name=technova-mcp-server" --project=technova-mcp-server --limit=50
```

### Test your container locally first

```bash
# Build and test locally with same environment as Cloud Run
docker build -t technova-mcp-server .
docker run -p 8080:8080 -e PORT=8080 technova-mcp-server

# In another terminal, test if it responds
curl http://localhost:8080
```

### Check service status

```bash
# Get service details
gcloud run services describe technova-mcp-server \
  --region us-central1 \
  --project technova-mcp-server

# List all revisions
gcloud run revisions list \
  --service technova-mcp-server \
  --region us-central1 \
  --project technova-mcp-server
```

---

## Quick Commands Summary

```bash
# Setup
gcloud config set project <PROJECT_ID>
gcloud services enable artifactregistry.googleapis.com run.googleapis.com

# Build & Push
docker build -t <IMAGE_NAME> .
docker tag <IMAGE_NAME> <REGION>-docker.pkg.dev/<PROJECT_ID>/<REPO_NAME>/<IMAGE_NAME>:latest
docker push <REGION>-docker.pkg.dev/<PROJECT_ID>/<REPO_NAME>/<IMAGE_NAME>:latest

# Deploy
gcloud run deploy <SERVICE_NAME> \
  --image <REGION>-docker.pkg.dev/<PROJECT_ID>/<REPO_NAME>/<IMAGE_NAME>:latest \
  --region <REGION> \
  --allow-unauthenticated
```