Skip to content

Commit

Permalink
Cloud SQL (MySQL): Add Cloud Run support and fix broken impleme… (#1508)
Browse files Browse the repository at this point in the history
* Add Cloud Run support to Cloud SQL (MySQL) sample

* Fix promise-mysql compatibility errors

* named functions for top-level async ops
  • Loading branch information
grayside authored Oct 8, 2019
1 parent afa34e5 commit d7ae96f
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 45 deletions.
26 changes: 26 additions & 0 deletions cloud-sql/mysql/mysql/Dockerfile
Original file line number Diff line number Diff line change
@@ -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" ]
38 changes: 37 additions & 1 deletion cloud-sql/mysql/mysql/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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/).
92 changes: 48 additions & 44 deletions cloud-sql/mysql/mysql/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
2 changes: 2 additions & 0 deletions run/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
|[Pub/Sub][pubsub] | Event-driven service with a Pub/Sub push subscription | [<img src="https://storage.googleapis.com/cloudrun/button.svg" alt="Run on Google Cloud" height="30"/>][run_button_pubsub] |
|[Image Processing][image_processing] | Event-driven image analysis & transformation | [<img src="https://storage.googleapis.com/cloudrun/button.svg" alt="Run on Google Cloud" height="30"/>][run_button_image_processing] |
|[Manual Logging][manual_logging] | Structured logging without client library | [<img src="https://storage.googleapis.com/cloudrun/button.svg" alt="Run on Google Cloud" height="30"/>][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? | [<img src="https://storage.googleapis.com/cloudrun/button.svg" alt="Run on Google Cloud" height="30"/>][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).
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit d7ae96f

Please sign in to comment.