fake-autoscaler.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. .. _fake-multinode:
  2. Testing Autoscaling Locally
  3. ===========================
  4. Testing autoscaling behavior is important for autoscaler development and the debugging of applications that depend
  5. on autoscaler behavior. You can run the autoscaler locally without needing to launch a real cluster with one of the
  6. following methods:
  7. Using ``RAY_FAKE_CLUSTER=1 ray start``
  8. --------------------------------------
  9. Instructions:
  10. 1. Navigate to the root directory of the Ray repo you have cloned locally.
  11. 2. Locate the `fake_multi_node/example.yaml <https://github.com/ray-project/ray/blob/master/python/ray/autoscaler/_private/fake_multi_node/example.yaml>`__ example file and fill in the number of CPUs and GPUs the local machine has for the head node type config. The YAML follows the same format as cluster autoscaler configurations, but some fields are not supported.
  12. 3. Configure worker types and other autoscaling configs as desired in the YAML file.
  13. 4. Start the fake cluster locally:
  14. .. code-block:: shell
  15. $ ray stop --force
  16. $ RAY_FAKE_CLUSTER=1 ray start \
  17. --autoscaling-config=./python/ray/autoscaler/_private/fake_multi_node/example.yaml \
  18. --head --block
  19. 5. Connect your application to the fake local cluster with ``ray.init("auto")``.
  20. 6. Run ``ray status`` to view the status of your cluster, or ``cat /tmp/ray/session_latest/logs/monitor.*`` to view the autoscaler monitor log:
  21. .. code-block:: shell
  22. $ ray status
  23. ======== Autoscaler status: 2021-10-12 13:10:21.035674 ========
  24. Node status
  25. ---------------------------------------------------------------
  26. Healthy:
  27. 1 ray.head.default
  28. 2 ray.worker.cpu
  29. Pending:
  30. (no pending nodes)
  31. Recent failures:
  32. (no failures)
  33. Resources
  34. ---------------------------------------------------------------
  35. Usage:
  36. 0.0/10.0 CPU
  37. 0.00/70.437 GiB memory
  38. 0.00/10.306 GiB object_store_memory
  39. Demands:
  40. (no resource demands)
  41. Using ``ray.cluster_utils.AutoscalingCluster``
  42. ----------------------------------------------
  43. To programmatically create a fake multi-node autoscaling cluster and connect to it, you can use `cluster_utils.AutoscalingCluster <https://github.com/ray-project/ray/blob/master/python/ray/cluster_utils.py>`__. Here's an example of a basic autoscaling test that launches tasks triggering autoscaling:
  44. .. literalinclude:: /../../python/ray/tests/test_autoscaler_fake_multinode.py
  45. :language: python
  46. :dedent: 4
  47. :start-after: __example_begin__
  48. :end-before: __example_end__
  49. Python documentation:
  50. .. autoclass:: ray.cluster_utils.AutoscalingCluster
  51. :members:
  52. Features and Limitations of ``fake_multinode``
  53. ----------------------------------------------
  54. Most of the features of the autoscaler are supported in fake multi-node mode. For example, if you update the contents of the YAML file, the autoscaler will pick up the new configuration and apply changes, as it does in a real cluster. Node selection, launch, and termination are governed by the same bin-packing and idle timeout algorithms as in a real cluster.
  55. However, there are a few limitations:
  56. 1. All node raylets run uncontainerized on the local machine, and hence they share the same IP address. See the :ref:`fake_multinode_docker <fake-multinode-docker>` section for an alternative local multi node setup.
  57. 2. Configurations for auth, setup, initialization, Ray start, file sync, and anything cloud-specific are not supported.
  58. 3. It's necessary to limit the number of nodes / node CPU / object store memory to avoid overloading your local machine.
  59. .. _fake-multinode-docker:
  60. Testing containerized multi nodes locally with Docker compose
  61. =============================================================
  62. To go one step further and locally test a multi node setup where each node uses its own container (and thus
  63. has a separate filesystem, IP address, and Ray processes), you can use the ``fake_multinode_docker`` node provider.
  64. The setup is very similar to the :ref:`fake_multinode <fake-multinode>` provider. However, you need to start a monitoring process
  65. (``docker_monitor.py``) that takes care of running the ``docker compose`` command.
  66. Prerequisites:
  67. 1. Make sure you have `docker <https://docs.docker.com/get-docker/>`_ installed.
  68. 2. Make sure you have the `docker compose V2 plugin <https://docs.docker.com/compose/cli-command/#installing-compose-v2>`_ installed.
  69. Using ``RAY_FAKE_CLUSTER=1 ray up``
  70. -----------------------------------
  71. Instructions:
  72. 1. Navigate to the root directory of the Ray repo you have cloned locally.
  73. 2. Locate the `fake_multi_node/example_docker.yaml <https://github.com/ray-project/ray/blob/master/python/ray/autoscaler/_private/fake_multi_node/example_docker.yaml>`__ example file and fill in the number of CPUs and GPUs the local machine has for the head node type config. The YAML follows the same format as cluster autoscaler configurations, but some fields are not supported.
  74. 3. Configure worker types and other autoscaling configs as desired in the YAML file.
  75. 4. Make sure the ``shared_volume_dir`` is empty on the host system
  76. 5. Start the monitoring process:
  77. .. code-block:: shell
  78. $ python ./python/ray/autoscaler/_private/fake_multi_node/docker_monitor.py \
  79. ./python/ray/autoscaler/_private/fake_multi_node/example_docker.yaml
  80. 6. Start the Ray cluster using ``ray up``:
  81. .. code-block:: shell
  82. $ RAY_FAKE_CLUSTER=1 ray up -y ./python/ray/autoscaler/_private/fake_multi_node/example_docker.yaml
  83. 7. Connect your application to the fake local cluster with ``ray.init("ray://localhost:10002")``.
  84. 8. Alternatively, get a shell on the head node:
  85. .. code-block:: shell
  86. $ docker exec -it fake_docker_fffffffffffffffffffffffffffffffffffffffffffffffffff00000_1 bash
  87. Using ``ray.autoscaler._private.fake_multi_node.test_utils.DockerCluster``
  88. --------------------------------------------------------------------------
  89. This utility is used to write tests that use multi node behavior. The ``DockerCluster`` class can
  90. be used to setup a Docker-compose cluster in a temporary directory, start the monitoring process,
  91. wait for the cluster to come up, connect to it, and update the configuration.
  92. Please see the API documentation and example test cases on how to use this utility.
  93. .. autoclass:: ray.autoscaler._private.fake_multi_node.test_utils.DockerCluster
  94. :members:
  95. Features and Limitations of ``fake_multinode_docker``
  96. -----------------------------------------------------
  97. The fake multinode docker node provider provides fully fledged nodes in their own containers. However,
  98. some limitations still remain:
  99. 1. Configurations for auth, setup, initialization, Ray start, file sync, and anything cloud-specific are not supported
  100. (but might be in the future).
  101. 2. It's necessary to limit the number of nodes / node CPU / object store memory to avoid overloading your local machine.
  102. 3. In docker-in-docker setups, a careful setup has to be followed to make the fake multinode docker provider work (see below).
  103. Shared directories within the docker environment
  104. ------------------------------------------------
  105. The containers will mount two locations to host storage:
  106. - ``/cluster/node``: This location (in the container) will point to ``cluster_dir/nodes/<node_id>`` (on the host).
  107. This location is individual per node, but it can be used so that the host can examine contents stored in this directory.
  108. - ``/cluster/shared``: This location (in the container) will point to ``cluster_dir/shared`` (on the host). This location
  109. is shared across nodes and effectively acts as a shared filesystem (comparable to NFS).
  110. Setting up in a Docker-in-Docker (dind) environment
  111. ---------------------------------------------------
  112. When setting up in a Docker-in-Docker (dind) environment (e.g. the Ray OSS Buildkite environment), some
  113. things have to be kept in mind. To make this clear, consider these concepts:
  114. * The **host** is the not-containerized machine on which the code is executed (e.g. Buildkite runner)
  115. * The **outer container** is the container running directly on the **host**. In the Ray OSS Buildkite environment,
  116. two containers are started - a *dind* network host and a container with the Ray source code and wheel in it.
  117. * The **inner container** is a container started by the fake multinode docker node provider.
  118. The control plane for the multinode docker node provider lives in the outer container. However, ``docker compose``
  119. commands are executed from the connected docker-in-docker network. In the Ray OSS Buildkite environment, this is
  120. the ``dind-daemon`` container running on the host docker. If you e.g. mounted ``/var/run/docker.sock`` from the
  121. host instead, it would be the host docker daemon. We will refer to both as the **host daemon** from now on.
  122. The outer container modifies files that have to be mounted in the inner containers (and modified from there
  123. as well). This means that the host daemon also has to have access to these files.
  124. Similarly, the inner containers expose ports - but because the containers are actually started by the host daemon,
  125. the ports are also only accessible on the host (or the dind container).
  126. For the Ray OSS Buildkite environment, we thus set some environment variables:
  127. * ``RAY_TEMPDIR="/ray-mount"``. This environment variable defines where the temporary directory for the
  128. cluster files should be created. This directory has to be accessible by the host, the outer container,
  129. and the inner container. In the inner container, we can control the directory name.
  130. * ``RAY_HOSTDIR="/ray"``. In the case where the shared directory has a different name on the host, we can
  131. rewrite the mount points dynamically. In this example, the outer container is started with ``-v /ray:/ray-mount``
  132. or similar, so the directory on the host is ``/ray`` and in the outer container ``/ray-mount`` (see ``RAY_TEMPDIR``).
  133. * ``RAY_TESTHOST="dind-daemon"`` As the containers are started by the host daemon, we can't just connect to
  134. ``localhost``, as the ports are not exposed to the outer container. Thus, we can set the Ray host with this environment
  135. variable.
  136. Lastly, docker-compose obviously requires a docker image. The default docker image is ``rayproject/ray:nightly``.
  137. The docker image requires ``openssh-server`` to be installed and enabled. In Buildkite we build a new image from
  138. ``rayproject/ray:nightly-py37-cpu`` to avoid installing this on the fly for every node (which is the default way).
  139. This base image is built in one of the previous build steps.
  140. Thus, we set
  141. * ``RAY_DOCKER_IMAGE="rayproject/ray:multinode-py37"``
  142. * ``RAY_HAS_SSH=1``
  143. to use this docker image and inform our multinode infrastructure that SSH is already installed.
  144. Local development
  145. -----------------
  146. If you're doing local development on the fake multi node docker module, you can set
  147. * ``FAKE_CLUSTER_DEV="auto"``
  148. this will mount the ``ray/python/ray/autoscaler`` directory to the started nodes. Please note that
  149. this is will probably not work in your docker-in-docker setup.
  150. If you want to to specify which top-level Ray directories to mount, you can use e.g.
  151. * ``FAKE_CLUSTER_DEV_MODULES="autoscaler,tune"``
  152. This will mount both ``ray/python/ray/autoscaler`` and ``ray/python/ray/tune`` within the node containers. The
  153. list of modules should be comma separated and without spaces.