Getting serious with Juju - multiple models, management and constraints

In the last introductory post for Juju we'll cover working with multiple models, basic management and setting some constraints. For now you should be familiar with the basic concepts and probably be able to work with a simple model. It's time to check what it's all about.

Multiple models

As I mentioned in the previous posts, by default a bootstrap creates two models - admin and default. The former is designed for managing some internal stuff, the latter is what you have access to and can work with. Initially it seems reasonable, but sooner than later you'll understand, that having everything(web applications, big data, analytics etc.) in on place just muddles things. To separate concerns we can have multiple models residing on the same controller.

Models listed with juju models command show both machines and cores count

You can add a new model easily either with a GUI(with a "Start a new model" button) or with a CLI(using juju add-model <model_name> command). To switch active model you can do the same - either select it from a dropdown or with a juju switch command.

Importing & exporting models

The important thing is Juju is the possibility to import/export a model. With this feature you can easily share an infrastructure you've modeled or use model designed by other experts. The best thing about this is the fact, that you pass only an idea - a physical part is detached from a model. What is more, since models are just YAML files, you can easily version them using a version control system of your choice. Take a look how a simple model is descibed:

/
series: xenial
applications: 
  wordpress: 
    charm: "cs:trusty/wordpress-5"
    num_units: 1
    annotations: 
      "gui-x": "300"
      "gui-y": "300"
    to: 
      - "1"
  mysql: 
    charm: "cs:mysql-57"
    num_units: 1
    annotations: 
      "gui-x": "695"
      "gui-y": "395"
    to: 
      - "0"
relations: 
  - - "mysql:db"
    - "wordpress:db"
machines: 
  "0": 
    series: xenial
    constraints: "arch=amd64 cpu-cores=1 mem=1792 root-disk=30720"
  "1": 
    series: trusty
    constraints: "arch=amd64 cpu-cores=1 mem=3584 root-disk=30720"

As you can see, all "beings" like charms, relations and machines are here and can be customized without interacting with Juju. 

Management

When it comes to management features, Juju comes with two major concepts - commands restrictions and network spaces.

Commands

It's always a good idea to restrict potentially dangerous features of a tool or an application you're using. When it comes to Juju, we have two groups - destroy and remove. A good reference which command falls to which group can be found here. The important thing about this is that in most case a user will be affected by those restriction only when it logs again. If you go with following commands:

/
juju disable-command destroy-model
juju destroy-model <model>

You won't have problems with removing a model. Another thing is using --force switch with Juju commands. Have in mind that this means, that all your restrictions will be bypassed.

Network spaces

Since infrastructure made with Juju can become quite complicated, some advanced networking features are available. One of those are "spaces", well described in the documentation:

A space is made up of one or more routable subnets with common ingress and egress rules. The Juju operator can model this topology in such a way that applications gain the required network connectivity without generating complex network IP maps that are not portable. This gives the operator much better and finer-grained control over all networking aspects of a model and its application deployments.

To make the long story short - spaces let you orchestrate your subnets and ease connection between them when it comes to communication. What is more, once spaces are configured, you can constraint deploying charms to the particular ones. 

To only downside of this is the fact, that currently spaces are only supported by MAAS so it's not available out of the box. Still, if you're interested in such feature, take a look here.

Constraints

The last but not least thing are constraints. They allow you to set some limits when it comes to setting a machine. The important thing here is the difference between different cloud vendors - depending on the cloud, some constraints can be available or generating conflicts. 

Constraints have two characteristic:

  • work on "a better" basis - you are passing the minimum requirement for a component
  • can be ignored by passing a null value

You can set constraints either for an environment(controller), a model, an application or a machine.

You may wonder what is the purpose of working on "a better" basis. To understand reasons behind this setting you have to change your mindset a little when working with Juju - it is designed to provide the best performance to coordinated components, not to manage them in terms of used resources. It's all about modeling a solution which works flawlessly.

Summary

In this short journey we've learned some basic stuff in Juju. We know what are the main components, how a model is built and how we can manage it. We'll come back to Juju in future to create custom charms with Azure resources.

 

The real magic is here - charms in Juju

In this post we'll focus on the most crucial thing of Juju's models - charms. To make the long story short - charms are software components containing instructions necessary for deploying and configuring applications. You can think about them as packages containing both installer and scripts designed to make a thing work automatically. 

Important thing is the fact, that scaling in Juju happens having a charm in mind. For example - if you have provisioned a single machine running a database and you scale it, you'll have it deployed to N machines(depending on your demands). This, however, won't affect other charms dependent on this specific one.

Relations

A charm may have a relation. From the modelling point of view, adding a relation creates a virtual link between two or more charms. In fact when you add a relation, Juju will arrange a communication protocol for linked charms to allow them to exchange necessary information. You, as a model author, can just sit and relax.

When obtaining a charm for the store, you can ensure what are the possible relations for it

This is what makes Juju so powerful - once relations are configured, most things just happen seamlessly. 

Status of a model while a charm is being deployed

Scaling

Scaling is the second very important feature, which is what makes Juju so attractive. All it's about is to tell a controller to scale a charm up(or have a script, which will do it for you). The way how it is handled in Juju depends on the charm - some charms require external load balancer to actually distribute traffic, some have build-int load balancing and need only a command to grow.

When scaling applications, you can either co-locate them on a one machine or spawn multiple small machines and handle each one separately. Either way you don't care about what happens behind the scenes - Juju will orchestrate everything and make sure it works.

Status of a model when scaling from a single MariaDB instance to 4 different ones. Note that 3 instances are co-located.

Summary

In this post we played a little with charms, which are the very foundations of Juju. We're aware of features like scaling and relations and what are the ideas behind them. In the last post we'll talk a bit about managing our controller - having multiple models, importing them and setting constraints.