Skip to content

Commit

Permalink
feat: add support for build arguments when building Docker images usi…
Browse files Browse the repository at this point in the history
…ng Kaniko
  • Loading branch information
mojtaba-esk committed Sep 30, 2024
1 parent f694c3a commit 599e47c
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 35 deletions.
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

0 comments on commit 599e47c

Please sign in to comment.