Skip to content
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
bdf2904
Add local image flag for fast context loading
8W9aG Mar 31, 2025
4a9a669
Merge branch 'main' into sackfield/add-local-image-flag
8W9aG Mar 31, 2025
6b1c59e
Fix no tmpMount usage
8W9aG Mar 31, 2025
759fe41
Potential fix for code scanning alert no. 24: Potentially unsafe quoting
8W9aG Mar 31, 2025
93d9726
Fix lint
8W9aG Mar 31, 2025
8e39434
Use . in non local image for copy
8W9aG Mar 31, 2025
9c11d64
Add back weights copy exclusion from non local images
8W9aG Mar 31, 2025
0d93f0a
Send standard build directory if not local image
8W9aG Mar 31, 2025
fc23efc
Fix calculating rel dir on relative dir
8W9aG Mar 31, 2025
d15a45e
Build then predict in int test
8W9aG Mar 31, 2025
68685e7
Add fast and local image to predict test
8W9aG Apr 1, 2025
4c1f97d
Merge branch 'main' into sackfield/add-local-image-flag
8W9aG Apr 1, 2025
1ffbb25
Use the image name from the config in predict
8W9aG Apr 1, 2025
2d0883d
Fix cog predict build on fast build
8W9aG Apr 1, 2025
f9a222a
Feed docker image in directly
8W9aG Apr 1, 2025
db768c6
Use projectDir to fill in weights path
8W9aG Apr 1, 2025
fc6e034
Put debug in the right position
8W9aG Apr 1, 2025
eb60a50
Remove -t in cog predict
8W9aG Apr 1, 2025
09071f8
Capture output of test and check return code
8W9aG Apr 2, 2025
1b0534c
Merge branch 'main' into sackfield/add-local-image-flag
8W9aG Apr 2, 2025
9217afc
Use absolute path for weights manifest
8W9aG Apr 2, 2025
5a2a60f
Merge branch 'main' into sackfield/add-local-image-flag
8W9aG Apr 2, 2025
4fa0ed5
Use hard links rather than file copies
8W9aG Apr 2, 2025
817ec3d
Mirror the local directories permissions
8W9aG Apr 2, 2025
5d27e08
Follow symlink to target
8W9aG Apr 2, 2025
7ee7e15
Make sure directory permissions are aligned
8W9aG Apr 2, 2025
37178d1
Merge branch 'main' into sackfield/add-local-image-flag
8W9aG Apr 2, 2025
359cb38
Fix fast push
8W9aG Apr 3, 2025
1d038ef
Use MkdirAll
8W9aG Apr 3, 2025
dd9ee6a
Use a set for weight path check
8W9aG Apr 3, 2025
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
2 changes: 1 addition & 1 deletion pkg/cli/baseimage.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func newBaseImageBuildCommand() *cobra.Command {
}
baseImageName := dockerfile.BaseImageName(baseImageCUDAVersion, baseImagePythonVersion, baseImageTorchVersion)

err = docker.Build(cwd, dockerfileContents, baseImageName, []string{}, buildNoCache, buildProgressOutput, config.BuildSourceEpochTimestamp)
err = docker.Build(cwd, dockerfileContents, baseImageName, []string{}, buildNoCache, buildProgressOutput, config.BuildSourceEpochTimestamp, dockerfile.StandardBuildDirectory, nil)
if err != nil {
return err
}
Expand Down
10 changes: 9 additions & 1 deletion pkg/cli/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var buildUseCogBaseImage bool
var buildStrip bool
var buildPrecompile bool
var buildFast bool
var buildLocalImage bool

const useCogBaseImageFlagKey = "use-cog-base-image"

Expand All @@ -48,6 +49,7 @@ func newBuildCommand() *cobra.Command {
addStripFlag(cmd)
addPrecompileFlag(cmd)
addFastFlag(cmd)
addLocalImage(cmd)
cmd.Flags().StringVarP(&buildTag, "tag", "t", "", "A name for the built image in the form 'repository:tag'")
return cmd
}
Expand All @@ -74,7 +76,7 @@ func buildCommand(cmd *cobra.Command, args []string) error {
return err
}

if err := image.Build(cfg, projectDir, imageName, buildSecrets, buildNoCache, buildSeparateWeights, buildUseCudaBaseImage, buildProgressOutput, buildSchemaFile, buildDockerfileFile, DetermineUseCogBaseImage(cmd), buildStrip, buildPrecompile, buildFast, nil); err != nil {
if err := image.Build(cfg, projectDir, imageName, buildSecrets, buildNoCache, buildSeparateWeights, buildUseCudaBaseImage, buildProgressOutput, buildSchemaFile, buildDockerfileFile, DetermineUseCogBaseImage(cmd), buildStrip, buildPrecompile, buildFast, nil, buildLocalImage); err != nil {
return err
}

Expand Down Expand Up @@ -147,6 +149,12 @@ func addFastFlag(cmd *cobra.Command) {
_ = cmd.Flags().MarkHidden(fastFlag)
}

func addLocalImage(cmd *cobra.Command) {
const localImage = "x-localimage"
cmd.Flags().BoolVar(&buildLocalImage, localImage, false, "Whether to use the experimental local image features")
_ = cmd.Flags().MarkHidden(localImage)
}

func checkMutuallyExclusiveFlags(cmd *cobra.Command, args []string) error {
flags := []string{useCogBaseImageFlagKey, "use-cuda-base-image", "dockerfile"}
var flagsSet []string
Expand Down
4 changes: 3 additions & 1 deletion pkg/cli/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ func newDebugCommand() *cobra.Command {
addDockerfileFlag(cmd)
addUseCogBaseImageFlag(cmd)
addBuildTimestampFlag(cmd)
addFastFlag(cmd)
addLocalImage(cmd)
cmd.Flags().StringVarP(&imageName, "image-name", "", "", "The image name to use for the generated Dockerfile")

return cmd
Expand All @@ -39,7 +41,7 @@ func cmdDockerfile(cmd *cobra.Command, args []string) error {
}

command := docker.NewDockerCommand()
generator, err := dockerfile.NewGenerator(cfg, projectDir, false, command)
generator, err := dockerfile.NewGenerator(cfg, projectDir, buildFast, command, buildLocalImage)
if err != nil {
return fmt.Errorf("Error creating Dockerfile generator: %w", err)
}
Expand Down
43 changes: 28 additions & 15 deletions pkg/cli/predict.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ the prediction on that.`,
addGpusFlag(cmd)
addSetupTimeoutFlag(cmd)
addFastFlag(cmd)
addLocalImage(cmd)

cmd.Flags().StringArrayVarP(&inputFlags, "input", "i", []string{}, "Inputs, in the form name=value. if value is prefixed with @, then it is read from a file on disk. E.g. -i [email protected]")
cmd.Flags().StringVarP(&outPath, "output", "o", "", "Output path")
Expand All @@ -76,22 +77,27 @@ func cmdPredict(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}

if cfg.Build.Fast {
buildFast = cfg.Build.Fast
}

if imageName, err = image.BuildBase(cfg, projectDir, buildUseCudaBaseImage, DetermineUseCogBaseImage(cmd), buildProgressOutput); err != nil {
return err
}
if buildFast {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can you just throw this into the block above

if cfg.Build.Fast {
    buildFast = true
    imageName = config.DockerImageName(projectDir)
} else {
    ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I don't think we can, config fast build overwrites any CLI flag which is the first block, but in the 2nd block we need to know whether the fast build flag is in general on and overwrite the imageName

imageName = config.DockerImageName(projectDir)
} else {
if imageName, err = image.BuildBase(cfg, projectDir, buildUseCudaBaseImage, DetermineUseCogBaseImage(cmd), buildProgressOutput); err != nil {
return err
}

// Base image doesn't have /src in it, so mount as volume
volumes = append(volumes, docker.Volume{
Source: projectDir,
Destination: "/src",
})
// Base image doesn't have /src in it, so mount as volume
volumes = append(volumes, docker.Volume{
Source: projectDir,
Destination: "/src",
})

if gpus == "" && cfg.Build.GPU {
gpus = "all"
if gpus == "" && cfg.Build.GPU {
gpus = "all"
}
}

} else {
Expand Down Expand Up @@ -127,13 +133,17 @@ func cmdPredict(cmd *cobra.Command, args []string) error {

console.Info("")
console.Infof("Starting Docker image %s and running setup()...", imageName)
dockerCommand := docker.NewDockerCommand()

predictor := predict.NewPredictor(docker.RunOptions{
predictor, err := predict.NewPredictor(docker.RunOptions{
GPUs: gpus,
Image: imageName,
Volumes: volumes,
Env: envFlags,
}, false, buildFast)
}, false, buildFast, dockerCommand)
if err != nil {
return err
}

go func() {
captureSignal := make(chan os.Signal, 1)
Expand All @@ -155,11 +165,14 @@ func cmdPredict(cmd *cobra.Command, args []string) error {
console.Info("Missing device driver, re-trying without GPU")

_ = predictor.Stop()
predictor = predict.NewPredictor(docker.RunOptions{
predictor, err = predict.NewPredictor(docker.RunOptions{
Image: imageName,
Volumes: volumes,
Env: envFlags,
}, false, buildFast)
}, false, buildFast, dockerCommand)
if err != nil {
return err
}

if err := predictor.Start(os.Stderr, timeout); err != nil {
return err
Expand All @@ -177,7 +190,7 @@ func cmdPredict(cmd *cobra.Command, args []string) error {
}
}()

return predictIndividualInputs(predictor, inputFlags, outPath, false)
return predictIndividualInputs(*predictor, inputFlags, outPath, false)
}

func isURI(ref *openapi3.Schema) bool {
Expand Down
7 changes: 6 additions & 1 deletion pkg/cli/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func newPushCommand() *cobra.Command {
addStripFlag(cmd)
addPrecompileFlag(cmd)
addFastFlag(cmd)
addLocalImage(cmd)

return cmd
}
Expand Down Expand Up @@ -63,6 +64,10 @@ func push(cmd *cobra.Command, args []string) error {
if err := docker.ManifestInspect(imageName); err != nil && strings.Contains(err.Error(), `"code":"NAME_UNKNOWN"`) {
return fmt.Errorf("Unable to find Replicate existing model for %s. Go to replicate.com and create a new model before pushing.", imageName)
}
} else {
if buildLocalImage {
return fmt.Errorf("Unable to push a local image model to a non replicate host, please disable the local image flag before pushing to this host.")
}
}

annotations := map[string]string{}
Expand All @@ -76,7 +81,7 @@ func push(cmd *cobra.Command, args []string) error {

startBuildTime := time.Now()

if err := image.Build(cfg, projectDir, imageName, buildSecrets, buildNoCache, buildSeparateWeights, buildUseCudaBaseImage, buildProgressOutput, buildSchemaFile, buildDockerfileFile, DetermineUseCogBaseImage(cmd), buildStrip, buildPrecompile, buildFast, annotations); err != nil {
if err := image.Build(cfg, projectDir, imageName, buildSecrets, buildNoCache, buildSeparateWeights, buildUseCudaBaseImage, buildProgressOutput, buildSchemaFile, buildDockerfileFile, DetermineUseCogBaseImage(cmd), buildStrip, buildPrecompile, buildFast, annotations, buildLocalImage); err != nil {
return err
}

Expand Down
7 changes: 7 additions & 0 deletions pkg/cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func newRunCommand() *cobra.Command {
addUseCogBaseImageFlag(cmd)
addGpusFlag(cmd)
addFastFlag(cmd)
addLocalImage(cmd)

flags := cmd.Flags()
// Flags after first argument are considered args and passed to command
Expand Down Expand Up @@ -67,6 +68,8 @@ func run(cmd *cobra.Command, args []string) error {
gpus = "all"
}

dockerCommand := docker.NewDockerCommand()

runOptions := docker.RunOptions{
Args: args,
Env: envFlags,
Expand All @@ -75,6 +78,10 @@ func run(cmd *cobra.Command, args []string) error {
Volumes: []docker.Volume{{Source: projectDir, Destination: "/src"}},
Workdir: "/src",
}
runOptions, err = docker.FillInWeightsManifestVolumes(dockerCommand, runOptions)
if err != nil {
return err
}

if util.IsAppleSiliconMac(runtime.GOOS, runtime.GOARCH) {
runOptions.Platform = "linux/amd64"
Expand Down
5 changes: 5 additions & 0 deletions pkg/cli/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func cmdServe(cmd *cobra.Command, arg []string) error {
"--await-explicit-shutdown", "true",
}

dockerCommand := docker.NewDockerCommand()
runOptions := docker.RunOptions{
Args: args,
Env: envFlags,
Expand All @@ -77,6 +78,10 @@ func cmdServe(cmd *cobra.Command, arg []string) error {
Volumes: []docker.Volume{{Source: projectDir, Destination: "/src"}},
Workdir: "/src",
}
runOptions, err = docker.FillInWeightsManifestVolumes(dockerCommand, runOptions)
if err != nil {
return err
}

if util.IsAppleSiliconMac(runtime.GOOS, runtime.GOARCH) {
runOptions.Platform = "linux/amd64"
Expand Down
19 changes: 12 additions & 7 deletions pkg/cli/train.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ func cmdTrain(cmd *cobra.Command, args []string) error {
volumes := []docker.Volume{}
gpus := gpusFlag

cfg, projectDir, err := config.GetConfig(projectDirFlag)
if err != nil {
return err
}

if len(args) == 0 {
// Build image

cfg, projectDir, err := config.GetConfig(projectDirFlag)
if err != nil {
return err
}
if cfg.Build.Fast {
buildFast = cfg.Build.Fast
}
Expand Down Expand Up @@ -108,14 +109,18 @@ func cmdTrain(cmd *cobra.Command, args []string) error {

console.Info("")
console.Infof("Starting Docker image %s...", imageName)
dockerCommand := docker.NewDockerCommand()

predictor := predict.NewPredictor(docker.RunOptions{
predictor, err := predict.NewPredictor(docker.RunOptions{
GPUs: gpus,
Image: imageName,
Volumes: volumes,
Env: trainEnvFlags,
Args: []string{"python", "-m", "cog.server.http", "--x-mode", "train"},
}, true, buildFast)
}, true, buildFast, dockerCommand)
if err != nil {
return err
}

go func() {
captureSignal := make(chan os.Signal, 1)
Expand All @@ -141,5 +146,5 @@ func cmdTrain(cmd *cobra.Command, args []string) error {
}
}()

return predictIndividualInputs(predictor, trainInputFlags, trainOutPath, true)
return predictIndividualInputs(*predictor, trainInputFlags, trainOutPath, true)
}
8 changes: 6 additions & 2 deletions pkg/docker/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/replicate/cog/pkg/util/console"
)

func Build(dir, dockerfileContents, imageName string, secrets []string, noCache bool, progressOutput string, epoch int64) error {
func Build(dir, dockerfileContents, imageName string, secrets []string, noCache bool, progressOutput string, epoch int64, contextDir string, buildContexts map[string]string) error {
var args []string

args = append(args, "buildx", "build")
Expand Down Expand Up @@ -52,11 +52,15 @@ func Build(dir, dockerfileContents, imageName string, secrets []string, noCache
args = append(args, "--cache-to", "type=inline")
}

for name, dir := range buildContexts {
args = append(args, "--build-context", name+"="+dir)
}

args = append(args,
"--file", "-",
"--tag", imageName,
"--progress", progressOutput,
".",
contextDir,
)

cmd := exec.Command("docker", args...)
Expand Down
1 change: 1 addition & 0 deletions pkg/docker/command/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ const R8PythonVersionEnvVarName = "R8_PYTHON_VERSION"
var CogConfigLabelKey = global.LabelNamespace + "config"
var CogVersionLabelKey = global.LabelNamespace + "version"
var CogOpenAPISchemaLabelKey = global.LabelNamespace + "openapi_schema"
var CogWeightsManifestLabelKey = global.LabelNamespace + "r8_weights_manifest"
27 changes: 27 additions & 0 deletions pkg/docker/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package docker
import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
Expand All @@ -15,8 +16,10 @@ import (

"github.com/mattn/go-isatty"

"github.com/replicate/cog/pkg/docker/command"
"github.com/replicate/cog/pkg/util"
"github.com/replicate/cog/pkg/util/console"
"github.com/replicate/cog/pkg/weights"
)

type Port struct {
Expand Down Expand Up @@ -207,3 +210,27 @@ func GetPort(containerID string, containerPort int) (int, error) {
return 0, fmt.Errorf("did not find port bound to 0.0.0.0 in `docker port` output")

}

func FillInWeightsManifestVolumes(dockerCommand command.Command, runOptions RunOptions) (RunOptions, error) {
// Check if the image has a weights manifest
manifest, err := dockerCommand.Inspect(runOptions.Image)
if err != nil {
return runOptions, err
}
weightsManifest, ok := manifest.Config.Labels[command.CogWeightsManifestLabelKey]
if ok {
var weightsPaths []weights.WeightManifest
err = json.Unmarshal([]byte(weightsManifest), &weightsPaths)
if err != nil {
return runOptions, err
}
for _, weightPath := range weightsPaths {
runOptions.Volumes = append(runOptions.Volumes, Volume{
Source: weightPath.Source,
Destination: "/src/" + weightPath.Destination,
})
}
}

return runOptions, nil
}
2 changes: 1 addition & 1 deletion pkg/dockerfile/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func (g *BaseImageGenerator) GenerateDockerfile() (string, error) {
return "", err
}

generator, err := NewGenerator(conf, "", false, g.command)
generator, err := NewGenerator(conf, "", false, g.command, true)
if err != nil {
return "", err
}
Expand Down
6 changes: 4 additions & 2 deletions pkg/dockerfile/build_tempdir.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"time"
)

const CogBuildArtifactsFolder = ".cog"

func BuildCogTempDir(dir string, subDir string) (string, error) {
rootTmp := path.Join(dir, ".cog", "tmp", subDir)
if err := os.MkdirAll(rootTmp, 0o755); err != nil {
rootTmp := path.Join(dir, CogBuildArtifactsFolder, "tmp", subDir)
if err := os.MkdirAll(rootTmp, 0o777); err != nil {
return "", err
}
return rootTmp, nil
Expand Down
Loading
Loading