Skip to content

Commit 553977b

Browse files
author
Andrey Klimentyev
committed
Queue algorithm simplification
Also, prioritize checking previously failed images
1 parent a34dd18 commit 553977b

File tree

10 files changed

+221
-239
lines changed

10 files changed

+221
-239
lines changed

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ module github.com/flant/k8s-image-availability-exporter
33
go 1.16
44

55
require (
6-
github.com/emirpasic/gods v1.12.0
6+
github.com/gammazero/deque v0.1.0
77
github.com/google/go-containerregistry v0.6.0
88
github.com/prometheus/client_golang v1.11.0
99
github.com/sirupsen/logrus v1.8.1
10+
github.com/stretchr/testify v1.7.0
1011
github.com/vdemeester/k8s-pkg-credentialprovider v1.21.0
1112
k8s.io/api v0.22.2
1213
k8s.io/apimachinery v0.22.2

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,6 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
304304
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
305305
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
306306
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
307-
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
308-
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
309307
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
310308
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
311309
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -330,6 +328,8 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo
330328
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
331329
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
332330
github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
331+
github.com/gammazero/deque v0.1.0 h1:f9LnNmq66VDeuAlSAapemq/U7hJ2jpIWa4c09q8Dlik=
332+
github.com/gammazero/deque v0.1.0/go.mod h1:KQw7vFau1hHuM8xmI9RbgKFbAsQFWmBpqQ2KenFLk6M=
333333
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
334334
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
335335
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=

main.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ func main() {
6565
prometheus.MustRegister(liveTicksCounter)
6666

6767
registryChecker := registry_checker.NewRegistryChecker(
68+
stopCh,
6869
kubeClient,
6970
*insecureSkipVerify,
7071
strings.Split(*ignoredImagesStr, ","),
@@ -73,8 +74,6 @@ func main() {
7374
)
7475
prometheus.MustRegister(registryChecker)
7576

76-
registryChecker.Run(stopCh)
77-
7877
http.Handle("/metrics", promhttp.Handler())
7978
http.HandleFunc("/healthz", handlers.Healthz)
8079
go func() {
@@ -84,7 +83,7 @@ func main() {
8483
handlers.UpdateHealth(true)
8584

8685
wait.Until(func() {
87-
registryChecker.Check()
86+
registryChecker.Tick()
8887
liveTicksCounter.Inc()
8988
}, *imageCheckInterval, stopCh)
9089
}

pkg/context/context.go

Lines changed: 0 additions & 58 deletions
This file was deleted.

pkg/registry_checker/checker.go

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package registry_checker
22

33
import (
4+
"context"
45
"crypto/tls"
56
"errors"
6-
appsv1 "k8s.io/api/apps/v1"
7-
"k8s.io/apimachinery/pkg/util/wait"
87
"net/http"
9-
"sync"
8+
"path"
109
"time"
1110

11+
"github.com/prometheus/client_golang/prometheus"
12+
appsv1 "k8s.io/api/apps/v1"
13+
"k8s.io/apimachinery/pkg/util/wait"
14+
"k8s.io/client-go/tools/cache"
15+
1216
"github.com/google/go-containerregistry/pkg/name"
1317
"github.com/google/go-containerregistry/pkg/v1/remote"
1418
"github.com/sirupsen/logrus"
@@ -21,11 +25,12 @@ import (
2125

2226
"github.com/flant/k8s-image-availability-exporter/pkg/store"
2327
"k8s.io/client-go/kubernetes"
24-
"k8s.io/client-go/tools/cache"
2528
)
2629

2730
const (
28-
resyncPeriod = time.Hour
31+
resyncPeriod = time.Hour
32+
failedCheckBatchSize = 20
33+
checkBatchSize = 50
2934
)
3035

3136
type registryCheckerConfig struct {
@@ -53,6 +58,7 @@ type RegistryChecker struct {
5358
}
5459

5560
func NewRegistryChecker(
61+
stopCh <-chan struct{},
5662
kubeClient *kubernetes.Clientset,
5763
skipVerify bool,
5864
ignoredImages []string,
@@ -71,8 +77,6 @@ func NewRegistryChecker(
7177
}
7278

7379
rc := &RegistryChecker{
74-
imageStore: store.NewImageStore(),
75-
7680
deploymentsInformer: informerFactory.Apps().V1().Deployments(),
7781
statefulSetsInformer: informerFactory.Apps().V1().StatefulSets(),
7882
daemonSetsInformer: informerFactory.Apps().V1().DaemonSets(),
@@ -94,10 +98,8 @@ func NewRegistryChecker(
9498
rc.ignoredImages[image] = struct{}{}
9599
}
96100

97-
return rc
98-
}
101+
rc.imageStore = store.NewImageStore(rc.Check, checkBatchSize, failedCheckBatchSize)
99102

100-
func (rc *RegistryChecker) Run(stopCh <-chan struct{}) {
101103
rc.deploymentsInformer.Informer().AddEventHandlerWithResyncPeriod(cache.ResourceEventHandlerFuncs{
102104
AddFunc: func(obj interface{}) {
103105
rc.reconcile(obj)
@@ -177,6 +179,26 @@ func (rc *RegistryChecker) Run(stopCh <-chan struct{}) {
177179
cache.WaitForCacheSync(stopCh, rc.deploymentsInformer.Informer().HasSynced, rc.statefulSetsInformer.Informer().HasSynced,
178180
rc.daemonSetsInformer.Informer().HasSynced, rc.cronJobsInformer.Informer().HasSynced, rc.secretsInformer.Informer().HasSynced)
179181
logrus.Info("Caches populated successfully")
182+
183+
rc.imageStore.RunGC(rc.controllerIndexers.GetContainerInfosForImage)
184+
185+
return rc
186+
}
187+
188+
// Collect implements prometheus.Collector.
189+
func (rc *RegistryChecker) Collect(ch chan<- prometheus.Metric) {
190+
metrics := rc.imageStore.ExtractMetrics()
191+
192+
for _, m := range metrics {
193+
ch <- m
194+
}
195+
}
196+
197+
// Describe implements prometheus.Collector.
198+
func (rc *RegistryChecker) Describe(_ chan<- *prometheus.Desc) {}
199+
200+
func (rc RegistryChecker) Tick() {
201+
rc.imageStore.Check()
180202
}
181203

182204
func (rc *RegistryChecker) reconcile(obj interface{}) {
@@ -208,12 +230,13 @@ func (rc *RegistryChecker) reconcile(obj interface{}) {
208230
}
209231
}
210232

211-
if skipObject || !rc.controllerIndexers.CheckImageExistence(image) {
212-
rc.imageStore.RemoveImage(image)
233+
if skipObject {
234+
rc.imageStore.ReconcileImage(image, []store.ContainerInfo{})
213235
continue
214236
}
215237

216-
rc.imageStore.AddOrUpdateImage(image, time.Time{})
238+
containerInfos := rc.controllerIndexers.GetContainerInfosForImage(image)
239+
rc.imageStore.ReconcileImage(image, containerInfos)
217240
}
218241
}
219242

@@ -225,30 +248,11 @@ func (rc *RegistryChecker) reconcileUpdate(a, b interface{}) {
225248
rc.reconcile(b)
226249
}
227250

228-
func (rc *RegistryChecker) Check() {
229-
// TODO: tweak const
230-
oldImages := rc.imageStore.PopOldestImages(rc.imageStore.Length() / 40)
231-
232-
var processingGroup sync.WaitGroup
233-
for _, image := range oldImages {
234-
keyChain := rc.controllerIndexers.GetKeychainForImage(rc.kubeClient, image)
251+
func (rc *RegistryChecker) Check(imageName string) store.AvailabilityMode {
252+
keyChain := rc.controllerIndexers.GetKeychainForImage(rc.kubeClient, imageName)
235253

236-
// TODO: backoff
237-
processingGroup.Add(1)
238-
go func(imageName string, kc *keychain) {
239-
defer processingGroup.Done()
240-
241-
log := logrus.WithField("image_name", imageName)
242-
availMode := rc.checkImageAvailability(log, imageName, kc)
243-
244-
rc.imageStore.AddOrUpdateImage(imageName, time.Now(), availMode)
245-
}(image, keyChain)
246-
247-
containerInfos := rc.controllerIndexers.GetContainerInfosForImage(image)
248-
rc.imageStore.UpdateContainerAssociations(image, containerInfos)
249-
}
250-
251-
processingGroup.Wait()
254+
log := logrus.WithField("image_name", imageName)
255+
return rc.checkImageAvailability(log, imageName, keyChain)
252256
}
253257

254258
func checkImageNameParseErr(log *logrus.Entry, err error) store.AvailabilityMode {
@@ -286,12 +290,16 @@ func (rc *RegistryChecker) checkImageAvailability(log *logrus.Entry, imageName s
286290
Factor: 2,
287291
Steps: 2,
288292
}, func() (bool, error) {
293+
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
294+
defer cancel()
295+
289296
if kc != nil {
290297
for i := 0; i < kc.size; i++ {
291298
indexedKeychain := *kc
292299
indexedKeychain.index = i
293300

294-
_, imgErr = remote.Head(ref, remote.WithAuthFromKeychain(&indexedKeychain), remote.WithTransport(rc.registryTransport))
301+
_, imgErr = remote.Head(ref, remote.WithAuthFromKeychain(&indexedKeychain), remote.WithTransport(rc.registryTransport),
302+
remote.WithContext(ctx))
295303

296304
if imgErr != nil {
297305
continue
@@ -302,7 +310,7 @@ func (rc *RegistryChecker) checkImageAvailability(log *logrus.Entry, imageName s
302310
}
303311
}
304312
} else {
305-
_, imgErr = remote.Head(ref, remote.WithTransport(rc.registryTransport))
313+
_, imgErr = remote.Head(ref, remote.WithTransport(rc.registryTransport), remote.WithContext(ctx))
306314
}
307315

308316
availMode = store.Available

pkg/registry_checker/image_pull.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package registry_checker
22

33
import (
44
"errors"
5+
56
"github.com/google/go-containerregistry/pkg/v1/remote"
67
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
78
)

pkg/registry_checker/indexers.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,12 +208,6 @@ func (ci ControllerIndexers) GetKeysByIndex(image string) (ret []string) {
208208
return
209209
}
210210

211-
func (ci ControllerIndexers) CheckImageExistence(image string) bool {
212-
keys := ci.GetKeysByIndex(image)
213-
214-
return len(keys) > 0
215-
}
216-
217211
func (ci ControllerIndexers) GetContainerInfosForImage(image string) (ret []store.ContainerInfo) {
218212
objs := ci.GetObjectsByIndex(image)
219213

pkg/registry_checker/metrics_registry.go

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)