Machine Constraints
Machine constraints allow you to pick the hardware to which your services will be deployed.
Constraints can be set for environments and services, with lookups for each key falling back from more specific to more general settings, and with default values set by juju when otherwise unspecified. Changes to constraints do not affect any unit that has already been assigned to a machine.
Constraints will be controlled with a new command, juju set-constraints, taking an optional --service arg, and any number of key=value pairs. When the service name is specified, the constraints are set on that service; otherwise they are set on the environment.
Valid choices for the value are generally dependent on the particular constraint, with two exceptions:
- An empty value always means "use the juju default setting". This allows you to ignore environment settings at the service level without having to explicitly remember and re-set the juju default values. Note that there is no way to change the juju default values.
- A value of any explicitly unsets a constraint, and will cause it to be chosen completely arbitrarily.
We also extend the syntax for juju deploy, and juju bootstrap, such that --constraints expects a single string of space-separated constraints, understood as above; deployment constraints will be set on the service before the first unit is deployed, and bootstrap constraints will be set on the environment and used to provision the initial master machine.
Please note that there are no changes to the juju add-unit command; juju is explicitly focused on service orchestration, and it is counterproductive to encourage users to consider individual units. This can be worked around by setting new service constraints before adding new units, but is not encouraged.
The new juju get-constraints command is used to see the currently applicable constraints. When called without arguments, it outputs the environment constraints as a single yaml-formatted dict; alternatively, it can be called with any number of arguments referencing any mix of services, service units, or machines, and will output a yaml-formatted dict of dicts with the outer dict keyed on the requested entities.
Examples
Deploy MySQL on a machine with at least 32GiB of RAM, and at least 8 ECU of CPU power (architecture will be inherited from the environment, or default to amd64):
juju deploy --constraints "cpu-cores=8 mem=32G" mysql
Deploy to t1.micros on AWS:
juju bootstrap --constraints "cpu-power=0 cpu-power=0 mem=512M"
Launch all future "mysql" machines with at least 8GiB of RAM and 4 ECU:
juju set-constraints --service mysql mem=8G cpu-cores=4
Output current environment constraints:
juju get-constraints
Output constraints for machine 3, service "mysql", and service unit "wordpress/7":
juju get-constraints 3 mysql wordpress/7
Provider Constraints
The constraints available vary by provider, but should include:
- cpu-cores: The minimum processing power of the machine, measured in ECU,defaulting to 1; any real number >= 0 is valid.
- mem: The minimum memory for the machine, defaulting to 512MB; any real number >= 0, and optionally suffixed with M, G or T is valid.
- arch: The machine's processor architecture, defaulting to "amd64". Valid values are "i386", "amd64", and "arm".
The currently available MAAS constraint is:
- maas-name: The MAAS name to which each unit must be deployed. This is philosophically problematic, on the basis that teaching users that it's OK to specify single machines will lead them to pain when they attempt to scale out large deployments; but it's justified on the basis that MAAS itself needs to act as a stepping stone between the "metal" and "cloud" mindsets. maas-name is unset by default, and should correspond to a name known by the MAAS provider.
Working with constraints
Here are some examples of working with constraints.
When bootstrapping an environment, you can set the constraints directly:
juju bootstrap --constraints arch=i386
The above command did two things:
Set the environment constraints to require machines with an i386 architecture, leaving the other defaults untouched; this is precisely equivalent to:
juju bootstrap --constraints "arch=i386 cpu-cores= mem= "
...but rather more convenient to type.
Started the bootstrap/master machine with the above constraints.
Because the environment constraints were set, subsequent deployments will use the same values:
juju deploy mysql
...but other services can be started with their own constraints:
juju deploy wordpress --constraints mem=1024
Note that the arch=i386 constraint is still inherited from the environment, and that this presents a potential problem:
juju deploy minecraft --constraints instance-type=cc2.8xlarge
The above command will still inherit the environment constraints, and will lead to an undeployable service (because cc2.8xlarge cannot run on i386). Running juju debug-log will expose the problem; you can fix it as follows:
juju remove-unit minecraft/0
juju terminate-machine 1
juju set-constraints --service minecraft arch=amd64 instance-type=cc2.8xlarge
juju add-unit minecraft
(You need to remove machine 1's assigned unit before you can terminate it; you need to explicitly terminate the machine to stop the provisioning agent from continuing to attempt to launch it; and you need to set the new service constraints before adding a new unit that will use those constraints.)
Work on the constraints feature is ongoing, and it will shortly become impossible to specify knowably inconsistent constraints; but it is in general impossible to detect undeployable constraints with absolute certainty (for example, you could deploy with ec2-zone=a and be running perfectly happily, but see us-east-1a suddenly go down just as you add a unit).
Distinctions Between Entities
As noted, it is impossible to directly set constraints on machines or service units; however, it is still possible to call juju get-constraints on those entities. In either case, the constraints are a snapshot of the applicable constraints at entity creation time; so the unit constraints are the combined environment/service constraints from the time at which the unit was created, and the machine constraints are a copy of the unit constraints at that same point in time.
Storing this data allows us to automatically reprovision unexpectedly dead machines (for example, if you terminate machine 7 via the AWS management console, the provisioning agent will spin up a new instance with the same constraints and redeploy the assigned units); and making the data available via the CLI gives you visibility into the state of your deployment, and allows you to answer questions like "why is this unit running on that machine?".
Legacy Deployments
Attempting to use constraints against a deployment that predates their inclusion in juju will not work, because the running legacy code (specifically, the provisioning agent) will not be able to interpret them. Therefore, attempts to specify constraints against legacy deployments will generate errors to inform users of their invalidity; at the agent level they are simply ignored.
All commands valid before the client upgrade should continue to work as before, as will the EC2 default-image-id and default-instance-type environment settings.