Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for building functions with the OpenFaaS function Builder API. #33

Merged
merged 1 commit into from
Aug 9, 2024

Conversation

welteki
Copy link
Member

@welteki welteki commented Jul 30, 2024

Description

Add a package builder to support building function using the Function Builder API

The README was updated to include a full example for building functions with a more detailed explanation for each step.

Motivation and context

Support building OpenFaaS functions from go code using the SDK.

How has this been tested

Modified the go example from the function builder examples to use the go-sdk for E2E testing.

var (
	image        string
	handler      string
	lang         string
	functionName string
	platformsStr string
	buildArgsStr string
)

func main() {
	flag.StringVar(&image, "image", "", "Docker image name to build")
	flag.StringVar(&handler, "handler", "", "Directory with handler for function, e.g. handler.js")
	flag.StringVar(&lang, "lang", "", "Language or template to use, e.g. node17")
	flag.StringVar(&functionName, "name", "", "Name of the function")
	flag.StringVar(&platformsStr, "platforms", "linux/amd64", "Comma separated list of target platforms for multi-arch image builds.")
	flag.StringVar(&buildArgsStr, "build-args", "", "Additional build arguments for the docker build in the form of key1=value1,key2=value2")
	flag.Parse()

	platforms := strings.Split(platformsStr, ",")
	buildArgs := parseBuildArgs(buildArgsStr)

	// Get the HMAC secret used for payload authentication with the builder API.
	payloadSecret, err := os.ReadFile("payload.txt")
	if err != nil {
		log.Fatal(err)
	}
	payloadSecret = bytes.TrimSpace(payloadSecret)

	// Initialize a new builder client.
	builderURL, _ := url.Parse("http://127.0.0.1:8081")
	b := builder.NewFunctionBuilder(builderURL, http.DefaultClient, builder.WithHmacAuth(string(payloadSecret)))

	// Create the function build context using the provided function handler and language template.
	buildContext, err := builder.CreateBuildContext(functionName, handler, lang, []string{})
	if err != nil {
		log.Fatalf("failed to create build context: %s", err)
	}

	// Create a temporary file for the build tar.
	tarFile, err := os.CreateTemp(os.TempDir(), "build-context-*.tar")
	if err != nil {
		log.Fatalf("failed to temporary file: %s", err)
	}
	tarFile.Close()

	tarPath := tarFile.Name()
	defer os.Remove(tarPath)

	// Configuration for the build.
	// Set the image name plus optional build arguments and target platforms for multi-arch images.
	buildConfig := builder.BuildConfig{
		Image:     image,
		Platforms: platforms,
		BuildArgs: buildArgs,
	}

	// Prepare a tar archive that contains the build config and build context.
	// By default the faas-cli shrinkwraps functions in the `build` folder in the current working directory.
	// MakeTar takes the path to the build context as the second argument.
	if err := builder.MakeTar(tarPath, buildContext, &buildConfig); err != nil {
		log.Fatal(err)
	}

	// Invoke the function builder with the tar archive containing the build config and context
	// to build and push the function image.
	result, err := b.Build(tarPath)
	if err != nil {
		log.Fatal(err)
	}

	// Print build logs
	for _, logMsg := range result.Log {
		fmt.Printf("%s\n", logMsg)
	}
}

@welteki welteki changed the title Add support for building function use the OpenFaaS function Builder API. Add support for building function with the OpenFaaS function Builder API. Jul 30, 2024
@welteki welteki changed the title Add support for building function with the OpenFaaS function Builder API. Add support for building functions with the OpenFaaS function Builder API. Jul 30, 2024
@alexellis
Copy link
Member

Just a thought b.Build is really more like b.Publish since an image is always pushed/published.

Do you have a multi-arch example too with platforms?

@alexellis
Copy link
Member

alexellis commented Aug 1, 2024

Do we perhaps want to include the BuildConfig struct and a method to write it out?

I can see that much more than just a build API call is being done via the build() function, it's not obvious from reading that from the function name.

I think the tar step and writing the config could be made more visible to the user. The goal isn't to make this more abstract, but to make it quick to integrate with using the SDK and Go.

@welteki
Copy link
Member Author

welteki commented Aug 1, 2024

I can see that much more than just a build API call is being done via the build() function, it's not obvious from reading that from the function name.

I think the tar step and writing the config could be made more visible to the user. The goal isn't to make this more abstract, but to make it quick to integrate with using the SDK and Go.

I designed this by taking a look at how we would use this SDK functionality in the faas-cli. We allow users to switch between two builders there. The local builder using docker and the remote builder using the OpenFaaS Builder API.

Both ways of building take the same argument: a build context, image name, platforms, build args, etc. Based on this config they build (and push) the function container image.

The fact that in the case of the Remote Build the build context and config are combined in a tar that needs to be send to the builder API is an implementation detail that does not need to be exposed to the caller.

However a do agree that we can take a different approach and have the SDK expose the functions that are now abstracted by the Build method.

It would by up the the users of the SDK to use these function to build a similar abstraction if needed.

Just a thought b.Build is really more like b.Publish since an image is always pushed/published.

My thought around this, building on my previous arguments is that I took a similar approach to the docker buildx command. There is a single build command and you can set the --push flag to publish. In case of the Remote builder implementation the push config parameter would always be true.

Do you have a multi-arch example too with platforms?

That is not in the REAMDE yet but I will add an example of how to specify target architectures.

@welteki
Copy link
Member Author

welteki commented Aug 2, 2024

The PR has been updated with the requested changes.

  • The builder package provides a set of functions and structs quickly integrate with the builder API without abstracting all preparation steps.
  • The config file is written to the tar archive directly instead of adding it in the provided context path first to ensure context directory is not modified.

@alexellis
Copy link
Member

This is much closer to what I had in mind.

Do you have sample arguments I can run to try it out with the tester program?

README.md Show resolved Hide resolved
builder/builder.go Outdated Show resolved Hide resolved
Copy link
Member

@alexellis alexellis left a comment

Choose a reason for hiding this comment

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

I think I'd like to change the approach to shrinkwrap before we move this forward.

@welteki
Copy link
Member Author

welteki commented Aug 9, 2024

I think I'd like to change the approach to shrinkwrap before we move this forward.

The ShrinkWrap helper function has been removed an replaced with CreateBuildContext to programmatically create a Docker build context by providing the function handler and template.

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
Signed-off-by: Han Verstraete (OpenFaaS Ltd) <han@openfaas.com>
Copy link
Member

@alexellis alexellis left a comment

Choose a reason for hiding this comment

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

Approved

@alexellis alexellis merged commit b43ff91 into openfaas:master Aug 9, 2024
1 check passed
@alexellis
Copy link
Member

OK that looks good 👍 let's get it written up quickly on the blog and the vendoring back to the CLI can come later on.

@alexellis
Copy link
Member

@welteki welteki deleted the function-builder branch August 9, 2024 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants