Skip to content
This repository has been archived by the owner on Jul 19, 2022. It is now read-only.

vmware-archive/pcf-workshop-microservices

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

43 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Monolithic to Microservices Cloud Native Apps

Goals

To take a monolithic app, rebuild it as cloud native app using loosely coupled microservices and deploy it on the platform

Prerequisites

  1. Java SDK 1.6+

  2. Git github.com

  3. Cloud Foundry CLI CF CLI Releases

  4. Curl curl

  5. Pivotal Web Services Account. Create a free trial account here Pivotal Web Services

  6. Familiarity with Spring Spring IO

Pre-work

  1. Fork and Clone PCF Workspace for Microservices

  2. Review the Overview of the cities application.

Steps

In this workshop we are going to follow these steps to first deploy a monolothic app, and then deploy the microservice version of the same app on Cloud foundry and walk through the 12 factor app design principles and CF platform to support CNA.

Mono to Microservices CNA on CF

Introduction

This lab demonstrates the benefits of deploying microservice applications to Cloud Foundry and building those applications with the Spring framework. It will also get you more comfortable working with the CF CLI.

The lab starts with a monolithic v1 version of the cities-app, which is a Angular.js/Spring Boot/Spring Web/Spring Data application that provides a simple UI for searching for cities that are stored in a relational database. It’s pushed as a single CF app.

It’s a perfectly nice app, and does a lot with a little code thanks to the use of Spring Boot, Web and Data projects. But seeing the wisdom of microservices, you decide it’s time to refactor this app into two tiers

  • a microservice tier that implements the core cities CRUD operations and provides a REST API via Spring Data Rest

  • a UI tier that calls this REST API and uses a CF user provided service to reference the connection parameters from the CF environment

You’ll deploy the refactoried v2 cities-app as two separate apps (an app for each tier), giving you the flexibility to update and scale each tier independently.

Then the lab will then take you through a blue/green deployment to route 'production' traffic from your v1 app to your v2 app and demonstrate how the CF router simplifies application upgrades.

Instructions

Note
The instructions in this document are for Mac/Linux based CLI/Shell. If you are using Windows, you can use Windows CLI or a Virtual Box / Vagrant with a Linux VM.

PART 1: Build and Run a Monolithic App in a container

Run the monolithic Spring Boot app in tomcat

$ cd pcf-workspace-microservices/mono
$ ./gradlew clean
$ ./gradlew build
$ java -jar build/libs/cities-monolithic.jar

Launch the app

Open the App from the Web browser http://localhost:8080

Cities UI

Discuss issues and List them on a Whiteboard

Runtime/Platform

  1. Scaling ..

Architecture

  1. Dependency and Coupling

  2. Access to mounted, shared filesystems

  3. Peer-to-peer application server clustering

  4. Shared libraries

  5. Configuration files sitting in well-known locations

PART 2: Run the Monolithic App on the Platform

Pushing the cities-mono app using CLI

Use cf help and/or cf <command> --help for details on each of the commands below.

  1. Review the docs: http://docs.pivotal.io/pivotalcf/devguide/deploy-apps/deploy-app.html

  2. Login to the PCF Env. Edit and Source the env file cities folder

    ---
     export CF_SYSTEM_DOMAIN=
     export CF_APPS_DOMAIN=
     export CF_USER=
     export CF_ORG=
     export CF_SPACE=
    ---
    $ source ./env
    $ cf login -a https://api.$CF_SYSTEM_DOMAIN -u $CF_USER -o $CF_ORG -s $CF_SPACE
    Note
    add --skip-ssl-validation if you are pointing to CF installation which is using self signed certificates.
  3. Verify you are logged in with your own userid (not admin) and targeted to your PCF instance:

    $ cf target
  4. Push the cities-service: Before pushing the app, check if the route exists and we can reach it.

    $ cd mono
    $ cf check-route <first-initial><last-initial>-cities-monolithic cfapps.io
    $ cf push <first-initial><last-initial>-cities-monolithic -i 1 -m 512M -p build/libs/cities-monolithic.jar
    • Be sure to name your application '<first-initial><last-initial>-cities-monolithic'

  5. Verify you can access your application from a Web Browser http://<first-initial><last-initial>-cities-monolithic.cfapps.io

Health, logging & events via the CLI

Learning about how your application is performing is critical to help you diagnose and troubleshoot potential issues. Cloud Foundry gives you options for viewing the logs.

To tail the logs of your application perform this command:

// For recent logs
$ cf logs <first-initial><last-initial>-cities-monolithic.cfapps.io --recent
// For current logs
$ cf logs <first-initial><last-initial>-cities-monolithic.cfapps.io

Notice that nothing is showing because there isn’t any activity. Use the following curl commmand to see the application working:

$ curl -i http://<first-initial><last-initial>-cities-monolithic.cfapps.io/cities/10

For other ways of viewing logs check out the documentation here: http://docs.pivotal.io/pivotalcf/devguide/deploy-apps/streaming-logs.html#view

To view recent events, including application crashes, and error codes, you can see them from the App Manager or from the cli.

$ cf events <first-initial><last-initial>-cities-monolithic

To view the health of the application you can see from the App Manager or from the cli:

+

$ cf app <first-initial><last-initial>-cities-monolithic

+ You will get detailed output of the health

Showing health and status for app cities-monolithic in org Central / space development as ...
OK

requested state: started
instances: 1/1
usage: 512M x 1 instances
urls: cities-app-pisiform-chattiness.cfapps.io, cities-app-unenraptured-shantung.cfapps.io
last uploaded: Fri May 29 15:51:12 UTC 2015
stack: cflinuxfs2

     state     since                    cpu    memory         disk           details
#0   running   2015-05-29 11:52:14 AM   0.1%   470M of 512M   148.9M of 1G

Environment variables

View the environment variable and explanation of link:http://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html#view-env [VCAP Env]

$ cf env <first-initial><last-initial>-cities-monolithic

You will get the output similar to this on your terminal

Getting env variables for app cities-monolithic in org Central / space development as ...
OK

System-Provided:
{
 "VCAP_SERVICES": {
  "cleardb": [
   {
    "credentials": {
     "hostname": "us-cdbr-iron-east-02.cleardb.net",
     "jdbcUrl": "jdbc:mysql://xxx@us-cdbr-iron-east-02.cleardb.net:3306/xxx",
     "name": "xxx",
     "password": "xxx",
     "port": "3306",
     "uri": "mysql://xxx@us-cdbr-iron-east-02.cleardb.net:3306/xxx?reconnect=true",
     "username": "xxxx"
    },
    "label": "cleardb",
    "name": "rj-cities-db",
    "plan": "spark",
    "tags": [
     "Data Stores",
     "Data Store",
     "mysql",
     "relational"
    ]
   }
  ]
 }
}

{
 "VCAP_APPLICATION": {
  "application_name": "cities-monolithic",
  "application_uris": [
   "cities-app-pisiform-chattiness.cfapps.io",
   "cities-app-unenraptured-shantung.cfapps.io"
  ],
  "application_version": "9efbf06e-2e3a-4752-89db-77f59d570128",
  "limits": {
   "disk": 1024,
   "fds": 16384,
   "mem": 512
  },
  "name": "cities-monolithic",
  "space_id": "56e1d8ef-e87f-4b1c-930b-e7f46c00e483",
  "space_name": "development",
  "uris": [
   "cities-app-pisiform-chattiness.cfapps.io",
   "cities-app-unenraptured-shantung.cfapps.io"
  ],
  "users": null,
  "version": "9efbf06e-2e3a-4752-89db-77f59d570128"
 }
}

User-Provided:
JAVA_OPTS: -Djava.security.egd=file:///dev/urandom
SPRING_PROFILES_ACTIVE: cloud
VERSION: CITIES_APP_1_0

No running env variables have been set

No staging env variables have been set

Scaling apps

Applications can be scaled via the command line or the console. When we talk about scale, there are two different types of scale: Vertical and Horizontal. Read this doc on more details on scaling applications.

When you Vertically scale your application, you are increasing the amount of memory made available to your application. Scaling your application horizontally means that you are adding application instances.

Let’s vertically scale the application to 1 GB of RAM.

$ cf scale <first-initial><last-initial>-cities-mono -m 1G

Now scale your application down to 512 MB.

Next, let’s scale up your application to 2 instances

$ cf scale scale <first-initial><last-initial>-cities-mono -i 2

To check the status of your applications you can check from the command line to see how many instances your app is running and their current state

$ cf app <first-initial><last-initial>-cities-monolithic

Discuss Issues / Advantages of the platform/Strike from Whiteboard

Runtime/Platform

  1. Scaling ..

Architecture

  1. Dependency and Coupling

  2. Access to mounted, shared filesystems

  3. Peer-to-peer application server clustering

  4. Shared libraries

  5. Configuration files sitting in well-known locations

PART 3: Re-design the app using Microservice for the Platform

Delete the PCF cities-mono app

$ cf delete -r <first-initial><last-initial>-cities-monolithic

Deploy the v2 Microservices App

Now it’s time to deploy the v2 microservice version of the app:

$ cd micro
$ ./gradlew assemble

Under this folder are 3 subfolders

  • cities-service - the microservice app that exposes a REST API from the CityRepository class via a few simple RestResource annotations

  • cities-ui - the UI app that connects to the microservice

  • cities-client - client API used by cities-ui to connect to cities-service microservice, leveraging Spring Cloud and Netflix Feign

Check out the app docs for a thorough coverage of the application design.

First we’ll deploy the cites-service microservice app, which defines in the manifest.yml the 'host' as 'cities-service-${random-word}' and 'cities-db' as a service the app will bind to (i.e. it will bind to the same db we created for the v1 app).

$ cd cities-service
$ cf push

Use 'cf apps' to determine the URL to reference the cities microservice.

  • We’ll refer to this URL as YOUR_CITIES_SERVICE_URL below, and in the example output below YOUR_CITIES_SERVICE_URL=cities-service-nonterminable-runback.cfapps.io

$ cf apps
…
name                requested state   instances   memory   disk   urls
cities-service      started           1/1         512M     1G     cities-service-nonterminable-runback.cfapps.io

Validate that the REST endpoints are working for this service using curl

$ curl -i YOUR_CITIES_SERVICE_URL/cities
$ curl -i YOUR_CITIES_SERVICE_URL/cities/search
$ curl -i YOUR_CITIES_SERVICE_URL/cities/search/nameContains?q=TEMPLE
$ curl -i YOUR_CITIES_SERVICE_URL/cities/829

Create the cities-ws user provided service that will store the cities-service connection parameters in the CF environment and make them available to the cities-ui app.

  • NOTE: YOU MUST USE 'http://' before the YOUR_CITIES_SERVICE_URL! (https will not work)

  • Don’t forget to substitute your specific URL for YOUR_CITIES_SERVICE_URL

$ cf create-user-provided-service cities-ws -p uri,tag

uri> http://YOUR_CITIES_SERVICE_URL

tag> cities
Creating user provided service cities-ws in org...
OK

Validate the user provided service was created

$ cf services
…
name             service         plan     bound apps
cities-db        cleardb         spark    cities-monolithic, cities-service
cities-ws        user-provided

Before pushing the cities-ui app that connects to the cities-service microservice app, take a look at the cities-ui manifest.yml to see

  • The app will bind to the cities-ws user provided service you just created

  • The app will use cities-ui-${random-word} as the host (URL prefix)

  • The app sets the VERSION environment variable to CITIES_APP_2_0

$ cd ../cities-ui
$ cat manifest.yml
---
applications:
- name: cities-ui
  memory: 512M
  instances: 1
  path: build/libs/cities-ui.jar
  services: [ cities-ws ]
  host: cities-ui-${random-word}
  env:
    SPRING_PROFILES_ACTIVE: cloud
    VERSION: CITIES_APP_2_0

Now deploy the cities-ui app

$ cf push

Test that the app works by opening the cities-ui URL that is displayed by the 'cf apps' command. The UI should look the same as the v1 version, but it’s of course getting the data via REST from the cities-service microservice.

Now that the cities-ui app is pushed and bound to the cities-ws service, you can use 'cf env' to validate the cities-service URL/URI it found in the environment.

$ cf env cities-ui
…
System-Provided:
{
  "VCAP_SERVICES": {
    "user-provided": [
      {
        "credentials": {
          "tag": "cities",
          "uri": "http://cities-service-nonterminable-runback.cfapps.io"
        },
        "label": "user-provided",
        "name": "cities-ws",
        "syslog_drain_url": "",
        "tags": []
      }
    ]
  }
}

User-Provided:
SPRING_PROFILES_ACTIVE: cloud
VERSION: CITIES_APP_2_0
)

Discuss Issues / Advantages of the Platform+Microservices/Strike from Whiteboard

Runtime/Platform

  1. Scaling ..

Architecture

  1. Dependency and Coupling

  2. Access to mounted, shared filesystems

  3. Peer-to-peer application server clustering

  4. Shared libraries

  5. Configuration files sitting in well-known locations

PART 4: Build for continuous delivery

At this point, you are prepared to reap the benefits of having a separate microservice that can be scaled and deployed independently of the UI tier. However, let’s hold off on scaling until we’re done with the blue/green deployment and can delete the v1 app (a PWS trial has a 2G limit, which we’re not too far from at this point).

Perform Blue/Green Deployment

Now you’re ready to perform a blue/green deployment. First we’ll list our existing routing table:

$ cf routes
…
host                                      domain      apps
cities-service-nonterminable-runback      cfapps.io   cities-service
cities-app-unplodding-tetrarch            cfapps.io   cities-monolithic
cities-ui-slumberous-arroyo               cfapps.io   cities-ui

The host and domain listed for the cities-monolithic app is the 'production' URL that we want to remain constant during the upgrade process so our users are not aware that the v1 app is being replaced by the v2 app.

We can validate that that this URL is referencing our v1 app by using the /cities/version request mapping to retrieve the VERSION environment variable

  • Substitute your cities-monolithic URL below

$ curl cities-app-unplodding-tetrarch.cfapps.io/cities/version
CITIES_APP_1_0

We can also validate the version of the cities-ui route, which is our v2 app

$ curl cities-ui-slumberous-arroyo.cfapps.io/cities/version
CITIES_APP_2_0

In a more realistic blue/green deployment scenario, we’d have a cluster of multiple v1 app instances deployed already, but since we’re short on memory (i.e. PWS trial 2G limit), we’ll stick with our single instance ''cluster''.

Now we add our v2 'canary' to the v1 cluster my mapping the v1 'production' route to the cities-ui app (i.e. the -n parameter is the host for cities-monolithic returned by 'cf routes')

$ cf map-route cities-ui cfapps.io -n cities-app-unplodding-tetrarch

Now if we repeatedly visit our production URL, we’ll see the CF router is load balancing requests between the v1 and v2 apps.

$ curl cities-app-unplodding-tetrarch.cfapps.io/cities/version
CITIES_APP_1_0
$ curl cities-app-unplodding-tetrarch.cfapps.io/cities/version
CITIES_APP_2_0

Our current deployment architecture looks like this:

Canary in blue/green deployment

Another look at our routes shows both apps are now mapped to the production route as expected

$ cf routes
…
host                                      domain      apps
cities-service-nonterminable-runback      cfapps.io   cities-service
cities-app-unplodding-tetrarch            cfapps.io   cities-monolithic,cities-ui
cities-ui-slumberous-arroyo               cfapps.io   cities-ui

After performing some validation that our v2 canary is working as expected, we’re ready to retire the v1 app instances from the cluster by unmapping the production route to the v1 cities-monolithic app, using 'cf unmap'

$ cf unmap-route cities-monolithic cfapps.io -n cities-app-unplodding-tetrarch.cfapps.io

Then test our production URL to see all traffic is going to v2:

$ curl cities-app-unplodding-tetrarch.cfapps.io/cities/version
CITIES_APP_2_0
$ curl cities-app-unplodding-tetrarch.cfapps.io/cities/version
CITIES_APP_2_0
…

At this point we can delete our v1 app

$ cf delete cities-monolithic

Congratulations, you have successfully performed a blue/green deployment, and done so without massive amounts of custom scripting.

Finally, with a bit of spare memory, you can try scaling both tiers of your v2 microservice app.

$ cf scale cities-ui -i 2
$ cf scale cities-service -i 2
$ cf apps

UI request will now be load balanced across two instances of cities-ui, and REST requests made by cities-ui to cities-service will be automatically load balanced as well. Wow, microservices, Spring and CF are a great combination!

Wrap up "How to build Cloud Native Application on the Platform with Countinous Deployment"

Runtime/Platform

  1. Scaling ..

Architecture

  1. Dependency and Coupling

  2. Access to mounted, shared filesystems

  3. Peer-to-peer application server clustering

  4. Shared libraries

  5. Configuration files sitting in well-known locations

Mono to Microservices CNA on CF

Q/A

About

Microservcies Module for CF Workshops

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published