diff --git a/cloud-sql/mysql/mysql/Dockerfile b/cloud-sql/mysql/mysql/Dockerfile
new file mode 100644
index 0000000000..a278f69ca5
--- /dev/null
+++ b/cloud-sql/mysql/mysql/Dockerfile
@@ -0,0 +1,26 @@
+# Copyright 2019 Google LLC. All rights reserved.
+# Use of this source code is governed by the Apache 2.0
+# license that can be found in the LICENSE file.
+
+# Use the official lightweight Node.js 10 image.
+# https://hub.docker.com/_/node
+FROM node:10-slim
+
+# Create and change to the app directory.
+WORKDIR /usr/src/app
+
+# Copy application dependency manifests to the container image.
+# A wildcard is used to ensure both package.json AND package-lock.json are copied.
+# Copying this separately prevents re-running npm install on every code change.
+COPY package*.json ./
+
+# Install dependencies.
+# If you add a package-lock.json speed your build by switching to 'npm ci'.
+# RUN npm ci --only=production
+RUN npm install --production
+
+# Copy local code to the container image.
+COPY . ./
+
+# Run the web service on container startup.
+CMD [ "npm", "start" ]
diff --git a/cloud-sql/mysql/mysql/README.md b/cloud-sql/mysql/mysql/README.md
index fb5ccd40b1..2ddef9457b 100644
--- a/cloud-sql/mysql/mysql/README.md
+++ b/cloud-sql/mysql/mysql/README.md
@@ -32,7 +32,7 @@ secure solution such as [Cloud KMS](https://cloud.google.com/kms/) to help keep
## Running locally
To run this application locally, download and install the `cloud_sql_proxy` by
-following the instructions [here](https://cloud.google.com/sql/docs/mysql/sql-proxy#install).
+[following the instructions](https://cloud.google.com/sql/docs/mysql/sql-proxy#install).
Once the proxy is ready, use the following command to start the proxy in the
background:
@@ -90,3 +90,39 @@ command:
gcloud app browse
```
+## Deploy to Cloud Run
+
+See the [Cloud Run documentation](https://cloud.google.com/run/docs/configuring/connect-cloudsql)
+for more details on connecting a Cloud Run service to Cloud SQL.
+
+1. Build the container image:
+
+```sh
+gcloud builds submit --tag gcr.io/[YOUR_PROJECT_ID]/run-mysql
+```
+
+2. Deploy the service to Cloud Run:
+
+```sh
+gcloud beta run deploy run-mysql --image gcr.io/[YOUR_PROJECT_ID]/run-mysql
+```
+
+Take note of the URL output at the end of the deployment process.
+
+3. Configure the service for use with Cloud Run
+
+```sh
+gcloud beta run services update run-mysql \
+ --add-cloudsql-instances [INSTANCE_CONNECTION_NAME] \
+ --set-env-vars CLOUD_SQL_CONNECTION_NAME=[INSTANCE_CONNECTION_NAME],\
+ DB_USER=[MY_DB_USER],DB_PASS=[MY_DB_PASS],DB_NAME=[MY_DB]
+```
+Replace environment variables with the correct values for your Cloud SQL
+instance configuration.
+
+This step can be done as part of deployment but is separated for clarity.
+
+4. Navigate your browser to the URL noted in step 2.
+
+For more details about using Cloud Run see http://cloud.run.
+Review other [Node.js on Cloud Run samples](../../../run/).
diff --git a/cloud-sql/mysql/mysql/server.js b/cloud-sql/mysql/mysql/server.js
index 774a0f5976..69e6e55fe8 100644
--- a/cloud-sql/mysql/mysql/server.js
+++ b/cloud-sql/mysql/mysql/server.js
@@ -43,58 +43,62 @@ const logger = winston.createLogger({
});
// [START cloud_sql_mysql_mysql_create]
-const pool = mysql.createPool({
- user: process.env.DB_USER, // e.g. 'my-db-user'
- password: process.env.DB_PASS, // e.g. 'my-db-password'
- database: process.env.DB_NAME, // e.g. 'my-database'
- // If connecting via unix domain socket, specify the path
- socketPath: `/cloudsql/${process.env.CLOUD_SQL_CONNECTION_NAME}`,
- // If connecting via TCP, enter the IP and port instead
- // host: 'localhost',
- // port: 3306,
-
- //[START_EXCLUDE]
-
- // [START cloud_sql_mysql_mysql_limit]
- // 'connectionLimit' is the maximum number of connections the pool is allowed
- // to keep at once.
- connectionLimit: 5,
- // [END cloud_sql_mysql_mysql_limit]
-
- // [START cloud_sql_mysql_mysql_timeout]
- // 'connectTimeout' is the maximum number of milliseconds before a timeout
- // occurs during the initial connection to the database.
- connectTimeout: 10000, // 10 seconds
- // 'acquireTimeout' is the maximum number of milliseconds to wait when
- // checking out a connection from the pool before a timeout error occurs.
- acquireTimeout: 10000, // 10 seconds
- // 'waitForConnections' determines the pool's action when no connections are
- // free. If true, the request will queued and a connection will be presented
- // when ready. If false, the pool will call back with an error.
- waitForConnections: true, // Default: true
- // 'queueLimit' is the maximum number of requests for connections the pool
- // will queue at once before returning an error. If 0, there is no limit.
- queueLimit: 0, // Default: 0
- // [END cloud_sql_mysql_mysql_timeout]
-
- // [START cloud_sql_mysql_mysql_backoff]
- // The mysql module automatically uses exponential delays between failed
- // connection attempts.
- // [END cloud_sql_mysql_mysql_backoff]
-
- //[END_EXCLUDE]
-});
+let pool;
+const createPool = async () => {
+ pool = await mysql.createPool({
+ user: process.env.DB_USER, // e.g. 'my-db-user'
+ password: process.env.DB_PASS, // e.g. 'my-db-password'
+ database: process.env.DB_NAME, // e.g. 'my-database'
+ // If connecting via unix domain socket, specify the path
+ socketPath: `/cloudsql/${process.env.CLOUD_SQL_CONNECTION_NAME}`,
+ // If connecting via TCP, enter the IP and port instead
+ // host: 'localhost',
+ // port: 3306,
+
+ //[START_EXCLUDE]
+
+ // [START cloud_sql_mysql_mysql_limit]
+ // 'connectionLimit' is the maximum number of connections the pool is allowed
+ // to keep at once.
+ connectionLimit: 5,
+ // [END cloud_sql_mysql_mysql_limit]
+
+ // [START cloud_sql_mysql_mysql_timeout]
+ // 'connectTimeout' is the maximum number of milliseconds before a timeout
+ // occurs during the initial connection to the database.
+ connectTimeout: 10000, // 10 seconds
+ // 'acquireTimeout' is the maximum number of milliseconds to wait when
+ // checking out a connection from the pool before a timeout error occurs.
+ acquireTimeout: 10000, // 10 seconds
+ // 'waitForConnections' determines the pool's action when no connections are
+ // free. If true, the request will queued and a connection will be presented
+ // when ready. If false, the pool will call back with an error.
+ waitForConnections: true, // Default: true
+ // 'queueLimit' is the maximum number of requests for connections the pool
+ // will queue at once before returning an error. If 0, there is no limit.
+ queueLimit: 0, // Default: 0
+ // [END cloud_sql_mysql_mysql_timeout]
+
+ // [START cloud_sql_mysql_mysql_backoff]
+ // The mysql module automatically uses exponential delays between failed
+ // connection attempts.
+ // [END cloud_sql_mysql_mysql_backoff]
+
+ //[END_EXCLUDE]
+ });
+};
+createPool();
// [END cloud_sql_mysql_mysql_create]
-// When the server starts, check for tables in the database.
-app.on('listening', async () => {
+const ensureSchema = async () => {
// Wait for tables to be created (if they don't already exist).
await pool.query(
`CREATE TABLE IF NOT EXISTS votes
( vote_id SERIAL NOT NULL, time_cast timestamp NOT NULL,
candidate CHAR(6) NOT NULL, PRIMARY KEY (vote_id) );`
);
-});
+};
+ensureSchema();
// Serve the index page, showing vote tallies.
app.get('/', async (req, res) => {
diff --git a/run/README.md b/run/README.md
index 2cfa44ead3..d99e5022aa 100644
--- a/run/README.md
+++ b/run/README.md
@@ -13,6 +13,7 @@
|[Pub/Sub][pubsub] | Event-driven service with a Pub/Sub push subscription | [
][run_button_pubsub] |
|[Image Processing][image_processing] | Event-driven image analysis & transformation | [
][run_button_image_processing] |
|[Manual Logging][manual_logging] | Structured logging without client library | [
][run_button_manual_logging] |
+|[Cloud SQL (MySQL)][mysql] | Use MySQL with Cloud Run | - |
|[Hello Broken][hello_broken] | Something is wrong, how do you fix it? | [
][run_button_hello_broken] |
For more Cloud Run samples beyond Node.js, see the main list in the [Cloud Run Samples repository](https://github.com/GoogleCloudPlatform/cloud-run-samples).
@@ -116,6 +117,7 @@ for more information.
[pubsub]: pubsub/
[image_processing]: image-processing/
[manual_logging]: logging-manual/
+[mysql]: ../cloud-sql/mysql/mysql
[hello_broken]: hello-broken/
[run_button_helloworld]: https://console.cloud.google.com/cloudshell/editor?shellonly=true&cloudshell_image=gcr.io/cloudrun/button&cloudshell_git_repo=https://github.com/knative/docs&cloudshell_working_dir=docs/serving/samples/hello-world/helloworld-nodejs
[run_button_system_package]: https://console.cloud.google.com/cloudshell/editor?shellonly=true&cloudshell_image=gcr.io/cloudrun/button&cloudshell_git_repo=https://github.com/GoogleCloudPlatform/nodejs-docs-samples&cloudshell_working_dir=run/system-package