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
22 changes: 22 additions & 0 deletions pkg/distribution/oci/authn/authn.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,28 @@ func getAuthFromConfig(registry string) (Authenticator, error) {
return nil, nil
}

// FromDockerConfig resolves credentials for registry from ~/.docker/config.json
// alone — credential helpers (credHelpers), then the credential store
// (credsStore), then inline auths entries.
//
// Unlike DefaultKeychain.Resolve it deliberately does not consult the
// DOCKER_USERNAME/DOCKER_HUB_USER environment variables, so a caller that must
// not offer Hub credentials to an unrelated host (for example a corporate
// registry mirror) can scope that decision itself.
//
// A nil Authenticator with a nil error means no credentials were found. That is
// not an error: the registry may allow anonymous access.
func FromDockerConfig(registry string) (Authenticator, error) {
auth, err := getAuthFromConfig(registry)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil, nil
}
return nil, err
}
return auth, nil
}

// getServerAddressForRegistry returns the server address used for credential lookup.
// Docker Hub credentials are stored under "https://index.docker.io/v1/".
func getServerAddressForRegistry(registry string) string {
Expand Down
26 changes: 15 additions & 11 deletions pkg/inference/backends/diffusers/diffusers.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,16 @@ type diffusers struct {
installDir string
// registryMirrors is the list of registry mirrors to try before registry-1.docker.io.
registryMirrors []string
// registryCredentials, if non-nil, resolves credentials for the registry (or
// mirror) the backend image is fetched from.
registryCredentials inference.RegistryCredentials
// commandModifier, if non-nil, is applied to the server process before it starts.
commandModifier func(*exec.Cmd)
}

// New creates a new diffusers-based backend for image generation.
// customPythonPath is an optional path to a custom python3 binary; if empty, the default installation is used.
func New(log logging.Logger, modelManager *models.Manager, serverLog logging.Logger, conf *Config, customPythonPath string, registryMirrors []string, commandModifier func(*exec.Cmd)) (inference.Backend, error) {
func New(log logging.Logger, modelManager *models.Manager, serverLog logging.Logger, conf *Config, customPythonPath string, registryMirrors []string, registryCredentials inference.RegistryCredentials, commandModifier func(*exec.Cmd)) (inference.Backend, error) {
// If no config is provided, use the default configuration
if conf == nil {
conf = NewDefaultConfig()
Expand All @@ -75,15 +78,16 @@ func New(log logging.Logger, modelManager *models.Manager, serverLog logging.Log
installDir := filepath.Join(homeDir, defaultInstallDir)

return &diffusers{
log: log,
modelManager: modelManager,
serverLog: serverLog,
config: conf,
status: inference.FormatNotInstalled(""),
customPythonPath: customPythonPath,
installDir: installDir,
registryMirrors: registryMirrors,
commandModifier: commandModifier,
log: log,
modelManager: modelManager,
serverLog: serverLog,
config: conf,
status: inference.FormatNotInstalled(""),
customPythonPath: customPythonPath,
installDir: installDir,
registryMirrors: registryMirrors,
registryCredentials: registryCredentials,
commandModifier: commandModifier,
}, nil
}

Expand Down Expand Up @@ -158,7 +162,7 @@ func (d *diffusers) downloadAndExtract(ctx context.Context) error {

// Pull the image
image := fmt.Sprintf("registry-1.docker.io/docker/model-runner:diffusers-%s", diffusersVersion)
if err := dockerhub.PullPlatform(ctx, image, filepath.Join(downloadDir, "image.tar"), runtime.GOOS, runtime.GOARCH, d.registryMirrors); err != nil {
if err := dockerhub.PullPlatform(ctx, image, filepath.Join(downloadDir, "image.tar"), runtime.GOOS, runtime.GOARCH, d.registryMirrors, d.registryCredentials); err != nil {
return fmt.Errorf("failed to pull image: %w", err)
}

Expand Down
16 changes: 8 additions & 8 deletions pkg/inference/backends/llamacpp/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,12 @@ func (l *llamaCpp) downloadLatestLlamaCpp(ctx context.Context, log logging.Logge

// Resolve the desired tag to a digest via the Registry HTTP API v2. This
// honors l.registryMirrors (typically a corporate Artifactory / Nexus /
// Harbor mirror configured for docker.io) and credentials populated by
// `docker login`, so customers behind a private mirror with no direct
// egress to registry-1.docker.io can still resolve and pull the backend
// image. See docker/model-runner#TBD.
// Harbor mirror configured for docker.io) and l.registryCredentials — or,
// when those are nil, credentials populated by `docker login` — so customers
// behind a private mirror with no direct egress to registry-1.docker.io can
// still resolve and pull the backend image.
tagRef := fmt.Sprintf("registry-1.docker.io/%s/%s:%s", hubNamespace, hubRepo, desiredTag)
latest, err := dockerhub.ResolveDigest(ctx, tagRef, l.registryMirrors)
latest, err := dockerhub.ResolveDigest(ctx, tagRef, l.registryMirrors, l.registryCredentials)
if err != nil {
log.Warn("could not resolve llama.cpp tag", "tag", desiredTag, "mirrors", l.registryMirrors, "error", err)
return fmt.Errorf("could not resolve the %s tag: %w", desiredTag, err)
Expand All @@ -126,7 +126,7 @@ func (l *llamaCpp) downloadLatestLlamaCpp(ctx context.Context, log logging.Logge
defer os.RemoveAll(downloadDir)

l.status = inference.FormatInstalling(fmt.Sprintf("%s llama.cpp %s", inference.DetailDownloading, desiredTag))
if extractErr := extractFromImage(ctx, log, image, runtime.GOOS, runtime.GOARCH, downloadDir, l.registryMirrors); extractErr != nil {
if extractErr := extractFromImage(ctx, log, image, runtime.GOOS, runtime.GOARCH, downloadDir, l.registryMirrors, l.registryCredentials); extractErr != nil {
return fmt.Errorf("could not extract image: %w", extractErr)
}

Expand Down Expand Up @@ -215,14 +215,14 @@ func (l *llamaCpp) writeInstalledVersion(log logging.Logger, rec installedVersio
}

//nolint:unused // Used in platform-specific files (download_darwin.go, download_windows.go)
func extractFromImage(ctx context.Context, log logging.Logger, image, requiredOs, requiredArch, destination string, mirrors []string) error {
func extractFromImage(ctx context.Context, log logging.Logger, image, requiredOs, requiredArch, destination string, mirrors []string, creds inference.RegistryCredentials) error {
log.Info("Extracting image", "image", image, "destination", destination)
tmpDir, err := os.MkdirTemp("", "docker-tar-extract")
if err != nil {
return err
}
imageTar := filepath.Join(tmpDir, "save.tar")
if err := dockerhub.PullPlatform(ctx, image, imageTar, requiredOs, requiredArch, mirrors); err != nil {
if err := dockerhub.PullPlatform(ctx, image, imageTar, requiredOs, requiredArch, mirrors, creds); err != nil {
return err
}
return dockerhub.Extract(imageTar, requiredArch, requiredOs, destination)
Expand Down
22 changes: 14 additions & 8 deletions pkg/inference/backends/llamacpp/llamacpp.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ type llamaCpp struct {
gpuSupported bool
// registryMirrors is the list of registry mirrors to try before registry-1.docker.io.
registryMirrors []string
// registryCredentials, if non-nil, resolves credentials for the registry (or
// mirror) the backend image is fetched from. When nil, credentials come from
// the environment and ~/.docker/config.json.
registryCredentials inference.RegistryCredentials
// commandModifier, if non-nil, is applied to the server process before it starts.
commandModifier func(*exec.Cmd)
}
Expand All @@ -67,6 +71,7 @@ func New(
installDir string,
conf config.BackendConfig,
registryMirrors []string,
registryCredentials inference.RegistryCredentials,
commandModifier func(*exec.Cmd),
) (inference.Backend, error) {
// If no config is provided, use the default configuration
Expand All @@ -83,14 +88,15 @@ func New(
}

return &llamaCpp{
log: log,
modelManager: modelManager,
serverLog: serverLog,
installDir: installDir,
status: inference.FormatNotInstalled(""),
config: conf,
registryMirrors: registryMirrors,
commandModifier: commandModifier,
log: log,
modelManager: modelManager,
serverLog: serverLog,
installDir: installDir,
status: inference.FormatNotInstalled(""),
config: conf,
registryMirrors: registryMirrors,
registryCredentials: registryCredentials,
commandModifier: commandModifier,
}, nil
}

Expand Down
37 changes: 21 additions & 16 deletions pkg/inference/backends/vllm/vllm.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,21 @@ type vLLM struct {
customBinaryPath string
// registryMirrors is the list of registry mirrors to try before registry-1.docker.io.
registryMirrors []string
// registryCredentials, if non-nil, resolves credentials for the registry (or
// mirror) the backend image is fetched from.
registryCredentials inference.RegistryCredentials
// commandModifier, if non-nil, is applied to the server process before it starts.
commandModifier func(*exec.Cmd)
}

// Options holds the configuration for the unified vLLM backend constructor.
type Options struct {
Config *Config // Linux-only: extra vllm args (nil = defaults)
LinuxBinaryPath string // Linux: custom vllm binary path
MetalPythonPath string // macOS ARM64: custom python path
RegistryMirrors []string // registry mirrors tried before registry-1.docker.io
CommandModifier func(*exec.Cmd) // applied to the server process before it starts
Config *Config // Linux-only: extra vllm args (nil = defaults)
LinuxBinaryPath string // Linux: custom vllm binary path
MetalPythonPath string // macOS ARM64: custom python path
RegistryMirrors []string // registry mirrors tried before registry-1.docker.io
RegistryCredentials inference.RegistryCredentials // resolves credentials for the registry or mirror; nil falls back to the environment and ~/.docker/config.json
CommandModifier func(*exec.Cmd) // applied to the server process before it starts
}

// New creates the appropriate vLLM backend for the current platform.
Expand All @@ -65,9 +69,9 @@ type Options struct {
// methods return errors.
func New(log logging.Logger, modelManager *models.Manager, serverLog logging.Logger, opts Options) (inference.Backend, error) {
if platform.SupportsVLLMMetal() {
return newMetal(log, modelManager, serverLog, opts.MetalPythonPath, opts.RegistryMirrors, opts.CommandModifier)
return newMetal(log, modelManager, serverLog, opts.MetalPythonPath, opts.RegistryMirrors, opts.RegistryCredentials, opts.CommandModifier)
}
return newLinux(log, modelManager, serverLog, opts.Config, opts.LinuxBinaryPath, opts.RegistryMirrors, opts.CommandModifier)
return newLinux(log, modelManager, serverLog, opts.Config, opts.LinuxBinaryPath, opts.RegistryMirrors, opts.RegistryCredentials, opts.CommandModifier)
}

// NeedsDeferredInstall reports whether vllm on the current platform
Expand All @@ -78,21 +82,22 @@ func NeedsDeferredInstall() bool {

// newLinux creates a new Linux vLLM-based backend.
// customBinaryPath is an optional path to a custom vllm binary; if empty, the default path is used.
func newLinux(log logging.Logger, modelManager *models.Manager, serverLog logging.Logger, conf *Config, customBinaryPath string, registryMirrors []string, commandModifier func(*exec.Cmd)) (inference.Backend, error) {
func newLinux(log logging.Logger, modelManager *models.Manager, serverLog logging.Logger, conf *Config, customBinaryPath string, registryMirrors []string, registryCredentials inference.RegistryCredentials, commandModifier func(*exec.Cmd)) (inference.Backend, error) {
// If no config is provided, use the default configuration
if conf == nil {
conf = NewDefaultVLLMConfig()
}

return &vLLM{
log: log,
modelManager: modelManager,
serverLog: serverLog,
config: conf,
status: inference.FormatNotInstalled(""),
customBinaryPath: customBinaryPath,
registryMirrors: registryMirrors,
commandModifier: commandModifier,
log: log,
modelManager: modelManager,
serverLog: serverLog,
config: conf,
status: inference.FormatNotInstalled(""),
customBinaryPath: customBinaryPath,
registryMirrors: registryMirrors,
registryCredentials: registryCredentials,
commandModifier: commandModifier,
}, nil
}

Expand Down
24 changes: 14 additions & 10 deletions pkg/inference/backends/vllm/vllm_metal.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,28 +53,32 @@ type vllmMetal struct {
status string
// registryMirrors is the list of registry mirrors to try before registry-1.docker.io.
registryMirrors []string
// registryCredentials, if non-nil, resolves credentials for the registry (or
// mirror) the backend image is fetched from.
registryCredentials inference.RegistryCredentials
// commandModifier, if non-nil, is applied to the server process before it starts.
commandModifier func(*exec.Cmd)
}

// newMetal creates a new vllm-metal backend.
// customPythonPath is an optional path to a custom python3 binary; if empty, the default installation is used.
func newMetal(log logging.Logger, modelManager *models.Manager, serverLog logging.Logger, customPythonPath string, registryMirrors []string, commandModifier func(*exec.Cmd)) (inference.Backend, error) {
func newMetal(log logging.Logger, modelManager *models.Manager, serverLog logging.Logger, customPythonPath string, registryMirrors []string, registryCredentials inference.RegistryCredentials, commandModifier func(*exec.Cmd)) (inference.Backend, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return nil, fmt.Errorf("failed to get user home directory: %w", err)
}
installDir := filepath.Join(homeDir, defaultInstallDir)

return &vllmMetal{
log: log,
modelManager: modelManager,
serverLog: serverLog,
customPythonPath: customPythonPath,
installDir: installDir,
status: inference.FormatNotInstalled(""),
registryMirrors: registryMirrors,
commandModifier: commandModifier,
log: log,
modelManager: modelManager,
serverLog: serverLog,
customPythonPath: customPythonPath,
installDir: installDir,
status: inference.FormatNotInstalled(""),
registryMirrors: registryMirrors,
registryCredentials: registryCredentials,
commandModifier: commandModifier,
}, nil
}

Expand Down Expand Up @@ -149,7 +153,7 @@ func (v *vllmMetal) downloadAndExtract(ctx context.Context, _ *http.Client) erro

// Pull the image
image := fmt.Sprintf("registry-1.docker.io/docker/model-runner:vllm-metal-%s", vllmMetalVersion)
if err := dockerhub.PullPlatform(ctx, image, filepath.Join(downloadDir, "image.tar"), runtime.GOOS, runtime.GOARCH, v.registryMirrors); err != nil {
if err := dockerhub.PullPlatform(ctx, image, filepath.Join(downloadDir, "image.tar"), runtime.GOOS, runtime.GOARCH, v.registryMirrors, v.registryCredentials); err != nil {
return fmt.Errorf("failed to pull image: %w", err)
}

Expand Down
20 changes: 20 additions & 0 deletions pkg/inference/credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package inference

// RegistryCredentials resolves registry credentials for a registry host,
// returning the username and secret to authenticate with. Returning an empty
// username and secret with a nil error means no credentials are available for
// that host and anonymous access should be attempted.
//
// An embedder that already holds registry credentials in process supplies one of
// these so backend image pulls authenticate without shelling out to a
// docker-credential-* helper — which also removes any dependency on the helper
// being on PATH. Docker Desktop does this: it is itself the credential backend.
//
// When nil, backends fall back to resolving credentials from the environment and
// ~/.docker/config.json (including credHelpers and credsStore).
//
// The host is the registry the request is being made to, so for a pull routed
// through a registry mirror it is the mirror's host, not registry-1.docker.io.
// Credentials must therefore be resolved per host: Docker Hub credentials do not
// apply to a third-party mirror.
type RegistryCredentials func(host string) (username, secret string, err error)
Loading