This repository was archived by the owner on Oct 6, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
Add install-runner and uninstall-runner to manage Docker Model Runner #48
Merged
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
c50ddf1
Add `docker model install-runner`
doringeman 74ed2ed
Add `docker model uninstall-runner`
doringeman e8537b9
commands: rename install-runner.go for consistency
xenoscopic cf09faf
install: restrict platforms on which installation is supported
xenoscopic 5c2ebfc
install: use CLI to construct Docker API client
xenoscopic b5f5037
install: make non-GPU install the default
xenoscopic 06b6444
install: switch to JSONMessage type for status updates
xenoscopic 9ab08aa
install: use strong typing for port argument
xenoscopic a3884dd
install: switch to final image name / tags
xenoscopic da2a0ac
install: extract common definitions and fix image names
xenoscopic d2b3074
install: refactor and extract install code into standalone package
xenoscopic fbe96b7
install: auto-invoke install-runner when required
xenoscopic 288bdc4
compose: enable support for standalone installs
xenoscopic 99dc177
all: rename DMR_HOST to MODEL_RUNNER_HOST
xenoscopic 4f6be97
nit: avoid Printf whenever possible
xenoscopic fd935cc
nit: wrap errors
xenoscopic 6895c5e
uninstall: simplify image removal error handling
xenoscopic 4199c7f
compose: fix support for new context awareness
xenoscopic de7a6af
compose: fix formatting verb
xenoscopic b8b852e
Update commands/uninstall-runner.go
xenoscopic 59cbdd5
uninstall: use image name constants and clarify uninstall behavior
xenoscopic File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| package commands | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "os" | ||
| "time" | ||
|
|
||
| "github.com/docker/model-cli/commands/completion" | ||
| "github.com/docker/model-cli/desktop" | ||
| "github.com/docker/model-cli/pkg/standalone" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| type noopPrinter struct{} | ||
|
|
||
| func (*noopPrinter) Printf(format string, args ...any) {} | ||
|
|
||
| func (*noopPrinter) Println(args ...any) {} | ||
|
|
||
| // ensureStandaloneRunnerAvailable is a utility function that other commands can | ||
| // use to initialize a default standalone model runner. It is a no-op in | ||
| // unsupported contexts or if automatic installs have been disabled. | ||
| func ensureStandaloneRunnerAvailable(ctx context.Context, printer standalone.StatusPrinter) error { | ||
| // If we're not in a supported model runner context, then don't do anything. | ||
| if modelRunner.EngineKind() != desktop.ModelRunnerEngineKindMoby { | ||
| return nil | ||
| } | ||
|
|
||
| // If automatic installation has been disabled, then don't do anything. | ||
| if os.Getenv("MODEL_RUNNER_NO_AUTO_INSTALL") != "" { | ||
| return nil | ||
| } | ||
|
|
||
| // Ensure that the output printer is non-nil. | ||
| if printer == nil { | ||
| printer = &noopPrinter{} | ||
| } | ||
|
|
||
| // Create a Docker client for the active context. | ||
| dockerClient, err := desktop.DockerClientForContext(dockerCLI, dockerCLI.CurrentContext()) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to create Docker client: %w", err) | ||
| } | ||
|
|
||
| // Check if a model runner container exists. | ||
| container, _, err := standalone.FindControllerContainer(ctx, dockerClient) | ||
| if err != nil { | ||
| return fmt.Errorf("unable to identify existing standalone model runner: %w", err) | ||
| } else if container != "" { | ||
| return nil | ||
| } | ||
|
|
||
| // Ensure that we have an up-to-date copy of the image. | ||
| if err := standalone.EnsureControllerImage(ctx, dockerClient, false, printer); err != nil { | ||
| return fmt.Errorf("unable to pull latest standalone model runner image: %w", err) | ||
| } | ||
|
|
||
| // Ensure that we have a model storage volume. | ||
| modelStorageVolume, err := standalone.EnsureModelStorageVolume(ctx, dockerClient, printer) | ||
| if err != nil { | ||
| return fmt.Errorf("unable to initialize standalone model storage: %w", err) | ||
| } | ||
|
|
||
| // Create the model runner container. | ||
| if err := standalone.CreateControllerContainer(ctx, dockerClient, standalone.DefaultControllerPort, false, modelStorageVolume, printer); err != nil { | ||
| return fmt.Errorf("unable to initialize standalone model runner container: %w", err) | ||
| } | ||
|
|
||
| // Give the model runner one second to start. | ||
| time.Sleep(1 * time.Second) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func newInstallRunner() *cobra.Command { | ||
| var port uint16 | ||
| var gpu bool | ||
| c := &cobra.Command{ | ||
| Use: "install-runner", | ||
| Short: "Install Docker Model Runner", | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| // Ensure that we're running in a supported model runner context. | ||
| if kind := modelRunner.EngineKind(); kind == desktop.ModelRunnerEngineKindDesktop { | ||
| // TODO: We may eventually want to auto-forward this to | ||
| // docker desktop enable model-runner, but we should first make | ||
| // sure the CLI flags match. | ||
| cmd.Println("Standalone installation not supported with Docker Desktop") | ||
| cmd.Println("Use `docker desktop enable model-runner` instead") | ||
| return nil | ||
| } else if kind == desktop.ModelRunnerEngineKindMobyManual { | ||
| cmd.Println("Standalone installation not supported with MODEL_RUNNER_HOST set") | ||
| return nil | ||
| } else if kind == desktop.ModelRunnerEngineKindCloud { | ||
| cmd.Println("Standalone installation not required with Docker Cloud") | ||
| return nil | ||
| } | ||
|
|
||
| // Create a Docker client for the active context. | ||
| dockerClient, err := desktop.DockerClientForContext(dockerCLI, dockerCLI.CurrentContext()) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to create Docker client: %w", err) | ||
| } | ||
|
|
||
| // Check if an active model runner container already exists. | ||
| if ctrID, ctrName, err := standalone.FindControllerContainer(cmd.Context(), dockerClient); err != nil { | ||
| return err | ||
| } else if ctrID != "" { | ||
| if ctrName != "" { | ||
| cmd.Printf("Model Runner container %s (%s) is already running\n", ctrName, ctrID[:12]) | ||
| } else { | ||
| cmd.Printf("Model Runner container %s is already running\n", ctrID[:12]) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // Ensure that we have an up-to-date copy of the image. | ||
| if err := standalone.EnsureControllerImage(cmd.Context(), dockerClient, gpu, cmd); err != nil { | ||
| return fmt.Errorf("unable to pull latest standalone model runner image: %w", err) | ||
| } | ||
|
|
||
| // Ensure that we have a model storage volume. | ||
| modelStorageVolume, err := standalone.EnsureModelStorageVolume(cmd.Context(), dockerClient, cmd) | ||
| if err != nil { | ||
| return fmt.Errorf("unable to initialize standalone model storage: %w", err) | ||
| } | ||
|
|
||
| // Create the model runner container. | ||
| if err := standalone.CreateControllerContainer(cmd.Context(), dockerClient, port, gpu, modelStorageVolume, cmd); err != nil { | ||
| return fmt.Errorf("unable to initialize standalone model runner container: %w", err) | ||
| } | ||
|
|
||
| return nil | ||
| }, | ||
| ValidArgsFunction: completion.NoComplete, | ||
| } | ||
| c.Flags().Uint16Var(&port, "port", standalone.DefaultControllerPort, | ||
| "Docker container port for Docker Model Runner") | ||
| c.Flags().BoolVar(&gpu, "gpu", false, "Enable GPU support") | ||
| return c | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| package commands | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/docker/model-cli/commands/completion" | ||
| "github.com/docker/model-cli/desktop" | ||
| "github.com/docker/model-cli/pkg/standalone" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| func newUninstallRunner() *cobra.Command { | ||
| var models, images bool | ||
| c := &cobra.Command{ | ||
| Use: "uninstall-runner", | ||
| Short: "Uninstall Docker Model Runner", | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| // Ensure that we're running in a supported model runner context. | ||
| if kind := modelRunner.EngineKind(); kind == desktop.ModelRunnerEngineKindDesktop { | ||
| // TODO: We may eventually want to auto-forward this to | ||
| // docker desktop disable model-runner, but we should first | ||
| // make install-runner forward in the same way. | ||
| cmd.Println("Standalone uninstallation not supported with Docker Desktop") | ||
| cmd.Println("Use `docker desktop disable model-runner` instead") | ||
| return nil | ||
| } else if kind == desktop.ModelRunnerEngineKindMobyManual { | ||
| cmd.Println("Standalone uninstallation not supported with MODEL_RUNNER_HOST set") | ||
| return nil | ||
| } else if kind == desktop.ModelRunnerEngineKindCloud { | ||
| cmd.Println("Standalone uninstallation not supported with Docker Cloud") | ||
| return nil | ||
| } | ||
|
|
||
| // Create a Docker client for the active context. | ||
| dockerClient, err := desktop.DockerClientForContext(dockerCLI, dockerCLI.CurrentContext()) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to create Docker client: %w", err) | ||
| } | ||
|
|
||
| // Remove any model runner containers. | ||
| if err := standalone.PruneControllerContainers(cmd.Context(), dockerClient, cmd); err != nil { | ||
| return fmt.Errorf("unable to remove model runner container(s): %w", err) | ||
| } | ||
|
|
||
| // Remove model runner images, if requested. | ||
| if images { | ||
| if err := standalone.PruneControllerImages(cmd.Context(), dockerClient, cmd); err != nil { | ||
| return fmt.Errorf("unable to remove model runner image(s): %w", err) | ||
| } | ||
| } | ||
|
|
||
| // Remove model storage, if requested. | ||
| if models { | ||
| if err := standalone.PruneModelStorageVolumes(cmd.Context(), dockerClient, cmd); err != nil { | ||
| return fmt.Errorf("unable to remove model storage volume(s): %w", err) | ||
| } | ||
| } | ||
|
|
||
| return nil | ||
| }, | ||
| ValidArgsFunction: completion.NoComplete, | ||
| } | ||
| c.Flags().BoolVar(&models, "models", false, "Remove model storage volume") | ||
| c.Flags().BoolVar(&images, "images", false, "Remove "+standalone.ControllerImage+" images") | ||
| return c | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @glours and @ndeloof - we're trying to figure out the best way to make the DMR + Compose integration work with the standalone Docker Model Runner containers that we're now supporting on Docker CE. Since Compose projects don't attach their service containers to the host bridge network by default, using the
172.17.0.1address doesn't work. I'm trying to figure out a more elegant solution without requiring users to change their Compose YAML. Do you have any ideas about a good convention that we could use here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The best idea I have at the moment is just to default to
http://host.docker.internal:12434/engines/v1/and require ahost.docker.internal:host-gatewaymapping for every container needing the standalone model runner.