Ubuntu Juju

Ubuntu’s Juju platform provides the scaffolding for building complex systems in a consistent way independent of the underlying infrastructure the components are being deployed on. Components are wrapped up as charms which are deployable services that can be used as building blocks for larger systems. Relationships can be established between services to allow them to interact.

SiteWhere provides a charm that allows it to easily be deployed to all of the environments Juju supports including OpenStack, Microsoft Azure, Amazon EC2, VMware, and many other providers. Juju also supports running a local container and deploying to it. A great feature of Juju deployment is that commands are consistent across all environments. Deploying on your local environment is accomplished with exactly the same commands necessary for deploying to any of the cloud providers. Environment-specific settings are captured separately and become a non-factor in the deployment process.

Deploying SiteWhere on Juju

The first step in deploying SiteWhere to Juju is setting up the Juju environment. The Juju installation guide provides an easy path to installing on your native operating system and deploying a sample application. With Juju up and running locally, we are ready to deploy SiteWhere and its dependencies. If you have not already done so, bootstrap a local Juju environment as shown below:

juju bootstrap -e local

The next step in deployment is to install the charms we will need to build the system. In this case, we need to install SiteWhere Server, MongoDB for the datastore, and Mosquitto for an MQTT broker. The components can be installed using the following commands:

juju deploy cs:~sitewhere/trusty/sitewhere sitewhere
juju deploy cs:~sitewhere/trusty/sitewhere-mongodb mongodb
juju deploy cs:~tasdomas/trusty/mosquitto

Juju will copy the files associated with the charms to the environment and run the built-in installation scripts to create the services. By default, Juju will create a single unit for each deployed service. By adding more units for a given service it can be scaled to handle a heavier load. Keep in mind that the default behavior in Juju is to use a separate virtual machine per unit, so when running in the cloud, adding more units will add to your bill. To check on the progress of Juju creating the units, type:

juju stat

The response will be in the form of a YAML document that describes all aspects of the current environment. While the units are allocating and installing the output will look something like below:

environment: local

machines:

  "0":

    agent-state: started

    agent-version: 1.24.0.1

    dns-name: localhost

    instance-id: localhost

    series: utopic

    state-server-member-status: has-vote

  "1":

    agent-state: pending

    instance-id: osboxes-local-machine-1

    series: trusty

    hardware: arch=amd64

  "2":

    agent-state: pending

    instance-id: osboxes-local-machine-2

    series: trusty

    hardware: arch=amd64

  "3":

    agent-state: pending

    instance-id: osboxes-local-machine-3

    series: trusty

    hardware: arch=amd64

services:

  mongodb:

    charm: cs:~sitewhere/trusty/sitewhere-mongodb-1

    exposed: false

    service-status:

      current: unknown

      message: Waiting for agent initialization to finish

      since: 01 Aug 2015 15:54:05+01:00

    relations:

      replica-set:

      - mongodb

    units:

      mongodb/0:

        workload-status:

          current: unknown

          message: Waiting for agent initialization to finish

          since: 01 Aug 2015 15:54:05+01:00

        agent-status:

          current: allocating

          since: 01 Aug 2015 15:54:05+01:00

        agent-state: pending

        machine: "2"

  mosquitto:

    charm: cs:~tasdomas/trusty/mosquitto-0

    exposed: false

    service-status:

      current: unknown

      message: Waiting for agent initialization to finish

      since: 01 Aug 2015 15:54:25+01:00

    units:

      mosquitto/0:

        workload-status:

          current: unknown

          message: Waiting for agent initialization to finish

          since: 01 Aug 2015 15:54:25+01:00

        agent-status:

          current: allocating

          since: 01 Aug 2015 15:54:25+01:00

        agent-state: pending

        machine: "3"

  sitewhere:

    charm: cs:~sitewhere/trusty/sitewhere-7

    exposed: false

    service-status:

      current: unknown

      message: Waiting for agent initialization to finish

      since: 01 Aug 2015 15:53:50+01:00

    units:

      sitewhere/0:

        workload-status:

          current: unknown

          message: Waiting for agent initialization to finish

          since: 01 Aug 2015 15:53:50+01:00

        agent-status:

          current: allocating

          since: 01 Aug 2015 15:53:50+01:00

        agent-state: pending

        machine: "1"

The initialization process takes some time as Juju has to spin up the virtual machines, start them, then install the charm software. Whether you are running locally, on Amazon AC2, on Microsoft Azure, or elsewhere, the juju stat command will allow you to see the current state of the environment. In our case, the state when completed will have changed to:

environment: local

machines:

  "0":

    agent-state: started

    agent-version: 1.24.0.1

    dns-name: localhost

    instance-id: localhost

    series: utopic

    state-server-member-status: has-vote

  "1":

    agent-state: started

    agent-version: 1.24.0.1

    dns-name: 10.0.3.138

    instance-id: osboxes-local-machine-1

    series: trusty

    hardware: arch=amd64

  "2":

    agent-state: started

    agent-version: 1.24.0.1

    dns-name: 10.0.3.76

    instance-id: osboxes-local-machine-2

    series: trusty

    hardware: arch=amd64

  "3":

    agent-state: started

    agent-version: 1.24.0.1

    dns-name: 10.0.3.97

    instance-id: osboxes-local-machine-3

    series: trusty

    hardware: arch=amd64

services:

  mongodb:

    charm: cs:~sitewhere/trusty/sitewhere-mongodb-1

    exposed: false

    service-status:

      current: unknown

      since: 01 Aug 2015 16:02:20+01:00

    relations:

      replica-set:

      - mongodb

    units:

      mongodb/0:

        workload-status:

          current: unknown

          since: 01 Aug 2015 16:02:20+01:00

        agent-status:

          current: idle

          since: 01 Aug 2015 16:02:23+01:00

          version: 1.24.0.1

        agent-state: started

        agent-version: 1.24.0.1

        machine: "2"

        open-ports:

        - 27017/tcp

        - 27019/tcp

        - 27021/tcp

        - 28017/tcp

        public-address: 10.0.3.76

  mosquitto:

    charm: cs:~tasdomas/trusty/mosquitto-0

    exposed: false

    service-status:

      current: unknown

      since: 01 Aug 2015 16:03:48+01:00

    units:

      mosquitto/0:

        workload-status:

          current: unknown

          since: 01 Aug 2015 16:03:48+01:00

        agent-status:

          current: idle

          since: 01 Aug 2015 16:03:50+01:00

          version: 1.24.0.1

        agent-state: started

        agent-version: 1.24.0.1

        machine: "3"

        open-ports:

        - 1883/tcp

        public-address: 10.0.3.97

  sitewhere:

    charm: cs:~sitewhere/trusty/sitewhere-7

    exposed: false

    service-status:

      current: blocked

      message: Waiting for MongoDB relation to be established.

      since: 01 Aug 2015 16:11:29+01:00

    units:

      sitewhere/0:

        workload-status:

          current: blocked

          message: Waiting for MongoDB relation to be established.

          since: 01 Aug 2015 16:11:29+01:00

        agent-status:

          current: idle

          since: 01 Aug 2015 16:11:31+01:00

          version: 1.24.0.1

        agent-state: started

        agent-version: 1.24.0.1

        machine: "1"

        open-ports:

        - 8080/tcp

        public-address: 10.0.3.138

Note that there is a lot more information available once the agents have started, including the public ip address where the unit can be reached and many other details. Also note that the workload-status field for unit sitewhere/0 is marked as blocked indicating it is waiting on MongoDB to be attached.

The next step in creating a working system is to establish relations between the services. This provides details to the running units about how to interact with other units. For instance, establishing a relationship between SiteWhere and MongoDB passes the hostname and port SiteWhere needs to use to connect to MongoDB. Execute the commands below to establish the needed relations:

juju add-relation sitewhere mongodb
juju add-relation sitewhere mosquitto

After a short period of time, the relations will have been established. Executing the juju stat command will show the current status. Once the SiteWhere unit shows a status of active, the system is properly configured and ready to be used. By default, Juju runs units within a protected virtual network that prevents external access to the units. In order to access the SiteWhere administrative console, we need to ask Juju to expose the service as shown below:

juju expose sitewhere

The exposed flag on the SiteWhere service will change to true and port 8080 will become accessible. To test the configuration, open a browser and navigate to:

http://{public.address}:8080/sitewhere/admin

The public address you use should be the one listed for the sitewhere/0 unit. If everything went as expected, the SiteWhere administrative console machine should be displayed in the browser:

We now have a completely functional SiteWhere deployment including a MongoDB datastore and a Mosquitto MQTT broker configured.

Changing the Default Configuration

In the deployment above we are falling back on the default system configuration, but SiteWhere is intended to be configurable so that many other protocols can be used. It is possible to use SSH to connect with the SiteWhere unit and directly edit the configuration file. To use this method, execute the following command:

juju ssh sitewhere/0

The juju ssh command is a simple way to interact directly with the internals of a unit. The downside of going this route is that reconfiguring multiple units requires an SSH into each one. Also, deploying new units for the service will start the units with the default configuration. Rather than manually configuring each unit, Juju allows configuration to be done at the service level. The SiteWhere Juju charm allows the configuration to be loaded from an external URL as shown below:

juju set sitewhere config-url=https://goo.gl/V6d9t5

The URL you point to must be resolvable from the environment the system is running on. A great option for storing configuration files is checking them in to GitHub, since it allows the configurations to be versioned over time and rolled back if needed. Once the configuration URL has been set for the service, all new units will be configured with the same URL.

Next Steps

Now that we have a working base configuration, we can start looking at building out more complex SiteWhere deployments. In future tutorials, we will take a look at models for scaling SiteWhere across many units to spread the workload and improve performance.