App Engine (GAE) - Introduction

An overview to App Engine on GCP and how to deploy a sample Flask Python application on the Standard Environment

Β·

8 min read

Introduction to App Engine + Python Environment πŸ‘‹

Google App Engine (GAE) is a fully managed and serverless platform for deploying applications. Focus on writing your code and easily deploy it on the cloud without worrying about operational overhead. It supports various languages including Python, Java, Ruby, and Go and the service can scale to varying demand to ensure reliable performance.

Features βœ”οΈ

What makes App Engine a great service for developers? These are the features it provides:

  • Supports many popular languages like Node.js, Java, Ruby, C#, Go, Python, or PHP in the Standard environment. Otherwise, use Flexible environment for other runtimes
  • If you prefer to use Docker containers then that's possible with Flexible environment
  • Fully Managed! A cloud favourite buzzword, but it's worth hyping because it means as a developer you focus more on your code and less on operations
  • Host different versions of your app for easy testing, staging and managing environments
  • A/B testing of versions by using traffic splitting
  • Built in application security with SSL/TLS certificates and App Engine firewalls
  • Easily integrate with other Google Cloud products!

Concepts πŸ‘©β€πŸ«

Before diving into an example of deploying a Flask application lets look at a couple important concepts.

Environment Types πŸ—ΊοΈ

App Engine offers two environments - Standard and Flexible. There are a couple differences that may affect your environment decision. I've summarised the main differences in the following table:

Category Standard Flexible
Deployment Method App is deployed in a sandbox, which restricts what your app can do App is run by Docker containers on GAE virtual machines
Programming Languages Requires specific versions. For example Python version must be either 3.7, 3.8 or 3.9 Can support any version and includes languages like .NET, which isn't available in Standard
Free Tier Yes No
Traffic Good for rapid scaling for huge traffic spikes Better for consistent traffic or regular traffic fluctuations
Scale to Zero Yes No, minimum 1 instance
Multiprocessing No Yes

If you're looking for specific differences, such as which versions of Python can write to local disk or SSH debugging availability, then refer to Google's documentation here.

Overall, the cheaper and easier environment to use is Standard, but if you have specific requirements or functionality you need then you'll likely need Flexible.

Additionally, the documentation points out it's possible to combine both environments in your applications. How is that possible? Before I explain let's go through a few more concepts.

Architecture πŸŒ‰

Applications in App Engine consists of a layered architecture with each layer containing one or more lower level items.

img

  1. Application: This top-level container includes everything that make up your application. All resources created and app metadata will be stored in your chosen region.
  2. Service: Logical components of your application. Services behave like microservices so each one should have a specific task it completes, such as handling API requests or processing backend data. It's not mandatory to break down your app into multiple services - everything can be bundled under the default service.
  3. Version: Every service can have multiple versions so you can split your traffic to a new version for testing or rollback to an old version if something goes wrong.
  4. Instances: Compute for running your application. App Engine can provision additional instances to scale performance for higher traffic to ensure consistent performance. There are different scaling methods and configuration settings to when instances should be added.

If you split your application into multiple services then each service can be run in either the standard environment or flex environment. To do this in App engine we store configuration settings in a app.yaml file, which I will cover shortly.

Creating an App on App Engine πŸ‘©β€πŸ’»

I'll go through an example of deploying a Flask application to App Engine on the Standard Environment using the default service only. This application will call an API ('official-joke-api.appspot.com/random_joke') and it will obtain a joke each time a button is pressed.

Code & Setup πŸ–₯️

In your desired GCP project run a gcloud command to create an App Engine application in the current project. Pick a region that is close to you and make sure it's the one you want as you can't change it.

gcloud app create --region=europe-west2

Code ⌨️

This is the folder structure for the basic Flask application I'll be deploying.

your-app/
    app.yaml
    main.py
    requirements.txt
static/
    style.css
templates/
    index.html

You can add more directories or adjust the structure, but ensure you have app.yaml file in the main directory and your python file is called main.py.

Python Flask Code 🐍

To get started open your favourite code editor or Cloud Shell. If you're unfamiliar with Cloud Shell it's a handy online development environment embedded in Google Cloud Platform. The editor is similar to Visual Studio Code and supports various languages and development tools including gcloud, Kubernetes, Docker and more. Every user gets 5GB of persistent disk storage so anything you store in your home directory persists.

Read more on Google Cloud Shell Here

There are two ways of accessing Google Cloud Shell

  1. Visit this link here
  2. From the browser

Click on the >_ button on the top right corner. This will pop open a screen at the bottom.

image.png

Then click on the box with the arrow pointing upwards. This will open the window in another tab so it's easier to see.

image.png

Finally click on the Pencil icon and you will have the editor open.

image.png

image.png

The code creates a Flask application that pulls a Joke from an API. It's very simple as I want to focus on App Engine in this tutorial.

image.png

The main.py has the following code:

import os
import ast
import secrets
import datetime
import requests
from flask import Flask, render_template, redirect, request, url_for, session

app = Flask(__name__)
app.secret_key = os.getenv('APP_SECRET_KEY', secrets.token_urlsafe(16))
joke_url = 'https://official-joke-api.appspot.com/random_joke'

@app.route("/")
def index():
    joke = session.get('joke', None)
    return render_template("index.html", current_date=datetime.datetime.now(), joke=joke)

@app.route("/joke")
def joke():
    joke = requests.get(joke_url)
    joke_dict = ast.literal_eval(joke.content.decode('utf-8'))
    session['joke'] = f"{joke_dict['setup']}? {joke_dict['punchline']}"
    return redirect(url_for('index'))

if __name__ == "__main__":
    app.run()

Our app can be run with Gunicorn when deployed to App Engine. We can test this locally by running gunicorn --bind localhost:5000 main:app, which will run a Gunicorn production server for our Flask application. This command binds the host and port to Gunicorn and provides the entry point as main:app - this is the name of the python file and name of the callable in the application.

Just in case it's unclear when you run a Flask application on the development server by default it'll run on localhost:5000. In our configuration file however we change the port to $PORT, which is an environment variable in App Engine to automatically link to the NGINX layer.

app.yaml

We need to configure our application or default service for App Engine. The only mandatory field is runtime, but we'll add a couple other things for our application.

runtime: python37
instance_class: F1
entrypoint: gunicorn --bind localhost:$PORT main:app

handlers:
- url: /static
  static_dir: static

  # This handler routes all requests not caught above to your main app. It is
  # required when static routes are defined, but can be omitted (along with
  # the entire handlers section) when there are no static files defined.
- url: /.*
  script: auto
  secure: always

Let's go over these parameters and what they mean:

  • runtime - Python version to use
  • instance_class - The instance class to use which defines a memory limit and CPU limit
  • entrypoint - The command that should be run for executing the entrypoint command
  • handlers - A list of URL patterns and how they should be handled
  • static_dir - The path to directory containing static files
  • script - Specifies that requests to a specific handler should target your app
  • secure - A configuration for either always, never or optionally using https

Other Files πŸ—„οΈ

Here are the other files I have used.

Requirements.txt

Flask==2.0.1
requests==2.25.1
gunicorn==20.1.0

static/style.css

@import url('https://fonts.googleapis.com/css2?family=Montserrat&display=swap');

body {
  font-family: 'Montserrat', sans-serif;
  text-align: center;
  background-color: lavender;
}

hr {
    width: 80%;
    border-top: 1px solid  #f0f0f5;
}

templates/index.html

<html>
    <head>
        <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
    </head>
    <body>
        <h1>Hello!</h1>
        <h3>Welcome to my website!</h3>
        <h4>The current time is {{ current_date }} </h4>
        <hr>

         {% if joke %}
         <p>{{ joke }}</p>
         {% endif %}

        <form action="/joke">
            <input type="submit" value="I want a joke!"/>
        </form>
    </body>
</html>

Deploying πŸ†—

In the root of your directory run the following command. This deploys your service(s) as a new version and behind the scenes Google will create a container using Cloud Build and keeps a copy in Google Cloud Storage before deploying on App Engine.

# Deploy a new version to GAE
gcloud app deploy

# Get the URL of your application
gcloud app browser

To view your application in the browser either run gcloud app browser or visit your app engine URL at https://[PROJECT_ID].[REGION_ID].r.appspot.com if you're not usng a custom domain.

NOTE If you get an error (gcloud.app.deploy) NOT_FOUND: Unable to retrieve P4SA: wait a few seconds and try running the command again.

Deployed App πŸ“±

image.png

This is what my simple Flask application looks like. Every time you click the button it retrieves another joke from the API.

App Engine Interface πŸ“Š

image.png

On Google Cloud you can see information on your application including number of requests, 4xx or 5xx responses, visited URIs and their response times and traces, and much more. The great thing is this is all built into the service so it's ready to use.

image.png

I can see all of my versions, split traffic to run A/B testing and view information such as logs, source code or view the app in GCP's Debugging tool.

Conclusion & Thank You πŸ‘‹

This is only scratching the surface in terms of App Engine's features and capabilities. I hope you found this introduction to App Engine and Python 3 Standard Environment useful. In a future post I'll be covering another Flask example except it will use OAuth2 to pull data from Google and store user data in a database.

Thanks for reading and I would love to hear your comments.