Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions cmd/cli/commands/install-runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,15 @@ func ensureStandaloneRunnerAvailable(ctx context.Context, printer standalone.Sta

// Create the model runner container.
port := uint16(standalone.DefaultControllerPortMoby)
// For auto-installation, always bind to localhost for security.
// Users can run install-runner explicitly with --host to change this.
host := "127.0.0.1"
environment := "moby"
if engineKind == types.ModelRunnerEngineKindCloud {
port = standalone.DefaultControllerPortCloud
environment = "cloud"
}
if err := standalone.CreateControllerContainer(ctx, dockerClient, port, environment, false, gpu, modelStorageVolume, printer, engineKind); err != nil {
if err := standalone.CreateControllerContainer(ctx, dockerClient, port, host, environment, false, gpu, modelStorageVolume, printer, engineKind); err != nil {
return nil, fmt.Errorf("unable to initialize standalone model runner container: %w", err)
}

Expand All @@ -159,6 +162,7 @@ func ensureStandaloneRunnerAvailable(ctx context.Context, printer standalone.Sta

func newInstallRunner() *cobra.Command {
var port uint16
var host string
var gpuMode string
var doNotTrack bool
c := &cobra.Command{
Expand Down Expand Up @@ -245,7 +249,7 @@ func newInstallRunner() *cobra.Command {
return fmt.Errorf("unable to initialize standalone model storage: %w", err)
}
// Create the model runner container.
if err := standalone.CreateControllerContainer(cmd.Context(), dockerClient, port, environment, doNotTrack, gpu, modelStorageVolume, cmd, engineKind); err != nil {
if err := standalone.CreateControllerContainer(cmd.Context(), dockerClient, port, host, environment, doNotTrack, gpu, modelStorageVolume, cmd, engineKind); err != nil {
return fmt.Errorf("unable to initialize standalone model runner container: %w", err)
}

Expand All @@ -256,6 +260,7 @@ func newInstallRunner() *cobra.Command {
}
c.Flags().Uint16Var(&port, "port", 0,
"Docker container port for Docker Model Runner (default: 12434 for Docker CE, 12435 for Cloud mode)")
c.Flags().StringVar(&host, "host", "127.0.0.1", "Host address to bind Docker Model Runner")
c.Flags().StringVar(&gpuMode, "gpu", "auto", "Specify GPU support (none|auto|cuda)")
c.Flags().BoolVar(&doNotTrack, "do-not-track", false, "Do not track models usage in Docker Model Runner")
return c
Expand Down
96 changes: 96 additions & 0 deletions cmd/cli/commands/install-runner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package commands

import (
"testing"
)

func TestInstallRunnerHostFlag(t *testing.T) {
// Create the install-runner command
cmd := newInstallRunner()

// Verify the --host flag exists
hostFlag := cmd.Flags().Lookup("host")
if hostFlag == nil {
t.Fatal("--host flag not found")
}

// Verify the default value
if hostFlag.DefValue != "127.0.0.1" {
t.Errorf("Expected default host value to be '127.0.0.1', got '%s'", hostFlag.DefValue)
}

// Verify the flag type
if hostFlag.Value.Type() != "string" {
t.Errorf("Expected host flag type to be 'string', got '%s'", hostFlag.Value.Type())
}

// Test setting the flag value
testCases := []struct {
name string
value string
}{
{"localhost", "127.0.0.1"},
{"all interfaces", "0.0.0.0"},
{"specific IP", "192.168.1.100"},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Reset the command for each test
cmd := newInstallRunner()
err := cmd.Flags().Set("host", tc.value)
if err != nil {
t.Errorf("Failed to set host flag to '%s': %v", tc.value, err)
}

// Verify the value was set
hostValue, err := cmd.Flags().GetString("host")
if err != nil {
t.Errorf("Failed to get host flag value: %v", err)
}
if hostValue != tc.value {
t.Errorf("Expected host value to be '%s', got '%s'", tc.value, hostValue)
}
})
}
}

func TestInstallRunnerCommandFlags(t *testing.T) {
cmd := newInstallRunner()

// Verify all expected flags exist
expectedFlags := []string{"port", "host", "gpu", "do-not-track"}
for _, flagName := range expectedFlags {
if cmd.Flags().Lookup(flagName) == nil {
t.Errorf("Expected flag '--%s' not found", flagName)
}
}
}

func TestInstallRunnerCommandType(t *testing.T) {
cmd := newInstallRunner()

// Verify command properties
if cmd.Use != "install-runner" {
t.Errorf("Expected command Use to be 'install-runner', got '%s'", cmd.Use)
}

if cmd.Short != "Install Docker Model Runner (Docker Engine only)" {
t.Errorf("Unexpected command Short description: %s", cmd.Short)
}

// Verify RunE is set
if cmd.RunE == nil {
t.Error("Expected RunE to be set")
}
}

func TestInstallRunnerValidArgsFunction(t *testing.T) {
cmd := newInstallRunner()

// The install-runner command should not accept any arguments
// So ValidArgsFunction should be set to handle no arguments
if cmd.ValidArgsFunction == nil {
t.Error("Expected ValidArgsFunction to be set")
}
}
11 changes: 6 additions & 5 deletions cmd/cli/docs/reference/model_install-runner.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ Install Docker Model Runner (Docker Engine only)

### Options

| Name | Type | Default | Description |
|:-----------------|:---------|:--------|:---------------------------------------------------------------------------------------------------|
| `--do-not-track` | `bool` | | Do not track models usage in Docker Model Runner |
| `--gpu` | `string` | `auto` | Specify GPU support (none\|auto\|cuda) |
| `--port` | `uint16` | `0` | Docker container port for Docker Model Runner (default: 12434 for Docker CE, 12435 for Cloud mode) |
| Name | Type | Default | Description |
|:-----------------|:---------|:------------|:---------------------------------------------------------------------------------------------------|
| `--do-not-track` | `bool` | | Do not track models usage in Docker Model Runner |
| `--gpu` | `string` | `auto` | Specify GPU support (none\|auto\|cuda) |
| `--host` | `string` | `127.0.0.1` | Host address to bind Docker Model Runner |
| `--port` | `uint16` | `0` | Docker container port for Docker Model Runner (default: 12434 for Docker CE, 12435 for Cloud mode) |


<!---MARKER_GEN_END-->
Expand Down
11 changes: 7 additions & 4 deletions cmd/cli/pkg/standalone/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ func ensureContainerStarted(ctx context.Context, dockerClient client.ContainerAP
}

// CreateControllerContainer creates and starts a controller container.
func CreateControllerContainer(ctx context.Context, dockerClient *client.Client, port uint16, environment string, doNotTrack bool, gpu gpupkg.GPUSupport, modelStorageVolume string, printer StatusPrinter, engineKind types.ModelRunnerEngineKind) error {
func CreateControllerContainer(ctx context.Context, dockerClient *client.Client, port uint16, host string, environment string, doNotTrack bool, gpu gpupkg.GPUSupport, modelStorageVolume string, printer StatusPrinter, engineKind types.ModelRunnerEngineKind) error {
// Determine the target image.
var imageName string
switch gpu {
Expand Down Expand Up @@ -260,11 +260,14 @@ func CreateControllerContainer(ctx context.Context, dockerClient *client.Client,
Name: "always",
},
}
portBindings := []nat.PortBinding{{HostIP: "127.0.0.1", HostPort: portStr}}
portBindings := []nat.PortBinding{{HostIP: host, HostPort: portStr}}
if os.Getenv("_MODEL_RUNNER_TREAT_DESKTOP_AS_MOBY") != "1" {
// Don't bind the bridge gateway IP if we're treating Docker Desktop as Moby.
if bridgeGatewayIP, err := determineBridgeGatewayIP(ctx, dockerClient); err == nil && bridgeGatewayIP != "" {
portBindings = append(portBindings, nat.PortBinding{HostIP: bridgeGatewayIP, HostPort: portStr})
// Only add bridge gateway IP binding if host is 127.0.0.1
if host == "127.0.0.1" {
if bridgeGatewayIP, err := determineBridgeGatewayIP(ctx, dockerClient); err == nil && bridgeGatewayIP != "" {
portBindings = append(portBindings, nat.PortBinding{HostIP: bridgeGatewayIP, HostPort: portStr})
}
}
}
hostConfig.PortBindings = nat.PortMap{
Expand Down
Loading