Using constraints
A constraint is a user-defined minimum hardware specification for a machine that is spawned by Juju. There are a total of nine types of constraint, with the most common ones being 'mem', 'cores', 'root-disk', and 'arch'. The definitive constraint resource is found on the Reference: Juju constraints page.
Several noteworthy constraint characteristics:
- A constraint can be specified whenever a new machine is spawned with
commands
bootstrap
,deploy
, oradd-machine
. - Some constraints are only supported by certain clouds.
- When used with
deploy
the constraint becomes the application's default constraint. - Multiple constraints are logically AND'd (i.e. the machine must satisfy all constraints).
- When used in conjunction with a placement directive (
--to
option), the placement directive takes precedence.
Clouds and constraints
The idealized use case is that of stipulating a constraint when deploying an application and the backing cloud providing a machine with those exact resources. In the majority of cases, however, default constraints may have been set (at various levels) and the cloud is unable to supply those exact resources.
When the backing cloud is unable to precisely satisfy a constraint, the resulting system's resources will exceed the constraint-defined minimum. However, if the cloud cannot satisfy a constraint at all then an error will be emitted and a machine will not be provisioned.
When using the localhost cloud, constraints are ineffectual due the nature of this cloud's underlying technology (LXD), where each machine will, by default, have access to all of the LXD host's resources. Here, an exact hardware specification can be requested, but is done at the LXD level (see example below).
Constraint scopes, defaults, and precedence
Constraints can be applied to various levels or scopes. Defaults can be set on some of them, and in the case of overlapping configurations a precedence is adhered to. Changing a default does not affect existing machines.
On a per-controller basis, the following constraint scopes exist:
- Controller machine
- All models
- Single model
- Single application
- All units of an application
- Single machine
So a constraint can apply to any of the above. We will see how to target each later on.
Among the scopes, default constraints can be set for each with the exception of the controller and single machines.
The all-units scope has its default set dynamically. It is the possible constraint used in the initial deployment of an application.
The following precedence is observed (in order of priority):
- Machine
- Application (and its units)
- Model
- All models
For instance, if a default constraint ('mem') applies to a single model and
the same constraint has been stipulated when adding a machine (add-machine
)
within that model then the machine's constraint value will be applied.
The dynamic default for units can be overridden by either setting the application's default or by adding a machine with a constraint and then applying the new unit to that machine.
Setting constraints for a controller
Constraints are applied to the controller during its creation using the
--bootstrap-constraints
option:
juju bootstrap --bootstrap-constraints cores=2 google
Here, we want to ensure that the controller has at least two CPUs.
See Creating a controller for details and further examples.
Note: Constraints applied with '--bootstrap-constraints' will automatically apply to any future controllers provisioned for high availability (HA). See Controller high availability.
Setting constraints for the initial 'controller' and 'default' models
Constraints can be applied to every machine (controller and non-controller)
in the 'controller' and 'default' models. This is done, again, during the
controller-creation process, but by using the --constraints
option instead:
juju bootstrap --constraints mem=4G aws
See Creating a controller for more guidance.
Important: Individual constraints from --bootstrap-constraints
override any identical constraints from --constraints
if these options are used in combination.
For the LXD cloud, the following invocation will place a limit of 2GiB of memory for each machine:
juju bootstrap --constraints mem=2G localhost
For the localhost cloud, the following invocation will achieve a similar goal to the previous command (assuming that the LXD containers are using the 'default' LXD profile):
lxc profile set default limits.memory 2GB
Such a command can be issued before or after juju bootstrap
because it
affects both future and existing (in real time) machines. See the
LXD documentation for more on this topic.
Warning: LXD resource limit changes can potentially impact all containers on the host - not only those acting as Juju machines.
Setting and displaying constraints for a model
A model's constraints are set, thereby affecting any subsequent machines in
that model, with the set-model-constraints
command:
juju set-model-constraints mem=4G
A model's constraints are displayed with the get-model-constraints
command:
juju get-model-constraints
A model's constraints can be reset by assigning the null value to it:
juju set-model-constraints mem=
Setting, displaying, and updating constraints for an application
Constraints at the application level can be set at deploy time, via the
deploy
command. To deploy the 'mariadb' charm to a machine that has at least
4 GiB of memory:
juju deploy mariadb --constraints mem=4G
To deploy MySQL on a machine that has at least 6 GiB of memory and 2 CPUs:
juju deploy mysql --constraints "mem=6G cores=2"
Note: Multiple constraints are space-separated and placed within quotation marks.
To deploy Apache and ensure its machine will have 4 GiB of memory (or more) as
well as ignore a possible cores
constraint (previously set at either the
model or application level):
juju deploy apache2 --constraints "mem=4G cores="
An application's current constraints are displayed with the get-constraints
command:
juju get-constraints mariadb
An application's constraints are updated, thereby affecting any additional
units, with the set-constraints
command:
juju set-constraints mariadb cores=2
An application's default cannot be set until the application has been deployed.
Note: Both the get-constraints
and set-constraints
commands work with application custom names. See Deploying applications for how to set a custom name.
Setting constraints when adding a machine
Constraints at the machine level can be set when adding a machine with the
add-machine
command. Doing so provides a way to override defaults at the
all-units, application, model, and all-models levels.
Once such a machine has been provisioned it can be used for an initial
deployment (deploy
) or a scale out deployment (add-unit
). See
Deploying to specific machines for
the command syntax to use.
A machine can be added that satisfies a constraint in this way:
juju add-machine --constraints arch=arm
To add a machine that is connected to a space, such as 'storage':
juju add-machine --constraints spaces=storage
If a space constraint is prefixed by '^' then the machine will not be connected to that space. For example, given the following:
--constraints spaces=db-space,^storage,^dmz,internal
the resulting instance will be connected to both the 'db-space' and 'internal' spaces, and not connected to either the 'storage' or 'dmz' spaces.
See the Network spaces page for details on spaces.
To get exactly two CPUs for a machine in a localhost cloud:
juju add-machine lxc list lxc config set juju-ab31e2-0 limits.cpu 2
Above, it is presumed that lxc list
informed us that the new machine is
backed by a LXD container whose name is 'juju-ab31e2-0'.
See the earlier example on LXD for more context.