### Description

The new [readiness port](https://www.elastic.co/guide/en/elasticsearch/reference/8.4/advanced-configuration.html#readiness-tcp-port) makes readiness checks on Kubernetes much easier. However the current implementation only allows connections through localhost. TCP probes on Kubernetes are run by the kubelet which is a process running on the Kubernetes node (and not from within the container or the Pod). The [Kubernetes documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#tcp-probes) mentions it, but it is kind of subtle: 

> For a TCP probe, the kubelet makes the probe connection at the node, not in the pod, which means that you can not use a service name in the host parameter since the kubelet is unable to resolve it.


That means a standard Kubernetes readiness probe cannot be used for Elasticsearch:
```
          readinessProbe:
            tcpSocket:
              port: 8080
```

Instead, only an `exec` probe that runs a shell command inside the container can be used that relies in this case on the presence of the `nc` command in the container image:

```
    readinessProbe:
      exec:
        command: ["nc", "-z", "-v", "-w5", "127.0.0.1", "8080"] 
```



x-pack/plugin/shutdown/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/shutdown/NodeShutdownIT.java
* A very basic smoke test to make sure the allocation decider is working.
     */
    @SuppressWarnings("unchecked")
    public void testAllocationPreventedForRemoval() throws Exception {
        String nodeIdToShutdown = getRandomNodeId();
        putNodeShutdown(nodeIdToShutdown, "REMOVE");
        
        final String indexName = "test-idx";
        Request createIndexRequest = new Request("PUT", indexName);
        createIndexRequest.setJsonEntity("{\"settings\":  {\"number_of_shards\": 1, \"number_of_replicas\": 3}}");
        assertOK(client().performRequest(createIndexRequest));
        
        assertUnassignedShard(nodeIdToShutdown, indexName);
        
        
        Request allocationExplainRequest = new Request("GET", "_cluster/allocation/explain");
        allocationExplainRequest.setJsonEntity("{\"index\": \"" + indexName + "\", \"shard\":  0, \"primary\":  false}");
        Map<String, Object> allocationExplainMap = entityAsMap(client().performRequest(allocationExplainRequest));
        List<Map<String, Object>> decisions = (List<Map<String, Object>>) allocationExplainMap.get("node_allocation_decisions");
        assertThat(decisions, notNullValue());
        Optional<Map<String, Object>> maybeDecision = decisions.stream()
            .filter(decision -> nodeIdToShutdown.equals(decision.get("node_id")))
            .findFirst();
        assertThat("expected decisions for node, but not found", maybeDecision.isPresent(), is(true));
        Map<String, Object> decision = maybeDecision.get();
        assertThat("node should have deciders", decision.containsKey("deciders"), is(true));
        List<Map<String, Object>> deciders = (List<Map<String, Object>>) decision.get("deciders");
        assertThat(
            "the node_shutdown allocation decider should have decided NO",
            deciders.stream()