Create a service with placement constraints and preferences
In this step, you will learn how to use placement constraints and preferences to control where your service tasks are deployed within the Docker Swarm. Placement constraints are hard requirements that a node must meet for a task to be scheduled on it. Placement preferences are soft requirements that influence scheduling but do not prevent a task from being scheduled if no node meets the preference.
First, let's inspect the current node to see its labels. Labels are key-value pairs that you can attach to nodes to provide metadata.
docker node inspect self --format '{{ .Spec.Labels }}'
This command inspects the current node (identified by self
) and formats the output to show its labels. By default, there might not be any custom labels.
Let's add a label to the current node. We will add a label node_type=app
.
docker node update --label-add node_type=app self
This command updates the current node and adds the label node_type=app
.
Now, let's verify that the label has been added.
docker node inspect self --format '{{ .Spec.Labels }}'
You should see map[node_type:app]
in the output, indicating that the label has been successfully added.
Now, let's create a replicated service named my-constrained-service
with a placement constraint that requires the node to have the label node_type=app
. We will use the nginx
image.
docker service create \
--name my-constrained-service \
--replicas 1 \
--constraint 'node.labels.node_type == app' \
nginx:latest
This command creates a service with a constraint. --constraint 'node.labels.node_type == app'
specifies that tasks for this service can only be scheduled on nodes where the label node_type
is equal to app
. Since we added this label to the current node, the task should be scheduled here.
Check the service status and tasks:
docker service ls
docker service ps my-constrained-service
You should see my-constrained-service
listed and its task running on the current node.
Now, let's create another service with a placement preference. Placement preferences are used to guide the scheduler but are not strictly enforced. We will use the busybox
image and prefer nodes with the label node_type=database
. Since our current node does not have this label, the task will still be scheduled on the current node, but if there were other nodes with that label, the scheduler would prefer them.
First, pull the busybox
image.
docker pull busybox:latest
Now, create the service with a placement preference.
docker service create \
--name my-preferred-service \
--replicas 1 \
--placement-pref 'spread=node.labels.node_type' \
busybox:latest sleep infinity
The --placement-pref 'spread=node.labels.node_type'
option tells the scheduler to spread the tasks across nodes based on the value of the node_type
label. In a multi-node swarm with different node_type
labels, this would distribute tasks more evenly. In this single-node environment, the task will simply be scheduled on the available node.
Check the service status and tasks:
docker service ls
docker service ps my-preferred-service
You should see my-preferred-service
listed and its task running on the current node.