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

Support parallel local builds (defaults to sequential) #3471

Merged
merged 1 commit into from
Jan 8, 2020
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
8 changes: 7 additions & 1 deletion docs/content/en/schemas/v2alpha2.json
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,11 @@
},
"LocalBuild": {
"properties": {
"concurrency": {
"type": "integer",
"description": "how many artifacts can be built concurrently. 0 means \"no-limit\" Defaults to 1.",
"x-intellij-html-description": "how many artifacts can be built concurrently. 0 means "no-limit" Defaults to 1."
},
"push": {
"type": "boolean",
"description": "should images be pushed to a registry. If not specified, images are pushed only if the current Kubernetes context connects to a remote cluster.",
Expand All @@ -1673,7 +1678,8 @@
"preferredOrder": [
"push",
"useDockerCLI",
"useBuildkit"
"useBuildkit",
"concurrency"
],
"additionalProperties": false,
"description": "*beta* describes how to do a build on the local docker daemon and optionally push to a repository.",
Expand Down
2 changes: 1 addition & 1 deletion pkg/skaffold/build/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (b *Builder) Build(ctx context.Context, out io.Writer, tags tag.ImageTags,
defer b.localDocker.Close()

// TODO(dgageot): parallel builds
return build.InSequence(ctx, out, tags, artifacts, b.buildArtifact)
return build.InParallel(ctx, out, tags, artifacts, b.buildArtifact, *b.cfg.Concurrency)
}

func (b *Builder) buildArtifact(ctx context.Context, out io.Writer, artifact *latest.Artifact, tag string) (string, error) {
Expand Down
8 changes: 5 additions & 3 deletions pkg/skaffold/build/local/local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/event"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext"
Expand Down Expand Up @@ -226,7 +227,8 @@ func TestLocalRun(t *testing.T) {
})

builder, err := NewBuilder(stubRunContext(latest.LocalBuild{
Push: util.BoolPtr(test.pushImages),
Push: util.BoolPtr(test.pushImages),
Concurrency: &constants.DefaultLocalConcurrency,
}))
t.CheckNoError(err)

Expand Down Expand Up @@ -272,7 +274,7 @@ func TestNewBuilder(t *testing.T) {
},
shouldErr: false,
expectedBuilder: &Builder{
cfg: &latest.LocalBuild{},
cfg: latest.LocalBuild{},
kubeContext: "",
localDocker: dummyDaemon,
localCluster: false,
Expand All @@ -298,7 +300,7 @@ func TestNewBuilder(t *testing.T) {
shouldErr: false,
expectedBuilder: &Builder{
pushImages: false, //this will be false too
cfg: &latest.LocalBuild{ // and the config is inherited
cfg: latest.LocalBuild{ // and the config is inherited
Push: util.BoolPtr(false),
},
kubeContext: "",
Expand Down
4 changes: 2 additions & 2 deletions pkg/skaffold/build/local/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (

// Builder uses the host docker daemon to build and tag the image.
type Builder struct {
cfg *latest.LocalBuild
cfg latest.LocalBuild

localDocker docker.LocalDaemon
localCluster bool
Expand Down Expand Up @@ -72,7 +72,7 @@ func NewBuilder(runCtx *runcontext.RunContext) (*Builder, error) {
}

return &Builder{
cfg: runCtx.Cfg.Build.LocalBuild,
cfg: *runCtx.Cfg.Build.LocalBuild,
kubeContext: runCtx.KubeContext,
localDocker: localDocker,
localCluster: localCluster,
Expand Down
2 changes: 2 additions & 0 deletions pkg/skaffold/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ const (
var (
Pod latest.ResourceType = "pod"
Service latest.ResourceType = "service"

DefaultLocalConcurrency = 1
)

var (
Expand Down
22 changes: 20 additions & 2 deletions pkg/skaffold/schema/defaults/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ func Set(c *latest.SkaffoldConfig) error {
}
}

withLocalBuild(c,
setDefaultConcurrency,
)

withCloudBuildConfig(c,
setDefaultCloudBuildDockerImage,
setDefaultCloudBuildMavenImage,
Expand Down Expand Up @@ -103,7 +107,21 @@ func defaultToKubectlDeploy(c *latest.SkaffoldConfig) {
c.Deploy.DeployType.KubectlDeploy = &latest.KubectlDeploy{}
}

func withCloudBuildConfig(c *latest.SkaffoldConfig, operations ...func(kaniko *latest.GoogleCloudBuild)) {
func withLocalBuild(c *latest.SkaffoldConfig, operations ...func(*latest.LocalBuild)) {
if local := c.Build.LocalBuild; local != nil {
for _, operation := range operations {
operation(local)
}
}
}

func setDefaultConcurrency(local *latest.LocalBuild) {
if local.Concurrency == nil {
local.Concurrency = &constants.DefaultLocalConcurrency
}
}

func withCloudBuildConfig(c *latest.SkaffoldConfig, operations ...func(*latest.GoogleCloudBuild)) {
if gcb := c.Build.GoogleCloudBuild; gcb != nil {
for _, operation := range operations {
operation(gcb)
Expand Down Expand Up @@ -182,7 +200,7 @@ func setDefaultWorkspace(a *latest.Artifact) {
a.Workspace = valueOrDefault(a.Workspace, ".")
}

func withClusterConfig(c *latest.SkaffoldConfig, opts ...func(cluster *latest.ClusterDetails) error) error {
func withClusterConfig(c *latest.SkaffoldConfig, opts ...func(*latest.ClusterDetails) error) error {
clusterDetails := c.Build.BuildType.Cluster
if clusterDetails == nil {
return nil
Expand Down
9 changes: 9 additions & 0 deletions pkg/skaffold/schema/defaults/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,15 @@ func TestSetDefaultsOnCloudBuild(t *testing.T) {
testutil.CheckDeepEqual(t, constants.DefaultCloudBuildGradleImage, cfg.Build.GoogleCloudBuild.GradleImage)
}

func TestSetDefaultsOnLocalBuild(t *testing.T) {
cfg := &latest.SkaffoldConfig{}

err := Set(cfg)

testutil.CheckError(t, false, err)
testutil.CheckDeepEqual(t, 1, *cfg.Build.LocalBuild.Concurrency)
}

func TestSetDefaultPortForwardNamespace(t *testing.T) {
tests := []struct {
description string
Expand Down
4 changes: 4 additions & 0 deletions pkg/skaffold/schema/latest/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ type LocalBuild struct {

// UseBuildkit use BuildKit to build Docker images.
UseBuildkit bool `yaml:"useBuildkit,omitempty"`

// Concurrency is how many artifacts can be built concurrently. 0 means "no-limit"
// Defaults to 1.
Concurrency *int `yaml:"concurrency,omitempty"`
}

// GoogleCloudBuild *beta* describes how to do a remote build on
Expand Down
2 changes: 1 addition & 1 deletion pkg/skaffold/schema/versions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ func config(ops ...func(*latest.SkaffoldConfig)) *latest.SkaffoldConfig {

func withLocalBuild(ops ...func(*latest.BuildConfig)) func(*latest.SkaffoldConfig) {
return func(cfg *latest.SkaffoldConfig) {
b := latest.BuildConfig{BuildType: latest.BuildType{LocalBuild: &latest.LocalBuild{}}}
b := latest.BuildConfig{BuildType: latest.BuildType{LocalBuild: &latest.LocalBuild{Concurrency: &constants.DefaultLocalConcurrency}}}
for _, op := range ops {
op(&b)
}
Expand Down