Last updated on: 20/06/2019
Cloud Run allows running HTTP stateless containers in a completely managed, way so without worrying about provisioning of VMs, clusters, TLS (https) or app auto-scaling.
Also it charges you only the actual request execution time, therefore it is a fully serverless solution but unlike other established serverless solutions like App Engine and Cloud Functions (see a comparative) it allows to deploy applications written in any language because the final deployed service is a baked container image (that follows a specific runtime contract ).
How is billed time calculated?
The official pricing page shows how billing is calculated:
Contrary to most serverless products Cloud Run is able to handle multiple requests simultaneously (currently 80 as default): the billable time begins with the start of the first request and ends at the end of the last request (see image above).
You are paying only for CPU, memory and the traffic sent to the client from your application (egress traffic) during the working time of the container.
Outside that time-frame, your application is free of charge.
There is also a monthly “Free Tier” so you are billed only for usage past the free quota.
In Acadevmy we are very focused on serverless products and starting from this article we will try to show several deployment examples of famous web applications.
Let’s begin from one “quite” famous app: the classic Wordpress blog!
To get the job done, we will do the following steps:
- GCP environment setup
- Create a MySQL instance
- Create one database and a user for Wordpress
- Create a container image for Wordpress
- Build & Deploy of the container image on Cloud Run
- Wordpress installation
The complete repo is available on GitHub:
Deploy a Wordpress site on Google Cloud Run. Contribute to acadevmy/cloud-run-wordpress development by creating an…
If you are already familiar with container deployments just clone the repo and launch only the commands about database creation and the build & deploy of the service.
GCP environment setup
To setup the GCP environment let’s follow the official guide:
Setting Up Your Environment | Cloud Run | Google Cloud
Whether your business is early in its journey or well on its way to digital transformation, Google Cloud’s solutions…
The steps addressed in the guide are basically:
- Sign in on GCP and select/create a new project.
- Enable the Cloud Run API billing.
- Install the gcloud CLI (beta components included).
- Set the default region.
- Optional: install Docker to build the image in your local machine.
PLEASE NOTE: currently it seems only region
us-central1 is supported on Cloud Run so we set our default region and zone like the following:
gcloud config set compute/region us-central1
gcloud config set compute/zone us-central1-a
If everything has been properly configured, launching the command:
gcloud config list
We should get a result similar to the following:
region = us-central1
zone = us-central1-a
account = email@example.com
disable_usage_reporting = True
project = cr-test-wordpress
Create a MySQL instance
Wordpress need a MySQL database to save the site’s data.
To create a second generation MySQL instance on GCP you can refer to the following article:
Creating instances | Cloud SQL for MySQL | Google Cloud
Whether your business is early in its journey or well on its way to digital transformation, Google Cloud’s solutions…
However the required commands should be the following:
# instance creation
#gcloud sql instances create [INSTANCE_NAME] --tier=[MACHINE_TYPE] -#-region=[REGION]# create a minimal (micro) instance
gcloud sql instances create mysql --tier=db-f1-micro --region=us-central1
You have to wait a few minutes before the instance becomes available and you could get this error:
ERROR: (gcloud.sql.instances.create) Operation https://www.googleapis.com/sql/v1beta4/projects/cr-test-wordpress/operations/a0a22c4e-2222-1111-yyyy-xxxx is taking longer than expected. You can continue waiting for the operation by running `gcloud beta sql operations wait --project cr-test-wordpress a0a22c4e-2222-1111-yyyy-xxxx`
As described by the message, you have to launch the suggested command to monitor the operations progress.
At the end you should get the following:
NAME TYPE START END ERROR STATUS
a0a22c4e-2222-1111-yyyy-xxxx CREATE 2019-06-12T09:05:11.593+00:00 2019-06-12T09:12:04.976+00:00 - DONE
Now you can set the database root password, typing:
# set the root password
gcloud sql users set-password root --host % --instance mysql --password [PASSWORD]
Great! Now let’s add a user and a schema for our Wordpress site.
Create one database and a user for Wordpress
# create wordpress database
gcloud sql databases create wordpress --instance=mysql --charset=utf8 --collation=utf8_general_ci# create wordpress user
gcloud sql users create wordpress \
--host=% --instance=mysql --password=[PASSWORD]
[PASSWORD] as necessary.
After the instance/database/user creation you can check that everything was successful opening a Google Cloud Shell and typing:
gcloud sql connect mysql --user=wordpress --quiet
PLEASE NOTE: Users created using Cloud SQL have all privileges except
If you need to change the privileges for a user, use the
mysql client with classical
Create a container image for Wordpress
Now, let’s create a custom container image to deploy Wordpress on Cloud Run.
We start from the official image present on Docker Hub https://hub.docker.com/_/wordpress/.
We need to change it just a little in order to fulfill the following points:
- Respect the runtime contract about the listening port.
- Connect with our MySQL instance through Cloud Sql Proxy.
- Set the database access credentials for MySQL inside the Wordpress
- Force the use of HTTPS still inside
Let’s take a look at our Dockerfile:
To fulfill point 1, our application must have a web server listening on 0.0.0.0 port 8080 (the port contained in the PORT environment variable).
Therefore, among the available tags we choose a
-apache tag like the
The default Apache image listens on the port 80, so we make a search&replace through
sed(Dockerfile line 6) to change 80 with PORT on
Cloud SQL Proxy provides secure access to your Cloud SQL instances without having to whitelist IP addresses or configure SSL.
So, let’s install the Google binary (Dockerfile lines 10–13) and change the default image entrypoint to run
cloud_sql_proxy(Dockerfile lines 16 and 18).
We have to do also:
- Navigate to IAM and add role CloudSQL Client to the service account of Cloud Run (ending with
- Enable Cloud SQL Admin APIs visiting https://console.developers.google.com/apis/library/sqladmin.googleapis.com?project=[PROJECT_ID] and clicking on ENABLE
At this stage
cloud_sql_proxy should be authorized to connect with database, it just need the instance name as <project>:<region>:<instance-name>; We will use and environment variable called
to accomplish this task.
Here our complete custom entrypoint:
We are almost there!
Now let’s see the points 3 e 4 regarding
First, we set the credentials to access to the database through environment variables (we use PHP function getenv):
define( 'DB_NAME', getenv('DB_NAME') );
/** MySQL database username */
define( 'DB_USER', getenv('DB_USER') );
/** MySQL database password */
define( 'DB_PASSWORD', getenv('DB_PASSWORD') );
/** MySQL hostname */
define( 'DB_HOST', getenv('DB_HOST') );
It would be correct to pass this sensitive data through secrets but they are not (currently) natively supported by Cloud Run: for the sake of simplicity we will just pass them as plain-text but for production deploy it is absolutely recommended to use one of the possible workarounds available here https://www.sethvargo.com/secrets-in-serverless/.
As last point, we need to force HTTPS for the WP admin area (and so for the WP installation) as explained at https://wordpress.org/support/article/administration-over-ssl/#using-a-reverse-proxy.
strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false
$_SERVER['HTTPS'] = 'on';
Cloud Run give us HTTPS urls like
*.run.app for our service (we can also use a custom domain following https://cloud.google.com/run/docs/mapping-custom-domains ).
X-Forwarded-Proto header we can identify that our domain is under HTTPS and force the relative constant for Wordpress.
Hurrah! The Dockerfile is finally ready, so is time to build our final container image and deploy everything on Cloud Run.
Build & Deploy of the container image on Cloud Run
From the directory containing the Dockerfile:
gcloud builds submit --tag gcr.io/[PROJECT-ID]/wp:v1
[PROJECT-ID] is our GCP project id. We can get it using:
gcloud config get-value project
Immediately after starting the build command we will be asked if we wish to activate the API [cloudbuild.googleapis.com], we answer yes and then gcloud will start the build process:
at the end of the process it will push the image on the Container Registry with name:tag
Now that our custom Wordpress container image is on Registry we can deploy it using the following command:
gcloud beta run deploy wp --image gcr.io/[PROJECT-ID]/wp:v1 \
--add-cloudsql-instances <instance-name> \
--imageshows the path of the Registry from which to retrieve the container image.
--add-cloudsql-instances <instance-name>as mentioned in this article, authorizes our service to access to the instance.
--update-env-varsset the environment vars (NAME=value) for our service.
You can notice that the db host is 127.0.0.1 because we have installed and started
cloud_sql_proxyinside our container image.
the final deploy command should be similar to:
gcloud beta run deploy wp --image gcr.io/cr-test-wordpress/wp:v1 \
--add-cloudsql-instances mysql \
We can run the deploy command now: we respond
Y to both questions about activation of API [run.googleapis.com]and at unauthenticated invocations (we want our service publicly accessible).
If all the steps will be successful, you will get the https address of your Wordpress site!
Now we are ready to the Wordpress installation wizard:
at the end of installation we can start using our brand new blog.
Themes and plugins
To extend your blog with custom themes and plugins you should add their sources to Dockerfile mounting the paths recommended in the original docker image Wordpress:
Themes go in a subdirectory in /var/www/html/wp-content/themes/
Plugins go in a subdirectory in /var/www/html/wp-content/plugins/
Admin area would be available only in the warm state and in any case beyond the deployment of a new revision.
Conversely, once added to the container image they will be available even if the service should switch into the “cold” state, the state in which the service is “asleep” waiting to be “awakened” by a request that will download the image again and start a container that will serve the request.
Save your media files on the Cloud
Because we can’t rely on the local filesystem we must use one cloud storage for our media library files.
From now on, our assets will be uploaded on Google Cloud Storage and we won’t use the local filesystem anymore.
Logs & Metrics
All service summary metrics will be available in the service control panel, in addition to the latency and CPU / Memory used.
There will be also a list of previous revisions (one for each new deployment) and a tab logs that show us the list of request received by the service, managed through the integrated product Stackdriver.
Despite being in beta, Google Cloud Run, is for sure a very interesting service: it overcomes brilliantly some of the limitations of actual serverless solutions on the market, making the hosting of stateless services absolutely cost-effective.
For any questions regarding this or anything I should add, correct or remove, feel free to comment, email or DM me on Twitter at @xantrix.
Thanks to Ahmet Alp Balkan for pointing out we must use a cloud storage to save assets files.