This page describes how to install Metacontroller, either to develop your own controllers or just to run third-party controllers that depend on it.


  • Kubernetes v1.11+
  • You should have kubectl available and configured to talk to the desired cluster.

Running on kubernetes older than 1.16

As metacontroller does not have direct dependency on kubernetes API it have wide range of supported kubernetes versions. However, to be able to install it on clusters older than 1.16, CRD with schema in version v1beta1 must be used then.

Grant yourself cluster-admin (GKE only)

Due to a known issue in GKE, you'll need to first grant yourself cluster-admin privileges before you can install the necessary RBAC manifests.

kubectl create clusterrolebinding <user>-cluster-admin-binding --clusterrole=cluster-admin --user=<user>@<domain>

Replace <user> and <domain> above based on the account you use to authenticate to GKE.

Install Metacontroller

# Apply all set of production resources defined in kustomization.yaml in `production` directory .
kubectl apply -k

If you prefer to build and host your own images, please see the build instructions in the contributor guide.

If your kubectl version does does not support -k flag, please install resources mentioned in manifests/production/kustomization.yaml one by one manually with kubectl apply -f {{filename}} command.

Compatibility note CRD's are shipped in two versions:

  • v1 - supposed to be used when your kubernetes cluster is 1.16+
  • v1beta1 otherwise


The Metacontroller server has a few settings that can be configured with command-line flags (by editing the Metacontroller StatefulSet in manifests/metacontroller.yaml):

-vSet the logging verbosity level (e.g. -v=4). Level 4 logs Metacontroller's interaction with the API server. Levels 5 and up additionally log details of Metacontroller's invocation of lambda hooks. See the troubleshooting guide for more.
--discovery-intervalHow often to refresh discovery cache to pick up newly-installed resources (e.g. --discovery-interval=10s).
--cache-flush-intervalHow often to flush local caches and relist objects from the API server (e.g. --cache-flush-interval=30m).
--client-config-pathPath to kubeconfig file (same format as used by kubectl); if not specified, use in-cluster config (e.g. --client-config-path=/path/to/kubeconfig).
--client-go-qpsNumber of queries per second client-go is allowed to make (default 5, e.g. --client-go-qps=100)
--client-go-burstAllowed burst queries for client-go (default 10, e.g. --client-go-burst=200)
--workersNumber of sync workers to run (default 5, e.g. --workers=100)
--events-qpsRate of events flowing per object (default - 1 event per 5 minutes, e.g. --client-go-qps=0.0033)
--events-burstNumber of events allowed to send per object (default 25, e.g. --client-go-burst=25)

Migrating from /GoogleCloudPlatform/metacontroller

As current version of metacontroller uses different name of the finalizer than GCP version (GCP -, current version - thus after installing metacontroller you might need to clean up old finalizers, i.e. by running:

kubectl get <comma separated list of your resource types here> --no-headers --all-namespaces | awk '{print $2 " -n " $1}' | xargs -L1 -P 50 -r kubectl patch -p '{"metadata":{"finalizers": [null]}}' --type=merge