Summary

In this codelab, you'll learn to deploy a simple Python Flask web app to the App Engine flexible environment. The app allows a user to upload a photo of a person's face and learn how likely it is that the person is happy. It uses Google Cloud APIs for Cloud Vision, Cloud Storage, and Datastore.

About App Engine

Google App Engine app are easy to create, maintain, and scale as your traffic and data storage needs change. With App Engine, there are no servers to maintain. You simply upload your app and it's ready to go.

App Engine apps automatically scale based on incoming traffic. Load balancing, microservices, authorization, SQL and NoSQL databases, traffic splitting, logging, search, versioning, roll out and roll backs, and security scanning are all natively supported natively and are highly customizable.

The App Engine flexible environment supports many programming languages, including C#, Go, Java, Node.js, PHP, Python, and Ruby. The flexible environment runs your application within Docker containers running on Compute Engine virtual machine (VM) instances.

The App Engine standard environment is an alternative option for certain languages, including Python. The standard environment runs your app in a more restrictive sandbox environment. Read Choosing an App Engine Environment for more information.

What you'll learn

What you'll need

Project Creation

If you don't already have a Google Account, then you must create one. Sign into Cloud Console and create a new project:

Remember the project ID, a unique name across all Google Cloud projects (the name above has already been taken and will not work for you, sorry!). It will be referred to later in the codelab as PROJECT_ID.

Billing

Next, you need to enable billing in the Cloud Console in order to use Google Cloud resources.

Running through the codelab shouldn't cost you more than a few dollars, but it could be more if you decide to use more resources or if you leave them running.

New users of Google Cloud are eligible for a $300 free trial.

While Google Cloud can be operated remotely from your laptop, you'll use Cloud Shell, a command-line environment running in the Cloud. The Debian-based VM is loaded with the development tools that you'll need—gcloud command-line tool, Python, virtualenv, pip, and more, it offers a persistent 5GB home directory, and it runs in Google Cloud, greatly enhancing network performance and authentication. That means that all you need is a web browser, such as Google Chrome.

To activate Cloud Shell from the Cloud Console, simply click the button on the top right-hand side (it should only take a few moments to provision and connect to the environment).

Once connected to the Cloud Shell, you should see that you're already authenticated and that the project is already set to your PROJECT_ID.

gcloud auth list
Credentialed accounts:
- <myaccount>@<mydomain>.com (active)
gcloud config list project
[core]
Project = <PROJECT_ID>

If, for some reason, the project is not set, simply issue the following command:

gcloud config set project <PROJECT_ID>

Looking for your PROJECT_ID? Check out what Project ID you used in the setup steps or look it up in the Cloud Console dashboard.

In Cloud Shell, on the command line, run the following command to clone the Github repository:

git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

Change the directory into python-docs-samples/codelabs/flex_and_vision:

cd python-docs-samples/codelabs/flex_and_vision

Before we can begin using the APIs for Cloud Vision, Cloud Storage, and Datastore, you must enable the APIs with the following commands:

gcloud services enable vision.googleapis.com
gcloud services enable storage-component.googleapis.com
gcloud services enable datastore.googleapis.com

In order to make requests to the APIs for Cloud Vision, Cloud Storage, and Datastore, you need service account credentials. Service account credentials from your project can be generated using the gcloud command-line tool.

Set an environment variable for your PROJECT_ID, replacing [YOUR_PROJECT_ID] with your project ID:

export PROJECT_ID=[YOUR_PROJECT_ID]

Create a service account to access the Google Cloud APIs when locally testing.

gcloud iam service-accounts create codelab \
  --display-name "My Codelab Service Account"

Give your newly created Service Account appropriate permissions.

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member serviceAccount:codelab@${PROJECT_ID}.iam.gserviceaccount.com \
--role roles/owner

After creating your service account, create a service account key:

gcloud iam service-accounts keys create ~/key.json \
--iam-account codelab@${PROJECT_ID}.iam.gserviceaccount.com

That command generates a service account key stored in a JSON file named key.json in your home directory.

Using the absolute path of the generated key, set an environment variable for your service account key in the Cloud Shell:

export GOOGLE_APPLICATION_CREDENTIALS="/home/${USER}/key.json"

For further information, read more about authenticating the Vision API.

Start your virtual environment and install dependencies

Create an isolated Python 3 environment named env with virtualenv:

virtualenv -p python3 env

Enter your newly created virtualenv named env:

source env/bin/activate

Use pip to install dependencies for your project from the requirements.txt file:

pip install -r requirements.txt

The requirements.txt file is a list of package dependencies that you need for your project. The above command downloaded all of those listed package dependencies to the virtualenv.

Create an App Engine App

Next, create an App Engine instance by using:

gcloud app create

Create a storage bucket

First, set the environment variable CLOUD_STORAGE_BUCKET equal to the name of your PROJECT_ID. (It's generally recommended to name your bucket the same as your PROJECT_ID for convenience purposes).

export CLOUD_STORAGE_BUCKET=${PROJECT_ID}

Your app uses a Cloud Storage bucket, which you will need to create from Cloud Shell with a tool called gsutil. Run the following command, which creates a bucket with the same name as your PROJECT_ID:

gsutil mb gs://${PROJECT_ID}

Run the app

python main.py

Once the application starts, click on Web Preview in the Cloud Shell toolbar and choose Preview on port 8080.

A tab in your browser opens and connects to the server that you started. You should see something like this:

Screen Shot 2017-02-23 at 7.22.50 PM.png

Try uploading a photo that contains a human face. Click the Choose File button, choose an image from your computer, and then click Submit.

After uploading a photo, you should see something like this:

Screen Shot 2017-02-23 at 7.32.08 PM.png

Sample code layout

The sample code has the following layout:

templates/
  homepage.html   /* HTML template that uses Jinja2 */
app.yaml          /* App Engine application configuration file */
main.py           /* Python Flask web application */
requirements.txt  /* List of dependencies for the project */

main.py

The Python file is a Flask web app. The app allows users to submit photos (preferably of faces), which are stored in Cloud Storage and analyzed using the face detection feature of the Cloud Vision API. Key information about each photo is stored in Datastore, the Google Cloud NoSQL database, where it is accessed each time a user visits the website.

The app uses the Google Cloud client libraries for Cloud Storage, Datastore, and Cloud Vision. Those client libraries make it easy to access Google Cloud APIs from your favorite programming languages.

Take a look at some key snippets of the code.

The imports section at the top is where you import the various packages that you need for your code. That's how you import your Google Cloud client libraries for Datastore, Cloud Storage, and Cloud Vision

from google.cloud import datastore
from google.cloud import storage
from google.cloud import vision

Here is the code for what happens when a user visits the root URL of the website. You create a Datastore client object, which is used to access the Datastore client library. You then run a query on Datastore for entities of kind Faces. Finally, you render your HTML template, passing in the image_entities that you extract from Datastore as a variable.

@app.route('/')
def homepage():
    # Create a Cloud Datastore client.
    datastore_client = datastore.Client()

    # Use the Cloud Datastore client to fetch information from Datastore about
    # each photo.
    query = datastore_client.query(kind='Faces')
    image_entities = list(query.fetch())

    # Return a Jinja2 HTML template and pass in image_entities as a parameter.
    return render_template('homepage.html', image_entities=image_entities)

Take a look at how entities are saved to Datastore. Datastore is Google Cloud's NoSQL database solution. Data is stored in objects called entities. Each entity is assigned a unique identifying key, which can be created using a kind and a key name string. A kind is an organizational bucket for what type of entity it is. For example, you might want to set up kinds for photos, people, and animals.

Each entity can have multiple developer-defined properties, which can have values of a number of types, including integers, floats, strings, dates, or binary data.

    # Create a Cloud Datastore client.
    datastore_client = datastore.Client()

    # Fetch the current date / time.
    current_datetime = datetime.now()

    # The kind for the new entity.
    kind = 'Faces'

    # The name/ID for the new entity.
    name = blob.name

    # Create the Cloud Datastore key for the new entity.
    key = datastore_client.key(kind, name)

    # Construct the new entity using the key. Set dictionary values for entity
    # keys blob_name, storage_public_url, timestamp, and joy.
    entity = datastore.Entity(key)
    entity['blob_name'] = blob.name
    entity['image_public_url'] = blob.public_url
    entity['timestamp'] = current_datetime
    entity['joy'] = face_joy

    # Save the new entity to Datastore.
    datastore_client.put(entity)

The Cloud Storage and Cloud Vision client libraries can be accessed programmatically in a similar manner to Datastore. You can open the main.py file yourself using vim, emacs, or GNU nano to explore all the sample code.

Learn more about Flask here.

Learn more about client libraries here.

homepage.html

The Flask web framework leverages Jinja2 as a template engine. That allows you to pass in variables and expressions from main.py into homepage.html that get replaced with values once the page is rendered.

Learn more about Jinja2 here.

This Jinja2 HTML template displays a form for users to submit photos to the database. It also displays each previously submitted image along with its file name, upload date/time, and the likelihood that the face detected by the Vision API is happy.

homepage.html

<h1>Google Cloud Platform - Face Detection Sample</h1>

<p>This Python Flask application demonstrates App Engine Flexible, Google Cloud
Storage, Datastore, and the Cloud Vision API.</p>

<br>

<html>
  <body>
    <form action="upload_photo" method="POST" enctype="multipart/form-data">
      Upload File: <input type="file" name="file"><br>
      <input type="submit" name="submit" value="Submit">
    </form>
    {% for image_entity in image_entities %}
      <img src="{{image_entity['image_public_url']}}" width=200 height=200>
      <p>{{image_entity['blob_name']}} was uploaded {{image_entity['timestamp']}}.</p>
      <p>Joy Likelihood for Face: {{image_entity['joy']}}</p>
    {% endfor %}
  </body>
</html>

The App Engine flexible environment uses a file called app.yaml to describe an app's deployment configuration. If this file is not present, App Engine will try to guess the deployment configuration. However, it is a good idea to provide that file.

Next, you will modify app.yaml using the GNU nano editor.

nano app.yaml

app.yaml

runtime: python
env: flex
entrypoint: gunicorn -b :$PORT main:app

runtime_config:
    python_version: 3

env_variables:
    CLOUD_STORAGE_BUCKET: <your-cloud-storage-bucket>

That's the basic configuration needed to deploy a Python 3 App Engine flexible environment app. You can learn more about configuring App Engine here.

Once you have app.yaml open, replace < your-cloud-storage-bucket > with the name of your Cloud Storage bucket. (If you forgot the name of your Cloud Storage bucket, copy the Google Cloud Project ID from Qwiklabs, which is the same). The env_variables section sets up environment variables that will be used in main.py once the app is deployed.

You can now close and save, and close the file in GNU nano by using Control+S (Command+S on Macintosh), which will prompt the following:

Screen Shot 2017-02-17 at 4.47.12 PM.png

Type y and then press the enter key one more time to confirm the filename for the following prompt:

Screen Shot 2017-02-24 at 4.18.23 PM.png

Deploy your app on App Engine by using the gcloud command-line tool.

gcloud app deploy

After the app is deployed, you can visit it by opening the URL https://< PROJECT_ID >.appspot.com in your web browser.

Summary

You set up a Python web app and deployed it to the App Engine flexible environment!

You learned how to write and deploy your first App Engine flexible environment web app!

Clean up

To avoid incurring charges to your Google Account for the resources used, do the following:

Learn more

License

This work is licensed under a Creative Commons Attribution 2.0 Generic License.