Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cloud SQL (MySQL): Add Cloud Run support and fix broken implementation #1508

Merged
merged 5 commits into from
Oct 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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