A step-by-step guide for students to build Docker images and deploy them to Google Cloud Run.
- Docker installed on your machine
- A Google Cloud account
- A project with Docker files ready to deploy
# Template
gcloud projects create <PROJECT_ID> --name="<PROJECT_NAME>"
# Example
gcloud projects create technova-mcp-server --name="Technova MCP Server"# Template
gcloud config set project <PROJECT_ID>
# Example
gcloud config set project technova-mcp-serverbrew install google-cloud-sdkDownload from: https://cloud.google.com/sdk/docs/install
curl https://sdk.cloud.google.com | bash
exec -l $SHELLgcloud auth loginThis opens your browser to sign in with your Google account.
# Template
docker build -t <IMAGE_NAME> .
# Example important we need to specify platform
docker build --platform linux/amd64 -t technova-mcp-server .
docker images# Template
gcloud services enable artifactregistry.googleapis.com --project=<PROJECT_ID>
# Example
gcloud services enable artifactregistry.googleapis.com --project=technova-mcp-server# Template
gcloud services enable run.googleapis.com --project=<PROJECT_ID>
# Example
gcloud services enable run.googleapis.com --project=technova-mcp-server# 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# Template
gcloud auth configure-docker <REGION>-docker.pkg.dev
# Example
gcloud auth configure-docker us-central1-docker.pkg.dev# 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"# 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"# 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# 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# 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 8080Note: This example uses the consistent project ID technova-mcp-server throughout._ID>
--allow-unauthenticated
--memory <MEMORY_SIZE>
--platform managed
--port
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
| 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 |
gcloud run services list --project=<PROJECT_ID>gcloud run services describe <SERVICE_NAME> \
--region=<REGION> \
--project=<PROJECT_ID> \
--format="value(status.url)"gcloud logs tail --project=<PROJECT_ID>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>
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.
1. Check your application code
Your app must listen on the port specified by the PORT environment variable:
// 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/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
# 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:80803. Check your Dockerfile Ensure your Dockerfile doesn't hardcode a different port:
# β Bad - hardcoded port
EXPOSE 3000
CMD ["node", "server.js"]
# β
Good - uses environment variable
EXPOSE 8080
CMD ["node", "server.js"]4. Deploy with increased timeout
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 15. Check logs for more details
gcloud logs tail --project=technova-mcp-server- App listens on
process.env.PORTor equivalent - App binds to
0.0.0.0, notlocalhostor127.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)
# 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# 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# 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# 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