github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/build/gcb/docker.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 gcb 18 19 import ( 20 "errors" 21 "fmt" 22 "os" 23 24 cloudbuild "google.golang.org/api/cloudbuild/v1" 25 26 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker" 27 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/platform" 28 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" 29 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util/stringslice" 30 ) 31 32 // dockerBuildSpec lists the build steps required to build a docker image. 33 func (b *Builder) dockerBuildSpec(a *latest.Artifact, tag string, platforms platform.Matcher) (cloudbuild.Build, error) { 34 a = adjustCacheFrom(a, tag) 35 36 args, err := b.dockerBuildArgs(a, tag, a.Dependencies, platforms) 37 if err != nil { 38 return cloudbuild.Build{}, err 39 } 40 steps := b.cacheFromSteps(a.DockerArtifact, platforms) 41 buildStep := &cloudbuild.BuildStep{ 42 Name: b.DockerImage, 43 Args: args, 44 } 45 if platforms.IsNotEmpty() { 46 // cross-platform build requires buildkit enabled 47 buildStep.Env = append(buildStep.Env, "DOCKER_BUILDKIT=1") 48 } 49 steps = append(steps, buildStep) 50 51 return cloudbuild.Build{ 52 Steps: steps, 53 Images: []string{tag}, 54 }, nil 55 } 56 57 // cacheFromSteps pulls images used by `--cache-from`. 58 func (b *Builder) cacheFromSteps(artifact *latest.DockerArtifact, platforms platform.Matcher) []*cloudbuild.BuildStep { 59 var steps []*cloudbuild.BuildStep 60 argFmt := "docker pull %s || true" 61 if platforms.IsNotEmpty() { 62 argFmt = "docker pull --platform " + platforms.String() + " %s || true" 63 } 64 for _, cacheFrom := range artifact.CacheFrom { 65 steps = append(steps, &cloudbuild.BuildStep{ 66 Name: b.DockerImage, 67 Entrypoint: "sh", 68 Args: []string{"-c", fmt.Sprintf(argFmt, cacheFrom)}, 69 }) 70 } 71 72 return steps 73 } 74 75 // dockerBuildArgs lists the arguments passed to `docker` to build a given image. 76 func (b *Builder) dockerBuildArgs(a *latest.Artifact, tag string, deps []*latest.ArtifactDependency, platforms platform.Matcher) ([]string, error) { 77 d := a.DockerArtifact 78 // TODO(nkubala): remove when buildkit is supported in GCB (#4773) 79 if len(d.Secrets) > 0 || d.SSH != "" { 80 return nil, errors.New("docker build options, secrets and ssh, are not currently supported in GCB builds") 81 } 82 requiredImages := docker.ResolveDependencyImages(deps, b.artifactStore, true) 83 buildArgs, err := docker.EvalBuildArgs(b.cfg.Mode(), a.Workspace, d.DockerfilePath, d.BuildArgs, requiredImages) 84 if err != nil { 85 return nil, fmt.Errorf("unable to evaluate build args: %w", err) 86 } 87 88 ba, err := docker.ToCLIBuildArgs(d, buildArgs) 89 if err != nil { 90 return nil, fmt.Errorf("getting docker build args: %w", err) 91 } 92 93 args := []string{"build", "--tag", tag, "-f", d.DockerfilePath} 94 if platforms.IsNotEmpty() { 95 args = append(args, "--platform", platforms.String()) 96 } 97 args = append(args, ba...) 98 args = append(args, ".") 99 100 return args, nil 101 } 102 103 // adjustCacheFrom returns an artifact where any cache references from the artifactImage is changed to the tagged built image name instead. 104 func adjustCacheFrom(a *latest.Artifact, artifactTag string) *latest.Artifact { 105 if os.Getenv("SKAFFOLD_DISABLE_GCB_CACHE_ADJUSTMENT") != "" { 106 // allow this behaviour to be disabled 107 return a 108 } 109 110 if !stringslice.Contains(a.DockerArtifact.CacheFrom, a.ImageName) { 111 return a 112 } 113 114 cf := make([]string, 0, len(a.DockerArtifact.CacheFrom)) 115 for _, image := range a.DockerArtifact.CacheFrom { 116 if image == a.ImageName { 117 cf = append(cf, artifactTag) 118 } else { 119 cf = append(cf, image) 120 } 121 } 122 copy := *a 123 copy.DockerArtifact.CacheFrom = cf 124 return © 125 }