Self-hosted service
keel-hq/keel avatar
keel-hq/keel

keel-hq/keel: label-driven Kubernetes deployment updates

Kubernetes Operator to automate Helm, DaemonSet, StatefulSet & Deployment updates

2,730 stars321 forksGoMPL-2.0

At a glance

What is it?
Keel watches container registries and rolls out new image tags to Deployments, DaemonSets and StatefulSets based on semver annotations. It has no CLI, and the whole contract lives in labels and webhooks.
Who is it for?
Adopt Keel if you already run Kubernetes and want tag-driven rollouts without a delivery pipeline that owns every manifest. Do not adopt it if you need a CLI or API to drive updates, if you rely on Helm v2 (Tiller), or if you want a rollback mechanism: the README documents none.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 12 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap Keel fills: registry events that never reach your cluster

Most clusters have a build step that pushes a new image tag and then stops. Something has to notice the tag and change the workload. The usual answer is a pipeline that holds cluster credentials and runs kubectl or helm upgrade, which means the deployment history lives outside the cluster and every manifest change has to be routed back through the pipeline.

Keel moves that decision into the cluster. It is described in the README as "a tool for automating Kubernetes deployment updates," and the design choice that follows from that sentence is the interesting part: Keel has no CLI and no API for triggering updates. The README states this directly, saying it gets the job done "through labels, annotations, charts." The audience is teams running Kubernetes who want the cluster itself to react to a new image, and who are willing to express their rollout rules as annotations on the workloads they already have.

How Keel learns about a new image: webhooks, polling and GCR subscriptions

Keel has three ways to find out that an image changed, and the choice is per workload.

The first is a registry webhook. The README lists native webhook support for DockerHub, Harbor, Quay and Azure container registry, plus Google Container Registry. When a webhook arrives, Keel identifies the affected deployments and updates them.

The second is polling. The README describes polling as the fallback "when webhooks and pubsub aren't available," and it checks the Docker registry for new tags when the current tag is semver, or for a digest change on the same tag (the README's example is latest). That distinction matters: a workload pinned to 0.0.8 will only move when a higher tag appears, while a workload on latest moves when the digest behind that tag changes.

The third is specific to Google Container Registry. Keel automatically sets up the topic and subscriptions for your deployment images by periodically scanning your environment, so GCR users do not have to wire the notification path by hand. For Harbor, the README notes that project names stay in the repository path, so harbor.example.com/library/ai-rag:latest is polled at /v2/library/ai-rag/..., and public projects need no registry-specific configuration.

Around all of this sits the policy layer. The annotation keel.sh/policy takes a semver policy name, and Keel applies it per Deployment or Helm release. The README also mentions a Helm provider and a Kubernetes provider as the two integrations, with the Helm provider targeting Helm v3.

Installing Keel with Helm and annotating your first Deployment

The Helm chart in chart/keel is described in the README as the recommended and maintained install method, and it supports upgrades and configuration through values.yaml. Add the chart repository first.

bash
helm repo add keel https://keel-hq.github.io/keel/
helm repo update

Then install the operator. The README shows this exact command, with the Helm provider enabled by default.

bash
helm upgrade --install keel --namespace=kube-system keel/keel

If your workloads are plain Kubernetes manifests rather than Helm releases, the README gives a variant that turns the Helm provider off and installs into a separate namespace.

bash
helm upgrade --install keel --namespace=keel keel/keel --set helmProvider.enabled="false"

There is also a static manifest path for people who cannot use Helm. The repository ships a ready-to-run set under docs/manifests/keel/ containing the Deployment, Service, RBAC and a Basic Auth Secret with marked placeholders. The README says to set your Basic Auth password in docs/manifests/keel/20-secret.yaml first, then apply the directory so the filename order keeps the namespace and RBAC first.

bash
kubectl apply -f docs/manifests/keel/

The README still calls the Helm chart preferred, because it keeps your deployment up to date with future releases.

With Keel running, the only thing left is the annotation block on the workload. This is the example from the README, trimmed to the parts that drive Keel.

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wd
  namespace: default
  labels:
    name: "wd"
  annotations:
    keel.sh/policy: minor
    keel.sh/trigger: poll
spec:
  template:
    spec:
      containers:
        - image: karolisr/webhook-demo:0.0.8
          imagePullPolicy: Always
          name: wd

The two annotations are the whole contract. keel.sh/policy takes a policy name from semver.org, and keel.sh/trigger set to poll makes Keel actively query the registry instead of waiting for a webhook. Omit the trigger annotation and the workload defaults to webhooks, which means nothing happens until your registry sends an event.

Where Keel stops being the right tool

The absence of a CLI and API is a deliberate simplification, and it is also the sharpest limitation. If your release process needs to force an update, query what Keel is about to do, or script a promotion across environments, there is no command to call. You change an annotation or you push an image. Teams that treat deployment as an auditable, on-demand operation will find that constraint uncomfortable rather than liberating.

The README does not document rollback. There is no described mechanism for reverting a workload that Keel moved to a bad tag, which means the recovery path is whatever your cluster and your image registry already provide. That is a real gap for anyone used to a pipeline that can redeploy the previous revision.

Polling has its own boundary. Keel checks the registry for new tags only when the current tag is semver, or for a digest change on the same tag. A workload pinned to a non-semver tag that is not meant to move will not be updated by polling at all, and a workload tracking latest will be updated on every digest change, which is exactly the behaviour some teams spend effort avoiding.

Finally, Helm v2 (Tiller) is no longer supported. The Helm provider targets Helm v3, so clusters still running Tiller are out of scope regardless of how the annotations are written.

Nightly images exist for people who want master before a tagged release. The README is explicit that they are built from master after the unit test suite passes, published as a rolling nightly tag and a date-stamped nightly-YYYYMMDD tag, and that they are pre-releases not supported for production use.

Keel against a pipeline-driven deploy, and against Argo CD style GitOps

The obvious alternative is the one most teams already have: a CI pipeline that builds the image and then runs kubectl set image or helm upgrade against the cluster. The difference is where the decision lives. A pipeline decides at build time and pushes the result; Keel decides inside the cluster, at the moment a registry event or a poll result arrives, using an annotation that was written when the workload was created. The pipeline approach gives you ordering, approvals and a log of who deployed what. Keel gives you less machinery and no external credentials in the deploy path, at the cost of having no single place to look at for a rollout history.

The other family of alternatives is GitOps-style reconciliation, where a controller compares the cluster against a Git repository and reverts drift. That inverts the trigger: Git changes drive the cluster, and an image tag bump has to be committed somewhere. Keel does the opposite, treating the registry as the source of truth for the image and leaving the manifest alone. If your organisation already requires every cluster change to be traceable to a commit, Keel's model will fight that requirement rather than satisfy it.

Upgrades, release cadence and what the MPL-2.0 licence means here

Keel is licensed under MPL-2.0. That is a file-level copyleft licence: modifications to files that are part of Keel must be made available under the same licence when distributed, while separate files you add can carry other terms. If you fork the operator and ship a modified binary, the modified Keel files carry the obligation. This is a description of the licence text, not legal advice, and anyone redistributing a modified build should read the LICENSE file in the repository.

The repository was last pushed on 2026-09-18, and the most recent releases listed are 0.22.3 and keel-v1.2.2, both dated 2026-08-31, with 0.22.2 on 2026-08-30. The two parallel version lines are worth noting if you pin versions: a 0.22.x line and a keel-v1.2.x line appear in the same release window, so check which one your chart or manifest references before upgrading.

The upgrade cost itself is low if you installed through Helm, since the README presents the chart as the maintained path that supports upgrades and configuration through values.yaml. The static manifest route in docs/manifests/keel/ is the one that carries ongoing cost, because the README warns it will not automatically track future releases. The go.mod file pins Kubernetes libraries to v0.31.3 and Helm to v3.13.1 through replace directives, and the build image is golang:1.26.5-alpine, which tells you the toolchain expectations if you build from source. The Dockerfile builds the UI with node:24.11.0-alpine and runs npm run typecheck, npm run lint, npm test and npm run build as part of the image build, so a source build fails on a UI test failure, not just on a Go compile error.

Editorial conclusion

Adopt Keel if you already run Kubernetes and want tag-driven rollouts without a delivery pipeline that owns every manifest. Do not adopt it if you need a CLI or API to drive updates, if you rely on Helm v2 (Tiller), or if you want a rollback mechanism: the README documents none. Before you install, verify that your registry is one of the supported webhook sources or that polling can reach it, and confirm which of your workloads carry a semver tag, because polling only works when the current tag is semver or when you intend to track a moving tag such as latest.

Frequently asked questions

Does keel-hq/keel have a CLI or an API for triggering updates?

No. The README states that Keel has no CLI or API, and that it gets the job done through labels, annotations and charts. Updates are driven by registry webhooks, polling, or GCR pubsub notifications rather than by a command you run.

How do I install keel-hq/keel on Kubernetes?

The README recommends the Helm chart: add the repository with helm repo add keel https://keel-hq.github.io/keel/, run helm repo update, then helm upgrade --install keel --namespace=kube-system keel/keel. A static manifest set under docs/manifests/keel/ exists as an alternative, but the README says the chart remains preferred because it keeps your deployment up to date with future releases.

What does the keel.sh/policy annotation do in a keel-hq/keel deployment?

It sets the update policy for that workload individually, using a policy name from semver.org. In the README's Deployment example, keel.sh/policy is set to minor, and a companion annotation keel.sh/trigger set to poll makes Keel actively query the registry instead of waiting for a webhook.

Does keel-hq/keel work with Helm v2?

No. The README states that the Helm provider targets Helm v3 and is enabled by default, and that Helm v2 (Tiller) is no longer supported. Installing with --set helmProvider.enabled="false" is the documented option for clusters that work mostly with regular Kubernetes manifests.

How does keel-hq/keel detect a new image when webhooks are not available?

It polls the Docker registry. The README describes polling as checking for new tags when the current tag is semver, or for a same-tag SHA digest change such as with latest. You opt in per workload with the keel.sh/trigger: poll annotation.

Official sources

  1. keel-hq/keel on GitHub
  2. License: MPL-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/keel-hq-keel.svg)](https://hysenlabs.com/projects/keel-hq-keel)