packaged by Chainguard
Contact our team to test out this image for free. Please also indicate any other images you would like to evaluate.
Minimal Ray image for distributed Python and AI workloads, with the CLI, dashboard, and Ray Serve.
Chainguard Containers are regularly-updated, secure-by-default container images.
For those with access, this container image is available on cgr.dev:
Be sure to replace the ORGANIZATION placeholder with the name used for your organization's private repository within the Chainguard Registry.
This image is a drop-in replacement for the upstream rayproject/ray image for the CPU-only, Python 3.11 case. It keeps upstream's launch behavior: no entrypoint with CMD ["/bin/bash"], uid 1000 (ray, gid 100), work-dir and HOME of /home/ray, and Ray's Python environment first on PATH so bare ray and python resolve to it.
It differs from upstream in the following ways:
/home/ray/anaconda3, which accounts for most of that image. Here Ray lives in a virtual environment at /opt/chainguard/ray, which PATH points at. This matters for one Ray feature: runtime_env accepts pip, uv, and conda, and only conda is unavailable — it fails with Could not find Conda executable. Use pip or uv, both of which work, or point RAY_CONDA_HOME at a conda you supply yourself.-gpu/-cu12x tags have no equivalent here.-py3xx tag matrix, and its latest, 2.58.0, and 2.58.0-cpu tags are all the Python 3.10 build; 2.58.0-py311-cpu is a different digest. Ray compares Python versions down to the patch level by default, so a node or driver refuses to join a cluster started on any other Python build — including upstream's 2.58.0-py311-cpu — unless RAY_DEFAULT_PYTHON_VERSION_MATCH_LEVEL=minor is set. Do not mix this image with upstream's tags, and widen any cp310 wheel pins.sudo, git, gnupg, or standalone uv. Upstream's base layer leaves sudo (with a passwordless sudoers entry for ray), git, gnupg, and a uv binary in the image; none are here. cmake, zlib1g-dev, and g++ are installed upstream only to build psutil and are autoremoved again on the CPU image, so they are absent there too. The practical effect is that runtime_env pip requirements using git+https:// URLs fail at task setup. The -dev variant carries git, and Custom Assembly can add the rest. The autoscaler's own dependencies — rsync, openssh-client, tmux, and screen — are present, so the packages ray up, ray attach, ray exec, and ray rsync-up/rsync-down need are in place./opt/chainguard/ray is root-owned, so pip install as the default uid 1000 fails with EACCES. Upstream's conda tree is owned by its runtime user, so the same command succeeds there. In a derived build, switch to USER 0 for the install step, or install into a runtime_env instead. The environment is also installed with --no-compile and is unwritable at runtime, so __pycache__ is never populated and each process recompiles Ray's modules on import; upstream's conda tree ships .pyc files.Shell in the image config. Upstream sets Shell: ["/bin/bash", "-c"], which apko does not express. Shell-form RUN and CMD in a derived Dockerfile fall back to /bin/sh; use exec form, or set SHELL ["/bin/bash", "-c"] explicitly./home/ray is empty. Upstream ships requirements_compiled.txt and python_depset.lock there, which Ray's docs reference for constraining user installs to the base image's pins. Those files are not present; use pip freeze against /opt/chainguard/ray/bin/python if you need the equivalent.memray. Upstream installs it, and the dashboard's memory-profiling action shells out to it; here that action returns Failed to execute: memray is not installed. CPU profiling with py-spy is unaffected.None to run Ray locally. On Kubernetes, Ray is deployed by the KubeRay operator, which schedules this image as the head and worker containers of a RayCluster.
Start a single-node cluster and run a distributed task against it:
Ray's object store is backed by /dev/shm; Docker's 64MB default makes the head spill to disk, so --shm-size is worth setting. Once docker exec ray-head ray status reports a node, schedule work on it:
Submit a job through the dashboard's jobs API, which is also what ray job uses:
The dashboard is served on port 8265; with the -p above it is reachable at http://localhost:8265.
Install the KubeRay operator, then point the ray-cluster chart at this image:
KubeRay generates the ray start command itself and runs it through /bin/bash -c, and injects readiness and liveness probes that call the raylet and GCS healthz endpoints. Once the pods are ready, run work on the head:
Ray is configured mostly through ray start flags, with a smaller set of environment variables such as RAY_CONDA_HOME above. The defaults bind the dashboard to localhost, so exposing it to other containers or through a Kubernetes Service needs --dashboard-host=0.0.0.0, as in the examples above. --num-cpus is worth setting explicitly in a container: Ray reads the cgroup CPU quota and cpuset when one is set, but falls back to the host's CPU count for an unlimited container, which leads to oversubscription.
Ray Serve is included. Its ingress runs on Serve's own Python proxy by default; HAProxy is shipped too, for the opt-in RAY_SERVE_ENABLE_HA_PROXY=1 path.
Chainguard's free tier of Starter container images are built with Wolfi, our minimal Linux undistro.
All other Chainguard Containers are built with Chainguard OS, Chainguard's minimal Linux operating system designed to produce container images that meet the requirements of a more secure software supply chain.
The main features of Chainguard Containers include:
For cases where you need container images with shells and package managers to build or debug, most Chainguard Containers come paired with a development, or -dev, variant.
In all other cases, including Chainguard Containers tagged as :latest or with a specific version number, the container images include only an open-source application and its runtime dependencies. These minimal container images typically do not contain a shell or package manager.
Although the -dev container image variants have similar security features as their more minimal versions, they include additional software that is typically not necessary in production environments. We recommend using multi-stage builds to copy artifacts from the -dev variant into a more minimal production image.
To improve security, Chainguard Containers include only essential dependencies. Need more packages? Chainguard customers can use Custom Assembly to add packages, either through the Console, chainctl, or API.
To use Custom Assembly in the Chainguard Console: navigate to the image you'd like to customize in your Organization's list of images, and click on the Customize image button at the top of the page.
Refer to our Chainguard Containers documentation on Chainguard Academy. Chainguard also offers VMs and Libraries — contact us for access.
This software listing is packaged by Chainguard. The trademarks set forth in this offering are owned by their respective companies, and use of them does not imply any affiliation, sponsorship, or endorsement by such companies.
Chainguard's container images contain software packages that are direct or transitive dependencies. The following licenses were found in the "latest" tag of this image:
Apache-2.0
BSD-2-Clause
BSD-3-Clause
CC-PDDC
GCC-exception-3.1
GPL-2.0-only
GPL-2.0-or-later
For a complete list of licenses, please refer to this Image's SBOM.
Software license agreementChainguard Containers are SLSA Level 3 compliant with detailed metadata and documentation about how it was built. We generate build provenance and a Software Bill of Materials (SBOM) for each release, with complete visibility into the software supply chain.
SLSA compliance at ChainguardThis image helps reduce time and effort in establishing PCI DSS 4.0 compliance with low-to-no CVEs.
PCI DSS at Chainguard