diff --git a/pkg/docker/docker.go b/pkg/docker/docker.go index 4144a0fe5..c9758c97f 100644 --- a/pkg/docker/docker.go +++ b/pkg/docker/docker.go @@ -19,6 +19,7 @@ import ( "fmt" "io" "os" + "path/filepath" "strconv" "strings" "time" @@ -33,7 +34,6 @@ import ( "github.com/moby/term" "github.com/sirupsen/logrus" - "github.com/tensorchord/envd/pkg/editor/jupyter" "github.com/tensorchord/envd/pkg/lang/ir" "github.com/tensorchord/envd/pkg/util/fileutil" ) @@ -174,14 +174,17 @@ func (c generalClient) StartEnvd(ctx context.Context, tag, name, buildContext st config := &container.Config{ Image: tag, Entrypoint: []string{ - "/var/envd/bin/envd-ssh", - "--no-auth", + "tini", + "--", + "bash", + "-c", }, ExposedPorts: nat.PortSet{}, } base := fileutil.Base(buildContext) - base = fmt.Sprintf("/home/envd/%s", base) + base = filepath.Join("/home/envd", base) config.WorkingDir = base + config.Entrypoint = append(config.Entrypoint, entrypointSH(g, config.WorkingDir)) mountOption := make([]mount.Mount, len(mountOptionsStr)+1) for i, option := range mountOptionsStr { @@ -226,11 +229,19 @@ func (c generalClient) StartEnvd(ctx context.Context, tag, name, buildContext st } config.ExposedPorts[natPort] = struct{}{} } + if gpuEnabled { logger.Debug("GPU is enabled.") // enable all gpus with -1 hostConfig.DeviceRequests = deviceRequests(-1) } + + logger = logger.WithFields(logrus.Fields{ + "entrypoint": config.Entrypoint, + "working-dir": config.WorkingDir, + }) + logger.Debugf("starting %s container", name) + resp, err := c.ContainerCreate(ctx, config, hostConfig, nil, nil, name) if err != nil { return "", "", err @@ -254,17 +265,6 @@ func (c generalClient) StartEnvd(ctx context.Context, tag, name, buildContext st return "", "", errors.Wrap(err, "failed to wait until the container is running") } - if g.JupyterConfig != nil { - cmd, err := jupyter.GenerateCommand(*ir.DefaultGraph, config.WorkingDir) - if err != nil { - return "", "", errors.Wrap(err, "failed to generate jupyter command") - } - logger.WithField("cmd", cmd).Debug("configuring jupyter") - err = c.Exec(ctx, container.Name, cmd) - if err != nil { - return "", "", errors.Wrap(err, "failed to exec the command") - } - } return container.Name, container.NetworkSettings.IPAddress, nil } diff --git a/pkg/docker/entrypoint.go b/pkg/docker/entrypoint.go new file mode 100644 index 000000000..a0503c64f --- /dev/null +++ b/pkg/docker/entrypoint.go @@ -0,0 +1,38 @@ +// Copyright 2022 The envd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package docker + +import ( + "fmt" + "strings" + + "github.com/tensorchord/envd/pkg/editor/jupyter" + "github.com/tensorchord/envd/pkg/lang/ir" +) + +const ( + template = `set -e +/var/envd/bin/envd-ssh --no-auth & +%s +wait -n` +) + +func entrypointSH(g ir.Graph, workingDir string) string { + if g.JupyterConfig != nil { + cmds := jupyter.GenerateCommand(g, workingDir) + return fmt.Sprintf(template, strings.Join(cmds, " ")) + } + return fmt.Sprintf(template, "") +} diff --git a/pkg/editor/jupyter/util.go b/pkg/editor/jupyter/util.go index 17e5ffc82..8330442f1 100644 --- a/pkg/editor/jupyter/util.go +++ b/pkg/editor/jupyter/util.go @@ -20,9 +20,9 @@ import ( "github.com/tensorchord/envd/pkg/lang/ir" ) -func GenerateCommand(g ir.Graph, notebookDir string) ([]string, error) { +func GenerateCommand(g ir.Graph, notebookDir string) []string { if g.JupyterConfig == nil { - return nil, nil + return nil } cmd := []string{ @@ -40,5 +40,5 @@ func GenerateCommand(g ir.Graph, notebookDir string) ([]string, error) { p := strconv.Itoa(int(g.JupyterConfig.Port)) cmd = append(cmd, "--port", p) } - return cmd, nil + return cmd } diff --git a/pkg/lang/ir/graph.go b/pkg/lang/ir/graph.go index ea02ee543..578d3f73d 100644 --- a/pkg/lang/ir/graph.go +++ b/pkg/lang/ir/graph.go @@ -39,11 +39,12 @@ func NewGraph() *Graph { CUDA: nil, CUDNN: nil, BuiltinSystemPackages: []string{ - // They are used by vscode remote. + // TODO(gaocegege): Move them into the base image. "curl", "openssh-client", "git", "sudo", + "tini", }, PyPIPackages: []string{}, @@ -168,7 +169,7 @@ func (g Graph) compilePyPIPackages(root llb.State) llb.State { } func (g Graph) compileBuiltinSystemPackages(root llb.State) llb.State { - // TODO(gaocegege): Refactor it to avoid configure shell in built-in system packages. + // TODO(gaocegege): Refactor it to avoid shell configuration in built-in system packages. // Do not need to install bash or sh since it is built-in if g.Shell == shellZSH { g.BuiltinSystemPackages = append(g.BuiltinSystemPackages, shellZSH) @@ -213,7 +214,6 @@ func (g Graph) compileSystemPackages(root llb.State) llb.State { // Compose the package install command. var sb strings.Builder - // TODO(gaocegege): Support per-user config to keep the mirror. sb.WriteString("apt-get install -y --no-install-recommends") for _, pkg := range g.SystemPackages { diff --git a/pkg/progress/compileui/types.go b/pkg/progress/compileui/types.go index 0bc2c01f5..9056bcf47 100644 --- a/pkg/progress/compileui/types.go +++ b/pkg/progress/compileui/types.go @@ -1,3 +1,17 @@ +// Copyright 2022 The envd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package compileui import (