Repository navigation
Conversation
The JobSet builder set spec.trainer.image on the node container of the trainer ancestor replicatedJob for every framework. Move it to EnforceMLPolicy, where each MLPolicy plugin sets the image on its trainer PodSet container, so a plugin can decide which containers run the TrainJob image. PlainML covers XGBoost, Flux and runtimes without an MLPolicy, as it does for env. No behaviour change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Matteo Bunino <48362942+matbun@users.noreply.github.com>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
The MPI plugin now also sets spec.trainer.image on the node container of the node replicatedJob, so the MPI processes run the same image as mpirun on the launcher. command and args still reach only the launcher, so the nodes keep running sshd. Other frameworks are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Matteo Bunino <48362942+matbun@users.noreply.github.com>
| // The TrainJob image runs mpirun on the launcher, the trainer step, and the MPI processes | ||
| // on the nodes, which must ship the same application and MPI versions as the launcher. | ||
| runtime.ApplyTrainerImage(info.FindContainerByPodSetAncestorContainerName(constants.AncestorTrainer, constants.Node), trainJob.Spec.Trainer) | ||
| runtime.ApplyTrainerImage(info.FindContainerByPodSetName(constants.Node, constants.Node), trainJob.Spec.Trainer) |
| // ApplyTrainerImage sets the image of the given trainer container from the TrainJob trainer. | ||
| // It is called by the MLPolicy plugins in EnforceMLPolicy, so each plugin decides which | ||
| // containers run the TrainJob image. | ||
| func ApplyTrainerImage(container *Container, jobTrainer *trainer.Trainer) { |
There was a problem hiding this comment.
| // ApplyTrainerImage sets the image of the given trainer container from the TrainJob trainer. | |
| // It is called by the MLPolicy plugins in EnforceMLPolicy, so each plugin decides which | |
| // containers run the TrainJob image. | |
| func ApplyTrainerImage(container *Container, jobTrainer *trainer.Trainer) { | |
| // SetContainerImageFromTrainer sets the container image from the TrainJob trainer image. | |
| // It is a no-op if the container is nil or the TrainJob trainer image is not set. | |
| func SetContainerImageFromTrainer(container *Container, jobTrainer *trainer.Trainer) { |
| return nil | ||
| } | ||
|
|
||
| // The TrainJob image runs mpirun on the launcher, the trainer step, and the MPI processes |
There was a problem hiding this comment.
Could you also update Flux plugin?
https://github.com/matbun/trainer/blob/9f331529afbeac8c36659c1207a37e655ae75e0a/pkg/runtime/framework/plugins/flux/flux.go
| Scheduler: &runtime.Scheduler{PodLabels: make(map[string]string)}, | ||
| }, | ||
| }, | ||
| "trainJob trainer image is set on the trainer container of XGBoost runtimes": { |
There was a problem hiding this comment.
This should go to XGBoost plugin, right?
There was a problem hiding this comment.
yes, removed it from the PlainML tests. The XGBoost tests already cover it: XGBoost training with GPU resources, resources set in TrainJob only and resources set in both Runtime and TrainJob now expect the TrainJob image on the trainer container
| } | ||
| } | ||
|
|
||
| func TestMPITrainerImage(t *testing.T) { |
There was a problem hiding this comment.
Rather than adding another test func, let's just add image in this test: https://github.com/matbun/trainer/blob/9f331529afbeac8c36659c1207a37e655ae75e0a/pkg/runtime/framework/plugins/mpi/mpi_test.go#L89
There was a problem hiding this comment.
Done, removed TestMPITrainerImage and moved the image into TestMPI.
Rename ApplyTrainerImage to SetContainerImageFromTrainer, and set the TrainJob image on the trainer container in the Flux and XGBoost plugins too, instead of relying on the PlainML fallback. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Matteo Bunino <48362942+matbun@users.noreply.github.com>
| // The TrainJob image runs mpirun on the launcher, the trainer step, and the MPI processes | ||
| // on the nodes, which must ship the same application and MPI versions as the launcher. | ||
| runtime.SetContainerImageFromTrainer(info.FindContainerByPodSetAncestorContainerName(constants.AncestorTrainer, constants.Node), trainJob.Spec.Trainer) | ||
| runtime.SetContainerImageFromTrainer(info.FindContainerByPodSetName(constants.Node, constants.Node), trainJob.Spec.Trainer) |
There was a problem hiding this comment.
Look up both PodSets by name, consistent with the rest of the MPI plugin (e.g. the volumes loop below):
| // The TrainJob image runs mpirun on the launcher, the trainer step, and the MPI processes | |
| // on the nodes, which must ship the same application and MPI versions as the launcher. | |
| runtime.SetContainerImageFromTrainer(info.FindContainerByPodSetAncestorContainerName(constants.AncestorTrainer, constants.Node), trainJob.Spec.Trainer) | |
| runtime.SetContainerImageFromTrainer(info.FindContainerByPodSetName(constants.Node, constants.Node), trainJob.Spec.Trainer) | |
| // Set the TrainJob image on the launcher and the nodes, since mpirun on the launcher starts | |
| // the MPI processes on the nodes, which must ship the same application and MPI versions. | |
| for _, psName := range []string{constants.Launcher, constants.Node} { | |
| runtime.SetContainerImageFromTrainer(info.FindContainerByPodSetName(psName, constants.Node), trainJob.Spec.Trainer) | |
| } |
| // The TrainJob image runs mpirun on the launcher, the trainer step, and the MPI processes | ||
| // on the nodes, which must ship the same application and MPI versions as the launcher. | ||
| runtime.SetContainerImageFromTrainer(info.FindContainerByPodSetAncestorContainerName(constants.AncestorTrainer, constants.Node), trainJob.Spec.Trainer) | ||
| runtime.SetContainerImageFromTrainer(info.FindContainerByPodSetName(constants.Node, constants.Node), trainJob.Spec.Trainer) |
There was a problem hiding this comment.
Test follow-ups for the node image:
- When moving the cases into
TestMPI, please also cover therunLauncherAsNode: truelayout. - In the "MPI launcher runs as a node" integration test (
test/integration/controller/trainjob_controller_test.go~L1334), addg.Expect(podSpec.Containers[cIdx].Image).Should(gomega.Equal("test:trainjob"))to verify the node image end to end.
There was a problem hiding this comment.
Done: TestMPI now checks the image on the launcher and the nodes in both the default layout (trainJob numNodes is respected rather than mlPolicy one) and runLauncherAsNode is true, and the launcher as a node integration test asserts the node image.
| Containers: []runtime.Container{{ | ||
| Name: constants.Node, | ||
| Name: constants.Node, | ||
| Image: "test:image", |
There was a problem hiding this comment.
These runtime containers have no image, so the tests only cover filling an empty image, not replacing one. Please set .WithImage("test:runtime") on the runtime container in at least one case (e.g. L420 here and jax_test.go L422). Similarly, the JAX/XGBoost/OpenMPI/Flux integration fixtures (trainjob_controller_test.go L1998, L2321, L1387, L2664) use test:trainjob for the runtime image too, so they can't detect a missing override.
There was a problem hiding this comment.
the runtime containers now use test:runtime in that Torch case, the JAX case, both MPI cases, and the JAX, XGBoost, OpenMPI and Flux integration fixtures, so the tests check that the TrainJob image replaces the runtime one
Signed-off-by: Matteo Bunino <48362942+matbun@users.noreply.github.com>
Co-authored-by: Andrey Velichkevich <andrey.velichkevich@gmail.com> Signed-off-by: Matteo Bunino <48362942+matbun@users.noreply.github.com>
Co-authored-by: Andrey Velichkevich <andrey.velichkevich@gmail.com> Signed-off-by: Matteo Bunino <48362942+matbun@users.noreply.github.com>
Co-authored-by: Andrey Velichkevich <andrey.velichkevich@gmail.com> Signed-off-by: Matteo Bunino <48362942+matbun@users.noreply.github.com>
Set the TrainJob image on the MPI launcher and nodes in one loop, as suggested in the review. Cover the image in both the default and the runLauncherAsNode layouts in TestMPI, give the runtime containers their own image in the Torch, JAX and MPI tests and in the JAX, XGBoost, OpenMPI and Flux integration fixtures, so the tests check that the TrainJob image replaces it, and assert the node image in the MPI launcher as a node integration test. Co-authored-by: Andrey Velichkevich <andrey.velichkevich@gmail.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Matteo Bunino <48362942+matbun@users.noreply.github.com>
…gins Give the runtime trainer container its own image in the XGBoost and Flux tests, so they check that the TrainJob image replaces it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Matteo Bunino <48362942+matbun@users.noreply.github.com>
andreyvelich
left a comment
There was a problem hiding this comment.
Thanks for this @matbun!
/lgtm
/assign @tenzen-y @robert-bell @akshaychitneni @abhijeet-dhumal
|
/retitle fix(framework): BREAKING CHANGE: Set the TrainJob image on the MPI launcher and nodes |
What this PR does / why we need it:
Follow up of the discussion in #4050. The JobSet builder set
spec.trainer.imageon thenodecontainer of the replicatedJob with the trainer ancestor label, the same container for every framework. This PR moves it toEnforceMLPolicy: each MLPolicy plugin sets the image on its trainer containers withSetContainerImageFromTrainer, and the JobSet plugin syncs it into the JobSet like the other PodSet fields.Torch, JAX, XGBoost, Flux and runtimes without an MLPolicy keep their current behaviour. The MPI plugin now sets the image on both the launcher and the nodes, so all MPI processes run the same application and MPI versions, while
commandandargsstill reach only the launcher and the nodes keep running the SSH server. MPI runtimes whose nodes used a different image than the TrainJob now run the TrainJob image on the nodes too, so the migration guide is updated. This supersedes #4050.Tested with the unit tests and with the controller and webhook integration tests.
Which issue(s) this PR fixes (optional, in
Fixes #<issue number>, #<issue number>, ...format, will close the issue(s) when PR gets merged):Fixes #4030
Checklist: