Skip to content

[Bug]: Pull-through cache re-triggers upstream pulls, exhausting rate limits and downloading all archs #3129

Description

@lgtm-dude

zot version

ghcr.io/project-zot/zot-linux-amd64:v2.1.3-rc5

Describe the bug

Please don't get me wrong, I really, really like the ZOT registry its a cool piece of software, thanks for developing it :-)

Description of my deployment:

  • Internal zot registry, authenticated Users (Keycloak / oidc) are able to delete images from cache
    • Even unauthenticated users can pull Docker images from my intranet
  • The ZOT registry works as a pull through cache, it's the only kind that will work in my situation.

Current available Versions:
The problem is critical in v2.1.2 and earlier, ghcr.io/project-zot/zot-linux-amd64:v2.1.3-rc5 seems to reduce the impact between v2.1.2 and v2.1.3-rc5 it's still awful.

Problems:
I am using the ZOT Image Registry to cache docker.io Images because I do not want to run into the PULL Limits within the first 60 Minutes of the day (many users try to pull behind same NAT including my CI/CD). As ma internet connection is quite low, useless fetches are a huge problem as well.

I need to be able to fetch all possible Images from docker.io (quay, gcr as well, without restriction) so I cannot reduce the surface given by prefix: "**" and even if I do so, the Problem is still there but with reduced collision area.

  1. The main problem is, as soon an docker.io Image is being cached and gets refetched by a client, ZOT starts to reevaluate all existing images within its registry and starts downloading the images again. That naturally eliminates my RATE limits (200 right now) within a pull of 3-8 already cached images, that's not what I need a Image registry for.

  2. When it starts retransmitting the Images, it also downloads ALL architectures, it literately DDOS'es my Internet connection.

  3. State of v2.1.3-rc5 i cannot pass a list of architectures to ZOT that i need which also nukes my storage ;-)

Possible fix?

  • As docker.io rate limits must not be wasted please consider:
    • Only pull the needed architectures of an image
    • Only pull an update of just the one image that is being requested and only if it really had an update
      • You may use insted of a PULL or GET /v2/reponame/manifests/ ,which counts toward pull limits, something different like HEAD /v2/reponame/manifests/ or GET /v2/reponame/tags/list or whatever possible (as far I know).
    • At least it would be fine having a switch that will not check for updates on an existing image (retagging images is not fine anyways, despite latest)

I really don't want to switch to harbor, nexus or whatever tools are out there and stick with ZOT but the time I can spend on ZOT is very limited, runs out and I might never ever come back again if that can't be fixed in a timely manner.

This is a real show stopper to me and I don't think I'm the only human out there that has that specific problem, please help!

To reproduce

  1. Configuration

apiVersion: v1
kind: ConfigMap
metadata:
  name: zot-config
  namespace: zot
data:
  config.yaml: |
    storage:
      rootDirectory: "/var/lib/zot"
      dedupe: true
      commit: true
      gc: true
      gcDelay: "1h"
      gcInterval: "24h"
      retention: {
        dryRun: false,
        delay: "1h",
        policies: [{
          repositories: ["docker-images/**", "k8s-images/**"],
          deleteReferrers: true,
          deleteUntagged: true,
          keepTags: [{
            patterns: [".*"],
            pulledWithin: "720h"
            }]
          }
        ]
      }
    log:
      level: "info"
    http:
      address: "0.0.0.0"
      port: 5000
      externalUrl: "https://zot.example.com"
      auth: {
        failDelay: 10,
        openid: {
          providers: {
            oidc: {
              name: "Keycloak",
              clientid: "myzotkeycloakclientid",
              clientsecret: ,
              keypath: "",
              issuer: "https://keycloak.example.com/realms/example",
              scopes: ["openid"]
            }
          }
        }
      }
      accessControl: {
        repositories: {
          "**": {
            defaultPolicy: ["read", "create", "update", "delete"],
            anonymousPolicy: ["read"]
          }
        }
      }
    extensions: {
      ui: {
        enable: true
      },
      scrub: {
        enable: true,
        interval: "24h"
      },
      search: {
        enable: true,
        cve: {
          updateInterval: 4h
        }
      },
      sync: {
        enable: true,
        credentialsFile: "/config/credentials.json",
        registries: [
          {
            urls: ["https://k8s.gcr.io"],
            maxRetries: 1,
            retryDelay: "10s",
            content: [
              {
                prefix: "**",
                destination: "/k8s-images"
              }
            ],
            onDemand: true,
            tlsVerify: true
          },
          {
            urls: ["https://docker.io"],
            maxRetries: 2,
            retryDelay: "10s",
            content: [
              {
                prefix: "**",
                destination: "/docker-images"
              }
            ],
            onDemand: true,
            tlsVerify: true
          },
          {
            urls: ["https://quay.io"],
            maxRetries: 1,
            retryDelay: "10s",
            content: [
              {
                prefix: "**",
                destination: "/quay-images"
              }
            ],
            onDemand: true,
            tlsVerify: true
          }
        ]
      },
      metrics: {
        enable: true,
        prometheus: {
          path: "/metrics"
        }
      }
    }
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: zot-credentials
  namespace: zot
data:
  credentials.json: |
    {
      "docker.io": {
        "username": "mydockeruser",
        "password": ""
      }
    }


  1. Client tool used
  2. Seen error

Expected behavior

  • ZOT checks for updates without consuming docker.io rate limits.
  • ZOT is able to fetch only images of an given array of architectures
  • ZOT is able to just auto update the requested Image, not everything stored in ZOT (no useless traffic, no waste of limits)
    • As an alternative, zot does not auto update images already within the ZOT store
  • ZOT Devs thaught about that limitations if they do also apply to quay.io and gcr.io

Screenshots

No response

Additional context

ZOT is a cool tool, keep it up and thank you for creating it :-)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingrm-externalRoadmap item submitted by non-maintainers

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions