Moving shards away from a node is a safe way to prepare Elasticsearch for hardware maintenance, OS upgrades, or decommissioning without deleting indices or stopping the cluster.

Shard placement is controlled by allocation deciders, and cluster-level allocation filters add rules that include, exclude, or require nodes based on attributes such as _name, _ip, and custom node.attr.* values.

Relocation runs asynchronously and can increase CPU, disk, and network load, so filters should be applied with enough spare capacity and during low-traffic windows; security-enabled clusters typically require authentication (-u user:pass or an API key header) and HTTPS for the same requests.

Steps to set shard allocation filters in Elasticsearch:

  1. List node names and IP addresses for the filter target.
    $ curl -s "http://localhost:9200/_cat/nodes?v&h=name,ip"
    name  ip
    node-01  192.0.2.40
    node-02  192.0.2.41
    node-03  192.0.2.42
  2. Exclude a node by name from shard allocation.
    $ curl -s -H "Content-Type: application/json" --request PUT "http://localhost:9200/_cluster/settings?pretty&flat_settings=true" --data '{
      "persistent": {
        "cluster.routing.allocation.exclude._name": "node-03"
      }
    }'
    {
      "acknowledged" : true,
      "persistent" : {
        "cluster.routing.allocation.exclude._name" : "node-03"
      },
      "transient" : { }
    }

    Multiple values can be supplied as a comma-separated list, and wildcards such as node-* are supported for matching.

    Excluding the wrong node can leave shards unassigned when remaining nodes cannot satisfy allocation rules or lack free disk.

  3. Verify the allocation filter is active in cluster settings.
    $ curl -s "http://localhost:9200/_cluster/settings?pretty&flat_settings=true&include_defaults=false"
    {
      "persistent" : {
        "cluster.routing.allocation.exclude._name" : "node-03"
      },
      "transient" : { }
    }

    transient settings reset after a full cluster restart, while persistent settings remain until cleared.

  4. Monitor shard relocation progress using the cat recovery API.
    $ curl -s "http://localhost:9200/_cat/recovery?v&active_only=true&h=index,shard,stage,source_node,target_node,bytes_percent"
    index shard stage source_node target_node bytes_percent
  5. Confirm the excluded node has drained shards.
    $ curl -s "http://localhost:9200/_cat/allocation?v&h=shards,disk.percent,node"
    shards disk.percent node
    3      6            node-01
    3      6            node-02
    0      6            node-03
  6. Check cluster health for relocating shards and unassigned shards.
    $ curl -s "http://localhost:9200/_cluster/health?pretty"
    {
      "cluster_name" : "search-cluster",
      "status" : "green",
      "number_of_nodes" : 3,
      "active_primary_shards" : 3,
      "active_shards" : 6,
      "relocating_shards" : 0,
      "initializing_shards" : 0,
      "unassigned_shards" : 0,
      "delayed_unassigned_shards" : 0,
      "number_of_pending_tasks" : 0,
      "number_of_in_flight_fetch" : 0,
      "task_max_waiting_in_queue_millis" : 0,
      "active_shards_percent_as_number" : 100.0
    }
  7. Clear the allocation filter after maintenance.
    $ curl -s -H "Content-Type: application/json" --request PUT "http://localhost:9200/_cluster/settings?pretty&flat_settings=true" --data '{
      "persistent": {
        "cluster.routing.allocation.exclude._name": null
      }
    }'
    {
      "acknowledged" : true,
      "persistent" : { },
      "transient" : { }
    }
  8. Confirm the allocation filter is removed.
    $ curl -s "http://localhost:9200/_cluster/settings?pretty&flat_settings=true&include_defaults=false"
    {
      "persistent" : { },
      "transient" : { }
    }