/gcr-cleaner

Delete untagged image refs in Google Container Registry, as a service

Primary LanguageGoApache License 2.0Apache-2.0

GCR Cleaner

GoDoc

GCR Cleaner deletes untagged images in Google Container Registry. This can help reduce costs and keep your container images list in order.

GCR Cleaner is available as a Go library (in pkg/gcrcleaner), but it is designed to be deployed as a Cloud Run service and invoked periodically via Cloud Scheduler via Cloud Pub/Sub.

+-------------------+    +-----------------+    +-------------+    +-------+
|  Cloud Scheduler  | -> |  Cloud Pub/Sub  | -> |  Cloud Run  | -> |  GCR  |
+-------------------+    +-----------------+    +-------------+    +-------+

GCR Cleaner is largely inspired by ahmetb's gcrgc.sh, but it is written in Go and is designed to be run as a service.

Setup

  1. Install the Cloud SDK for your operating system. Alternatively, you can run these commands from Cloud Shell, which has the SDK and other popular tools pre-installed.

  2. Export your project ID as an environment variable. The rest of this setup assumes this environment variable is set.

    PROJECT_ID=my-project
    

    Note this is your project ID, not the project number or name.

  3. Enable the Google APIs - this only needs to be done once per project:

    gcloud services enable --project ${PROJECT_ID} \
      appengine.googleapis.com \
      compute.googleapis.com \
      cloudbuild.googleapis.com \
      cloudscheduler.googleapis.com \
      pubsub.googleapis.com \
      run.googleapis.com
    

    This operation can take a few minutes, especially for recently-created projects.

  4. Build the gcr-cleaner container with Cloud Build:

    gcloud builds submit \
      --project ${PROJECT_ID} \
      --tag gcr.io/${PROJECT_ID}/gcr-cleaner \
      .
    
  5. Deploy the gcr-cleaner container on Cloud Run:

    gcloud beta run deploy gcr-cleaner \
      --project ${PROJECT_ID} \
      --image gcr.io/${PROJECT_ID}/gcr-cleaner \
      --region us-central1 \
      --timeout 60s \
      --quiet
    
  6. Capture the URL of the Cloud Run service:

    SERVICE_URL=$(gcloud beta run services describe gcr-cleaner --project ${PROJECT_ID} --region us-central1 --format 'value(status.domain)')
    
  7. Grant the Cloud Run service account access to delete references in Google Container Registry:

    PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format 'value(projectNumber)')
    
    gsutil acl ch -u ${PROJECT_NUMBER}-compute@developer.gserviceaccount.com:W gs://artifacts.${PROJECT_ID}.appspot.com
    

    To cleanup refs in other GCP projects, replace PROJECT_ID with the target project ID. For example, if the Cloud Run service was running in "project-a" and you wanted to grant it permission to cleanup refs in "gcr.io/project-b/image", you would need to grant the Cloud Run service account in project-a permission on artifacts.projects-b.appspot.com.

  8. Grant Cloud Pub/Sub the ability to invoke the Cloud Run function:

    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com \
      --role roles/iam.serviceAccountTokenCreator
    
    gcloud iam service-accounts create cloud-run-pubsub-invoker \
      --project ${PROJECT_ID} \
      --display-name "Cloud Run Pub/Sub Invoker"
    
    gcloud beta run services add-iam-policy-binding gcr-cleaner \
      --project ${PROJECT_ID} \
      --member serviceAccount:cloud-run-pubsub-invoker@${PROJECT_ID}.iam.gserviceaccount.com \
      --role roles/run.invoker
    
  9. Create a Cloud Pub/Sub topic and subscription with a service account that has permission to invoke Cloud Run:

    gcloud pubsub topics create gcr-cleaner \
      --project ${PROJECT_ID}
    
    gcloud beta pubsub subscriptions create cloud-run-gcr-cleaner \
      --project ${PROJECT_ID} \
      --topic gcr-cleaner \
      --message-retention-duration 15m \
      --push-endpoint ${SERVICE_URL}/pubsub \
      --push-auth-service-account cloud-run-pubsub-invoker@${PROJECT_ID}.iam.gserviceaccount.com
    
  10. Create a Cloud Scheduler Pub/Sub job to invoke the function every day:

    gcloud app create \
      --project ${PROJECT_ID} \
      --region us-central \
      --quiet
    
    # Replace this with the full name of the repository for which you
    # want to cleanup old references.
    REPO="gcr.io/my-project/my-image"
    
    gcloud beta scheduler jobs create pubsub gcrclean-myimage \
      --project ${PROJECT_ID} \
      --description "Cleanup ${REPO}" \
      --topic gcr-cleaner \
      --message-body "{\"repo\":\"${REPO}\"}" \
      --schedule "every monday 09:00"
    

    You can create multiple Cloud Scheduler instances against the same Cloud Pub/Sub topic with different payloads to clean multiple GCR repositories.

  11. (Optional) Run the scheduled job now:

    gcloud beta scheduler jobs run gcrclean-myimage \
      --project ${PROJECT_ID}
    

    Note: for initial job deployments, you must wait a few minutes before invoking.

Payload & Parameters

The payload is expected to be JSON with the following fields:

  • repo - Full name of the repository to clean, in the format gcr.io/project/repo. This field is required.

  • grace - Relative duration in which to ignore references. This value is specified as a time duration value like "5s" or "3h". If set, refs newer than the duration will not be deleted. If unspecified, the default is no grace period (all untagged image refs are deleted).

FAQ

How do I clean up multiple Google Container Registry repos at once?
To clean multiple repos, create a Cloud Scheduler job for each repo, altering the payload to use the correct repo.

Why are you using Cloud Pub/Sub?
At the time of this writing, Cloud Scheduler does not send authentication information to Cloud Run. As such, it is not possible for Cloud Scheduler to invoke a private Cloud Run function. This is a known issue and, when resolved, can be updated to drop Cloud Pub/Sub from the process. The server is already configurable to do this, since it serves both a /pubsub and /http endpoint.

License

This library is licensed under Apache 2.0. Full license text is available in LICENSE.