Skip to content

Improve caching #1755

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

Merged
merged 5 commits into from
Mar 11, 2019
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
34 changes: 25 additions & 9 deletions pkg/skaffold/build/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,7 @@ func NewCache(ctx context.Context, builder Builder, opts *skafconfig.SkaffoldOpt
}
client, err := newDockerCilent()
if err != nil {
logrus.Warnf("Error retrieving local daemon client, not using skaffold cache: %v", err)
return noCache
logrus.Warnf("Error retrieving local daemon client; local daemon will not be used as a cache: %v", err)
}
imageList, err := client.ImageList(ctx, types.ImageListOptions{})
if err != nil {
Expand Down Expand Up @@ -230,7 +229,7 @@ func (c *Cache) retrieveCachedArtifactDetails(ctx context.Context, a *latest.Art
needsRebuild: true,
}, nil
}
hashTag := fmt.Sprintf("%s:%s", a.ImageName, hash)
hashTag := HashTag(a)

// Check if we are using a local cluster
var existsRemotely bool
Expand All @@ -239,8 +238,14 @@ func (c *Cache) retrieveCachedArtifactDetails(ctx context.Context, a *latest.Art
existsRemotely = imageExistsRemotely(hashTag, imageDetails.Digest)
}

if existsRemotely {
return &cachedArtifactDetails{
hashTag: hashTag,
}, nil
}

// See if this image exists in the local daemon
if c.client.ImageExists(ctx, hashTag) {
if c.client != nil && c.client.ImageExists(ctx, hashTag) {
return &cachedArtifactDetails{
needsPush: (!existsRemotely && !localCluster) || (localCluster && c.needsPush),
hashTag: hashTag,
Expand Down Expand Up @@ -325,9 +330,12 @@ func (c *Cache) CacheArtifacts(ctx context.Context, artifacts []*latest.Artifact
if digest == "" {
logrus.Debugf("couldn't get image digest for %s, will try to cache just image id (expected with a local cluster)", tags[a.ImageName])
}
id, err := c.client.ImageID(ctx, tags[a.ImageName])
if err != nil {
logrus.Debugf("couldn't get image id for %s", tags[a.ImageName])
var id string
if c.client != nil {
id, err = c.client.ImageID(ctx, tags[a.ImageName])
if err != nil {
logrus.Debugf("couldn't get image id for %s", tags[a.ImageName])
}
}
if id == "" && digest == "" {
logrus.Debugf("both image id and digest are empty for %s, skipping caching", tags[a.ImageName])
Expand All @@ -343,7 +351,7 @@ func (c *Cache) CacheArtifacts(ctx context.Context, artifacts []*latest.Artifact

// Retag retags newly built images in the format [imageName:workspaceHash] and pushes them if using a remote cluster
func (c *Cache) Retag(ctx context.Context, out io.Writer, artifactsToBuild []*latest.Artifact, buildArtifacts []Artifact) {
if !c.useCache || len(artifactsToBuild) == 0 {
if !c.useCache || len(artifactsToBuild) == 0 || c.client == nil {
return
}
tags := map[string]string{}
Expand All @@ -369,8 +377,12 @@ func (c *Cache) Retag(ctx context.Context, out io.Writer, artifactsToBuild []*la
}
}

// Check local daemon for img digest
// Check local daemon for img digest, check remote digest if that doesn't work
func (c *Cache) retrieveImageDigest(ctx context.Context, img string) (string, error) {
if c.client == nil {
// Check for remote digest
return docker.RemoteDigest(img)
}
repoDigest, err := c.client.RepoDigest(ctx, img)
if err != nil {
return docker.RemoteDigest(img)
Expand Down Expand Up @@ -430,3 +442,7 @@ func cacheHasher(p string) (string, error) {
}
return hex.EncodeToString(h.Sum(nil)), nil
}

func HashTag(a *latest.Artifact) string {
return fmt.Sprintf("%s:%s", a.ImageName, a.WorkspaceHash)
}
29 changes: 21 additions & 8 deletions pkg/skaffold/build/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ func TestRetrieveCachedArtifactDetails(t *testing.T) {
artifact *latest.Artifact
hashes map[string]string
digest string
api testutil.FakeAPIClient
api *testutil.FakeAPIClient
cache *Cache
expected *cachedArtifactDetails
}{
Expand All @@ -299,7 +299,7 @@ func TestRetrieveCachedArtifactDetails(t *testing.T) {
name: "image in cache and exists remotely, remote cluster",
artifact: &latest.Artifact{ImageName: "image"},
hashes: map[string]string{"image": "hash"},
api: testutil.FakeAPIClient{
api: &testutil.FakeAPIClient{
TagToImageID: map[string]string{"image:hash": "image:tag"},
ImageSummaries: []types.ImageSummary{
{
Expand All @@ -322,7 +322,7 @@ func TestRetrieveCachedArtifactDetails(t *testing.T) {
artifact: &latest.Artifact{ImageName: "image"},
hashes: map[string]string{"image": "hash"},
localCluster: true,
api: testutil.FakeAPIClient{
api: &testutil.FakeAPIClient{
TagToImageID: map[string]string{"image:hash": "image:tag"},
ImageSummaries: []types.ImageSummary{
{
Expand Down Expand Up @@ -356,10 +356,7 @@ func TestRetrieveCachedArtifactDetails(t *testing.T) {
},
digest: digest,
expected: &cachedArtifactDetails{
needsRetag: true,
needsPush: true,
prebuiltImage: "anotherimage:hash",
hashTag: "image:hash",
hashTag: "image:hash",
},
},
{
Expand Down Expand Up @@ -408,6 +405,20 @@ func TestRetrieveCachedArtifactDetails(t *testing.T) {
hashTag: "image:hash",
},
},
{
name: "no local daemon, image exists remotely",
artifact: &latest.Artifact{ImageName: "image"},
hashes: map[string]string{"image": "hash"},
cache: &Cache{
useCache: true,
needsPush: true,
artifactCache: ArtifactCache{"hash": ImageDetails{Digest: digest}},
},
digest: digest,
expected: &cachedArtifactDetails{
hashTag: "image:hash",
},
},
}

for _, test := range tests {
Expand All @@ -434,7 +445,9 @@ func TestRetrieveCachedArtifactDetails(t *testing.T) {
remoteDigest = originalRemoteDigest
}()

test.cache.client = docker.NewLocalDaemon(&test.api, nil)
if test.api != nil {
test.cache.client = docker.NewLocalDaemon(test.api, nil)
}
actual, err := test.cache.retrieveCachedArtifactDetails(context.Background(), test.artifact)
if err != nil {
t.Fatalf("error retrieving artifact details: %v", err)
Expand Down
6 changes: 6 additions & 0 deletions pkg/skaffold/build/kaniko/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"io"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/kaniko/sources"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes"
Expand Down Expand Up @@ -57,6 +58,11 @@ func (b *Builder) run(ctx context.Context, out io.Writer, artifact *latest.Artif
args = append(args, b.AdditionalFlags...)
args = append(args, docker.GetBuildArgs(artifact.DockerArtifact)...)

if artifact.WorkspaceHash != "" {
hashTag := build.HashTag(artifact)
args = append(args, []string{"--destination", hashTag}...)
}

if b.Cache != nil {
args = append(args, "--cache=true")
if b.Cache.Repo != "" {
Expand Down
25 changes: 16 additions & 9 deletions pkg/skaffold/plugin/environments/gcb/desc.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package gcb
import (
"fmt"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/defaults"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
Expand All @@ -28,7 +29,12 @@ import (
)

func (b *Builder) buildDescription(artifact *latest.Artifact, tag, bucket, object string) (*cloudbuild.Build, error) {
steps, err := b.buildSteps(artifact, tag)
tags := []string{tag}
if artifact.WorkspaceHash != "" {
tags = append(tags, build.HashTag(artifact))
}

steps, err := b.buildSteps(artifact, tags)
if err != nil {
return nil, err
}
Expand All @@ -42,7 +48,7 @@ func (b *Builder) buildDescription(artifact *latest.Artifact, tag, bucket, objec
},
},
Steps: steps,
Images: []string{tag},
Images: tags,
Options: &cloudbuild.BuildOptions{
DiskSizeGb: b.DiskSizeGb,
MachineType: b.MachineType,
Expand All @@ -51,28 +57,29 @@ func (b *Builder) buildDescription(artifact *latest.Artifact, tag, bucket, objec
}, nil
}

func (b *Builder) buildSteps(artifact *latest.Artifact, tag string) ([]*cloudbuild.BuildStep, error) {
func (b *Builder) buildSteps(artifact *latest.Artifact, tags []string) ([]*cloudbuild.BuildStep, error) {
switch {
case artifact.BuilderPlugin != nil:
return b.pluginBuildSteps(artifact, tag)
return b.pluginBuildSteps(artifact, tags)
case artifact.DockerArtifact != nil:
return b.dockerBuildSteps(artifact.DockerArtifact, tag), nil
return b.dockerBuildSteps(artifact.DockerArtifact, tags), nil

case artifact.BazelArtifact != nil:
return nil, errors.New("skaffold can't build a bazel artifact with Google Cloud Build")

// TODO: build multiple tagged images with jib in GCB (priyawadhwa@)
case artifact.JibMavenArtifact != nil:
return b.jibMavenBuildSteps(artifact.JibMavenArtifact, tag), nil
return b.jibMavenBuildSteps(artifact.JibMavenArtifact, tags[0]), nil

case artifact.JibGradleArtifact != nil:
return b.jibGradleBuildSteps(artifact.JibGradleArtifact, tag), nil
return b.jibGradleBuildSteps(artifact.JibGradleArtifact, tags[0]), nil

default:
return nil, fmt.Errorf("undefined artifact type: %+v", artifact.ArtifactType)
}
}

func (b *Builder) pluginBuildSteps(artifact *latest.Artifact, tag string) ([]*cloudbuild.BuildStep, error) {
func (b *Builder) pluginBuildSteps(artifact *latest.Artifact, tags []string) ([]*cloudbuild.BuildStep, error) {
switch artifact.BuilderPlugin.Name {
case constants.DockerBuilderPluginName:
var da *latest.DockerArtifact
Expand All @@ -83,7 +90,7 @@ func (b *Builder) pluginBuildSteps(artifact *latest.Artifact, tag string) ([]*cl
da = &latest.DockerArtifact{}
}
defaults.SetDefaultDockerArtifact(da)
return b.dockerBuildSteps(da, tag), nil
return b.dockerBuildSteps(da, tags), nil
default:
return nil, errors.Errorf("the '%s' builder is not supported", artifact.BuilderPlugin.Name)
}
Expand Down
8 changes: 6 additions & 2 deletions pkg/skaffold/plugin/environments/gcb/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
cloudbuild "google.golang.org/api/cloudbuild/v1"
)

func (b *Builder) dockerBuildSteps(artifact *latest.DockerArtifact, tag string) []*cloudbuild.BuildStep {
func (b *Builder) dockerBuildSteps(artifact *latest.DockerArtifact, tags []string) []*cloudbuild.BuildStep {
var steps []*cloudbuild.BuildStep

for _, cacheFrom := range artifact.CacheFrom {
Expand All @@ -35,7 +35,11 @@ func (b *Builder) dockerBuildSteps(artifact *latest.DockerArtifact, tag string)
})
}

args := append([]string{"build", "--tag", tag, "-f", artifact.DockerfilePath})
args := []string{"build"}
for _, t := range tags {
args = append(args, []string{"--tag", t}...)
}
args = append(args, []string{"-f", artifact.DockerfilePath}...)
args = append(args, docker.GetBuildArgs(artifact)...)
args = append(args, ".")

Expand Down
2 changes: 1 addition & 1 deletion pkg/skaffold/plugin/environments/gcb/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func TestPullCacheFrom(t *testing.T) {
DockerImage: "docker/docker",
},
}
steps := builder.dockerBuildSteps(artifact, "nginx2")
steps := builder.dockerBuildSteps(artifact, []string{"nginx2"})

expected := []*cloudbuild.BuildStep{{
Name: "docker/docker",
Expand Down