Skip to content

Commit

Permalink
feat: skip external clone with custom image (#1426)
Browse files Browse the repository at this point in the history
- significantly improved creation time when a custom image is used

Signed-off-by: Toma Puljak <toma.puljak@hotmail.com>
  • Loading branch information
Tpuljak authored Dec 6, 2024
1 parent 31b8cdd commit 785302a
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 38 deletions.
4 changes: 2 additions & 2 deletions pkg/cmd/workspace/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ func waitForDial(workspace *apiclient.Workspace, activeProfile *config.Profile,
return nil
}

time.Sleep(time.Second)
time.Sleep(100 * time.Millisecond)
}
}

Expand All @@ -503,7 +503,7 @@ func waitForDial(workspace *apiclient.Workspace, activeProfile *config.Profile,
connectChan <- dialConn.Close()
return
}
time.Sleep(time.Second)
time.Sleep(100 * time.Millisecond)
}
}()

Expand Down
2 changes: 2 additions & 0 deletions pkg/docker/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/daytonaio/daytona/pkg/gitprovider"
"github.com/daytonaio/daytona/pkg/workspace"
"github.com/daytonaio/daytona/pkg/workspace/project"
"github.com/daytonaio/daytona/pkg/workspace/project/buildconfig"
"github.com/stretchr/testify/suite"
)

Expand All @@ -21,6 +22,7 @@ var project1 = &project.Project{
Url: "https://github.com/daytonaio/daytona",
Name: "daytona",
},
BuildConfig: &buildconfig.BuildConfig{},
Image: "test-image:tag",
User: "test-user",
WorkspaceId: "123",
Expand Down
46 changes: 25 additions & 21 deletions pkg/docker/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,31 +40,35 @@ func (d *DockerClient) CreateProject(opts *CreateProjectOptions) error {
// This is only an optimisation for images with tag 'latest'
pulledImages := map[string]bool{}

err := d.PullImage(opts.BuilderImage, opts.BuilderContainerRegistry, opts.LogWriter)
if err != nil {
return err
}
pulledImages[opts.BuilderImage] = true
if opts.Project.BuildConfig != nil {
err := d.PullImage(opts.BuilderImage, opts.BuilderContainerRegistry, opts.LogWriter)
if err != nil {
return err
}
pulledImages[opts.BuilderImage] = true

err = d.cloneProjectRepository(opts)
if err != nil {
return err
}
err = d.cloneProjectRepository(opts)
if err != nil {
return err
}

builderType, err := detect.DetectProjectBuilderType(opts.Project.BuildConfig, opts.ProjectDir, opts.SshClient)
if err != nil {
return err
}
builderType, err := detect.DetectProjectBuilderType(opts.Project.BuildConfig, opts.ProjectDir, opts.SshClient)
if err != nil {
return err
}

switch builderType {
case detect.BuilderTypeDevcontainer:
_, _, err := d.CreateFromDevcontainer(d.toCreateDevcontainerOptions(opts, true))
return err
case detect.BuilderTypeImage:
return d.createProjectFromImage(opts, pulledImages)
default:
return fmt.Errorf("unknown builder type: %s", builderType)
switch builderType {
case detect.BuilderTypeDevcontainer:
_, _, err := d.CreateFromDevcontainer(d.toCreateDevcontainerOptions(opts, true))
return err
case detect.BuilderTypeImage:
return d.createProjectFromImage(opts, pulledImages, true)
default:
return fmt.Errorf("unknown builder type: %s", builderType)
}
}

return d.createProjectFromImage(opts, pulledImages, false)
}

func (d *DockerClient) cloneProjectRepository(opts *CreateProjectOptions) error {
Expand Down
31 changes: 18 additions & 13 deletions pkg/docker/create_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import (

// pulledImages map keeps track of pulled images for project creation in order to avoid pulling the same image multiple times
// This is only an optimisation for images with tag 'latest'
func (d *DockerClient) createProjectFromImage(opts *CreateProjectOptions, pulledImages map[string]bool) error {
func (d *DockerClient) createProjectFromImage(opts *CreateProjectOptions, pulledImages map[string]bool, mountProjectDir bool) error {
if pulledImages[opts.Project.Image] {
return d.initProjectContainer(opts)
return d.initProjectContainer(opts, mountProjectDir)
}

err := d.PullImage(opts.Project.Image, opts.ContainerRegistry, opts.LogWriter)
Expand All @@ -28,21 +28,24 @@ func (d *DockerClient) createProjectFromImage(opts *CreateProjectOptions, pulled
}
pulledImages[opts.Project.Image] = true

return d.initProjectContainer(opts)
return d.initProjectContainer(opts, mountProjectDir)
}

func (d *DockerClient) initProjectContainer(opts *CreateProjectOptions) error {
func (d *DockerClient) initProjectContainer(opts *CreateProjectOptions, mountProjectDir bool) error {
ctx := context.Background()

mounts := []mount.Mount{}
if mountProjectDir {
mounts = append(mounts, mount.Mount{
Type: mount.TypeBind,
Source: opts.ProjectDir,
Target: fmt.Sprintf("/home/%s/%s", opts.Project.User, opts.Project.Name),
})
}

c, err := d.apiClient.ContainerCreate(ctx, GetContainerCreateConfig(opts.Project), &container.HostConfig{
Privileged: true,
Mounts: []mount.Mount{
{
Type: mount.TypeBind,
Source: opts.ProjectDir,
Target: fmt.Sprintf("/home/%s/%s", opts.Project.User, opts.Project.Name),
},
},
Mounts: mounts,
ExtraHosts: []string{
"host.docker.internal:host-gateway",
},
Expand All @@ -67,11 +70,13 @@ func (d *DockerClient) initProjectContainer(opts *CreateProjectOptions) error {
}
}()

if runtime.GOOS != "windows" {
if runtime.GOOS != "windows" && mountProjectDir {
_, err = d.updateContainerUserUidGid(c.ID, opts)
}

err = d.apiClient.ContainerStop(ctx, c.ID, container.StopOptions{})
err = d.apiClient.ContainerStop(ctx, c.ID, container.StopOptions{
Signal: "SIGKILL",
})
if err != nil {
return err
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/docker/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ func (s *DockerClientTestSuite) TestCreateProject() {
s.mockClient.On("ContainerRemove", mock.Anything, mock.Anything, container.RemoveOptions{RemoveVolumes: true, Force: true}).Return(nil)
s.mockClient.On("ContainerStart", mock.Anything, mock.Anything, container.StartOptions{}).Return(nil)
s.mockClient.On("ContainerExecCreate", mock.Anything, mock.Anything, mock.Anything).Return(types.IDResponse{ID: "exec-id"}, nil)
s.mockClient.On("ContainerStop", mock.Anything, "123", container.StopOptions{}).Return(nil)
s.mockClient.On("ContainerStop", mock.Anything, "123", container.StopOptions{
Signal: "SIGKILL",
}).Return(nil)

_, client := net.Pipe()
s.mockClient.On("ContainerExecAttach", mock.Anything, "exec-id", container.ExecStartOptions{}).
Expand Down
2 changes: 1 addition & 1 deletion pkg/docker/start_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func (d *DockerClient) startImageProject(opts *CreateProjectOptions) error {
break
}

time.Sleep(1 * time.Second)
time.Sleep(100 * time.Millisecond)
}

// Find entrypoint metadata
Expand Down

0 comments on commit 785302a

Please sign in to comment.