Use constraints with Swarm mode

In this post, i will explain you how to use constraints to limit the set of nodes where a task can be scheduled.

It’s the purpose of a Swarm cluster, all your nodes can accept containers.

But sometimes, you need to specify a subset of nodes for some reasons. For example, maybe all your nodes have not the same hardware and some are more powerfull.

That’s where constraints appear ! They will let you specify on which nodes your service can be scheduled. Constraints are based on labels.

% docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
tez1zpw5oe5x8rrim4augz1h7 *   docker00            Ready               Active              Reachable           18.06.1-ce
w1rxedpb1mwkwbg97tb45x2dd     docker01            Ready               Active              Reachable           18.06.1-ce
jxgj5lhwlq7mep5e4jqx64frm     docker02            Ready               Active              Leader              18.06.1-ce
s6zwvwsit6t6pdj7epul8lctk     docker03            Ready               Active                                  18.06.1-ce
kw1q3i59pxh47uxjun5m3ahhd     docker04            Ready               Active                                  18.06.1-ce

This cluster have 3 managers and 2 workers. By default, a new service will be scheduled on one of this 5 nodes.

  1. Docker’s defaults constraints

    By default, nodes already have labels.

    You can use these labels to restrict scheduling on your service :

    % docker service create --name TEST --constraint 'node.role == manager' ...
    % docker service create --name TEST --constraint 'node.id == w1rxedpb1mwkwbg97tb45x2dd' ...
    % docker service create --name TEST --constraint 'node.hostname != docker01' ...
    

    If you specify multiples constraints, Docker will find nodes that satisfy every expression (it’s an AND match).

    % docker service create --name TEST --constraint 'node.role == manager' --constraint 'node.hostname != docker01' ...
    

    With this example, the new service will be scheduled on docker00 or docker02 (both are managers).

  2. Add your own’s labels

    With the defaults labels, you can affine scheduling but if you want to be more specific, add your own’s labels. Recently, in my cluster, i have updated docker00 and docker01 with the latest Raspberry Pi 3B+ (the others are Raspberry Pi 3B). So, i have 2 nodes more powerfull (cpu and network) than the others.

    It could be usefull to schedule containers that need more CPU or network on these nodes.

    For this, we need to :

    • Add a custom label to your nodes (only managers can add labels):

      % docker node update --label-add powerfull=true docker00
      % docker node update --label-add powerfull=true docker01
      

      We added the label powerfull : true to the 2 nodes.

      You can see labels with this command :

      % docker node inspect docker00
      ...
      "Spec": {
          "Labels": {
              "powerfull": "true"
          },
          "Role": "manager",
          "Availability": "active"
      },
      ...
      

      Start the service with the new constraint :

    • % docker service create --name TEST --constraint 'node.labels.powerfull == true' ...
      

      Please note that the syntax for your own’s labels is : node.labels.YOUR_LABEL_NAME

  3. Delete your own’s labels

    Just in case you need it :

    % docker node update --label-rm powerfull docker00