Skip to content

Commit 0613141

Browse files
committed
Remove filesystem image layer cache
The image layer cache was not thread-safe and caused random redhat_manifests.redhat_manifests_missing violations when validating multiple images sharing layers (#1109). All Tekton tasks already disabled it via EC_CACHE=false, and benchmarking showed no measurable performance gain from caching. Remove the cache entirely rather than fixing it: - Remove imgCache/initCache and cache.Image wrapping from OCI client - Remove EC_CACHE env var from Tekton task definitions - Remove EC_CACHE=false from benchmark setup - Remove related test (TestCacheInit) and simplify TestImage - Remove stale caching TODO in Layer() Ref: EC-1706 Ref: EC-1669 Signed-off-by: Rob Nester <rnester@redhat.com> Assisted-by: Cursor Made-with: Cursor
1 parent b84ac3b commit 0613141

6 files changed

Lines changed: 25 additions & 109 deletions

File tree

benchmark/simple/simple.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,6 @@ func ec(dir string) func() {
9797
}`, dir)
9898

9999
return func() {
100-
101-
os.Setenv("EC_CACHE", "false")
102-
103100
if err := suite.Execute([]string{
104101
"validate",
105102
"image",

internal/utils/oci/client.go

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,11 @@ import (
2020
"context"
2121
"fmt"
2222
"net/http"
23-
"os"
24-
"path"
2523
"runtime/trace"
26-
"strconv"
27-
"sync"
2824

2925
"github.com/google/go-containerregistry/pkg/authn"
3026
"github.com/google/go-containerregistry/pkg/name"
3127
v1 "github.com/google/go-containerregistry/pkg/v1"
32-
"github.com/google/go-containerregistry/pkg/v1/cache"
3328
"github.com/google/go-containerregistry/pkg/v1/remote"
3429
"github.com/sigstore/cosign/v3/pkg/cosign"
3530
"github.com/sigstore/cosign/v3/pkg/oci"
@@ -43,28 +38,6 @@ type contextKey string
4338

4439
const clientContextKey contextKey = "ec.oci.client"
4540

46-
var imgCache = sync.OnceValue(initCache)
47-
48-
func initCache() cache.Cache {
49-
// if a value was set and it is parsed as false, turn the cache off
50-
if v, err := strconv.ParseBool(os.Getenv("EC_CACHE")); err == nil && !v {
51-
return nil
52-
}
53-
54-
if userCache, err := os.UserCacheDir(); err != nil {
55-
log.Debug("unable to find user cache directory")
56-
return nil
57-
} else {
58-
imgCacheDir := path.Join(userCache, "ec", "images")
59-
if err := os.MkdirAll(imgCacheDir, 0700); err != nil {
60-
log.Debugf("unable to create temporary directory for image cache in %q: %v", imgCacheDir, err)
61-
return nil
62-
}
63-
log.Debugf("using %q directory to store image cache", imgCacheDir)
64-
return cache.NewFilesystemCache(imgCacheDir)
65-
}
66-
}
67-
6841
func CreateRemoteOptions(ctx context.Context) []remote.Option {
6942
backoff := remote.Backoff{
7043
Duration: echttp.DefaultBackoff.Duration,
@@ -217,16 +190,7 @@ func (c *defaultClient) Image(ref name.Reference) (v1.Image, error) {
217190
trace.Logf(c.ctx, "", "image=%q", ref)
218191
}
219192

220-
img, err := remote.Image(ref, c.opts...)
221-
if err != nil {
222-
return nil, err
223-
}
224-
225-
if c := imgCache(); c != nil {
226-
img = cache.Image(img, c)
227-
}
228-
229-
return img, nil
193+
return remote.Image(ref, c.opts...)
230194
}
231195

232196
func (c *defaultClient) Layer(ref name.Digest) (v1.Layer, error) {
@@ -236,8 +200,6 @@ func (c *defaultClient) Layer(ref name.Digest) (v1.Layer, error) {
236200
trace.Logf(c.ctx, "", "image=%q", ref)
237201
}
238202

239-
// TODO: Caching a layer directly is difficult and may not be possible, see:
240-
// https://github.com/google/go-containerregistry/issues/1821
241203
layer, err := remote.Layer(ref, c.opts...)
242204
if err != nil {
243205
return nil, fmt.Errorf("fetching layer: %w", err)

internal/utils/oci/client_test.go

Lines changed: 24 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@
1919
package oci
2020

2121
import (
22-
"bytes"
2322
"context"
2423
"fmt"
2524
"io"
2625
"log"
2726
"net/http"
2827
"net/http/httptest"
2928
"net/url"
30-
"strings"
3129
"testing"
3230

3331
"github.com/google/go-containerregistry/pkg/authn"
@@ -101,25 +99,11 @@ func TestCreateRemoteOptions(t *testing.T) {
10199
}
102100
}
103101

104-
func TestCacheInit(t *testing.T) {
105-
// by default the cache should be on
106-
assert.NotNil(t, initCache())
107-
108-
t.Setenv("EC_CACHE", "false")
109-
assert.Nil(t, initCache())
110-
111-
t.Cleanup(func() {
112-
t.Setenv("EC_CACHE", "true")
113-
assert.NotNil(t, initCache())
114-
})
115-
}
116-
117102
func TestImage(t *testing.T) {
118103
img, err := random.Image(4096, 2)
119104
require.NoError(t, err)
120105

121-
l := &bytes.Buffer{}
122-
registry := httptest.NewServer(registry.New(registry.Logger(log.New(l, "", 0))))
106+
registry := httptest.NewServer(registry.New(registry.Logger(log.New(io.Discard, "", 0))))
123107
t.Cleanup(registry.Close)
124108

125109
u, err := url.Parse(registry.URL)
@@ -130,35 +114,30 @@ func TestImage(t *testing.T) {
130114

131115
require.NoError(t, remote.Push(ref, img))
132116

133-
fetchFully := func() {
134-
client := defaultClient{}
117+
client := defaultClient{}
118+
fetched, err := client.Image(ref)
119+
require.NoError(t, err)
120+
121+
layers, err := fetched.Layers()
122+
require.NoError(t, err)
123+
assert.Len(t, layers, 2)
135124

136-
img, err := client.Image(ref)
137-
require.NoError(t, err)
138-
layers, err := img.Layers()
139-
require.NoError(t, err)
140-
for _, l := range layers {
125+
for _, l := range layers {
126+
func() {
141127
r, err := l.Uncompressed()
142128
require.NoError(t, err)
129+
defer r.Close()
143130
_, err = io.ReadAll(r)
144131
require.NoError(t, err)
145-
}
132+
}()
146133
}
147-
148-
fetchFully()
149-
fetchFully()
150-
fetchFully()
151-
152-
blobDownloadCount := strings.Count(l.String(), "GET /v2/repository/image/blobs/sha256:")
153-
assert.Equal(t, 5, blobDownloadCount) // three configs fetched each time and two layers fetched only once
154134
}
155135

156136
func TestLayer(t *testing.T) {
157137
layer, err := random.Layer(1024, types.OCIUncompressedLayer)
158138
require.NoError(t, err)
159139

160-
l := &bytes.Buffer{}
161-
registry := httptest.NewServer(registry.New(registry.Logger(log.New(l, "", 0))))
140+
registry := httptest.NewServer(registry.New(registry.Logger(log.New(io.Discard, "", 0))))
162141
t.Cleanup(registry.Close)
163142

164143
u, err := url.Parse(registry.URL)
@@ -174,24 +153,20 @@ func TestLayer(t *testing.T) {
174153
require.NoError(t, err)
175154
layerURI := fmt.Sprintf("%s@%s", uri, digest)
176155

177-
fetchCount := 5
178-
for i := 0; i < fetchCount; i++ {
179-
d, err := name.NewDigest(layerURI)
180-
require.NoError(t, err)
156+
d, err := name.NewDigest(layerURI)
157+
require.NoError(t, err)
181158

182-
client := defaultClient{}
183-
l, err := client.Layer(d)
159+
client := defaultClient{}
160+
fetched, err := client.Layer(d)
161+
require.NoError(t, err)
184162

185-
require.NoError(t, err)
186-
r, err := l.Uncompressed()
187-
require.NoError(t, err)
188-
_, err = io.ReadAll(r)
189-
require.NoError(t, err)
190-
}
163+
r, err := fetched.Uncompressed()
164+
require.NoError(t, err)
165+
defer r.Close()
191166

192-
msg := fmt.Sprintf("GET /v2/repository/image/blobs/%s", digest)
193-
blobDownloadCount := strings.Count(l.String(), msg)
194-
assert.Equal(t, fetchCount, blobDownloadCount)
167+
data, err := io.ReadAll(r)
168+
require.NoError(t, err)
169+
assert.NotEmpty(t, data)
195170
}
196171

197172
func TestScopedAuth(t *testing.T) {

tasks/verify-conforma-konflux-ta/0.1/verify-conforma-konflux-ta.yaml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -505,11 +505,6 @@ spec:
505505
# value expected by Tekton Pipelines. NOTE: If params.SSL_CERT_DIR is empty, the value
506506
# will contain a trailing ":" - this is ok.
507507
value: "/tekton-custom-certs:/etc/ssl/certs:/etc/pki/tls/certs:/system/etc/security/cacerts:$(params.SSL_CERT_DIR)"
508-
# The EC cache is used to avoid fetching the same image layers from the registry more than
509-
# once. However, this is not thread safe. This results in inconsistencies when extracting
510-
# files from an image, see https://github.com/conforma/cli/issues/1109
511-
- name: EC_CACHE
512-
value: "false"
513508
computeResources:
514509
requests:
515510
cpu: 250m

tasks/verify-conforma-konflux-vsa-ta/0.1/verify-conforma-konflux-vsa-ta.yaml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,6 @@ spec:
290290
- name: SSL_CERT_DIR
291291
value: >-
292292
/tekton-custom-certs:/etc/ssl/certs:/etc/pki/tls/certs:/system/etc/security/cacerts:$(params.SSL_CERT_DIR)
293-
- name: EC_CACHE
294-
value: "false"
295293
computeResources:
296294
requests:
297295
cpu: 100m
@@ -371,12 +369,6 @@ spec:
371369
# trailing ":" - this is ok.
372370
value: >-
373371
/tekton-custom-certs:/etc/ssl/certs:/etc/pki/tls/certs:/system/etc/security/cacerts:$(params.SSL_CERT_DIR)
374-
# The EC cache is used to avoid fetching the same image layers
375-
# from the registry more than once. However, this is not thread
376-
# safe. This results in inconsistencies when extracting files from
377-
# an image, see https://github.com/conforma/cli/issues/1109
378-
- name: EC_CACHE
379-
value: "false"
380372
computeResources:
381373
requests:
382374
cpu: 100m

tasks/verify-enterprise-contract/0.1/verify-enterprise-contract.yaml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -396,11 +396,6 @@ spec:
396396
# value expected by Tekton Pipelines. NOTE: If params.SSL_CERT_DIR is empty, the value
397397
# will contain a trailing ":" - this is ok.
398398
value: "/tekton-custom-certs:/etc/ssl/certs:/etc/pki/tls/certs:/system/etc/security/cacerts:$(params.SSL_CERT_DIR)"
399-
# The EC cache is used to avoid fetching the same image layers from the registry more than
400-
# once. However, this is not thread safe. This results in inconsistencies when extracting
401-
# files from an image, see https://github.com/conforma/cli/issues/1109
402-
- name: EC_CACHE
403-
value: "false"
404399
computeResources:
405400
requests:
406401
cpu: 1800m

0 commit comments

Comments
 (0)