Cloud Run without VPC Serverless

Illustration of a person gazing upwards with a smile, tied to a cloud by a string in a whimsical, sketchy style, surrounded by additional clouds and abstract orange lines rising up from the ground. Illustration of a person gazing upwards with a smile, tied to a cloud by a string in a whimsical, sketchy style, surrounded by additional clouds and abstract orange lines rising up from the ground.

Today, we are going to explore perhaps the end of a classic in GCP Cloud Run. Every time we want to communicate with a VPC, we need to use complex elements like Serverless VPC. We have numerous articles, videos, and even a webinar addressing this problem. However, since summer 2023, there has been a beta version that allows us to connect our Cloud Run service or job directly to a component inside a VPC without Serverless VPC.

First, we are going to create our destination, and to do that, we will start a Compute Engine machine with a Docker container running a web server.

Here's how we create the Compute Engine:

➜ cloudrun gcloud compute instances create my-instance \
    --zone=us-central1-a \
    --network=vpc-test \
    --subnet=vpc-test \
    --tags=http-server,ssh-tag,https-server

Once this is created, we will connect to the instance via SSH:

➜ cloudrun gcloud compute ssh my-instance --project=mkdev-dev --zone=us-central1-a

Next, we create the folder where we want to work:

sudo -i
mkdir my-app
cd my-app

Now, we create the app.py:

from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
    return "Hello from Internal Server!"
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80)

And the Dockerfile:

# Use the official Python runtime as a base image
FROM python:3.8-slim
# Set the working directory
WORKDIR /usr/src/app
# Copy the current directory contents into the container
COPY . .
# Install Flask
RUN pip install Flask
# Expose port 80 for the app
EXPOSE 80
# Define the command to run the app
CMD ["python", "app.py"]

Next, we can install Docker, build, and run our image:

apt-get install docker.io
sudo systemctl enable docker
docker build -t internal-server .
docker run -d -p 80:80 internal-server

Our Compute Engine will now be waiting for us on port 80. Before we leave the Compute Engine, we need to remember to save the private IP.

Now, we need to go to our Cloud Run. We are going to have code that communicates with the server we just created:

from flask import Flask, request, jsonify
import os
import requests
app = Flask(__name__)
@app.route('/')
def hello_world():
    try:
        response = requests.get('http://10.128.0.3:80')
        return response.text
    except Exception as e:
        return str(e), 500
if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

And now we can create the Dockerfile:

# Use the official lightweight Python image.
FROM python:3.9-slim
# Install production dependencies.
RUN pip install --no-cache-dir Flask requests
# Copy local code to the container image.
WORKDIR /app
COPY main.py .
# Set environment variables.
ENV PORT 8080
# Run the web service on container startup.
CMD ["python", "main.py"]


Next step, build the image:

gcloud builds submit --tag gcr.io/mkdev-dev/no-serverless-cloud-run

And now we can deploy our image to our Cloud Run simply by adding the beta:

cloud beta run deploy cloudrun \
--image=gcr.io/mkdev-dev/no-serverless-cloud-run \
--network=vpc-test \
--subnet=vpc-test \
--vpc-egress=all-traffic \
--region=us-central1


And now, when we go to the URL displayed on the screen, we can see:

Hello from Internal Server!


This confirms that we can connect to our VPC without a Serverless VPC.


Here' the same article in video form for your convenience: