cloudsoft.io

Compose a 3-tier Application (CLI)

Objectives

In this tutorial we will show you how to use the AMP CLI to deploy a three-tier web application.

Pre-requisites

This tutorial assumes you have installed Cloudsoft AMP.

Once downloaded, you need to login using br login http://localhost:8081/ admin password.

To get help on the available commands, use br --help.

Instructions

The following blueprint in YAML describes the topology of a three-tier web application.

tosca_definitions_version: tosca_simple_yaml_1_3

metadata:
   template_name: io.cloudsoft.3-tier-application-template
   template_version: 0.1.0-SNAPSHOT

topology_template:
   node_templates:
      db-instance:
         type: io.cloudsoft.smart-mysql-node
         properties:
            mysql_creation_script: classpath://io.cloudsoft.brooklyn.tosca13.tosca-3-tier:resources/creation-script-mysql.sql
      tomcat-cluster:
         type: tosca.entity.DynamicCluster
         properties:
            cluster.initial.size: 2
            dynamiccluster.memberspec:
               $brooklyn:entitySpec:
                  name: Apache Tomcat Member
                  type: io.cloudsoft.smart-tomcat9-node
                  brooklyn.config:
                     tomcat_db_url: { get_attribute: [ db-instance, db_instance_url ] }
                     tomcat_db_driver: { get_attribute: [ db-instance, db_instance_driver ] }
                     tomcat_deployment: classpath://io.cloudsoft.brooklyn.tosca13.tosca-3-tier:resources/tosca-hello-world-sql-webapp.war
      nginx-host:
         type: tosca.nodes.Compute
         capabilities:
            cloudsoft:
               properties:
                  required.ports: { get_property: [ nginx-instance, app.port ] }
      nginx-instance:
         type: tosca-nginx-node 
         requirements:
         - host: nginx-host
         properties:
            nginx.sticky: false
            addr.list: { get_attribute: [ tomcat-cluster, addr.list.string ] }

   groups:
   - add_brooklyn_types:
        members: [ tomcat-cluster ]
        type: brooklyn.tosca.groups.initializer
        properties:
           brooklyn.enrichers:
           - type: org.apache.brooklyn.enricher.stock.Aggregator
             brooklyn.config:
                enricher.sourceSensor: $brooklyn:sensor("app.endpoint") 
                enricher.targetSensor: $brooklyn:sensor("addr.list")
                enricher.aggregating.fromMembers: true
           - type: org.apache.brooklyn.enricher.stock.Joiner
             brooklyn.config:
                enricher.joiner.minimum: $brooklyn:config("cluster.initial.size")
                enricher.sourceSensor: $brooklyn:sensor("addr.list")
                enricher.targetSensor: $brooklyn:sensor("addr.list.string")
                enricher.joiner.separator: ","

The blueprint consists of the following items:

  • A dynamic cluster managing 2 Apache Tomcat nodes.
  • MySQL node, which is configured using SQL DDL script.
  • Nginx node that acts as a load-balancer for the previous cluster ot Apache Tomcat servers. When this node is created, its addr.list property is initialized with the list of application endpoints of all Apache Tomcat nodes managed by the cluster.

In order to deploy three-tier web application, add Linux (Ubuntu 20.04) location with ID ubuntu20-location first. Refer to creating first location for details.

Note, to increase deployment speed, use a Linux VM template that has MySQL 5, Apache Tomcat 9 (unpacked in /usr/local/tomcat) and Nginx installed.

Create directory tosca-3-tier and save the content of the blueprint above into file 3-tier-application-template.yaml which will form tosca-3-tier bundle with 3-tier web application template:

./tosca-3-tier/3-tier-application-template.yaml

Add the bundle to the catalog:

> cd tosca-3-tier
> br catalog add .

The response from AMP of successfully added bundle to the catalog will look like the following:

Installed AMP catalog bundle io.cloudsoft.3-tier-application-template:0.1.0-SNAPSHOT with ID xp51aywf3u [367]
* io.cloudsoft.3-tier-application-template:0.1.0-SNAPSHOT

Create another blueprint, 3-tier-application.yaml, with the following content:

tosca_definitions_version: tosca_simple_yaml_1_3

metadata:
   template_name: io.cloudsoft.3-tier-application
   template_version: 0.1.0-SNAPSHOT

topology_template:
   node_templates:
      3-tier-application:
         type: 'io.cloudsoft.3-tier-application-template:0.1.0-SNAPSHOT'
   groups:
   - add_brooklyn_types:
        members: [io.cloudsoft.3-tier-application]
        type: brooklyn.tosca.groups.initializer
        properties:
           location:
           - ubuntu20-location

Deploy 3-tier-application.yaml with br:

> br deploy 3-tier-application.yaml

Id:       | dnejwj36fg   
Name:     | io.cloudsoft.3-tier-application   
Status:   | In progress

Now inspect status of a deployed application with br:

> br application

Id           | Name                              | Status     | Location   
dnejwj36fg   | io.cloudsoft.3-tier-application   | STARTING   | n8k6oojhg8   

Status of application changes after deployment is complete:

> br application

Id           | Name                              | Status     | Location   
dnejwj36fg   | io.cloudsoft.3-tier-application   | RUNNING    | n8k6oojhg8   

The following YAML describes the topology of a three tier webapp, using a MySQL backing store and a cluster of Tomcat containers behind an Nginx load balancer.

services:
- type: org.apache.brooklyn.entity.database.mysql.MySqlNode
  id: db
  name: My DB (MySQL)
  brooklyn.config:
    datastore.creation.script.url: https://raw.githubusercontent.com/apache/brooklyn-library/master/examples/simple-web-cluster/src/main/resources/visitors-creation-script.sql
- type: org.apache.brooklyn.entity.group.DynamicCluster
  name: My Cluster
  id: cluster
  brooklyn.config:
    initialSize: 2
    memberSpec:
      $brooklyn:entitySpec:
        type: org.apache.brooklyn.entity.webapp.tomcat.TomcatServer
        name: Tomcat Server
        brooklyn.config:
          wars.root: http://search.maven.org/remotecontent?filepath=org/apache/brooklyn/example/brooklyn-example-hello-world-sql-webapp/0.9.0/brooklyn-example-hello-world-sql-webapp-0.9.0.war
          java.sysprops:
            brooklyn.example.db.url:
              $brooklyn:formatString:
              - "jdbc:%s%s?user=%s&password=%s"
              - $brooklyn:component("db").attributeWhenReady("datastore.url")
              - "visitors"
              - "brooklyn"
              - "br00k11n"
  brooklyn.enrichers:
  - type: org.apache.brooklyn.enricher.stock.Aggregator
    brooklyn.config:
      enricher.sourceSensor: $brooklyn:sensor("webapp.reqs.perSec.windowed")
      enricher.targetSensor: $brooklyn:sensor("webapp.reqs.perSec.perNode")
      enricher.aggregating.fromMembers: true
      transformation: average
- type: org.apache.brooklyn.entity.proxy.nginx.NginxController
  id: nginx
  name: My Load Balancer (nginx)
  brooklyn.config:
    loadbalancer.serverpool: $brooklyn:entity("cluster")
    nginx.sticky: false
brooklyn.enrichers:
- type: org.apache.brooklyn.enricher.stock.Propagator
  brooklyn.config:
    producer: $brooklyn:entity("nginx")
    propagating:
    - main.uri
    - main.uri.mapped.subnet
    - main.uri.mapped.public

This blueprint is composed of the following items:

  1. A MySQL node, which is configured with the URL of a database creation script.

  2. A DynamicCluster where all its children are of type org.apache.brooklyn.entity.webapp.tomcat.TomcatServer. Each child has a configuration of wars.root, which is the URL of an application WAR and some java system properties for the application to use. The only system property given here is the connection string to the MySQL node. The connection string is formed using a special syntax [ (the AMP DSL)

    to reference the other components in the blueprint; the component db in this case.

  3. A NginxController that act as a load-balancer for the previous cluster ot Tomcat servers.
    The entity knows about the cluster thanks to loadbalancer.serverpool and the [ DSL.

In order to deploy this blueprint, a location in which to deploy it is required. Firstly we need to create a location if none are available, then add a location: locationId section to the blueprint. This blueprint should then be saved to a file, three-tier.yaml for example.

Then to deploy the blueprint, run the command:

br deploy three-tier.yaml

Gotchas

This blueprint assume that your location is correctly configured for all the VMs to be able to talk to each other using their internal IPs. However, depending on your location configuration, the VMs might not be on the same network. If that is the case, the deployment will not fail but the load-balancer will have a wrong configuration.

Here are some quick workarounds:

  • You can configure Nginx to use a different sensor to build its configuration. For example, to use the public address, you can add the following line under brooklyn.config of nginx:
  member.sensor.hostname: host.address
  

Summary

The CLI is an alternative means of managing applications within AMP and is particularly suitable for automation.

Next