Published: Jul 6, 2019 by Isaac Johnson
Google Cloud App Engine Standard is an easy way to launch supported languages (Go, Java, PHP, Python and NodeJS) in a preconfigured cloud container. Google gives you 1Gb of data and traffic for free before you start getting charged. Let’s check out App Engine Standard by creating a basic Python app.
Set up your Environment
First, let’s update our GCP command line tool in case it’s out of date. I make this a habit every time i dig into GCP work.
Usually it will note that you have updates whenever you run a command:
Updates are available for some Cloud SDK components. To install them,
please run:
$ gcloud components update
We can then update
$ gcloud components update
Your current Cloud SDK version is: 252.0.0
You will be upgraded to version: 253.0.0
┌────────────────────────────────────────────────────┐
│ These components will be updated. │
├────────────────────────────┬────────────┬──────────┤
│ Name │ Version │ Size │
├────────────────────────────┼────────────┼──────────┤
│ BigQuery Command Line Tool │ 2.0.44 │ < 1 MiB │
│ Cloud SDK Core Libraries │ 2019.06.28 │ 11.0 MiB │
└────────────────────────────┴────────────┴──────────┘
The following release notes are new in this upgrade.
Please read carefully for information about new features, breaking changes,
and bugs fixed. The latest full release notes can be viewed at:
https://cloud.google.com/sdk/release_notes
253.0.0 (2019-07-02)
Breaking Changes
▪ **(Compute Engine)** Deprecated gcloud beta compute resource-policies
create-snapshot-schedule. Use gcloud beta compute resource-policies
create snapshot-schedule instead.
Cloud SDK
▪ Promoted --audiences flag of gcloud auth print-identity-token to GA.
App Engine
*
▪ Updated the Java SDK to version 1.9.76. Please visit the following
release notes for details:
<https://cloud.google.com/appengine/docs/java/release-notes>
BigQuery
▪ Added support for persistent user-defined functions and stored
procedures in bq show --routine, bq ls --routines, and bq rm --routine.
▪ Added support for creating scheduled queries; use bq query with
--schedule as well as --destination_table and --target_dataset flags.
▪ Increased number of projects listed from the 'bq show' command.
▪ Added 'clustered fields' information for list dataset and show table
commands.
▪ Modified bq show --connection to use the default location if the
connection name is given in 'short' form.
▪ Fixed Python 3 compatibility issues.
Cloud Firestore Emulator
▪ Release Cloud Firestore emulator v1.6.0.
◆ Calling SetSecurityRules with invalid rules is allowed.
Cloud Key Management Service
▪ Promoted gcloud kms import-jobs and other import-related commands to
beta.
Cloud Run
▪ Removed --kubeconfig and --context flags and --platform=kubernetes
option from gcloud beta run.
Cloud SQL
▪ Updated gcloud sql instances describe to show the 'STOPPED' instance
state, to be consistent with the 'gcloud sql instances list command.
Compute Engine
▪ Fixed bug where gcloud compute images import would create temporary
Cloud Storage bucket in US multi-region when source image file is in a
different region.
▪ Promoted gcloud compute instances get-guest-attributes to GA.
▪ Promoted --storage-location flag of gcloud compute images create to
beta.
▪ Modified gcloud compute backend-services <create|update> to relax
validation for specifying --enable-logging, and --logging-sample-rate.
▪ Promoted http2 value to v1 for --protocol flag of gcloud compute
backend-services <create|update>.
▪ Promoted gcloud compute start-iap-tunnel to GA.
▪ Promoted --tunnel-through-iap flag of gcloud compute ssh and gcloud
compute scp to GA.
▪ Promoted --internal-ip flag of gcloud compute scp to GA.
▪ Promoted gcloud compute health-checks <create|update> http2 commands
to GA.
▪ Promoted gcloud compute instances import to beta.
▪ Added --ssh_key_expiration and --ssh_key_expire_after flags to gcloud
compute scp, and gcloud compute ssh, and gcloud compute
connect-to-serial-port commands to set expirations for ssh keys.
Kubernetes Engine
▪ Promoted Google Kubernetes Engine kubectl to 1.12.9 from 1.12.8, to
address CVE-2019-11246.
▪ Promoted the following flags of gcloud container clusters update to
beta:
▪ --database-encryption-key
▪ --database-encryption-key-keyring
▪ --database-encryption-key-location
▪ --database-encryption-key-project
These flags control Database Encryption which encrypt Kubernetes Secrets at
the application layer. For more information, see
<https://cloud.google.com/kubernetes-engine/docs/how-to/encrypting-secrets>.
Subscribe to these release notes at
https://groups.google.com/forum/#!forum/google-cloud-sdk-announce
(https://groups.google.com/forum/#!forum/google-cloud-sdk-announce).
Do you want to continue (Y/n)? Y
╔════════════════════════════════════════════════════════════╗
╠═ Creating update staging area ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Uninstalling: BigQuery Command Line Tool ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Uninstalling: Cloud SDK Core Libraries ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: BigQuery Command Line Tool ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: Cloud SDK Core Libraries ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Creating backup and activating new installation ═╣
╚════════════════════════════════════════════════════════════╝
Performing post processing steps...done.
Update done!
To revert your SDK to the previously installed version, you may run:
$ gcloud components update --version 252.0.0
Next we need to login
$ gcloud auth login
Your browser has been opened to visit:
https://accounts.google.com/o/oauth2/auth?redirect_uri=http%3A%2F%2Flocalhost%3A8085%2F&prompt=select_account&response_type=code&client_id=1234512345.apps.googleusercontent.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fappengine.admin+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcompute+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Faccounts.reauth&access_type=offline
WARNING: `gcloud auth login` no longer writes application default credentials.
If you need to use ADC, see:
gcloud auth application-default --help
You are now logged in as [isaac.johnson@cyberdyne.com].
Your current project is [None]. You can change this setting by running:
$ gcloud config set project PROJECT_ID
Then we need to set the default project ID (which we can get from our console page)
$ gcloud config set project api-project-799042244963
Updated property [core/project].
Setting up App Engine Standard
Next we need a quick Python sample app. It works best to put the next two files in their own subdir.
$ cat myapp/myapp.py
import webapp2
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('I still like NodeJS better')
application = webapp2.WSGIApplication([('/', MainPage)], debug=True)
Next we need an app.yaml for GCP to know how to run it:
$ cat myapp/app.yaml
application: myapp
version: 1
runtime: python27
api_version: 1
threadsafe: false
handlers:
- url: /.*
script: myapp.application
We can first test our app with dev_appserver.py which comes with the GCP CLI installer and will launch our app on a dev instance:
$ dev_appserver.py myapp/
INFO 2019-07-06 14:47:16,249 devappserver2.py:278] Skipping SDK update check.
INFO 2019-07-06 14:47:16,339 api_server.py:275] Starting API server at: http://localhost:63354
WARNING 2019-07-06 14:47:16,340 dispatcher.py:338] Your python27 micro version is below 2.7.12, our current production version.
INFO 2019-07-06 14:47:16,347 dispatcher.py:256] Starting module "default" running at: http://localhost:8080
INFO 2019-07-06 14:47:16,349 admin_server.py:150] Starting admin server at: http://localhost:8000
INFO 2019-07-06 14:47:18,372 instance.py:294] Instance PID: 64150
INFO 2019-07-06 14:47:19,008 instance.py:294] Instance PID: 64152
INFO 2019-07-06 14:47:19,523 module.py:861] default: "GET / HTTP/1.1" 200 26
Deploying to GCP
Next we need to remove a couple lines GCP doesn’t care for and set our project (which i was surprised wasn’t already set from the start):
$ gcloud config set project api-project-799042244963
Updated property [core/project].
$ git diff
diff --git a/myapp/app.yaml b/myapp/app.yaml
index 2f3bb93..ad6a47a 100644
--- a/myapp/app.yaml
+++ b/myapp/app.yaml
@@ -1,5 +1,3 @@
-application: myapp
-version: 1
runtime: python27
api_version: 1
threadsafe: false
Now we can deploy:
$ gcloud app deploy app.yaml
You are creating an app for project [api-project-799042244963].
WARNING: Creating an App Engine application for a project is irreversible and the region
cannot be changed. More information about regions is at
<https://cloud.google.com/appengine/docs/locations>.
Please choose the region where you want your App Engine application
located:
[1] asia-east2 (supports standard and flexible)
[2] asia-northeast1 (supports standard and flexible)
[3] asia-northeast2 (supports standard and flexible)
[4] asia-south1 (supports standard and flexible)
[5] australia-southeast1 (supports standard and flexible)
[6] europe-west (supports standard and flexible)
[7] europe-west2 (supports standard and flexible)
[8] europe-west3 (supports standard and flexible)
[9] europe-west6 (supports standard and flexible)
[10] northamerica-northeast1 (supports standard and flexible)
[11] southamerica-east1 (supports standard and flexible)
[12] us-central (supports standard and flexible)
[13] us-east1 (supports standard and flexible)
[14] us-east4 (supports standard and flexible)
[15] us-west2 (supports standard and flexible)
[16] cancel
Please enter your numeric choice: 12
Creating App Engine application in project [api-project-799042244963] and region [us-central]....done.
Services to deploy:
descriptor: [/Users/isaac.johnson/Workspaces/gcloud-appengine/myapp/app.yaml]
source: [/Users/isaac.johnson/Workspaces/gcloud-appengine/myapp]
target project: [api-project-799042244963]
target service: [default]
target version: [20190706t095130]
target url: [https://api-project-799042244963.appspot.com]
Do you want to continue (Y/n)? Y
Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 2 files to Google Cloud Storage ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://api-project-799042244963.appspot.com]
You can stream logs from the command line by running:
$ gcloud app logs tail -s default
To view your application in the web browser run:
$ gcloud app browse
Let’s run that command to launch a browser to view our site:
$ gcloud app browse
Opening [https://api-project-799042244963.appspot.com] in a new tab in your default browser.
Updating an app:
Now let’s change and redeploy:
$ git diff myapp.py
diff --git a/myapp/myapp.py b/myapp/myapp.py
index ae0ea6f..2dc3184 100644
--- a/myapp/myapp.py
+++ b/myapp/myapp.py
@@ -3,6 +3,6 @@ import webapp2
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
- self.response.out.write('I still like NodeJS better')
+ self.response.out.write('Python is just fine')
application = webapp2.WSGIApplication([('/', MainPage)], debug=True)
$ gcloud app deploy app.yaml
Services to deploy:
descriptor: [/Users/isaac.johnson/Workspaces/gcloud-appengine/myapp/app.yaml]
source: [/Users/isaac.johnson/Workspaces/gcloud-appengine/myapp]
target project: [api-project-799042244963]
target service: [default]
target version: [20190706t123307]
target url: [https://api-project-799042244963.appspot.com]
Do you want to continue (Y/n)? Y
Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 1 file to Google Cloud Storage ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://api-project-799042244963.appspot.com]
You can stream logs from the command line by running:
$ gcloud app logs tail -s default
To view your application in the web browser run:
$ gcloud app browse
Canary deployments and Traffic Splitting
We can also split traffic between the new version and the last. This is useful if you wish to roll out a deployment slowly (Canary) or test routines (A/B testing) for end user reaction.
$ gcloud app services set-traffic default --splits 20190706t095130=0.5,20190706t123307=0.5
Setting the following traffic allocation:
- api-project-799042244963/default/20190706t123307: 0.5
- api-project-799042244963/default/20190706t095130: 0.5
NOTE: Splitting traffic by ip.
Any other versions of the specified service will receive zero traffic.
Do you want to continue (Y/n)? Y
Setting traffic split for service [default]...done.
Note: we got the versions for our command line from the output above. but we can always look up versions and existing split rules from the command-line as well:
$ gcloud app services describe default
id: default
name: apps/api-project-799042244963/services/default
split:
allocations:
20190706t095130: 0.5
20190706t123307: 0.5
shardBy: RANDOM
Random splitting:
GCP Console Details
We can see details of our service in the GCP console as well:
We can go to the App Engine dashboard to see details including billing:
The website also lets us examine all the versions of the code we have and our traffic splitting rules:
Under tools we can view logs and source:
We also have the power to change the traffic splitting, even doing things like randomly switching:
We can also use Migrate Traffic to force all traffic to one version:
We can also pick a version and choose delete to remove it. This is helpful when we are remotely managing an app and a deployment is causing issues. We can roll back to a prior version and delete the problematic deployment.
I’ve left it split randomly 50/50 if you want to try it: https://api-project-799042244963.appspot.com/
Summary
GCP App Engine Standard is a great way to launch a containerized app using a handful of well known and support languages. The free plan gives us a great way to try containerized web apps without the need of managing our own kubernetes cluster.