Skip to content
Permalink
Browse files
feat(buildah): add low level dockerfile stage builder
Signed-off-by: Ilya Lesikov <ilya@lesikov.com>
  • Loading branch information
ilya-lesikov committed Oct 4, 2022
1 parent d1965ae commit 76c98c66e08faa5153c9c62af476885936836e83
Show file tree
Hide file tree
Showing 14 changed files with 548 additions and 143 deletions.
@@ -4,15 +4,13 @@ import (
"context"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"

"github.com/opencontainers/runtime-spec/specs-go"

"github.com/werf/werf/pkg/buildah"
"github.com/werf/werf/pkg/util"
"github.com/werf/werf/pkg/werf"
)

@@ -81,32 +79,12 @@ func runDockerfile(ctx context.Context, mode buildah.Mode, dockerfilePath, conte
return fmt.Errorf("unable to create buildah client: %w", err)
}

dockerfileData, err := os.ReadFile(dockerfilePath)
if err != nil {
return fmt.Errorf("error reading %q: %w", dockerfilePath, err)
}

errCh := make(chan error, 0)
buildDoneCh := make(chan string, 0)

var contextTar io.Reader
if contextDir != "" {
contextTar = util.BufferedPipedWriterProcess(func(w io.WriteCloser) {
if err := util.WriteDirAsTar((contextDir), w); err != nil {
errCh <- fmt.Errorf("unable to write dir %q as tar: %w", contextDir, err)
return
}

if err := w.Close(); err != nil {
errCh <- fmt.Errorf("unable to close buffered piped writer for context dir %q: %w", contextDir, err)
return
}
})
}

go func() {
imageID, err := b.BuildFromDockerfile(ctx, dockerfileData, buildah.BuildFromDockerfileOpts{
ContextTar: contextTar,
imageID, err := b.BuildFromDockerfile(ctx, dockerfilePath, buildah.BuildFromDockerfileOpts{
ContextDir: contextDir,
CommonOpts: buildah.CommonOpts{
LogWriter: os.Stdout,
},
@@ -636,10 +636,10 @@ func (phase *BuildPhase) prepareStageInstructions(ctx context.Context, img *imag
for key, value := range serviceLabels {
labels = append(labels, fmt.Sprintf("%s=%v", key, value))
}
stageImage.Builder.DockerfileStageBuilder().AppendLabels(labels...)
stageImage.Builder.DockerfileBuilder().AppendLabels(labels...)

phase.Conveyor.AppendOnTerminateFunc(func() error {
return stageImage.Builder.DockerfileStageBuilder().Cleanup(ctx)
return stageImage.Builder.DockerfileBuilder().Cleanup(ctx)
})

default:
@@ -750,7 +750,7 @@ func (phase *BuildPhase) atomicBuildStageImage(ctx context.Context, img *image.I
if err := logboek.Context(ctx).Streams().DoErrorWithTag(fmt.Sprintf("%s/%s", img.LogName(), stg.Name()), img.LogTagStyle(), func() error {
switch {
case stg.Name() == "dockerfile":
return stageImage.Builder.DockerfileStageBuilder().Build(ctx)
return stageImage.Builder.DockerfileBuilder().Build(ctx)
case phase.Conveyor.UseLegacyStapelBuilder(phase.Conveyor.ContainerBackend):
return stageImage.Builder.LegacyStapelStageBuilder().Build(ctx, phase.ImageBuildOptions)
default:
@@ -117,16 +117,16 @@ func CheckImageDependenciesAfterPrepare(img *LegacyImageStub, stageBuilder *stag
}

if dep.TargetBuildArgImageName != "" {
Expect(util.IsStringsContainValue(stageBuilder.GetDockerfileStageBuilderImplementation().BuildDockerfileOptions.BuildArgs, fmt.Sprintf("%s=%s", dep.TargetBuildArgImageName, dep.GetDockerImageName()))).To(BeTrue())
Expect(util.IsStringsContainValue(stageBuilder.GetDockerfileBuilderImplementation().BuildDockerfileOptions.BuildArgs, fmt.Sprintf("%s=%s", dep.TargetBuildArgImageName, dep.GetDockerImageName()))).To(BeTrue())
}
if dep.TargetBuildArgImageRepo != "" {
Expect(util.IsStringsContainValue(stageBuilder.GetDockerfileStageBuilderImplementation().BuildDockerfileOptions.BuildArgs, fmt.Sprintf("%s=%s", dep.TargetBuildArgImageRepo, dep.DockerImageRepo))).To(BeTrue())
Expect(util.IsStringsContainValue(stageBuilder.GetDockerfileBuilderImplementation().BuildDockerfileOptions.BuildArgs, fmt.Sprintf("%s=%s", dep.TargetBuildArgImageRepo, dep.DockerImageRepo))).To(BeTrue())
}
if dep.TargetBuildArgImageTag != "" {
Expect(util.IsStringsContainValue(stageBuilder.GetDockerfileStageBuilderImplementation().BuildDockerfileOptions.BuildArgs, fmt.Sprintf("%s=%s", dep.TargetBuildArgImageTag, dep.DockerImageTag))).To(BeTrue())
Expect(util.IsStringsContainValue(stageBuilder.GetDockerfileBuilderImplementation().BuildDockerfileOptions.BuildArgs, fmt.Sprintf("%s=%s", dep.TargetBuildArgImageTag, dep.DockerImageTag))).To(BeTrue())
}
if dep.TargetBuildArgImageID != "" {
Expect(util.IsStringsContainValue(stageBuilder.GetDockerfileStageBuilderImplementation().BuildDockerfileOptions.BuildArgs, fmt.Sprintf("%s=%s", dep.TargetBuildArgImageID, dep.DockerImageID))).To(BeTrue())
Expect(util.IsStringsContainValue(stageBuilder.GetDockerfileBuilderImplementation().BuildDockerfileOptions.BuildArgs, fmt.Sprintf("%s=%s", dep.TargetBuildArgImageID, dep.DockerImageID))).To(BeTrue())
}
}
}
@@ -696,16 +696,16 @@ func (s *DockerfileStage) PrepareImage(ctx context.Context, c Conveyor, cr conta
return err
}

if err := s.SetupDockerImageBuilder(stageImage.Builder.DockerfileStageBuilder(), c); err != nil {
if err := s.SetupDockerImageBuilder(stageImage.Builder.DockerfileBuilder(), c); err != nil {
return err
}

stageImage.Builder.DockerfileStageBuilder().SetContextArchivePath(archivePath)
stageImage.Builder.DockerfileBuilder().SetContextArchivePath(archivePath)

stageImage.Builder.DockerfileStageBuilder().AppendLabels(fmt.Sprintf("%s=%s", image.WerfProjectRepoCommitLabel, c.GiterminismManager().HeadCommit()))
stageImage.Builder.DockerfileBuilder().AppendLabels(fmt.Sprintf("%s=%s", image.WerfProjectRepoCommitLabel, c.GiterminismManager().HeadCommit()))

if c.GiterminismManager().Dev() {
stageImage.Builder.DockerfileStageBuilder().AppendLabels(fmt.Sprintf("%s=true", image.WerfDevLabel))
stageImage.Builder.DockerfileBuilder().AppendLabels(fmt.Sprintf("%s=true", image.WerfDevLabel))
}

return nil
@@ -746,7 +746,7 @@ func (s *DockerfileStage) prepareContextArchive(ctx context.Context, giterminism
return archivePath, nil
}

func (s *DockerfileStage) SetupDockerImageBuilder(b stage_builder.DockerfileStageBuilderInterface, c Conveyor) error {
func (s *DockerfileStage) SetupDockerImageBuilder(b stage_builder.DockerfileBuilderInterface, c Conveyor) error {
b.SetDockerfile(s.dockerfile)
b.SetDockerfileCtxRelPath(s.dockerfilePath)

@@ -38,9 +38,13 @@ type CommonOpts struct {
LogWriter io.Writer
}

type BuildFromCommandsOpts struct {
CommonOpts
}

type BuildFromDockerfileOpts struct {
CommonOpts
ContextTar io.Reader
ContextDir string
BuildArgs map[string]string
Target string
}
@@ -81,6 +85,19 @@ type ConfigOpts struct {
User string
Workdir string
Healthcheck string
OnBuild string
StopSignal string
Shell []string
}

type CopyOpts struct {
CommonOpts
From string
}

type AddOpts struct {
CommonOpts
ContextDir string
}

type (
@@ -96,7 +113,7 @@ type (
type Buildah interface {
Tag(ctx context.Context, ref, newRef string, opts TagOpts) error
Push(ctx context.Context, ref string, opts PushOpts) error
BuildFromDockerfile(ctx context.Context, dockerfile []byte, opts BuildFromDockerfileOpts) (string, error)
BuildFromDockerfile(ctx context.Context, dockerfile string, opts BuildFromDockerfileOpts) (string, error)
RunCommand(ctx context.Context, container string, command []string, opts RunCommandOpts) error
FromCommand(ctx context.Context, container, image string, opts FromCommandOpts) (string, error)
Pull(ctx context.Context, ref string, opts PullOpts) error
@@ -107,6 +124,8 @@ type Buildah interface {
Umount(ctx context.Context, container string, opts UmountOpts) error
Commit(ctx context.Context, container string, opts CommitOpts) (string, error)
Config(ctx context.Context, container string, opts ConfigOpts) error
Copy(ctx context.Context, container, contextDir string, src []string, dst string, opts CopyOpts) error
Add(ctx context.Context, container string, src []string, dst string, opts AddOpts) error
}

type Mode string
@@ -37,7 +37,6 @@ import (
"github.com/sirupsen/logrus"
"gopkg.in/errgo.v2/fmt/errors"

"github.com/werf/logboek"
"github.com/werf/werf/pkg/buildah/thirdparty"
"github.com/werf/werf/pkg/util"
)
@@ -229,7 +228,7 @@ func (b *NativeBuildah) Push(ctx context.Context, ref string, opts PushOpts) err
return nil
}

func (b *NativeBuildah) BuildFromDockerfile(ctx context.Context, dockerfile []byte, opts BuildFromDockerfileOpts) (string, error) {
func (b *NativeBuildah) BuildFromDockerfile(ctx context.Context, dockerfile string, opts BuildFromDockerfileOpts) (string, error) {
buildOpts := define.BuildOptions{
Isolation: define.Isolation(b.Isolation),
Args: opts.BuildArgs,
@@ -257,20 +256,11 @@ func (b *NativeBuildah) BuildFromDockerfile(ctx context.Context, dockerfile []by
buildOpts.Err = errLog
}

sessionTmpDir, contextTmpDir, dockerfileTmpPath, err := b.prepareBuildFromDockerfile(dockerfile, opts.ContextTar)
if err != nil {
return "", fmt.Errorf("error preparing for build from dockerfile: %w", err)
}
defer func() {
if err = os.RemoveAll(sessionTmpDir); err != nil {
logboek.Warn().LogF("unable to remove session tmp dir %q: %s\n", sessionTmpDir, err)
}
}()
buildOpts.ContextDirectory = contextTmpDir
buildOpts.ContextDirectory = opts.ContextDir

imageId, _, err := imagebuildah.BuildDockerfiles(ctx, b.Store, buildOpts, dockerfileTmpPath)
imageId, _, err := imagebuildah.BuildDockerfiles(ctx, b.Store, buildOpts, dockerfile)
if err != nil {
return "", fmt.Errorf("unable to build Dockerfile %q:\n%s\n%w", dockerfileTmpPath, errLog.String(), err)
return "", fmt.Errorf("unable to build Dockerfile %q:\n%s\n%w", dockerfile, errLog.String(), err)
}

return imageId, nil
@@ -475,6 +465,10 @@ func (b *NativeBuildah) Config(ctx context.Context, container string, opts Confi
builder.SetPort(expose)
}

if len(opts.Shell) > 0 {
builder.SetShell(opts.Shell)
}

if len(opts.Cmd) > 0 {
builder.SetCmd(opts.Cmd)
}
@@ -499,9 +493,49 @@ func (b *NativeBuildah) Config(ctx context.Context, container string, opts Confi
}
}

if opts.StopSignal != "" {
builder.SetStopSignal(opts.StopSignal)
}

if opts.OnBuild != "" {
builder.SetOnBuild(opts.OnBuild)
}

return builder.Save()
}

func (b *NativeBuildah) Copy(ctx context.Context, container, contextDir string, src []string, dst string, opts CopyOpts) error {
builder, err := b.getBuilderFromContainer(ctx, container)
if err != nil {
return fmt.Errorf("error getting builder: %w", err)
}

if err := builder.Add(dst, false, buildah.AddAndCopyOptions{
PreserveOwnership: false,
ContextDir: contextDir,
}, src...); err != nil {
return fmt.Errorf("error copying files to %q: %w", dst, err)
}

return nil
}

func (b *NativeBuildah) Add(ctx context.Context, container string, src []string, dst string, opts AddOpts) error {
builder, err := b.getBuilderFromContainer(ctx, container)
if err != nil {
return fmt.Errorf("error getting builder: %w", err)
}

if err := builder.Add(dst, true, buildah.AddAndCopyOptions{
PreserveOwnership: false,
ContextDir: opts.ContextDir,
}, src...); err != nil {
return fmt.Errorf("error adding files to %q: %w", dst, err)
}

return nil
}

func (b *NativeBuildah) getImage(ref string) (*libimage.Image, error) {
image, _, err := b.Runtime.LookupImage(ref, &libimage.LookupImageOptions{
ManifestList: true,

0 comments on commit 76c98c6

Please sign in to comment.