Skip to content

Commit

Permalink
Adding GKE tutorial step (GoogleCloudPlatform#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Wayne Parrott authored and jmdobry committed Jun 9, 2016
1 parent 3247271 commit 5313067
Show file tree
Hide file tree
Showing 34 changed files with 3,379 additions and 0 deletions.
21 changes: 21 additions & 0 deletions optional-container-engine/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2015 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

node_modules
.dockerignore
Dockerfile
npm-debug.log
.git
.hg
.svn
3 changes: 3 additions & 0 deletions optional-container-engine/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
*.log
config.json
20 changes: 20 additions & 0 deletions optional-container-engine/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Dockerfile extending the generic Node image with application files for a
# single application.
FROM gcr.io/google_appengine/nodejs
# Check to see if the the version included in the base runtime satisfies
# '>=0.12.7', if not then do an npm install of the latest available
# version that satisfies it.
RUN /usr/local/bin/install_node '>=0.12.7'
COPY . /app/
# You have to specify "--unsafe-perm" with npm install
# when running as root. Failing to do this can cause
# install to appear to succeed even if a preinstall
# script fails, and may have other adverse consequences
# as well.
# This command will also cat the npm-debug.log file after the
# build, if it exists.
RUN npm install --unsafe-perm || \
((if [ -f npm-debug.log ]; then \
cat npm-debug.log; \
fi) && false)
CMD npm start
50 changes: 50 additions & 0 deletions optional-container-engine/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
GCLOUD_PROJECT:=$(shell gcloud config list project --format="value(core.project)")

.PHONY: all
all: deploy

.PHONY: create-cluster
create-cluster:
gcloud container clusters create bookshelf \
--scope "cloud-platform" \
--num-nodes 2
gcloud container clusters get-credentials bookshelf

.PHONY: create-bucket
create-bucket:
gsutil mb gs://$(GCLOUD_PROJECT)
gsutil defacl set public-read gs://$(GCLOUD_PROJECT)

.PHONY: build
build:
docker build -t gcr.io/$(GCLOUD_PROJECT)/bookshelf .

.PHONY: push
push: build
gcloud docker push gcr.io/$(GCLOUD_PROJECT)/bookshelf

.PHONY: template
template:
sed -i ".tmpl" "s/\$$GCLOUD_PROJECT/$(GCLOUD_PROJECT)/g" bookshelf-frontend.yaml
sed -i ".tmpl" "s/\$$GCLOUD_PROJECT/$(GCLOUD_PROJECT)/g" bookshelf-worker.yaml

.PHONY: create-service
create-service:
kubectl create -f bookshelf-service.yaml

.PHONY: deploy-frontend
deploy-frontend: push template
kubectl create -f bookshelf-frontend.yaml

.PHONY: deploy-worker
deploy-worker: push template
kubectl create -f bookshelf-worker.yaml

.PHONY: deploy
deploy: deploy-frontend deploy-worker create-service

.PHONY: delete
delete:
-kubectl delete -f bookshelf-frontend.yaml
-kubectl delete -f bookshelf-worker.yaml
-kubectl delete -f bookshelf-frontend.yaml
5 changes: 5 additions & 0 deletions optional-container-engine/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Deploy Bookshelf to Container Engine/Kubernetes

This optional tutorial will walk you through how to deploy the Bookshelf sample application to [Google Container Engine](https://cloud.google.com/container-engine/). This tutorial is also applicable to [Kubernetes](http://kubernetes.io/) outside of Container Engine, but may require additional steps for external load balancing.

Please refer to the [Tutorial](https://cloud.google.com/nodejs/tutorials/bookshelf-on-container-engine) for instructions on how to deploy this sample.
105 changes: 105 additions & 0 deletions optional-container-engine/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright 2015-2016, Google, Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

// Activate Google Cloud Trace and Debug when in production
if (process.env.NODE_ENV === 'production') {
require('@google/cloud-trace').start();
require('@google/cloud-debug');
}

var path = require('path');
var express = require('express');
var session = require('express-session');
var MemcachedStore = require('connect-memcached')(session);
var passport = require('passport');
var config = require('./config');
var logging = require('./lib/logging');

var app = express();

app.disable('etag');
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.set('trust proxy', true);

// Add the request logger before anything else so that it can
// accurately log requests.
app.use(logging.requestLogger);

// Configure the session and session storage.
var sessionConfig = {
resave: false,
saveUninitialized: false,
secret: config.get('SECRET'),
signed: true
};

// In production use the App Engine Memcache instance to store session data,
// otherwise fallback to the default MemoryStore in development.
if (config.get('NODE_ENV') === 'production') {
sessionConfig.store = new MemcachedStore({
hosts: [config.get('MEMCACHE_URL')]
});
}

app.use(session(sessionConfig));

// OAuth2
app.use(passport.initialize());
app.use(passport.session());
app.use(require('./lib/oauth2').router);

// Books
app.use('/books', require('./books/crud'));
app.use('/api/books', require('./books/api'));

// Redirect root to /books
app.get('/', function (req, res) {
res.redirect('/books');
});

// Our application will need to respond to health checks when running on
// Compute Engine with Managed Instance Groups.
app.get('/_ah/health', function (req, res) {
res.status(200).send('ok');
});

// Add the error logger after all middleware and routes so that
// it can log errors from the whole application. Any custom error
// handlers should go after this.
app.use(logging.errorLogger);

// Basic 404 handler
app.use(function (req, res) {
res.status(404).send('Not Found');
});

// Basic error handler
app.use(function (err, req, res, next) {
/* jshint unused:false */
// If our routes specified a specific response, then send that. Otherwise,
// send a generic message so as not to leak anything.
res.status(500).send(err.response || 'Something broke!');
});

if (module === require.main) {
// Start the server
var server = app.listen(config.get('PORT'), function () {
var port = server.address().port;
console.log('App listening on port %s', port);
});
}

module.exports = app;
115 changes: 115 additions & 0 deletions optional-container-engine/books/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright 2015-2016, Google, Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

var express = require('express');
var bodyParser = require('body-parser');
var config = require('../config');

function getModel () {
return require('./model-' + config.get('DATA_BACKEND'));
}

var router = express.Router();

// Automatically parse request body as JSON
router.use(bodyParser.json());

/**
* GET /api/books
*
* Retrieve a page of books (up to ten at a time).
*/
router.get('/', function list (req, res, next) {
getModel().list(10, req.query.pageToken, function (err, entities, cursor) {
if (err) {
return next(err);
}
res.json({
items: entities,
nextPageToken: cursor
});
});
});

/**
* POST /api/books
*
* Create a new book.
*/
router.post('/', function insert (req, res, next) {
getModel().create(req.body, true, function (err, entity) {
if (err) {
return next(err);
}
res.json(entity);
});
});

/**
* GET /api/books/:id
*
* Retrieve a book.
*/
router.get('/:book', function get (req, res, next) {
getModel().read(req.params.book, function (err, entity) {
if (err) {
return next(err);
}
res.json(entity);
});
});

/**
* PUT /api/books/:id
*
* Update a book.
*/
router.put('/:book', function update (req, res, next) {
getModel().update(req.params.book, req.body, true, function (err, entity) {
if (err) {
return next(err);
}
res.json(entity);
});
});

/**
* DELETE /api/books/:id
*
* Delete a book.
*/
router.delete('/:book', function _delete (req, res, next) {
getModel().delete(req.params.book, function (err) {
if (err) {
return next(err);
}
res.status(200).send('OK');
});
});

/**
* Errors on "/api/books/*" routes.
*/
router.use(function handleRpcError (err, req, res, next) {
// Format error and forward to generic error handler for logging and
// responding to the request
err.response = {
message: err.message,
internalCode: err.code
};
next(err);
});

module.exports = router;
Loading

0 comments on commit 5313067

Please sign in to comment.