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

feat: add support for build arguments when building Docker images usi… #569

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package system

import (
"context"
"fmt"
"strings"

"github.com/celestiaorg/knuu/pkg/builder"
Expand Down Expand Up @@ -73,8 +74,6 @@ func (s *Suite) TestBuildFromGitWithModifications() {
})
s.Require().NoError(err)

s.Require().NoError(target.Build().SetStartCommand("sleep", "infinity"))

const (
filePath = "/home/hello.txt"
expectedData = "Hello, world!"
Expand All @@ -92,3 +91,44 @@ func (s *Suite) TestBuildFromGitWithModifications() {

s.Assert().Equal([]byte(expectedData), gotData, "file bytes do not match.")
}

func (s *Suite) TestBuildWithBuildArgs() {
const (
namePrefix = "build-from-git-with-build-args"
maxRetries = 3

// This file is created by the dockerfile in the repo
// ref: https://github.com/celestiaorg/knuu/blob/test/build-from-git/Dockerfile
filePath = "/test.txt"
expectedData = "Hello, build arg!"
)

s.T().Log("Creating new instance")
target, err := s.Knuu.NewInstance(namePrefix)
s.Require().NoError(err)

s.T().Log("Setting git repo")
ctx := context.Background()
err = target.Build().SetGitRepo(ctx,
builder.GitContext{
Repo: gitRepo,
Branch: gitBranch,
Username: "",
Password: "",
},
&builder.BuildArg{
Value: fmt.Sprintf("MESSAGE=%s", expectedData),
},
)
s.Require().NoError(err)
s.Require().NoError(target.Build().Commit(ctx))

s.Require().NoError(target.Execution().Start(ctx))

gotData, err := target.Storage().GetFileBytes(ctx, filePath)
s.Require().NoError(err)

gotData = []byte(strings.TrimSpace(string(gotData)))

s.Assert().Equal([]byte(expectedData), gotData, "file bytes do not match.")
}
39 changes: 39 additions & 0 deletions pkg/builder/args.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package builder

const buildArgKey = "--build-arg"

type ArgInterface interface {
GetKey() string
GetValue() string
}

// BuildArg is a build argument that can be passed to the builder.
type BuildArg struct {
Value string
}

var _ ArgInterface = &BuildArg{}

func (b *BuildArg) GetKey() string {
return buildArgKey
}

func (b *BuildArg) GetValue() string {
return b.Value
}

// CustomArg is a custom argument that can be passed to the builder.
type CustomArg struct {
Key string
Value string
}

var _ ArgInterface = &CustomArg{}

func (c *CustomArg) GetKey() string {
return c.Key
}

func (c *CustomArg) GetValue() string {
return c.Value
}
2 changes: 1 addition & 1 deletion pkg/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type Builder interface {
type BuilderOptions struct {
ImageName string
BuildContext string
Args []string
Args []ArgInterface
Destination string
Cache *CacheOptions
}
Expand Down
61 changes: 35 additions & 26 deletions pkg/builder/kaniko/kaniko.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,10 @@ func (k *Kaniko) prepareJob(ctx context.Context, b *builder.BuilderOptions) (*ba
return nil, ErrParsingQuantity.Wrap(err)
}

parallelism := DefaultParallelism
backoffLimit := DefaultBackoffLimit
var (
parallelism = DefaultParallelism
backoffLimit = DefaultBackoffLimit
)
job := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: jobName,
Expand All @@ -158,15 +160,7 @@ func (k *Kaniko) prepareJob(ctx context.Context, b *builder.BuilderOptions) (*ba
{
Name: kanikoContainerName,
Image: kanikoImage, // debug has a shell
Args: []string{
`--context=` + b.BuildContext,
// TODO: see if we need it or not
// --git gitoptions Branch to clone if build context is a git repository (default branch=,single-branch=false,recurse-submodules=false)

// TODO: we might need to add some options to get the auth token for the registry
"--destination=" + b.Destination,
// "--verbosity=debug", // log level
},
Args: prepareArgs(b),
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceEphemeralStorage: ephemeralStorage,
Expand All @@ -187,21 +181,6 @@ func (k *Kaniko) prepareJob(ctx context.Context, b *builder.BuilderOptions) (*ba
}
}

// TODO: we need to add some configs to get the auth token for the cache repo
if b.Cache != nil && b.Cache.Enabled {
cacheArgs := []string{"--cache=true"}
if b.Cache.Dir != "" {
cacheArgs = append(cacheArgs, "--cache-dir="+b.Cache.Dir)
}
if b.Cache.Repo != "" {
cacheArgs = append(cacheArgs, "--cache-repo="+b.Cache.Repo)
}
job.Spec.Template.Spec.Containers[0].Args = append(job.Spec.Template.Spec.Containers[0].Args, cacheArgs...)
}

// Add extra args
job.Spec.Template.Spec.Containers[0].Args = append(job.Spec.Template.Spec.Containers[0].Args, b.Args...)

return job, nil
}

Expand Down Expand Up @@ -272,3 +251,33 @@ func (k *Kaniko) mountDir(ctx context.Context, bCtx string, job *batchv1.Job) (*

return job, nil
}

func prepareArgs(b *builder.BuilderOptions) []string {
args := []string{
"--context=" + b.BuildContext,
// TODO: see if we need it or not
// --git gitoptions Branch to clone if build context is a git repository (default branch=,single-branch=false,recurse-submodules=false)

// TODO: we might need to add some options to get the auth token for the registry
"--destination=" + b.Destination,
// "--verbosity=debug", // log level
}

// TODO: we need to add some configs to get the auth token for the cache repo
if b.Cache != nil && b.Cache.Enabled {
args = append(args, "--cache=true")
if b.Cache.Dir != "" {
args = append(args, "--cache-dir="+b.Cache.Dir)
}
if b.Cache.Repo != "" {
args = append(args, "--cache-repo="+b.Cache.Repo)
}
}

// Append other args e.g. build args
for _, a := range b.Args {
args = append(args, fmt.Sprintf("%s=%s", a.GetKey(), a.GetValue()))
}

return args
}
2 changes: 1 addition & 1 deletion pkg/builder/kaniko/kaniko_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func TestKanikoBuilder(t *testing.T) {
ImageName: testImage,
BuildContext: blCtx,
Destination: testDestination,
Args: []string{"--build-arg=value"},
Args: []builder.ArgInterface{&builder.BuildArg{Value: "SOME_ARG=some_value"}},
Cache: cacheOpts,
}

Expand Down
6 changes: 5 additions & 1 deletion pkg/container/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ type BuilderFactory struct {
imageBuilder builder.Builder
dockerFileInstructions []string
buildContext string
args []builder.ArgInterface
}

// NewBuilderFactory creates a new instance of BuilderFactory.
func NewBuilderFactory(imageName, buildContext string, imageBuilder builder.Builder) (*BuilderFactory, error) {
func NewBuilderFactory(imageName, buildContext string, imageBuilder builder.Builder, args []builder.ArgInterface) (*BuilderFactory, error) {
if err := os.MkdirAll(buildContext, 0755); err != nil {
return nil, ErrFailedToCreateContextDir.Wrap(err)
}
Expand All @@ -34,6 +35,7 @@ func NewBuilderFactory(imageName, buildContext string, imageBuilder builder.Buil
dockerFileInstructions: []string{"FROM " + imageName},
buildContext: buildContext,
imageBuilder: imageBuilder,
args: args,
}, nil
}

Expand Down Expand Up @@ -96,6 +98,7 @@ func (f *BuilderFactory) PushBuilderImage(ctx context.Context, imageName string)
ImageName: f.imageNameTo,
Destination: f.imageNameTo, // in docker the image name and destination are the same
BuildContext: builder.DirContext{Path: f.buildContext}.BuildContext(),
Args: f.args,
})

qStatus := logrus.TextFormatter{}.DisableQuote
Expand Down Expand Up @@ -133,6 +136,7 @@ func (f *BuilderFactory) BuildImageFromGitRepo(ctx context.Context, gitCtx build
Destination: imageName,
BuildContext: buildCtx,
Cache: cOpts,
Args: f.args,
})

qStatus := logrus.TextFormatter{}.DisableQuote
Expand Down
8 changes: 4 additions & 4 deletions pkg/instance/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (b *build) SetImagePullPolicy(pullPolicy v1.PullPolicy) {

// SetImage sets the image of the instance.
// It is only allowed in the 'None' and 'Preparing' states.
func (b *build) SetImage(ctx context.Context, image string) error {
func (b *build) SetImage(ctx context.Context, image string, args ...builder.ArgInterface) error {
if !b.instance.IsInState(StateNone, StatePreparing, StateStopped) {
if b.instance.sidecars.IsSidecar() {
return ErrSettingImageNotAllowedForSidecarsStarted
Expand All @@ -54,7 +54,7 @@ func (b *build) SetImage(ctx context.Context, image string) error {
}

// Use the builder to build a new image
factory, err := container.NewBuilderFactory(image, b.getBuildDir(), b.instance.ImageBuilder)
factory, err := container.NewBuilderFactory(image, b.getBuildDir(), b.instance.ImageBuilder, args)
if err != nil {
return ErrCreatingBuilder.Wrap(err)
}
Expand All @@ -66,7 +66,7 @@ func (b *build) SetImage(ctx context.Context, image string) error {

// SetGitRepo builds the image from the given git repo, pushes it
// to the registry under the given name and sets the image of the instance.
func (b *build) SetGitRepo(ctx context.Context, gitContext builder.GitContext) error {
func (b *build) SetGitRepo(ctx context.Context, gitContext builder.GitContext, args ...builder.ArgInterface) error {
if !b.instance.IsState(StateNone) {
return ErrSettingGitRepo.WithParams(b.instance.state.String())
}
Expand All @@ -80,7 +80,7 @@ func (b *build) SetGitRepo(ctx context.Context, gitContext builder.GitContext) e
return ErrGettingImageName.Wrap(err)
}

factory, err := container.NewBuilderFactory(imageName, b.getBuildDir(), b.instance.ImageBuilder)
factory, err := container.NewBuilderFactory(imageName, b.getBuildDir(), b.instance.ImageBuilder, args)
if err != nil {
return ErrCreatingBuilder.Wrap(err)
}
Expand Down
Loading