Configuring Website Deployment on Google Cloud (GCE/Cloud Run)
Google Cloud offers two main paths for web applications: Compute Engine (GCE) — virtual machines, Cloud Run — serverless containers with autoscaling to zero.
Cloud Run — Recommended Option
Cloud Run runs a Docker container and scales it from 0 to N instances. You pay only for actual request processing time.
# Project setup
gcloud config set project myproject-123456
# Build and deploy in one command
gcloud run deploy myapp \
--source . \
--region europe-west3 \
--platform managed \
--allow-unauthenticated \
--port 8080 \
--min-instances 1 \ # don't scale to zero (avoid cold start)
--max-instances 10 \
--memory 512Mi \
--cpu 1 \
--set-env-vars APP_ENV=production \
--set-secrets DB_PASSWORD=db-password:latest
Dockerfile for Cloud Run
FROM php:8.3-fpm-alpine
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-scripts
COPY . .
RUN php artisan config:cache && php artisan route:cache
# Cloud Run requires PORT from environment variable
ENV PORT=8080
EXPOSE 8080
CMD ["php", "artisan", "serve", "--host=0.0.0.0", "--port=8080"]
Terraform for Cloud Run
# main.tf
resource "google_cloud_run_v2_service" "myapp" {
name = "myapp"
location = "europe-west3"
template {
scaling {
min_instance_count = 1
max_instance_count = 20
}
containers {
image = "gcr.io/myproject/myapp:latest"
resources {
limits = {
cpu = "1"
memory = "512Mi"
}
cpu_idle = false
}
env {
name = "APP_ENV"
value = "production"
}
env {
name = "DB_PASSWORD"
value_source {
secret_key_ref {
secret = google_secret_manager_secret.db_password.secret_id
version = "latest"
}
}
}
startup_probe {
http_get { path = "/health" }
initial_delay_seconds = 5
timeout_seconds = 3
}
}
}
}
resource "google_cloud_run_v2_service_iam_member" "noauth" {
name = google_cloud_run_v2_service.myapp.name
role = "roles/run.invoker"
member = "allUsers"
}
Google Compute Engine (GCE)
# Create VM
gcloud compute instances create myapp-vm \
--machine-type=e2-medium \
--zone=europe-west3-a \
--image-family=ubuntu-2204-lts \
--image-project=ubuntu-os-cloud \
--tags=http-server,https-server \
--metadata-from-file startup-script=startup.sh
# Firewall rules
gcloud compute firewall-rules create allow-http \
--allow tcp:80,tcp:443 \
--target-tags=http-server
Cloud Build CI/CD
# cloudbuild.yaml
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA']
- name: 'gcr.io/cloud-builders/gcloud'
args:
- run
- deploy
- myapp
- '--image=gcr.io/$PROJECT_ID/myapp:$COMMIT_SHA'
- '--region=europe-west3'
- '--platform=managed'
timeout: '900s'
GitHub Actions + Google Cloud
- uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.GCP_CREDENTIALS }}
- uses: google-github-actions/setup-gcloud@v2
- name: Build and push
run: |
gcloud builds submit --tag gcr.io/$PROJECT_ID/myapp:$GITHUB_SHA
- name: Deploy to Cloud Run
run: |
gcloud run deploy myapp \
--image gcr.io/$PROJECT_ID/myapp:$GITHUB_SHA \
--region europe-west3 \
--platform managed
Static Site: GCS + Cloud CDN
# Create bucket
gsutil mb -l EUROPE-WEST3 gs://myapp-static
# Allow public access
gsutil iam ch allUsers:objectViewer gs://myapp-static
# Upload
gsutil -m rsync -r -d ./dist gs://myapp-static
# Configure as website
gsutil web set -m index.html -e index.html gs://myapp-static
Implementation Timeline
| Option | Timeline |
|---|---|
| Cloud Run (first deploy) | 1–2 days |
| Cloud Run + Terraform | 3–4 days |
| GCE with Load Balancer | 4–6 days |
| GCS static + Cloud CDN | 1 day |







