Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Commit

Permalink
Use bundled deps file with function file(url+zip etc.) (#1206)
Browse files Browse the repository at this point in the history
  • Loading branch information
SaigyoujiYuyuko233 authored Jan 8, 2021
1 parent 8eb6b46 commit 51d84f3
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 11 deletions.
15 changes: 15 additions & 0 deletions docs/advanced-function-deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ As any Kubernetes object, function objects have a maximum size of 1.5MiB (due to
function-content-type: url+zip
```

## Functions with bundled deps file

Since the dependencies file(for python runtime: ``requirement.txt``) will become long and difficult to put into kubernetes object as function getting complex, Kubeless support use the deps file in remote zip file with function.

Usage:

- 1.Compress your function and dependencies file(in this case: ``requirement.txt``) into a zip file
- 2.add ``+deps`` into ``function-content-type``

```yaml
checksum: sha256:d1f84e9f0a8ce27e7d9ce6f457126a8f92e957e5109312e7996373f658015547
function: https://github.com/kubeless/kubeless/blob/master/examples/nodejs/hellowithbundleddeps.zip?raw=true
function-content-type: url+zip+deps
```

## Custom Deployment

It is possible to specify a [`Deployment` spec](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#creating-a-deployment) in the Function spec that will be merged with default values set by the Kubeless controller. It is not necessary to specify all the fields of the deployment, just the fields you are interested on overwriting. For example:
Expand Down
Binary file added examples/python/hellowithbundleddeps.zip
Binary file not shown.
16 changes: 11 additions & 5 deletions pkg/langruntime/langruntime.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,17 @@ func (l *Langruntimes) GetBuildContainer(runtime, depsChecksum string, env []v1.
var command string
// Validate deps checksum
shaFile := "/tmp/deps.sha256"
command = appendToCommand(command,
fmt.Sprintf("echo '%s %s' > %s", depsChecksum, depsFile, shaFile),
fmt.Sprintf("sha256sum -c %s", shaFile),
imageInf.Command,
)

// if checksum exist, check sum
if depsChecksum != "" {
command = appendToCommand(command,
fmt.Sprintf("echo '%s %s' > %s", depsChecksum, depsFile, shaFile),
fmt.Sprintf("sha256sum -c %s", shaFile),
imageInf.Command,
)
} else {
command = appendToCommand(command, imageInf.Command)
}

env = append(
env,
Expand Down
30 changes: 30 additions & 0 deletions pkg/langruntime/langruntime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,33 @@ func TestGetBuildContainer(t *testing.T) {
t.Errorf("Unexpected result. Expecting:\n %+v\nReceived:\n %+v", expectedContainer, c)
}
}

func TestGetBuildContainerWithBundledDeps(t *testing.T) {
lr := SetupLangRuntime(clientset)
lr.ReadConfigMap()

// It should return the proper build image for python
vol1 := v1.VolumeMount{Name: "v1", MountPath: "/v1"}
resources := v1.ResourceRequirements{Limits: v1.ResourceList{v1.ResourceLimitsCPU: resource.MustParse("100m")}}
c, err := lr.GetBuildContainer("python2.7", "", []v1.EnvVar{}, vol1, resources)
if err != nil {
t.Errorf("Unexpected error: %s", err)
}
expectedContainer := v1.Container{
Name: "install",
Image: "python:2.7",
Command: []string{"sh", "-c"},
Args: []string{"foo"},
VolumeMounts: []v1.VolumeMount{vol1},
WorkingDir: "/v1",
ImagePullPolicy: v1.PullIfNotPresent,
Env: []v1.EnvVar{
{Name: "KUBELESS_INSTALL_VOLUME", Value: "/v1"},
{Name: "KUBELESS_DEPS_FILE", Value: "/v1/requirements.txt"},
},
Resources: v1.ResourceRequirements{Limits: v1.ResourceList{v1.ResourceLimitsCPU: resource.MustParse("100m")}},
}
if !reflect.DeepEqual(expectedContainer, c) {
t.Errorf("Unexpected result. Expecting:\n %+v\nReceived:\n %+v", expectedContainer, c)
}
}
18 changes: 12 additions & 6 deletions pkg/utils/kubelessutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func getProvisionContainer(function, checksum, fileName, handler, contentType, r

// Copy deps file to the installation path
runtimeInf, err := lr.GetRuntimeInfo(runtime)
if err == nil && runtimeInf.DepName != "" {
if err == nil && runtimeInf.DepName != "" && !strings.Contains(contentType, "deps") {
depsFile := path.Join(depsVolume.MountPath, runtimeInf.DepName)
prepareCommand = appendToCommand(prepareCommand,
fmt.Sprintf("cp %s %s", depsFile, runtimeVolume.MountPath),
Expand Down Expand Up @@ -404,13 +404,19 @@ func populatePodSpec(funcObj *kubelessApi.Function, lr *langruntime.Langruntimes
if len(result.Containers) > 0 {
envVars = result.Containers[0].Env
}
if funcObj.Spec.Deps != "" && err != nil {

hasDeps := funcObj.Spec.Deps != "" || strings.Contains(funcObj.Spec.FunctionContentType, "deps")
if hasDeps && err != nil {
return fmt.Errorf("Unable to install dependencies for the runtime %s", funcObj.Spec.Runtime)
} else if funcObj.Spec.Deps != "" {
depsChecksum, err := getChecksum(funcObj.Spec.Deps)
if err != nil {
return fmt.Errorf("Unable to obtain dependencies checksum: %v", err)
} else if hasDeps {
depsChecksum := ""
if funcObj.Spec.Deps != "" {
depsChecksum, err = getChecksum(funcObj.Spec.Deps)
if err != nil {
return fmt.Errorf("Unable to obtain dependencies checksum: %v", err)
}
}

depsInstallContainer, err := lr.GetBuildContainer(funcObj.Spec.Runtime, depsChecksum, envVars, runtimeVolumeMount, resources)
if err != nil {
return err
Expand Down
16 changes: 16 additions & 0 deletions pkg/utils/kubelessutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1056,4 +1056,20 @@ func TestGetProvisionContainer(t *testing.T) {
if !strings.Contains(c.Args[0], "tar xf /tmp/func.fromurl -C /runtime") {
t.Errorf("Unexpected command: %s", c.Args[0])
}

// if the function use bundled deps in remote zip file
c, err = getProvisionContainer("https://raw.githubusercontent.com/test/test/test/test.zip", "sha256:abc1234", "", "test.foo", "url+zip+deps", "python2.7", "unzip", rvol, dvol, resources, lr)
if err != nil {
t.Errorf("Unexpected error: %s", err)
}
if !strings.HasPrefix(c.Args[0], "curl 'https://raw.githubusercontent.com/test/test/test/test.zip' -L --silent --output /tmp/func.fromurl") {
t.Errorf("Unexpected command: %s", c.Args[0])
}
if !strings.Contains(c.Args[0], "unzip -o /tmp/func.fromurl -d /runtime") {
t.Errorf("Unexpected command: %s", c.Args[0])
}
// use bundled deps will not copy the requirements.txt to /runtime
if strings.Contains(c.Args[0], "cp /deps/requirements.txt /runtime") {
t.Errorf("Unexpected command: %s", c.Args[0])
}
}

0 comments on commit 51d84f3

Please sign in to comment.