Deploying a Python serverless function in minutes with GCP

Laurent Picard
Google Cloud - Community
7 min readSep 30, 2018

f( ☁️, 🐍 ) = 🌈🌤️🐍🐍🐍…

Hey Pythonistas, we can deploy Python functions!

Wikipedia is my source of truth to list an author’s bibliography, filmography… Unfortunately, not everything is available in digital form. For example, I’d like to list books actually available as ebooks. This is a very simple task, a microservice in fact. GCP’s Cloud Functions looks perfect for this. Let’s check it out, starting from scratch.

A few questions

What is Cloud Functions?

Cloud Functions is a managed service for serverless functions. The acronym describing such a service is FaaS (Function as a Service).

What’s a managed service?

It’s a service I don’t have to manage. I just use it.

What’s a serverless function?

Like a function in a program, a serverless (or cloud) function is an independent unit that can be naturally isolated in an app architecture.

How does it work?

The function is event driven: code will be called upon triggers such as an HTTP request, a file uploaded to a cloud storage, a message published…

What are the benefits of a serverless function?

  • The code itself can be directly deployed in an isolated cloud function.
  • The function resources scale automatically, up but also down, as the traffic evolves (the infra handles this for me).
  • The function is highly available (a benefit of using a managed service).
  • I only pay for what I use: if the function is not used, the cost is zero.

Why do I love serverless as a developer?

  • I can focus on code.
  • I have a clearer, yet robust and performant, architecture.
  • I can sleep on both ears. If there’s a service outage at 2am, reliability engineers will handle the issue.

How do I get started?

I just need a GCP account. GCP offers a generous free tier to get started and try different products:

  • First-time users get a $300 free credit to use over 12 months.
  • Additionally, every month, Cloud Functions is free for the first 2 million invocations (and below other high volume thresholds).

So, unless I deploy a very successful function invoked millions of times every month, this won’t cost anything. Did I say I love serverless?

What’s in my toolbox?

There are 3 ways I can work with Cloud Functions (or GCP in general):

  1. From the graphical user interface (GUI): I can deploy cloud functions straight from the browser, without installing any tool. This is perfect to monitor or just discover the service, but also for quick prototyping or debugging.
  2. From the command-line interface (CLI): in a proper development workflow, I will typically script everything and use gcloud(GCP’s main command-line utility).
  3. From the application programming interface (API): all GCP services are API based, allowing for fully industrialized developments. When I use the GUI or the CLI, I actually initiate web requests to the REST API undercover.

What’s my battle plan?

Let’s deploy a simple HTTP-triggered cloud function, first from the GUI, then from the CLI. But let’s prepare the code first.

Show me the code!

”Hello World!”

Flask is the underlying framework used to handle incoming HTTP requests. A typical “hello world” cloud function is as simple as this:

This gives, without parameters:

or, with a parameter:

Defining the HTTP entry point

I want to print out the list of available ebooks by a given author, in a given language. Based on the hello world sample above, I can define this simple Python function:

Getting the data from Google Books API

Requests is “an elegant and simple HTTP library for Python, built for human beings” (docs.python-requests.org) and indeed it is. This allows querying an API (such as the Google Books API) very easily:

Printing the result in plain text

Flask naturally handles HTML templates but, for the sake of simplicity, let’s define this basic function to return a plain text result:

Deploying a cloud function from the GUI

GCP offers a web console, a GUI that works from any browser, without any prior installation. The web console is perfect for testing a feature (which is my case right now), quickly building a proof of concept, and of course monitoring my services.

Opening the web console

Go to https://console.cloud.google.com

Creating a new project

Define the project name & ID

Monitoring my project from the dashboard

My project is ready

Using the “getting started” shortcut

“Getting started” lists the most common tasks

Creating my cloud function

Enable the Cloud Functions API first (one security control)
Switch the runtime value from default “Node.js” to “Python”
New: You can now specify if the function is to be private or public. As our use case is about exposing a public API, make sure option “Allow unauthenticated invocations” is checked.
Enter the function name, code, entry point & region, then create/deploy the function
The function is deployed. A simple HTTP request can now trigger the function.

Checking the function

This works. For an actual API, the result would of course be in json, not in plain text.

Deleting the project

Open the project settings, then shut down the project (to be actually deleted 30 days later)

Deploying a cloud function from the CLI

A command-line interface (CLI) is the preferred tool if you regularly manage cloud projects. GCP offers Cloud Shell, a standard bash environment working directly from your browser, without any prior installation. The magic behind it is that it automatically handles an SSH connection to a small VM where everything I need is pre-installed. The main command-line utility is gcloud. Let’s get a chrono (⌛) of each step…

Opening Cloud Shell (⌛15”)

Go to https://console.cloud.google.com and open Cloud Shell

Creating a new project (+11” → ⌛26”)

PROJECT_ID="MY-PROJECT-ID"
PROJECT_NAME="Get Ebooks PyGCF"
gcloud projects create $PROJECT_ID \
--name="$PROJECT_NAME" \
--set-as-default
Create in progress for [https://cloudresourcemanager.googleapis.com/v1/projects/...].
Waiting for [operations/cp...] to finish...done.
Updated property [core/project] to [PROJECT_ID].

Note: Project IDs are unique across GCP. I used get-ebooks-pygcf but you should define your own.

Linking the project to my billing account (+5” → ⌛31”)

BILLING_ACCOUNT=$(gcloud beta billing accounts list \
--format 'value(name)')
gcloud beta billing projects link $PROJECT_ID \
--billing-account $BILLING_ACCOUNT
billingAccountName: billingAccounts/XXXXXX-YYYYYY-ZZZZZZ
billingEnabled: true
name: projects/PROJECT_ID/billingInfo
projectId: PROJECT_ID

Enabling the Cloud Functions API (+11” → ⌛42”)

gcloud services enable cloudfunctions.googleapis.comOperation "operations/acf..." finished successfully.

Getting the code (+3” → ⌛45”)

git clone https://github.com/PicardParis/cloud-snippets.gitCloning into 'cloud-snippets'...
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 8 (delta 0), reused 8 (delta 0), pack-reused 0
Unpacking objects: 100% (8/8), done.
cd cloud-snippets/python/gcf-get-ebooks/
ls
main.py

Deploying the function (+1’42” → ⌛2’27”)

GCF_NAME="get-ebooks"
GCF_ENTRY="get_ebooks_by_author"
GCF_REGION="europe-west1"
gcloud functions deploy $GCF_NAME \
--entry-point $GCF_ENTRY \
--region $GCF_REGION \
--runtime python37 \
--trigger-http \
--allow-unauthenticated
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
entryPoint: get_ebooks_by_author
httpsTrigger:
url: https://GCF_REGION-PROJECT_ID.cloudfunctions.net/GCF_NAME
labels:
deployment-tool: cli-gcloud
name: projects/PROJECT_ID/locations/GCF_REGION/functions/GCF_NAME
runtime: python37
serviceAccountEmail: ...
sourceUploadUrl: ...
status: ACTIVE
timeout: 60s
updateTime: 'YYYY-MM-DDThh:mm:ssZ'
versionId: '1'

Notes:

  • The first deployment is longer (sets up the environment). If I update main.py and redeploy, the update takes ~25 seconds.
  • By default, deployed functions are private (they can only be called by authorized services within Google Cloud Platform). Flag --allow-unauthenticated makes the function public (so that we can call it with a curl command below). Unless you are creating public APIs or websites, you will generally not use this flag in production.

Calling the function (+1” → ⌛2’28”)

GCF_URL=https://$GCF_REGION-$PROJECT_ID.cloudfunctions.net/$GCF_NAMEcurl "$GCF_URL?author=saint+exupery&lang=fr"====================================================================
"saint exupery" ebooks (lang=fr)
====================================================================
# | Pages | Title
1 | 528 | Écrits de guerre (1939-1944)
2 | 384 | Carnets
3 | 240 | Lettres à sa mère
5 | 180 | Les plus belles pensées d'Antoine de Saint-Exupéry
6 | 48 | Saint-Exupéry - / Le Royaume des étoiles
7 | 36 | Le Petit Prince raconté aux enfants
...
curl "$GCF_URL?author=jrr+tolkien&lang=de"====================================================================
"jrr tolkien" ebooks (lang=de)
====================================================================
# | Pages | Title
1 | 1,568 | Der Herr der Ringe / Sonderausgabe
2 | 964 | Das Buch der verschollenen Geschichten / 1. & 2. Teil
3 | 720 | Nachrichten aus Mittelerde
4 | 608 | Der Herr der Ringe - Die Gefährten / Neuüberarbeitung
5 | 560 | Die Legende von Sigurd und Gudrún
6 | 558 | Das Silmarillion
7 | 444 | Der Herr der Ringe - Die Rückkehr des Königs /
...

Deleting the project (+5” → ⌛2’33”)

gcloud projects delete $PROJECT_ID

Level up!

Updates

  • 2019.12.16: Added flag --allow-unauthenticated to explicitly deploy a public function.

What’s next?

Deploying a Python serverless app in minutes (stay tuned)…

--

--

Laurent Picard
Google Cloud - Community

Tech lover, passionate about software, hardware, science and anything shaping the future • ⛅ explorer at Google • Opinions my own