Skip to content
Open
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
12 changes: 12 additions & 0 deletions fetch_issues.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import urllib.request, json
req = urllib.request.Request("https://api.github.com/repos/devspace-sh/devspace/issues?state=open&sort=created&direction=desc&per_page=40")
req.add_header('User-Agent', 'python-urllib')
try:
with urllib.request.urlopen(req) as response:
data = json.loads(response.read().decode())
for issue in data:
if issue['number'] in [3179, 3174, 3106]:
print(f"--- ISSUE #{issue['number']} ---")
print(issue['body'][:1000])
except Exception as e:
print(e)
92 changes: 46 additions & 46 deletions pkg/devspace/build/builder/buildkit/buildkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@ import (
"strconv"
"strings"
"time"

"github.com/loft-sh/devspace/pkg/devspace/pipeline/env"
"mvdan.cc/sh/v3/expand"

devspacecontext "github.com/loft-sh/devspace/pkg/devspace/context"
command2 "github.com/loft-sh/utils/pkg/command"

cliconfig "github.com/docker/cli/cli/config"
"github.com/docker/docker/api/types/build"
"github.com/loft-sh/devspace/pkg/devspace/build/builder/helper"
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
dockerpkg "github.com/loft-sh/devspace/pkg/devspace/docker"
"github.com/loft-sh/devspace/pkg/devspace/kubectl"
logpkg "github.com/loft-sh/devspace/pkg/util/log"
"github.com/pkg/errors"
"k8s.io/client-go/tools/clientcmd"
"github.com/docker/docker/api/types/build"
)

// EngineName is the name of the building engine
Expand All @@ -49,7 +49,7 @@ func NewBuilder(ctx devspacecontext.Context, imageConf *latest.Image, imageTags
return nil, err
}
}

return &Builder{
helper: helper.NewBuildHelper(ctx, EngineName, imageConf, imageTags),
skipPush: skipPush,
Expand All @@ -68,23 +68,23 @@ func (b *Builder) ShouldRebuild(ctx devspacecontext.Context, forceRebuild bool)
imageCache, _ := ctx.Config().LocalCache().GetImageCache(b.helper.ImageConf.Name)
imageName := imageCache.ResolveImage() + ":" + imageCache.Tag
rebuild, err := b.helper.ShouldRebuild(ctx, forceRebuild)

// Check if image is present in local docker daemon
if !rebuild && err == nil && b.helper.ImageConf.BuildKit.InCluster == nil {
if b.skipPushOnLocalKubernetes && ctx.KubeClient() != nil && kubectl.IsLocalKubernetes(ctx.KubeClient()) {
dockerClient, err := dockerpkg.NewClientWithMinikube(ctx.Context(), ctx.KubeClient(), b.helper.ImageConf.BuildKit.PreferMinikube == nil || *b.helper.ImageConf.BuildKit.PreferMinikube, ctx.Log())
if err != nil {
return false, err
}

found, err := b.helper.IsImageAvailableLocally(ctx, dockerClient)
if !found && err == nil {
ctx.Log().Infof("Rebuild image %s because it was not found in local docker daemon", imageName)
return true, nil
}
}
}

return rebuild, err
}

Expand All @@ -93,32 +93,32 @@ func (b *Builder) ShouldRebuild(ctx devspacecontext.Context, forceRebuild bool)
// dockerfilePath is the absolute path to the dockerfile WITHIN the contextPath
func (b *Builder) BuildImage(ctx devspacecontext.Context, contextPath, dockerfilePath string, entrypoint []string, cmd []string) error {
buildKitConfig := b.helper.ImageConf.BuildKit

// create the builder
builder, err := ensureBuilder(ctx.Context(), ctx.WorkingDir(), ctx.Environ(), ctx.KubeClient(), buildKitConfig, ctx.Log())
if err != nil {
return err
}

// create the context stream
body, writer, _, buildOptions, err := b.helper.CreateContextStream(contextPath, dockerfilePath, entrypoint, cmd, ctx.Log())
defer writer.Close()
if err != nil {
return err
}

// We skip pushing when it is the minikube client
usingLocalKubernetes := ctx.KubeClient() != nil && kubectl.IsLocalKubernetes(ctx.KubeClient())
if b.skipPushOnLocalKubernetes && usingLocalKubernetes {
b.skipPush = true
}

// Should we use the minikube docker daemon?
useMinikubeDocker := false
if ctx.KubeClient() != nil && kubectl.IsMinikubeKubernetes(ctx.KubeClient()) && (buildKitConfig.PreferMinikube == nil || *buildKitConfig.PreferMinikube) {
useMinikubeDocker = true
}

// Should we build with cli?
skipPush := b.skipPush || b.helper.ImageConf.SkipPush
return buildWithCLI(ctx.Context(), ctx.WorkingDir(), ctx.Environ(), body, writer, ctx.KubeClient(), builder, buildKitConfig, *buildOptions, useMinikubeDocker, skipPush, ctx.Log())
Expand All @@ -129,14 +129,14 @@ func buildWithCLI(ctx context.Context, dir string, environ expand.Environ, conte
if len(imageConf.Command) > 0 {
command = imageConf.Command
}

args := []string{"build"}
if options.BuildArgs != nil {
for k, v := range options.BuildArgs {
if v == nil {
continue
}

args = append(args, "--build-arg", k+"="+*v)
}
}
Expand Down Expand Up @@ -167,9 +167,9 @@ func buildWithCLI(ctx context.Context, dir string, environ expand.Environ, conte
return err
}
defer os.Remove(tempFile)

args = append(args, "--builder", builder)

// TODO: find a better solution than this
// we wait here a little bit, otherwise it might be possible that we get issues during
// parallel image building, as it seems that docker buildx has problems if the
Expand All @@ -178,14 +178,14 @@ func buildWithCLI(ctx context.Context, dir string, environ expand.Environ, conte
time.Sleep(time.Millisecond * time.Duration(rand.Intn(3000)+500))
}
args = append(args, imageConf.Args...)

args = append(args, "-")

log.Infof("Execute BuildKit command with: %s %s", strings.Join(command, " "), strings.Join(args, " "))
completeArgs := []string{}
completeArgs = append(completeArgs, command[1:]...)
completeArgs = append(completeArgs, args...)

var (
minikubeEnv map[string]string
err error
Expand All @@ -200,7 +200,7 @@ func buildWithCLI(ctx context.Context, dir string, environ expand.Environ, conte
if err != nil {
return err
}

if skipPush && kubeClient != nil && kubectl.GetKindContext(kubeClient.CurrentContext()) != "" {
// Load image if it is a kind-context
for _, tag := range options.Tags {
Expand All @@ -214,7 +214,7 @@ func buildWithCLI(ctx context.Context, dir string, environ expand.Environ, conte
log.Info("Image loaded to kind cluster")
}
}

return nil
}

Expand All @@ -240,27 +240,27 @@ func ensureBuilder(ctx context.Context, workingDir string, environ expand.Enviro
} else if kubeClient == nil {
return "", fmt.Errorf("cannot build in cluster wth build kit without a correct kubernetes context")
}

namespace := kubeClient.Namespace()
if imageConf.InCluster.Namespace != "" {
namespace = imageConf.InCluster.Namespace
}

name := "devspace-" + namespace
if imageConf.InCluster.Name != "" {
name = imageConf.InCluster.Name
}

// check if we should skip
if imageConf.InCluster.NoCreate {
return name, nil
}

command := []string{"docker", "buildx"}
if len(imageConf.Command) > 0 {
command = imageConf.Command
}

args := []string{"create", "--driver", "kubernetes", "--driver-opt", "namespace=" + namespace, "--name", name}
if imageConf.InCluster.Rootless {
args = append(args, "--driver-opt", "rootless=true")
Expand All @@ -274,38 +274,38 @@ func ensureBuilder(ctx context.Context, workingDir string, environ expand.Enviro
if len(imageConf.InCluster.CreateArgs) > 0 {
args = append(args, imageConf.InCluster.CreateArgs...)
}

completeArgs := []string{}
completeArgs = append(completeArgs, command[1:]...)
completeArgs = append(completeArgs, args...)

// check if builder already exists
builderPath := filepath.Join(getConfigStorePath(), "instances", name)
_, err := os.Stat(builderPath)
if err == nil {
if imageConf.InCluster.NoRecreate {
return name, nil
}

// update the builder if necessary
b, err := os.ReadFile(builderPath)
if err != nil {
log.Warnf("Error reading builder %s: %v", builderPath, err)
return name, nil
}

// parse builder config
ng := &NodeGroup{}
err = json.Unmarshal(b, ng)
if err != nil {
log.Warnf("Error decoding builder %s: %v", builderPath, err)
return name, nil
}

// check for: correct driver name, driver opts
if strings.ToLower(ng.Driver) == "kubernetes" && len(ng.Nodes) == 1 {
node := ng.Nodes[0]

// check driver options
namespaceCorrect := node.DriverOpts["namespace"] == namespace
if node.DriverOpts["rootless"] == "" {
Expand All @@ -314,28 +314,28 @@ func ensureBuilder(ctx context.Context, workingDir string, environ expand.Enviro
rootlessCorrect := strconv.FormatBool(imageConf.InCluster.Rootless) == node.DriverOpts["rootless"]
imageCorrect := imageConf.InCluster.Image == node.DriverOpts["image"]
nodeSelectorCorrect := imageConf.InCluster.NodeSelector == node.DriverOpts["nodeselector"]

// if builder up to date, exit here
if namespaceCorrect && rootlessCorrect && imageCorrect && nodeSelectorCorrect {
return name, nil
}
}

// recreate the builder
log.Infof("Recreate BuildKit builder because builder options differ")

// create a temporary kube context
tempFile, err := tempKubeContextFromClient(kubeClient)
if err != nil {
return "", err
}
defer os.Remove(tempFile)

// prepare the command
rmArgs := []string{}
rmArgs = append(rmArgs, command[1:]...)
rmArgs = append(rmArgs, "rm", name)

// execute the command
out, err := command2.CombinedOutput(ctx, workingDir, env.NewVariableEnvProvider(environ, map[string]string{
"KUBECONFIG": tempFile,
Expand All @@ -344,10 +344,10 @@ func ensureBuilder(ctx context.Context, workingDir string, environ expand.Enviro
log.Warnf("error deleting BuildKit builder: %s => %v", string(out), err)
}
}

// create the builder
log.Infof("Create BuildKit builder with: %s %s", strings.Join(command, " "), strings.Join(args, " "))

// This is necessary because docker would otherwise save the used kube config
// which we don't want because we will override it with our own temp kube config
// during building.
Expand All @@ -359,7 +359,7 @@ func ensureBuilder(ctx context.Context, workingDir string, environ expand.Enviro
return "", fmt.Errorf("error creating BuildKit builder: %s => %v", string(out), err)
}
}

return name, nil
}

Expand All @@ -370,7 +370,7 @@ func getConfigStorePath() string {
if buildxConfig := os.Getenv("BUILDX_CONFIG"); buildxConfig != "" {
return buildxConfig
}

stderr := &bytes.Buffer{}
configFile := cliconfig.LoadDefaultConfigFile(stderr)
buildxConfig := filepath.Join(filepath.Dir(configFile.Filename), "buildx")
Expand All @@ -385,21 +385,21 @@ func tempKubeContextFromClient(kubeClient kubectl.Client) (string, error) {
if !kubeClient.IsInCluster() {
rawConfig.CurrentContext = kubeClient.CurrentContext()
}

bytes, err := clientcmd.Write(rawConfig)
if err != nil {
return "", err
}

tempFile, err := os.CreateTemp("", "")
if err != nil {
return "", err
}

_, err = tempFile.Write(bytes)
if err != nil {
return "", errors.Wrap(err, "error writing to file")
}

return tempFile.Name(), nil
}
Loading