Skip to content
Open
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
1 change: 1 addition & 0 deletions cmd/cli/commands/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func newUpCommand() *cobra.Command {
return errors.New("unable to determine standalone runner endpoint")
}

syncDockerConfigForRegistry(cmd.Context(), asPrinter(cmd))
if err := downloadModelsOnlyIfNotFound(desktopClient, models); err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions cmd/cli/commands/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func newPullCmd() *cobra.Command {

func pullModel(cmd *cobra.Command, desktopClient *desktop.Client, model string) error {
printer := asPrinter(cmd)
syncDockerConfigForRegistry(cmd.Context(), printer)
response, _, err := desktopClient.Pull(model, printer)

if err != nil {
Expand Down
1 change: 1 addition & 0 deletions cmd/cli/commands/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func newPushCmd() *cobra.Command {

func pushModel(cmd *cobra.Command, desktopClient *desktop.Client, model string) error {
printer := asPrinter(cmd)
syncDockerConfigForRegistry(cmd.Context(), printer)
response, _, err := desktopClient.Push(model, printer)

if err != nil {
Expand Down
33 changes: 33 additions & 0 deletions cmd/cli/commands/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package commands

import (
"bytes"
"context"
"errors"
"fmt"
"io"
Expand All @@ -10,6 +11,7 @@ import (

"github.com/docker/model-runner/cmd/cli/desktop"
"github.com/docker/model-runner/cmd/cli/pkg/standalone"
"github.com/docker/model-runner/cmd/cli/pkg/types"
"github.com/docker/model-runner/pkg/distribution/distribution"
"github.com/docker/model-runner/pkg/distribution/oci/reference"
"github.com/docker/model-runner/pkg/inference/backends/vllm"
Expand Down Expand Up @@ -247,6 +249,37 @@ func addRunnerFlags(cmd *cobra.Command, opts runnerFlagOptions) {
}
}

// syncDockerConfigForRegistry copies the host's Docker config into the running
// container. Only applicable for Moby engine setups; a no-op otherwise.
func syncDockerConfigForRegistry(ctx context.Context, printer standalone.StatusPrinter) {
if modelRunner == nil {
return
}
engineKind := modelRunner.EngineKind()
if engineKind != types.ModelRunnerEngineKindMoby {
return
}
dockerClient, err := desktop.DockerClientForContext(dockerCLI, dockerCLI.CurrentContext())
Comment thread
areebahmeddd marked this conversation as resolved.
if err != nil {
printer.Printf("Warning: failed to create Docker client for credential sync: %v\n", err)
return
}
defer dockerClient.Close()

containerID, _, _, err := standalone.FindControllerContainer(ctx, dockerClient)
if err != nil {
printer.Printf("Warning: failed to find model runner container for credential sync: %v\n", err)
return
}
if containerID == "" {
return
}

if err := standalone.SyncDockerConfigToContainer(ctx, dockerClient, containerID, engineKind); err != nil {
printer.Printf("Warning: failed to sync Docker credentials to runner: %v\n", err)
}
}

// newTable creates a new table with Docker CLI-style formatting:
// no borders, no column separators, no header line, left-aligned, and 2-space padding.
func newTable(w io.Writer) *tablewriter.Table {
Expand Down
19 changes: 13 additions & 6 deletions cmd/cli/pkg/standalone/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,24 @@ import (
// controllerContainerName is the name to use for the controller container.
const controllerContainerName = "docker-model-runner"

// copyDockerConfigToContainer copies the Docker config file from the host to the container
// and sets up proper ownership and permissions for the modelrunner user.
// It does nothing for Desktop and Cloud engine kinds.
func copyDockerConfigToContainer(ctx context.Context, dockerClient *client.Client, containerID string, engineKind types.ModelRunnerEngineKind) error {
// SyncDockerConfigToContainer copies the host's ~/.docker/config.json into the
// running container. It is a no-op for Desktop and Cloud engine kinds.
func SyncDockerConfigToContainer(ctx context.Context, dockerClient *client.Client, containerID string, engineKind types.ModelRunnerEngineKind) error {
Comment thread
areebahmeddd marked this conversation as resolved.
Comment thread
areebahmeddd marked this conversation as resolved.
// Do nothing for Desktop and Cloud engine kinds
if engineKind == types.ModelRunnerEngineKindDesktop || engineKind == types.ModelRunnerEngineKindCloud ||
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
os.Getenv("_MODEL_RUNNER_TREAT_DESKTOP_AS_MOBY") == "1" {
return nil
}

dockerConfigPath := os.ExpandEnv("$HOME/.docker/config.json")
dockerConfigDir := os.Getenv("DOCKER_CONFIG")
if dockerConfigDir == "" {
homeDir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("failed to get home directory: %w", err)
}
dockerConfigDir = filepath.Join(homeDir, ".docker")
}
dockerConfigPath := filepath.Join(dockerConfigDir, "config.json")
if s, err := os.Stat(dockerConfigPath); err != nil || s.Mode()&os.ModeType != 0 {
return nil
}
Expand Down Expand Up @@ -622,7 +629,7 @@ func CreateControllerContainer(ctx context.Context, dockerClient *client.Client,

// Copy Docker config file if it exists and we're the container creator.
if created && !vllmOnWSL {
if err := copyDockerConfigToContainer(ctx, dockerClient, resp.ID, engineKind); err != nil {
if err := SyncDockerConfigToContainer(ctx, dockerClient, resp.ID, engineKind); err != nil {
// Log warning but continue - don't fail container creation
printer.Printf("Warning: failed to copy Docker config: %v\n", err)
}
Expand Down
34 changes: 34 additions & 0 deletions cmd/cli/pkg/standalone/containers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package standalone

import (
"testing"

"github.com/docker/model-runner/cmd/cli/pkg/types"
)

// TestSyncDockerConfigToContainer_NoopForDesktopAndCloud verifies that
// SyncDockerConfigToContainer skips Desktop and Cloud engine kinds.
Comment thread
areebahmeddd marked this conversation as resolved.
func TestSyncDockerConfigToContainer_NoopForDesktopAndCloud(t *testing.T) {
for _, engineKind := range []types.ModelRunnerEngineKind{
types.ModelRunnerEngineKindDesktop,
types.ModelRunnerEngineKindCloud,
} {
t.Run(engineKind.String(), func(t *testing.T) {
err := SyncDockerConfigToContainer(t.Context(), nil, "container-id", engineKind)
if err != nil {
t.Fatalf("SyncDockerConfigToContainer(%v) returned unexpected error: %v", engineKind, err)
}
})
}
}

// TestSyncDockerConfigToContainer_NoopWhenConfigMissing verifies that
// SyncDockerConfigToContainer skips when the host config file is absent.
func TestSyncDockerConfigToContainer_NoopWhenConfigMissing(t *testing.T) {
t.Setenv("DOCKER_CONFIG", t.TempDir())

err := SyncDockerConfigToContainer(t.Context(), nil, "container-id", types.ModelRunnerEngineKindMoby)
if err != nil {
t.Fatalf("SyncDockerConfigToContainer returned unexpected error for missing config: %v", err)
}
}