Giter Club home page Giter Club logo

bluechatter's Introduction

BlueChatter Overview

The BlueChatter app is a simple chat/IRC type application for your browser which allows multiple users to chat when online at the same time. The sample app is used to showcase how to deploy and scale a chat application using Cloud Foundry and Docker container service and Kubernetes approach. The demo demonstrates how quickly you can deploy and scale your application where been it's a Cloud Foundry, Docker Container Service or Kubernetes Cluster.

See how the browser chat application looks like: Application Diagram

Table of contents

Learning Objectives

  • Learn how to deploy and scale Cloud Foundry application using IBM Bluemix.
  • Learn how to deploy and scale a Kubernetes Cluster using IBM Bluemix Kubernetes approach.
  • Learn how to create a simple Chat application with NodeJs and Express.
  • Learn more on the tooling and reporting when working with Docker Containers and Kubernetes clusters.

Technologies Used

BlueChatter uses Node.js and Express for the server. On the frontend, BlueChatter uses Bootstrap and Jquery. The interesting part of this application is how the communication of messages is done. The application uses long polling to enable the clients (browsers) to listen for new messages. Once the app loads successfully, a client then issues a request to the server. The server waits to respond to the request until it receives a message. If no message is received from any of the chat participants, it responds back to the client with a 204 - no content. As soon as the client gets a response from the server, regardless of whether that response contains a message or not, the client will issue another request and the process continues.

The main goal of this application is to demonstrate the deployment and scaling of Docker container and Cloud Foundry application on IBM Bluemix. We will look at why and when you should deploy your application to a docker container over the classic Cloud Foundry root. You will learn on how to scale your application, scaling is big factor to any production applications, no matter which root you would take you would still need to scale your application for when traffic spike occur. With using the IBM Bluemix auto scaling service, we can automatically scale our Cloud Foundry Application or Docker Container application. To forwarder explain what scaling means, all scaling is to have multiple instance of the same application running at the same time, this means all users seen the same application while each user is directed to different instance of the application depending on the number of the instances you scale to.

Another area we should outline is how do the chat messages happen between the different servers, how do all instance of the applications talk to the same database to offer the chat experience to the users like if they are all on one instance? For that we use the pubsub feature of Redis to solve this. All the servers will be bound to a single Redis instance and each server is listening for messages on the same channel. When one chat server receives a chat message it publishes an event to Redis containing the message. The other servers then get notifications of the new messages and notify their clients of the. This design allows BlueChatter to scale nicely to meet the demand of its users.

1 Cloud Foundry Deployment Approach

  1. Create a Bluemix Account
    Signup for Bluemix, or use an existing account.

  2. Download and install the Cloud-foundry CLI tool

  3. If you have not already, [download node.js 6.7.0 or later][https://nodejs.org/download/] and install it on your local machine.

  4. Clone the app to your local environment from your terminal using the following command

git clone https://github.com/IBM-Bluemix/bluechatter.git
  1. cd into the bluechatter folder that you cloned
cd bluechatter
  1. Edit the manifest.yml file and change the application host to something unique. The host you use will determinate your application url initially, e.g. <host>.mybluemix.net.

  2. Connect and login to Bluemix $ bx login -a https://api.ng.bluemix.net

  3. Target your account ORG and SPACE bx target -o ORG -s SPACE

  4. Create a Redis service for the app to use, we will use the RedisCloud service. $ bx cf create-service compose-for-redis Standard redis-chatter

  5. Push the application bx cf push

Done, the app should be running on: <host>.mybluemix.net

1_1 Scaling Your Cloud Foundry Application

Since we are using Redis to send chat messages, you can scale this application as much as you would like and people can be connecting to various servers and still receive chat messages. We will be looking on how to scale the application runtime instances for when needed, to do this we are going to look at the manual scaling command or use the Auto-Scaling service to automatically increase or decrease the number of application instances based on a policy we set it.

Manual Scaling

  1. Manually scale the application to run 3 instances
$ cf scale my-blue-chatter-app-name -i 3
  1. Then check your that all your instances are up and running.
 $ cf app my-blue-chatter-app-name

Now switch over to your staging domain(<host>.mybluemix.net.) to see your running application. Note, you know which instance you are connecting to in the footer of the form. If you have more than one instance running chances are the instance id will be different between two different browsers.

Auto Scaling

2 Kubernetes Deployment Approach

IBM Bluemix now support Kubernetes clusters within the platform, kubernetes is the future of docker applications so lets explore how to deploy the BlueChatter application as a Kubernetes cluster. There are few compounds that you must understand before deploying a kubernetes cluster.

2_1 Before you begin

2_2 Create a Kubernetes cluster

  1. Create a Kubernetes cluster from the Bluemix Catalog. You will create a free cluster of type Lite and still be able to follow the guide and skip the appropriate sections. To bind a custom domain, You must create a Paid cluster of type Standard.

Note: For the ease of use, Check the configuration details like Number of CPUs, Memory and Number of Worker Nodes you will be getting under Lite and Standard plans.

Kubernetes Cluster Creation on IBM Cloud

> Note that you can also use an existing cluster

In the next step, you will configure kubectl to point to your newly created cluster going forward.

2_3 Configure kubectl and helm

kubectl is a a command line tool to interact with a Kubernetes cluster.

  1. Use bx login to login interactively. Provide the Organization (Org), Region and Space under which the cluster is created. You can reconfirm the details by running bx target command.

  2. Once the cluster is ready, retrieve the cluster configuration

    bx cs cluster-config <cluster-name>
    
  3. Copy and paste the export command to set the KUBECONFIG environment variable as directed. To verify whether the KUBECONFIG environment variable is set properly or not, run this command echo $KUBECONFIG

  4. Check that the kubectl command is correctly configured

    kubectl cluster-info
    
  5. Helm helps you manage Kubernetes applications through Helm Charts โ€” Helm Charts helps you define, install, and upgrade even the most complex Kubernetes application. Initialize Helm in your cluster.

    helm init
    

2_4 Build the Node.js application

  1. Clone the app to your local environment from your terminal using the following command

      git clone https://github.com/IBM-Bluemix/bluechatter.git
    
  2. cd into the bluechatter folder that you cloned

      cd bluechatter
    
  3. Start the Docker engine on your local computer

    See the Docker installation instructions if you don't yet have the Docker engine installed locally or need help in starting it.

  4. Log the local Docker client in to IBM Bluemix Container Registry:

    bx cr login
    

    This will configure your local Docker client with the right credentials to be able to push images to the Bluemix Container Registry.

  5. Retrieve the name of the namespace you are going to use to push your Docker images:

    bx cr namespace-list
    

    If you don't have a namespace, you can create one with bx cr namespace-create mynamespace as example.

  6. Check that you have installed Container Registry plugin and Container Service plugin with this command

    bx plugin list
    

    Output:
    listing installed plug-ins...
    Plugin Name Version
    schematics 1.2.0
    sdk-gen 0.1.3
    Cloud-Functions 1.0.2
    container-registry 0.1.215
    container-service 0.1.328
    dev 1.0.4

  7. Modify the kubernetes.yml with replacing the namespace with your namespace. Application Diagram

  8. Build the Docker image of the service

    In the following steps, make sure to replace <namespace> with your namespace name.

    docker build -t registry.ng.bluemix.net/<namespace>/bluechatter_app:latest .   
    
  9. Push the image to the registry

    docker push registry.ng.bluemix.net/<namespace>/bluechatter_app:latest
    

2_5 Deploy the cluster

Before deploying the cluster, make sure the steps above are complete and the cluster state is READY

  1. Retrieve the cluster configuration

    bx cs cluster-config <cluster-name>
    

    The output will look like:

    Downloading cluster config for mycluster
    OK
    The configuration for mycluster was downloaded successfully. Export environment variables to start using Kubernetes.
    
    export KUBECONFIG=/Users/Twana/.bluemix/plugins/container-service/clusters/mycluster/kube-config-prod-dal10-mycluster.yml
    
  2. Copy and paste the export KUBECONFIG=... line into your shell.

  3. Confirm the configuration worked by retrieving the cluster nodes:

    kubectl get nodes
    

    Output:
    NAME STATUS AGE
    10.44.103.74 Ready 2m

  4. Deploy the BlueChatter application to the cluster

  kubectl create -f kubernetes.yml

Output:
deployment "redis" created service "redis" created deployment "web" created service "web" created

  1. Wait a few minutes for your application to be deployed.

  2. Retrieve the public IP of your cluster workers.

    bx cs workers <your-cluster>
    
    OK
    ID                                                 Public IP        Private IP      Machine Type   State    Status
    kube-hou02-pa95994f682be3443fbc92959175674f84-w1   173.193.85.219   10.44.103.74   u1c.2x4        normal   Ready
    
  3. Retrieve the port assigned to your application.

    kubectl get services
    

    and locate your service in the list:

    NAME  		CLUSTER-IP    		EXTERNAL-IP   PORT(S)			AGE
    web   		172.21.220.28   	<nodes>       80:30089/TCP   	2m
    kubernetes	10.10.10.1    		<none>        443/TCP      		5m
    redis		None    			<none>        55555/TCP      	5m
    

    {: screen} alternatively you can use kubectl describe service [service-name]. In this example, the port is 30089.

  4. Access the application http://worker-ip-address:portnumber

    Example: http://173.193.85.219:30089

2_6 View Cluster Graphically

  1. To view the clusters graphically we are going to use Cloudweave to see graphically the different pods and overall cluster setup.

    Sign up for a free Cloudweave account: https://cloud.weave.works/signup and follow the steps to create your account.

  2. Click on the "Explore" option and run the commands provided by Cloudweave to connect to your cluster. This should be something like this:

    kubectl apply -n kube-system -f \
       "https://cloud.weave.works/k8s/scope.yaml?service-token=<TOEKN-XXXXXXXXXXXXXXXXXXX>-version=$(kubectl version | base64 | tr -d '\n')"
    

    Once Cloudweave is setup you then should see your cluster pods graphically. In the screenshots below you can see the BlueChatter Web and Redis pods created on the right. Application Diagram

  3. Additionally we can also view logs locally if you don't like using the graphical tool, a tool like kubetail can be used to tail the logs of multiple pods https://github.com/johanhaleby/kubetail. Once installed you can do kutetail fibo to watch the logs.

2_7 Manual Scaling

  1. First, run a command to see the number of running pods, we should see one pod for the redis service and one pod for the web application.

    kubectl get pods    
    
  2. Scale from 1 to 4 replicas, note in the kubernetes.yml we have set to have 1 replicas so with this command we tell it to have 4 replicas.

    kubectl scale --replicas=4 -f kubernetes.yml
    

    Application Diagram

  3. Scale back down to 1 replica

    kubectl scale --replicas=1 -f kubernetes.yml
    

2_8 Automatic Scaling

  1. Configure the automatic scaling for Kubernetes

    kubectl autoscale -f kubernetes.yml --cpu-percent=10 --min=1 --max=10
    

    This tells Kubernetes to maintain an average of 10% CPU usage over all pods in our deployment and to create at most 10 pod replicas.

    In order to see Auto Scaling in action, we would need to drive some traffic to the BlueChatter app in order to see the application scaling. You can use something like Apache JMeter to drive traffic to the application, in this demo we will not cover Apache JMeter given that there are many tutorials covering Apache JMeter.

  2. Use this command to see the Auto Scaling been setup

    kubectl get hpa
    

    Output:

    NAME      REFERENCE          TARGET    CURRENT     MINPODS   MAXPODS   AGE
    redis     Deployment/redis   10%       <waiting>   1         10        14m
    web       Deployment/web     10%       <waiting>   1         10        14m
    
  3. Remove the hpa

    kubectl delete hpa redis
    kubectl delete hpa web
    
  4. Scale back to down to 1 replica

    kubectl scale --replicas=1 -f kubernetes.yml
    

2_9 Why use the Kubernetes service on Bluemix?

Why Kubernetes Service on Bluemix?

For more details, visit IBM Bluemix Container Service

Done!

Useful Kubernetes commands

  1. Get services, pods and deployments

    kubectl get service
    kubectl get pods
    kubectl get deployments 
    
  2. Delete services, pods and deployments

    kubectl delete service <service-name>
    kubectl delete pods <pod-name>
    kubectl delete deployments <deployments-name>
    ``
    
  3. Get cluster node IP Address and state

    bx cs workers mycluster
    
  4. Get the port (NodePort)

    kubectl describe service web
    

Additional Links

For additional information about on IBM Containers see the the following links:
Bluemix documentation
Docker user manual PDF
Deploy Kubernetes cluster to Bluemix

License

This code is licensed under Apache v2. See the LICENSE file in the root of the repository.

Dependencies

For a list of 3rd party dependencies that are used see the package.json file in the root of the repository.

bluechatter's People

Contributors

chrisjtwomey-ibm avatar data-henrik avatar jsloyer avatar nihillno avatar ryanjbaxter avatar vidyasagarmsc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bluechatter's Issues

image ibmnode:latest not found - docker build and pull failing

While checking this sample, I had an hard stop with the below error. Even _docker pull i_s failing with the same error.

Sending build context to Docker daemon 12.14 MB
Step 1/8 : FROM registry.ng.bluemix.net/ibmnode:latest
Pulling repository registry.ng.bluemix.net/ibmnode
Error: image ibmnode:latest not found

Redis Not available in Lite Plan

Redis services are no longer available for free on IBMCloud.
CLI create-service ends with
Server error, status code: 502, error code: 10001, message: Service broker error: Lite org is not allowed to provision non-lite plans error.

XSS Vulnerabilities

The site is vulnerable to various XSS injection attacks. Is this considered a non-issue for this example ?

Service "redisCloud" not found

Hi!

First of all, thanks for the example code to start on Bluemix but there is a problem there because the rediscloud declared on the manifest.yml does not longer exist and it fails to initialize.

This can bring to some confusion to rookies like me. Is it possible to be fix?

I will try to replace it for the compose for reddis service.

Edit (19/12/2016):

It was pretty easy to replace one service from another, now I got it running by connecting on the Compose for Redis instead of rediscloud.

I'll do a pull request but I'm letting the changes performed here too:

app.js

//------------------------------------------------------------------------------
// Copyright IBM Corp. 2015
//
// 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.
//------------------------------------------------------------------------------

var express = require("express");
var fs = require('fs');
var http = require('http');
var path = require('path');
var cfenv = require("cfenv");
var pkg = require("./package.json");
var redis = require('redis');
var nconf = require('nconf');
var appEnv = cfenv.getAppEnv();
nconf.env();
var isDocker = nconf.get('DOCKER') == 'true';
var clients = [];

var app = express();
app.set('port', appEnv.port || 3000);
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json());

//Recover services from app
var services = appEnv.services;
//Recover compose-for-redis service
var redis_services = services["compose-for-redis"];
//Take credentials
var credentials = redis_services[0].credentials;

// We need 2 Redis clients one to listen for events, one to publish events
var subscriber = redis.createClient(credentials.uri);
subscriber.on('error', function (err) {
    if (isDocker && err.message.match('getaddrinfo EAI_AGAIN')) {
        console.log('Waiting for IBM Containers networking to be available...');
        return
    }
    console.error('There was an error with the subscriber redis client ' + err);
});
subscriber.on('connect', function () {
    console.log('The subscriber redis client has connected!');

    subscriber.on('message', function (channel, msg) {
        if (channel === 'chatter') {
            while (clients.length > 0) {
                var client = clients.pop();
                client.end(msg);
            }
        }
    });
    subscriber.subscribe('chatter');
});
var publisher = redis.createClient(credentials.uri);
publisher.on('error', function (err) {
    if (isDocker && err.message.match('getaddrinfo EAI_AGAIN')) {
        console.log('Waiting for IBM Containers networking to be available...');
        return
    }
    console.error('There was an error with the publisher redis client ' + err);
});
publisher.on('connect', function () {
    console.log('The publisher redis client has connected!');
});

if (credentials.password != '' && credentials.password != undefined) {
    subscriber.auth(credentials.password);
    publisher.auth(credentials.password);
}


// Serve up our static resources
app.get('/', function (req, res) {
    fs.readFile('./public/index.html', function (err, data) {
        res.end(data);
    });
});

// Poll endpoint
app.get('/poll/*', function (req, res) {
    clients.push(res);
});

// Msg endpoint
app.post('/msg', function (req, res) {
    message = req.body;
    publisher.publish("chatter", JSON.stringify(message), function (err) {
        if (!err) {
            console.log('published message: ' + JSON.stringify(message));
        } else {
            console.error('error publishing message: ' + err);
        }
    });
    res.end();
});

var instanceId = !appEnv.isLocal ? appEnv.app.instance_id : undefined;
app.get('/instanceId', function (req, res) {
    if (!instanceId) {
        res.writeHeader(204);
        res.end();
    } else {
        res.end(JSON.stringify({
            id: instanceId
        }));
    }
});

// This interval will clean up all the clients every minute to avoid timeouts
setInterval(function () {
    while (clients.length > 0) {
        var client = clients.pop();
        client.writeHeader(204);
        client.end();
    }
}, 60000);

http.createServer(app).listen(app.get('port'), function () {
    console.log('Express server listening on port ' + app.get('port'));
});

manifest.yml

#
# Copyright IBM Corp. 2015
#
# 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.
#
declared-services:
  redis-chatter: // **YOUR SERVICE NAME**
    label: Compose for Redis-do
    plan:  30mb
applications:
- name: bluechatter
  memory: 128M
  command: node app.js
  services:
  - redis-chatter //**YOUR SERVICE NAME**

Fails to deploy

I want to use this app as a demonstration of Bluemix with Docker. I simply used the deploy button on the project GitHub page.

But it fails in the "Docker Build" stage with the following messages:

2016-04-16 08:38:50 UTC : Installing IBM Container Service CLI
Installing Python 2.7
Python 2.7.6
2016-04-16 08:39:41 UTC : Successfully installed IBM Container Service CLI
2016-04-16 08:39:57 UTC : Successfully installed Docker version 1.6.2, build 7c8fca2
/tmp/extension_content ~/e71db19c-1c3c-4c7c-b44d-0a3419415822
2016-04-16 08:39:58 UTC : New EXT_DIR/cf version: /tmp/extension_content/cf version 6.13.0-e68ce0f-2015-10-15T22:53:58+00:00
~/e71db19c-1c3c-4c7c-b44d-0a3419415822
"/tmp/extension_content/cf ic init" did not return successfully. RC=1. Sleep 20 sec and try again.
2016-04-16 08:41:40 UTC : 'cf ic init' command failed with return code 1
We are sorry you are having trouble. 
There was 1 error recorded during execution:
2016-04-16 08:41:40 UTC : 'cf ic init' command failed with return code 1

I can't find any detailed message to further investigate this, thats all I can provide in this bug report.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.