Skip to content

Commit e51534c

Browse files
committed
Updated google cloud workflow
Signed-off-by: Mihai Criveti <[email protected]>
1 parent 5db2179 commit e51534c

File tree

3 files changed

+268
-142
lines changed

3 files changed

+268
-142
lines changed
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# ===============================================================
2+
# ☁️ MCP Gateway ▸ Build, Cache & Deploy to Google Cloud Run
3+
# ===============================================================
4+
# Maintainer: Mihai Criveti
5+
# Status: Inactive
6+
# This workflow:
7+
# • Restores / updates a local **BuildKit layer cache** ❄️
8+
# • Builds the Docker image from **Containerfile.lite** 🏗️
9+
# • Pushes the image to **Google Artifact Registry** 📤
10+
# • Deploys to **Google Cloud Run** with autoscale=1 🚀
11+
#
12+
# ---------------------------------------------------------------
13+
# Prerequisites (one-time setup)
14+
# ---------------------------------------------------------------
15+
# 1. Create a Google Cloud project and enable billing
16+
# 2. Enable required APIs:
17+
# gcloud services enable run.googleapis.com artifactregistry.googleapis.com
18+
# 3. Create an Artifact Registry repository:
19+
# gcloud artifacts repositories create mcpgateway \
20+
# --repository-format=docker \
21+
# --location=us-central1 \
22+
# --description="MCP Gateway Docker images"
23+
# 4. Create a service account with required permissions:
24+
# - Cloud Run Developer (only on mcpgateway service)
25+
# - Artifact Registry Writer (only on mcpgateway repository)
26+
# Example for restricted setup:
27+
# gcloud run services add-iam-policy-binding mcpgateway \
28+
# --region=us-central1 \
29+
# --member="serviceAccount:[email protected]" \
30+
# --role="roles/run.developer"
31+
# 5. Create Cloud SQL (PostgreSQL) and Memorystore (Redis) instances
32+
# (see deployment documentation for commands)
33+
#
34+
# ---------------------------------------------------------------
35+
# Required repository **secrets**
36+
# ---------------------------------------------------------------
37+
# ┌────────────────────────┬─────────────────────────────────────────────────────────────────────┐
38+
# │ Secret name │ Description / Example value │
39+
# ├────────────────────────┼─────────────────────────────────────────────────────────────────────┤
40+
# │ GCP_PROJECT_ID │ Your Google Cloud project identifier. │
41+
# │ │ While not a secret, it's sensitive and used as such for consistency.│
42+
# │ │ Example: "my-gcp-project-123456" │
43+
# ├────────────────────────┼─────────────────────────────────────────────────────────────────────┤
44+
# │ GCP_SERVICE_KEY │ Service account JSON key for authentication to Google Cloud │
45+
# │ │ Get from: IAM & Admin > Service Accounts > Keys > Add Key > JSON │
46+
# │ │ Example: {"type": "service_account", "project_id": "my-project"...} │
47+
# ├────────────────────────┼─────────────────────────────────────────────────────────────────────┤
48+
# │ JWT_SECRET_KEY │ Random secret for signing JWT authentication tokens │
49+
# │ │ Generate with: openssl rand -base64 32 │
50+
# │ │ Example: "xQ3Z5yDvEd2qP9kL7mN4wR8tU1aF6jH0bC3gI5sV" │
51+
# ├────────────────────────┼─────────────────────────────────────────────────────────────────────┤
52+
# │ BASIC_AUTH_PASSWORD │ Password for HTTP Basic Authentication (fallback auth method) │
53+
# │ │ Example: "changeme-to-something-secure" │
54+
# ├────────────────────────┼─────────────────────────────────────────────────────────────────────┤
55+
# │ DATABASE_URL │ PostgreSQL connection string for Cloud SQL instance │
56+
# │ │ Format: postgresql://USER:PASS@IP:PORT/DATABASE │
57+
# │ │ Example: "postgresql://postgres:[email protected]:5432/mcpgw" │
58+
# ├────────────────────────┼─────────────────────────────────────────────────────────────────────┤
59+
# │ REDIS_URL │ Redis connection string for Memorystore instance │
60+
# │ │ Format: redis://IP:PORT/DB_NUMBER │
61+
# │ │ Example: "redis://10.20.30.50:6379/0" │
62+
# └────────────────────────┴─────────────────────────────────────────────────────────────────────┘
63+
#
64+
# ---------------------------------------------------------------
65+
# Required repository **variables**
66+
# ---------------------------------------------------------------
67+
# ┌────────────────────────────┬─────────────────────────────────────────────────────────────────┐
68+
# │ Variable name │ Description / Example value │
69+
# ├────────────────────────────┼─────────────────────────────────────────────────────────────────┤
70+
# │ GCP_REGION │ Google Cloud region for deployment │
71+
# │ │ Example: "us-central1" (or us-east1, europe-west1, etc.) │
72+
# ├────────────────────────────┼─────────────────────────────────────────────────────────────────┤
73+
# │ GAR_REPO_NAME │ Artifact Registry repository name (must exist) │
74+
# │ │ Example: "mcpgateway" or "docker-images" │
75+
# ├────────────────────────────┼─────────────────────────────────────────────────────────────────┤
76+
# │ IMAGE_NAME │ Name for your Docker image │
77+
# │ │ Example: "mcpgateway" │
78+
# ├────────────────────────────┼─────────────────────────────────────────────────────────────────┤
79+
# │ CLOUD_RUN_SERVICE │ Name of the Cloud Run service │
80+
# │ │ Example: "mcpgateway" or "mcp-gateway-prod" │
81+
# ├────────────────────────────┼─────────────────────────────────────────────────────────────────┤
82+
# │ CLOUD_RUN_PORT │ Port number the container listens on (numeric, no quotes) │
83+
# │ │ Example: 4444 │
84+
# ├────────────────────────────┼─────────────────────────────────────────────────────────────────┤
85+
# │ BASIC_AUTH_USER │ Username for HTTP Basic Authentication │
86+
# │ │ Example: "admin" │
87+
# ├────────────────────────────┼─────────────────────────────────────────────────────────────────┤
88+
# │ CACHE_TYPE │ Cache backend type for MCP Gateway │
89+
# │ │ Example: "redis" (or "memory" for development) │
90+
# ├────────────────────────────┼─────────────────────────────────────────────────────────────────┤
91+
# │ HOST │ IP address to bind the service to (required for containers) │
92+
# │ │ Must be: "0.0.0.0" (to listen on all interfaces) │
93+
# ├────────────────────────────┼─────────────────────────────────────────────────────────────────┤
94+
# │ GUNICORN_WORKERS │ Number of Gunicorn worker processes (numeric, no quotes) │
95+
# │ │ Example: 1 (keep low for cost efficiency) │
96+
# ├────────────────────────────┼─────────────────────────────────────────────────────────────────┤
97+
# │ CLOUD_RUN_CPU │ Number of vCPUs allocated (numeric, no quotes) │
98+
# │ │ Example: 1 (minimum is 0.08, maximum is 8) │
99+
# ├────────────────────────────┼─────────────────────────────────────────────────────────────────┤
100+
# │ CLOUD_RUN_MEMORY │ Memory allocation for the service │
101+
# │ │ Example: "512Mi" (minimum is 128Mi, maximum is 32Gi) │
102+
# └────────────────────────────┴─────────────────────────────────────────────────────────────────┘
103+
#
104+
# Triggers:
105+
# • Every push to `main`
106+
# ===============================================================
107+
108+
name: Deploy to Google Cloud Run
109+
110+
on:
111+
push:
112+
branches: ["main"]
113+
114+
permissions:
115+
contents: read
116+
117+
env:
118+
# ─── project & registry ───────────────────────────
119+
GCP_REGION: ${{ vars.GCP_REGION }}
120+
GAR_REPO_NAME: ${{ vars.GAR_REPO_NAME }}
121+
IMAGE_NAME: ${{ vars.IMAGE_NAME }}
122+
IMAGE_TAG: ${{ github.sha }}
123+
CLOUD_RUN_SERVICE: ${{ vars.CLOUD_RUN_SERVICE }}
124+
CLOUD_RUN_PORT: ${{ vars.CLOUD_RUN_PORT }}
125+
126+
# ─── app configuration (non-secret) ──────────────
127+
BASIC_AUTH_USER: ${{ vars.BASIC_AUTH_USER }}
128+
CACHE_TYPE: ${{ vars.CACHE_TYPE }}
129+
HOST: ${{ vars.HOST }}
130+
GUNICORN_WORKERS: ${{ vars.GUNICORN_WORKERS }}
131+
CLOUD_RUN_CPU: ${{ vars.CLOUD_RUN_CPU }}
132+
CLOUD_RUN_MEMORY: ${{ vars.CLOUD_RUN_MEMORY }}
133+
134+
# ─── secrets ─────────────────────────────────────
135+
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
136+
JWT_SECRET_KEY: ${{ secrets.JWT_SECRET_KEY }}
137+
BASIC_AUTH_PASSWORD: ${{ secrets.BASIC_AUTH_PASSWORD }}
138+
DATABASE_URL: ${{ secrets.DATABASE_URL }}
139+
REDIS_URL: ${{ secrets.REDIS_URL }}
140+
141+
# ─── caching helpers ──────────────────────────────
142+
CACHE_DIR: /tmp/.buildx-cache
143+
144+
jobs:
145+
build-push-deploy:
146+
name: 🚀 Build, Cache, Push & Deploy
147+
runs-on: ubuntu-latest
148+
environment: google-cloud-run-production
149+
# Uses PostgreSQL database and Redis cache
150+
151+
steps:
152+
# -----------------------------------------------------------
153+
# 0️⃣ Checkout repository
154+
# -----------------------------------------------------------
155+
- name: ⬇️ Checkout source
156+
uses: actions/checkout@v4
157+
158+
# -----------------------------------------------------------
159+
# 1️⃣ Authenticate to Google Cloud
160+
# -----------------------------------------------------------
161+
- name: 🔐 Authenticate to Google Cloud
162+
uses: google-github-actions/auth@v2
163+
with:
164+
credentials_json: ${{ secrets.GCP_SERVICE_KEY }}
165+
166+
- name: 🧰 Set up gcloud SDK
167+
uses: google-github-actions/setup-gcloud@v2
168+
with:
169+
project_id: ${{ env.GCP_PROJECT_ID }}
170+
171+
# -----------------------------------------------------------
172+
# 2️⃣ Set up Docker Buildx + cache
173+
# -----------------------------------------------------------
174+
- name: 🛠️ Set up Docker Buildx
175+
uses: docker/setup-buildx-action@v3
176+
177+
- name: 🔄 Restore BuildKit cache
178+
uses: actions/cache@v4
179+
with:
180+
path: ${{ env.CACHE_DIR }}
181+
key: ${{ runner.os }}-buildx-${{ github.sha }}
182+
restore-keys: ${{ runner.os }}-buildx-
183+
184+
# -----------------------------------------------------------
185+
# 3️⃣ Configure Docker to use gcloud auth
186+
# -----------------------------------------------------------
187+
- name: 🔧 Configure Docker for Artifact Registry
188+
run: gcloud auth configure-docker ${{ env.GCP_REGION }}-docker.pkg.dev
189+
190+
# -----------------------------------------------------------
191+
# 4️⃣ Build & tag image
192+
# -----------------------------------------------------------
193+
- name: 🏗️ Build Docker image
194+
run: |
195+
docker buildx build \
196+
--file Containerfile.lite \
197+
--tag ${{ env.GCP_REGION }}-docker.pkg.dev/${{ env.GCP_PROJECT_ID }}/${{ env.GAR_REPO_NAME }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} \
198+
--cache-from type=local,src=${{ env.CACHE_DIR }} \
199+
--cache-to type=local,dest=${{ env.CACHE_DIR }},mode=max \
200+
--load \
201+
.
202+
203+
# -----------------------------------------------------------
204+
# 5️⃣ Push image to Artifact Registry
205+
# -----------------------------------------------------------
206+
- name: 📤 Push image to GAR
207+
run: |
208+
docker push ${{ env.GCP_REGION }}-docker.pkg.dev/${{ env.GCP_PROJECT_ID }}/${{ env.GAR_REPO_NAME }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
209+
210+
# -----------------------------------------------------------
211+
# 6️⃣ Deploy to Cloud Run
212+
# -----------------------------------------------------------
213+
- name: 🚀 Deploy to Cloud Run
214+
run: |
215+
gcloud run deploy "$CLOUD_RUN_SERVICE" \
216+
--image "$GCP_REGION-docker.pkg.dev/$GCP_PROJECT_ID/$GAR_REPO_NAME/$IMAGE_NAME:$IMAGE_TAG" \
217+
--region "$GCP_REGION" \
218+
--platform managed \
219+
--allow-unauthenticated \
220+
--port "$CLOUD_RUN_PORT" \
221+
--cpu "$CLOUD_RUN_CPU" \
222+
--memory "$CLOUD_RUN_MEMORY" \
223+
--max-instances 1 \
224+
--set-env-vars "JWT_SECRET_KEY=$JWT_SECRET_KEY" \
225+
--set-env-vars "BASIC_AUTH_USER=$BASIC_AUTH_USER" \
226+
--set-env-vars "BASIC_AUTH_PASSWORD=$BASIC_AUTH_PASSWORD" \
227+
--set-env-vars "AUTH_REQUIRED=true" \
228+
--set-env-vars "DATABASE_URL=$DATABASE_URL" \
229+
--set-env-vars "REDIS_URL=$REDIS_URL" \
230+
--set-env-vars "CACHE_TYPE=$CACHE_TYPE" \
231+
--set-env-vars "HOST=$HOST" \
232+
--set-env-vars "GUNICORN_WORKERS=$GUNICORN_WORKERS"
233+
234+
# -----------------------------------------------------------
235+
# 7️⃣ Show deployment status
236+
# -----------------------------------------------------------
237+
- name: 📈 Display deployment status
238+
run: |
239+
URL=$(gcloud run services describe "$CLOUD_RUN_SERVICE" --region "$GCP_REGION" --format "value(status.url)")
240+
echo "🎉 Service deployed to: $URL"
241+
echo "📊 Service details:"
242+
gcloud run services describe "$CLOUD_RUN_SERVICE" --region "$GCP_REGION"

0 commit comments

Comments
 (0)