Bundles Bundles Bundles!

You’ve gone through the process of sorting through various service orchestration solutions, and settled on Juju, since it will work with your existing frameworks and solutions, such as chef, puppet, and ansible. You’ve gone ahead and charmed up a few of your microservices so that you can get them deployed to your Juju environment. You’ve searched through the charmstore to find the databases, load balancers, and additional charms that you need to really make your project shine.

Whew! That’s gonna be a lot of docs to write for new hires, right?

Not necessarily! Here’s where bundles come into play!

Bundles allow you to pull all of your services, unit placements, and relations together into one YAML file. A bundle is basically an export of a Juju environment. In fact, if you use the Juju GUI, it literally is that: the GUI will export all of your services with all of their config values, all of the relations linking them together, and the way your units are placed on machines.

Bundles – V3 vs V4

First, a bit of an important note. Bundles have been around for a little while. Recent work, however, has meant that there are some changes in how bundles are structured. The older format, known as the V3 format (for the third version of the API), pulled multiple bundles together into a basket – this is no longer the case with the V4 API.

For instance, you might have a few wordpress bundles pulled together into a basket like so:

wordpress-single:
  services: ...
  relations: ...
  series: trusty

wordpress-scalable:
  services: ...
  relations: ...
  series: trusty

Since baskets are deprecated, trying to upload a basket to the charmstore now will result in that V3 series of bundles being migrated to individual V4 bundles.

The second difference between the two bundles formats is that the V4 format allows a machine specification. This means that you can have a top-level machines entry in your bundle.yaml file. This will contain a list of machine objects, which can have constraints, series, and annotationsobjects, which allow you finer-grained control over your machines:

machines:
  - "0":
    constraints: {mem: 4096, cpu-cores: 2}
  - "1":
    annotations: {foo: bar}
    series: trusty
  - "2": {}

Finally, the unit placement directives are different between the two formats. Previously, if you wanted to collocate two units, you would use a format unique to bundles, which used an equals sign to separate the name of the service from the unit number. With V4 bundles, however, you can simply use the unit syntax that you’re familiar with from working with juju.

service-1:
  charm: ...
  num-units: 2
service-2:
  charm: ...
  num-units: 2
  to:
    // collocate directly onto the machine that the first unit of service-1 is
    // on
    - service-1/0
    // collocate into an LXC container installed on the machine that the second
    // unit of service-1 is on
    - lxc:service-1/1

It’s also worth noting that placement directives can specify machines in the machine specification. That way, you can deploy units of a service to a given machine, either directly to the machine itself or to an lxc or kvm container (if supported).

This exposes one more difference between V3 and V4 bundles: in V3 bundles, the only machine you’re allowed to refer to is machine 0 (the bootstrap node), which allows you to place a service on the only machine guaranteed to be in your environment. You can do this in V4 bundles as well, but note that it is only possible if you do not have a machine spec in the bundle. This is because the system can’t be sure whether you mean the bootstrap node or the machine named “0” in the spec, so it defaults to placing it on the named machine (or erroring if there is no machine named “0”).

For more information on the bundle format specifications and the difference between V3 and V4 bundles, please be sure to check out the bundle doc in the charmstore! This should be kept up to date, as the Juju charmstore matures.

Creating bundles

The easiest way to create a bundle is through the Juju GUI. This even works in sandbox mode, so you can use demo.jujucharms.com to create your ideal environment without having to spin up any machines. Simply deploy and configure your services, add relations, place your units, and commit your changes to the sandbox, then you can export the environment as a bundle YAML file.

Bundle validation

You can easily validate a bundle.yaml file by dragging it onto the Juju GUI canvas and ensuring that all of the services, units, relations, and machines are created just how you specified. As with services, bundles dragged onto the canvas are in an uncommitted state until you hit the commit button. This means you can test in both sandbox and live environment modes without spinning up machines.

This works through a bit of magic called Juju bundlelib, which decomposes a bundle into a set of steps that will need to be undertaken to deploy all aspects of the bundle. Since this is a python utility that lives separate from the GUI, you can validate a bundle on the command line by running pip install jujubundlelib (in a virtualenv, if you wish), and then passing your bundle.yaml file as an argument to the command that it installs, getchangeset. If you have any errors in your bundle, the getchangeset command will enumerate the items that will need to be fixed; otherwise, it will output a JSON list of changes (the changeset) that your bundle produces.

Deploying bundles

There are a few ways to deploy bundles of charms. If you have the YAML file on your computer, you can drag that to the Juju GUI and the GUI will attempt to deploy the bundle for you by fetching the change set. This will leave all of the services, units, machines, and relations in an uncommitted state so that you can change anything you need to. Once you’re done, you can commit your changes to your environment.

Another way to deploy your bundle is using Juju Quickstart. This will spin up an environment for you (if you haven’t already), deploy the specified bundle along with the GUI, and get everything up and running for you. By default, Quickstart uses the Juju Deployer, but if you pass the -u option, your changes will be uncommitted and shown to you in the GUI.

You can also use the Juju Deployer on its own. It’s available on PyPI as well.

Once you publish your bundle to Launchpad, you will be able to navigate to view it onjujucharms.com and deploy it from the charmstore as well.

More information

Make sure to check out the full documentation for bundles to see all that can be done with them!