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
    charm: "cs:trusty/wordpress-5"
    num_units: 1
      "gui-x": "300"
      "gui-y": "300"
      - "1"
    charm: "cs:mysql-57"
    num_units: 1
      "gui-x": "695"
      "gui-y": "395"
      - "0"
  - - "mysql:db"
    - "wordpress:db"
    series: xenial
    constraints: "arch=amd64 cpu-cores=1 mem=1792 root-disk=30720"
    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. 


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


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.


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.


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.


EventStore on Azure and Ubuntu - it's a piece of cake! #4

Finally - the last but not least post about setting your own EventStore instance using Ubuntu on Azure. We've already prepared the majority of work needed here, so it shouldn't be difficult to adjust is just a bit to use DNS instead of hardcoded IPs.


Currently our configuration looks like this:

RunProjections: None
ClusterSize: 3
DiscoverViaDns: False

Clearly the first change is to get rid of the DiscoverViaDns property. The reason why we're going to remove it is the fact, that it's set to true by default. However, it appears that we need two more properties: ClusterDns and ClusterGossipPort. Additionally we'll remove the GossipSeed property as it also won't work here anymore. Let's get to work!

Network, DNS and Azure

When we created Ubuntu VMs in Azure we're given a single instance of a virtual network. You can think about it as a logical representation of your network in Azure - you manage IPs, DNS and other settings without installing physical devices. It gives you isolation and security - if you want to, you can forbid both inbound and outbound traffic. What we're interested in right now is its DNS capability. Currently you have two options:

  • use a DNS provided by Azure
  • use your own DNS 

Unfortunately using the former won't work here - we have to add records manually, what is not allowed when using Azure DNS. Obtaining and configuring a DNS server is beyond the scope of this post - if you're interested take a look here. The good thing is that it's still possible within Azure and additional tools are required. Once you have your DNS, the configuration should look similar to:

RunProjections: None
ClusterSize: 3
IntTcpPort: 1111
ExtTcpPort: 1112
IntHttpPort: 2113
ExtHttpPort: 2114
ClusterGossipPort: 2113

DNS entries

The tricky thing here is to set correct entries in your DNS server. What you have to do here is to add an A entry pointing to your private IPs inside a network. Note that there's no concerns in doing this - it's a common practice. The one issue here is that it describes a little how your local network looks like - while accessing domain from an Azure network will point to the correct machine, when one tries to access it from an external network, he will be redirected to the private IP being the same as the one used in an entry.


This is it - we've went through installing, configuring and managing EventStore using Ubuntu and Azure. I strongly encourage you to discover other OSS solution, which could be run using such configuration and play with them, it becomes more and more fun.