Update the docs with a section regarding the cache usage
Signed-off-by: Soule BA <soule@weave.works>
This commit is contained in:
parent
0f9302827c
commit
7ff96a8b0c
|
@ -463,10 +463,8 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *
|
|||
|
||||
// Try to retrieve the repository index from the cache
|
||||
if r.Cache != nil {
|
||||
if index, found := r.Cache.Get(r.Storage.LocalPath(*repo.GetArtifact())); err == nil {
|
||||
if found {
|
||||
chartRepo.Index = index.(*helmrepo.IndexFile)
|
||||
}
|
||||
if index, found := r.Cache.Get(r.Storage.LocalPath(*repo.GetArtifact())); found {
|
||||
chartRepo.Index = index.(*helmrepo.IndexFile)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -502,7 +500,7 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj *
|
|||
// Using r.Storage.LocalPath(*repo.GetArtifact() is safe as the path is in the format /<helm-repository-name>/<chart-name>/<filename>.
|
||||
err := r.Cache.Set(r.Storage.LocalPath(*repo.GetArtifact()), chartRepo.Index, r.TTL)
|
||||
if err != nil {
|
||||
r.eventLogf(ctx, obj, events.EventTypeTrace, sourcev1.CacheOperationFailedReason, "failed to cache index: %v", err)
|
||||
r.eventLogf(ctx, obj, events.EventTypeTrace, sourcev1.CacheOperationFailedReason, "failed to cache index: %s", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -390,6 +390,53 @@ Besides being reported in Events, the reconciliation errors are also logged by
|
|||
the controller. The Flux CLI offer commands for filtering the logs for a
|
||||
specific HelmChart, e.g. `flux logs --level=error --kind=HelmChart --name=<chart-name>`.
|
||||
|
||||
### Improving resource consumption by enabling the cache
|
||||
|
||||
When using a `HelmRepository` as Source for a `HelmChart`, the controller loads
|
||||
the repository index in memory to find the latest version of the chart.
|
||||
|
||||
The controller can be configured to cache Helm repository indexes in memory.
|
||||
The cache is used to avoid loading repository indexes for every `HelmChart`
|
||||
reconciliation.
|
||||
|
||||
The following flags are provided to enable and configure the cache:
|
||||
- `helm-cache-max-size`: The maximum size of the cache in number of indexes.
|
||||
If `0`, then the cache is disabled.
|
||||
- `helm-cache-ttl`: The TTL of an index in the cache.
|
||||
- `helm-cache-purge-interval`: The interval at which the cache is purged of
|
||||
expired items.
|
||||
|
||||
The caching strategy is to pull a repository index from the cache if it is
|
||||
available, otherwise to load the index, retrieve and build the chart,
|
||||
then cache the index. The cached index TTL is refreshed every time the
|
||||
Helm repository index is loaded with the `helm-cache-ttl` value.
|
||||
|
||||
The cache is purged of expired items every `helm-cache-purge-interval`.
|
||||
|
||||
When the cache is full, no more items can be added to the cache, and the
|
||||
source-controller will report a warning event instead.
|
||||
|
||||
In order to use the cache, set the related flags in the source-controller
|
||||
Deployment config:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --watch-all-namespaces
|
||||
- --log-level=info
|
||||
- --log-encoding=json
|
||||
- --enable-leader-election
|
||||
- --storage-path=/data
|
||||
- --storage-adv-addr=source-controller.$(RUNTIME_NAMESPACE).svc.cluster.local.
|
||||
## Helm cache with up to 10 items, i.e. 10 indexes.
|
||||
- --helm-cache-max-size=10
|
||||
## TTL of an index is 1 hour.
|
||||
- --helm-cache-ttl=1h
|
||||
## Purge expired index every 10 minutes.
|
||||
- --helm-cache-purge-interval=10m
|
||||
```
|
||||
|
||||
## HelmChart Status
|
||||
|
||||
### Artifact
|
||||
|
|
|
@ -26,14 +26,16 @@ type Cache struct {
|
|||
|
||||
// Item is an item stored in the cache.
|
||||
type Item struct {
|
||||
Object interface{}
|
||||
// Object is the item's value.
|
||||
Object interface{}
|
||||
// Expiration is the item's expiration time.
|
||||
Expiration int64
|
||||
}
|
||||
|
||||
type cache struct {
|
||||
// Items holds the elements in the cache.
|
||||
Items map[string]Item
|
||||
// Maximum number of items the cache can hold.
|
||||
// MaxItems is the maximum number of items the cache can hold.
|
||||
MaxItems int
|
||||
mu sync.RWMutex
|
||||
janitor *janitor
|
||||
|
@ -82,6 +84,9 @@ func (c *cache) Set(key string, value interface{}, expiration time.Duration) err
|
|||
return fmt.Errorf("Cache is full")
|
||||
}
|
||||
|
||||
// Add an item to the cache, existing items will not be overwritten.
|
||||
// To overwrite existing items, use Set.
|
||||
// If the cache is full, Add will return an error.
|
||||
func (c *cache) Add(key string, value interface{}, expiration time.Duration) error {
|
||||
c.mu.Lock()
|
||||
_, found := c.Items[key]
|
||||
|
@ -100,6 +105,8 @@ func (c *cache) Add(key string, value interface{}, expiration time.Duration) err
|
|||
return fmt.Errorf("Cache is full")
|
||||
}
|
||||
|
||||
// Get an item from the cache. Returns the item or nil, and a bool indicating
|
||||
// whether the key was found.
|
||||
func (c *cache) Get(key string) (interface{}, bool) {
|
||||
c.mu.RLock()
|
||||
item, found := c.Items[key]
|
||||
|
@ -117,18 +124,23 @@ func (c *cache) Get(key string) (interface{}, bool) {
|
|||
return item.Object, true
|
||||
}
|
||||
|
||||
// Delete an item from the cache. Does nothing if the key is not in the cache.
|
||||
func (c *cache) Delete(key string) {
|
||||
c.mu.Lock()
|
||||
delete(c.Items, key)
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// Clear all items from the cache.
|
||||
// This reallocate the inderlying array holding the items,
|
||||
// so that the memory used by the items is reclaimed.
|
||||
func (c *cache) Clear() {
|
||||
c.mu.Lock()
|
||||
c.Items = make(map[string]Item)
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// HasExpired returns true if the item has expired.
|
||||
func (c *cache) HasExpired(key string) bool {
|
||||
c.mu.RLock()
|
||||
item, ok := c.Items[key]
|
||||
|
@ -146,6 +158,8 @@ func (c *cache) HasExpired(key string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// SetExpiration sets the expiration for the given key.
|
||||
// Does nothing if the key is not in the cache.
|
||||
func (c *cache) SetExpiration(key string, expiration time.Duration) {
|
||||
c.mu.Lock()
|
||||
item, ok := c.Items[key]
|
||||
|
@ -157,6 +171,9 @@ func (c *cache) SetExpiration(key string, expiration time.Duration) {
|
|||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// GetExpiration returns the expiration for the given key.
|
||||
// Returns zero if the key is not in the cache or the item
|
||||
// has already expired.
|
||||
func (c *cache) GetExpiration(key string) time.Duration {
|
||||
c.mu.RLock()
|
||||
item, ok := c.Items[key]
|
||||
|
@ -174,6 +191,7 @@ func (c *cache) GetExpiration(key string) time.Duration {
|
|||
return time.Duration(item.Expiration - time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// DeleteExpired deletes all expired items from the cache.
|
||||
func (c *cache) DeleteExpired() {
|
||||
c.mu.Lock()
|
||||
for k, v := range c.Items {
|
||||
|
@ -185,12 +203,12 @@ func (c *cache) DeleteExpired() {
|
|||
}
|
||||
|
||||
type janitor struct {
|
||||
Interval time.Duration
|
||||
interval time.Duration
|
||||
stop chan bool
|
||||
}
|
||||
|
||||
func (j *janitor) Run(c *cache) {
|
||||
ticker := time.NewTicker(j.Interval)
|
||||
func (j *janitor) run(c *cache) {
|
||||
ticker := time.NewTicker(j.interval)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
|
@ -206,12 +224,13 @@ func stopJanitor(c *Cache) {
|
|||
c.janitor.stop <- true
|
||||
}
|
||||
|
||||
// New creates a new cache with the given configuration.
|
||||
func New(maxItems int, interval time.Duration) *Cache {
|
||||
c := &cache{
|
||||
Items: make(map[string]Item),
|
||||
MaxItems: maxItems,
|
||||
janitor: &janitor{
|
||||
Interval: interval,
|
||||
interval: interval,
|
||||
stop: make(chan bool),
|
||||
},
|
||||
}
|
||||
|
@ -219,7 +238,7 @@ func New(maxItems int, interval time.Duration) *Cache {
|
|||
C := &Cache{c}
|
||||
|
||||
if interval > 0 {
|
||||
go c.janitor.Run(c)
|
||||
go c.janitor.run(c)
|
||||
runtime.SetFinalizer(C, stopJanitor)
|
||||
}
|
||||
|
||||
|
|
4
main.go
4
main.go
|
@ -115,9 +115,9 @@ func main() {
|
|||
flag.DurationVar(&requeueDependency, "requeue-dependency", 30*time.Second,
|
||||
"The interval at which failing dependencies are reevaluated.")
|
||||
flag.IntVar(&helmCacheMaxSize, "helm-cache-max-size", 0,
|
||||
"The maximum size of the cache in number of items.")
|
||||
"The maximum size of the cache in number of indexes.")
|
||||
flag.StringVar(&helmCacheTTL, "helm-cache-ttl", "15m",
|
||||
"The TTL of an item in the cache. Valid time units are ns, us (or µs), ms, s, m, h.")
|
||||
"The TTL of an index in the cache. Valid time units are ns, us (or µs), ms, s, m, h.")
|
||||
flag.StringVar(&helmCachePurgeInterval, "helm-cache-purge-interval", "1m",
|
||||
"The interval at which the cache is purged. Valid time units are ns, us (or µs), ms, s, m, h.")
|
||||
|
||||
|
|
Loading…
Reference in New Issue