github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/build/local/local.go (about)

     1  /*
     2  Copyright 2019 The Skaffold Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package local
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  
    24  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
    25  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
    26  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output"
    27  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
    28  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/platform"
    29  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
    30  )
    31  
    32  // Build runs a docker build on the host and tags the resulting image with
    33  // its checksum. It streams build progress to the writer argument.
    34  func (b *Builder) Build(ctx context.Context, out io.Writer, a *latest.Artifact) build.ArtifactBuilder {
    35  	if b.prune {
    36  		b.localPruner.asynchronousCleanupOldImages(ctx, []string{a.ImageName})
    37  	}
    38  	builder := build.WithLogFile(b.buildArtifact, b.muted)
    39  	return builder
    40  }
    41  
    42  func (b *Builder) PreBuild(_ context.Context, out io.Writer) error {
    43  	if b.localCluster {
    44  		output.Default.Fprintf(out, "Found [%s] context, using local docker daemon.\n", b.kubeContext)
    45  	}
    46  	return nil
    47  }
    48  
    49  func (b *Builder) PostBuild(ctx context.Context, _ io.Writer) error {
    50  	defer b.localDocker.Close()
    51  	if b.prune {
    52  		if b.mode == config.RunModes.Build {
    53  			b.localPruner.synchronousCleanupOldImages(ctx, b.builtImages)
    54  		} else {
    55  			b.localPruner.asynchronousCleanupOldImages(ctx, b.builtImages)
    56  		}
    57  	}
    58  	return nil
    59  }
    60  
    61  func (b *Builder) Concurrency() *int { return b.local.Concurrency }
    62  
    63  func (b *Builder) PushImages() bool {
    64  	return b.pushImages
    65  }
    66  
    67  func (b *Builder) SupportedPlatforms() platform.Matcher { return platform.All }
    68  
    69  func (b *Builder) buildArtifact(ctx context.Context, out io.Writer, a *latest.Artifact, tag string, platforms platform.Matcher) (string, error) {
    70  	digestOrImageID, err := b.runBuildForArtifact(ctx, out, a, tag, platforms)
    71  	if err != nil {
    72  		return "", err
    73  	}
    74  
    75  	if b.pushImages {
    76  		// only track images for pruning when building with docker
    77  		// if we're pushing a bazel image, it was built directly to the registry
    78  		if a.DockerArtifact != nil {
    79  			imageID, err := b.getImageIDForTag(ctx, tag)
    80  			if err != nil {
    81  				log.Entry(ctx).Warn("unable to inspect image: built images may not be cleaned up correctly by skaffold")
    82  			}
    83  			if imageID != "" {
    84  				b.builtImages = append(b.builtImages, imageID)
    85  			}
    86  		}
    87  
    88  		digest := digestOrImageID
    89  		return build.TagWithDigest(tag, digest), nil
    90  	}
    91  
    92  	imageID := digestOrImageID
    93  	b.builtImages = append(b.builtImages, imageID)
    94  	return build.TagWithImageID(ctx, tag, imageID, b.localDocker)
    95  }
    96  
    97  func (b *Builder) runBuildForArtifact(ctx context.Context, out io.Writer, a *latest.Artifact, tag string, platforms platform.Matcher) (string, error) {
    98  	if !b.pushImages {
    99  		// All of the builders will rely on a local Docker:
   100  		// + Either to build the image,
   101  		// + Or to docker load it.
   102  		// Let's fail fast if Docker is not available
   103  		if _, err := b.localDocker.ServerVersion(ctx); err != nil {
   104  			return "", err
   105  		}
   106  	}
   107  
   108  	builder, err := newPerArtifactBuilder(b, a)
   109  	if err != nil {
   110  		return "", err
   111  	}
   112  	if platforms.IsNotEmpty() {
   113  		supported := builder.SupportedPlatforms()
   114  		if p := platforms.Intersect(supported); p.IsNotEmpty() {
   115  			platforms = p
   116  		} else {
   117  			return "", fmt.Errorf("builder for artifact %q doesn't support building for target platforms: %q. Supported platforms are %q", a.ImageName, platforms, supported)
   118  		}
   119  	}
   120  	return builder.Build(ctx, out, a, tag, platforms)
   121  }
   122  
   123  func (b *Builder) getImageIDForTag(ctx context.Context, tag string) (string, error) {
   124  	insp, _, err := b.localDocker.ImageInspectWithRaw(ctx, tag)
   125  	if err != nil {
   126  		return "", err
   127  	}
   128  	return insp.ID, nil
   129  }
   130  
   131  func (b *Builder) retrieveExtraEnv() []string {
   132  	return b.localDocker.ExtraEnv()
   133  }