{"id":44203269,"url":"https://github.com/linode/karpenter-provider-linode","last_synced_at":"2026-03-09T21:24:52.852Z","repository":{"id":333763748,"uuid":"1117602838","full_name":"linode/karpenter-provider-linode","owner":"linode","description":"Linode Karpenter provider","archived":false,"fork":false,"pushed_at":"2026-03-02T15:24:17.000Z","size":919,"stargazers_count":1,"open_issues_count":2,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-02T18:47:32.205Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/linode.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"code-of-conduct.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/security-notice.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-16T14:47:45.000Z","updated_at":"2026-03-02T15:27:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/linode/karpenter-provider-linode","commit_stats":null,"previous_names":["linode/karpenter-provider-linode"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/linode/karpenter-provider-linode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linode%2Fkarpenter-provider-linode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linode%2Fkarpenter-provider-linode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linode%2Fkarpenter-provider-linode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linode%2Fkarpenter-provider-linode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/linode","download_url":"https://codeload.github.com/linode/karpenter-provider-linode/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linode%2Fkarpenter-provider-linode/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30310296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T20:05:46.299Z","status":"ssl_error","status_checked_at":"2026-03-09T19:57:04.425Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-09T22:05:31.872Z","updated_at":"2026-03-09T21:24:52.761Z","avatar_url":"https://github.com/linode.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Karpenter Provider Linode\n\n\u003cp align=\"center\"\u003e\n\u003c!-- go doc / reference card --\u003e\n\u003ca href=\"https://pkg.go.dev/github.com/linode/karpenter-provider-linode\"\u003e\n\u003cimg src=\"https://pkg.go.dev/badge/github.com/linode/karpenter-provider-linode.svg\"\u003e\u003c/a\u003e\n\u003c!-- goreportcard badge --\u003e\n\u003ca href=\"https://goreportcard.com/report/github.com/linode/karpenter-provider-linode\"\u003e\n\u003cimg src=\"https://goreportcard.com/badge/github.com/linode/karpenter-provider-linode\"\u003e\u003c/a\u003e\n\u003c!-- join kubernetes slack channel for linode --\u003e\n\u003ca href=\"https://kubernetes.slack.com/messages/CD4B15LUR\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/join%20slack-%23linode-brightgreen\"\u003e\u003c/a\u003e\n\u003c!-- PRs welcome --\u003e\n\u003ca href=\"http://makeapullrequest.com\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/PRs-welcome-brightgreen.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n\u003c!-- go build / test CI --\u003e\n\u003ca href=\"https://github.com/linode/karpenter-provider-linode/actions/workflows/ci.yml\"\u003e\n\u003cimg src=\"https://github.com/linode/karpenter-provider-linode/actions/workflows/ci.yml/badge.svg\"\u003e\u003c/a\u003e\n\u003c!-- codecov badge --\u003e\n\u003ca href=\"https://codecov.io/github/linode/karpenter-provider-linode\" \u003e \n\u003cimg src=\"https://codecov.io/github/linode/karpenter-provider-linode/graph/badge.svg?token=YQFKF86KJ6\"/\u003e \n\u003c/a\u003e\n\u003c!-- ko build CI --\u003e\n\u003ca href=\"https://github.com/linode/karpenter-provider-linode/actions/workflows/release.yml\"\u003e\n\u003cimg src=\"https://github.com/linode/karpenter-provider-linode/actions/workflows/release.yml/badge.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n*PLEASE NOTE*: This project is considered ALPHA quality and should NOT be used for production, as it is currently in active development. Use at your own risk. APIs, configuration file formats, and functionality are all subject to change frequently. That said, please try it out in your development and test environments and let us know if it works. Contributions welcome! Thanks!\n\n---\n\nTable of contents:\n- [Features Overview](#features-overview)\n- [Installation](#installation)\n  - [Install utilities](#install-tools)\n  - [Create a cluster](#create-a-cluster)\n  - [Configure Helm chart values](#configure-helm-chart-values)\n  - [Install Karpenter](#install-karpenter)\n- [Using Karpenter](#using-karpenter)\n  - [Create NodePool](#create-nodepool)\n  - [Scale up deployment](#scale-up-deployment)\n  - [Scale down deployment](#scale-down-deployment)\n  - [Delete Karpenter nodes manually](#delete-karpenter-nodes-manually)\n- [Cleanup](#cleanup)\n  - [Delete the cluster](#delete-the-cluster)\n- [Known issues](#known-issues)\n\n## Features Overview\nThe LKE Karpenter Provider enables node autoprovisioning using [Karpenter](https://karpenter.sh/) on your LKE cluster.\nKarpenter improves the efficiency and cost of running workloads on Kubernetes clusters by:\n\n* **Watching** for pods that the Kubernetes scheduler has marked as unschedulable\n* **Evaluating** scheduling constraints (resource requests, nodeselectors, affinities, tolerations, and topology spread constraints) requested by the pods\n* **Provisioning** nodes that meet the requirements of the pods\n* **Removing** the nodes when the nodes are no longer needed\n\n## Provider Modes\n\nThis provider supports two operating modes:\n\n1.  **LKE Mode (Default)**: Creates LKE Node Pools for each provisioned node. This is the simplest method and recommended for most users.\n2.  **Instance Mode**: Creates standard Linode Instances. This offers granular control over instance settings (SSH keys, placement groups, etc.) but requires more manual configuration. This is currently in **development and not yet fully functional**.\n\nSee [Configuration Documentation](docs/CONFIGURATION.md) for full details on modes and available settings.\n\n## Installation\n\n### Install tools\n\nInstall these tools before proceeding:\n* [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)\n* [Helm](https://helm.sh/docs/intro/install/)\n\n### Create a cluster\n\n1. Create a new LKE cluster with any amount of nodes in any region.\nThis can be easily done in [Linode Cloud Manager](https://cloud.linode.com/) or via the [Linode CLI](https://techdocs.akamai.com/cloud-computing/docs/getting-started-with-the-linode-cli).\n2. Download the cluster's kubeconfig when ready.\n\n### Configure Helm chart values\n\nThe Karpenter Helm chart requires specific configuration values to work with an LKE cluster.\n\n1. Create a Linode PAT if you don't already have a `LINODE_TOKEN` env var set. Karpenter will use this for managing nodes in the LKE cluster.\n2. Set the variables:\n\n    ```bash\n    export CLUSTER_NAME=\u003ccluster name\u003e\n    export KUBECONFIG=\u003cpath to your LKE kubeconfig\u003e\n    export KARPENTER_NAMESPACE=kube-system\n    export LINODE_TOKEN=\u003cyour api token\u003e\n    # Optional: specify region explicitly (auto-discovered in LKE mode if not set)\n    # export LINODE_REGION=\u003cregion\u003e\n    # Optional: Set mode directly (default is lke)\n    # export KARPENTER_MODE=lke\n    ```\n\n**Note**: In LKE mode (default), Karpenter automatically discovers the cluster region from the Linode API using the cluster name. You can optionally set `LINODE_REGION` to override this behavior.\n\n### Install Karpenter\n\nUse the configured environment variables to install Karpenter using Helm:\n\n```bash\nhelm upgrade --install --namespace \"${KARPENTER_NAMESPACE}\" --create-namespace karpenter-crd charts/karpenter-crd\nhelm upgrade --install --namespace \"${KARPENTER_NAMESPACE}\" --create-namespace karpenter charts/karpenter \\\n\t\t--set settings.clusterName=${CLUSTER_NAME} \\\n\t\t--set apiToken=${LINODE_TOKEN} \\\n        --wait\n```\n\n**Optional Configuration:**\n\n- **Region**: Specify the region explicitly (only required for `instance` mode):\n  ```bash\n  --set region=${LINODE_REGION}\n  ```\n\n- **Mode**: Choose the operating mode (default is `lke`):\n  - `lke`: Provisions nodes using LKE NodePools (recommended for LKE clusters)\n  - `instance`: Provisions nodes as direct Linode instances\n  ```bash\n  --set settings.mode=lke\n  ```\n\nCheck karpenter deployed successfully:\n\n```bash\nkubectl get pods --namespace \"${KARPENTER_NAMESPACE}\" -l app.kubernetes.io/name=karpenter\n```\n\nCheck its logs:\n\n```bash\nkubectl logs -f -n \"${KARPENTER_NAMESPACE}\" -l app.kubernetes.io/name=karpenter -c controller\n```\n\n## Using Karpenter\n\n### Create NodePool\n\nA single Karpenter NodePool is capable of handling many different pod shapes. Karpenter makes scheduling and provisioning decisions based on pod attributes such as labels and affinity. In other words, Karpenter eliminates the need to manage many different node groups.\n\nCreate a default NodePool using the command below. (Additional examples available in the repository under [`examples/v1`](/examples/v1).) The `consolidationPolicy` set to `WhenUnderutilized` in the `disruption` block configures Karpenter to reduce cluster cost by removing and replacing nodes. As a result, consolidation will terminate any empty nodes on the cluster. This behavior can be disabled by setting consolidateAfter to `Never`, telling Karpenter that it should never consolidate nodes.\n\nNote: This NodePool will create capacity as long as the sum of all created capacity is less than the specified limit.\n\n```bash\ncat \u003c\u003cEOF | kubectl apply -f -\n---\napiVersion: karpenter.k8s.linode/v1alpha1\nkind: LinodeNodeClass\nmetadata:\n  name: default\nspec:\n  image: \"linode/ubuntu22.04\"\n---\napiVersion: karpenter.sh/v1\nkind: NodePool\nmetadata:\n  name: default\nspec:\n  template:\n    spec:\n      requirements:\n        - key: kubernetes.io/arch\n          operator: In\n          values: [\"amd64\"]\n        - key: kubernetes.io/os\n          operator: In\n          values: [\"linux\"]\n      nodeClassRef:\n        group: karpenter.k8s.linode\n        kind: LinodeNodeClass\n        name: default\n      expireAfter: 720h # 30 * 24h = 720h\n  limits:\n    cpu: 1000\nEOF\n```\n\nKarpenter is now active and ready to begin provisioning nodes.\n\n### Scale up deployment\n\nThis deployment uses the [pause image](https://www.ianlewis.org/en/almighty-pause-container) and starts with zero replicas.\n\n```bash\ncat \u003c\u003cEOF | kubectl apply -f -\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: inflate\nspec:\n  replicas: 0\n  selector:\n    matchLabels:\n      app: inflate\n  template:\n    metadata:\n      labels:\n        app: inflate\n    spec:\n      terminationGracePeriodSeconds: 0\n      securityContext:\n        runAsUser: 1000\n        runAsGroup: 3000\n        fsGroup: 2000\n      containers:\n      - name: inflate\n        image: public.ecr.aws/eks-distro/kubernetes/pause:3.7\n        resources:\n          requests:\n            cpu: 1\n        securityContext:\n          allowPrivilegeEscalation: false\nEOF\n\nkubectl scale deployment inflate --replicas 5\nkubectl logs -f -n \"${KARPENTER_NAMESPACE}\" -l app.kubernetes.io/name=karpenter -c controller\n```\n\n### Scale down deployment\n\nNow, delete the deployment. After a short amount of time, Karpenter should terminate the empty nodes due to consolidation.\n\n```bash\nkubectl delete deployment inflate\nkubectl logs -f -n \"${KARPENTER_NAMESPACE}\" -l app.kubernetes.io/name=karpenter -c controller\n```\n\n### Delete Karpenter nodes manually\n\nIf you delete a node with kubectl, Karpenter will gracefully cordon, drain, and shutdown the corresponding instance. Under the hood, Karpenter adds a finalizer to the node object, which blocks deletion until all pods are drained and the instance is terminated. Keep in mind, this only works for nodes provisioned by Karpenter.\n\n```bash\nkubectl delete node $NODE_NAME\n```\n\n## Cleanup\n\n### Delete the cluster\n\nTo avoid additional charges, remove the demo infrastructure from your Linode account.\n\n```bash\nhelm uninstall karpenter --namespace \"${KARPENTER_NAMESPACE}\"\nlinode-cli lke cluster-delete --label \"${CLUSTER_NAME}\"\n```\n\n## Known issues\n\nA duplicate `NodeClaim` (Linode instance) MAY be temporarily provisioned on Linode until Karpenter detects the original was able to register the original successfully. This is because:\n\n- Time from instance creation to that instance actually joining the cluster is SLOW (can take over 3 minutes for even non-GPU instances)\n- LKE standard does not yet support adding start-up taints to Kubelet (`karpenter.sh/unregistered` in particular is needed) to tell Karpenter to not go and create an extra `NodeClaim` because registration for the original is taking so long.\n\nTo address this gap in the meantime, we've configured the default `BATCH_IDLE_DURATION` and `BATCH_MAX_DURATION` for Karpenter to be quite long to avoid impatiently creating new `NodeClaim`s (see https://karpenter.sh/docs/reference/settings/ to read about these settings).\n\nThe trade-off of this approach is that while duplicate `NodeClaim`s are less likely to be created, Pods will be stuck in `Pending` for an extra 1 minute before a `NodeClaim` is created and subsquent instance creation request kicked off (`BATCH_IDLE_DURATION=1m`)\n\nIf a duplicate is created still (less likely, but still possible if instances take exceptionally long to join the cluster), the duplicate `NodeClaim` does get cleaned up after about a minute when Karpenter realizes it's not needed. You will see something like this in the Karpenter controller logs:\n\n```\n{\"level\":\"INFO\",\"time\":\"2026-01-26T19:42:57.156Z\",\"logger\":\"controller\",\"message\":\"launched nodeclaim\",\"commit\":\"237f3a9\",\"controller\":\"nodeclaim.lifecycle\",\"controllerGroup\":\"karpenter.sh\",\"controllerKind\":\"NodeClaim\",\"NodeClaim\":{\"name\":\"default-v2blg\"},\"namespace\":\"\",\"name\":\"default-v2blg\",\"reconcileID\":\"e85e6c72-8da1-4fea-af26-1fb0e676d502\",\"provider-id\":\"linode://90601036\",\"instance-type\":\"g6-standard-6\",\"zone\":\"\",\"capacity-type\":\"on-demand\",\"allocatable\":{\"cpu\":\"5915m\",\"memory\":\"13590Mi\",\"pods\":\"110\"}}\n{\"level\":\"ERROR\",\"time\":\"2026-01-26T19:44:22.686Z\",\"logger\":\"controller\",\"message\":\"node claim registration error\",\"commit\":\"237f3a9\",\"controller\":\"nodeclaim.lifecycle\",\"controllerGroup\":\"karpenter.sh\",\"controllerKind\":\"NodeClaim\",\"NodeClaim\":{\"name\":\"default-v2blg\"},\"namespace\":\"\",\"name\":\"default-v2blg\",\"reconcileID\":\"e3ab7681-c8fb-489a-9f6b-63036fa52090\",\"provider-id\":\"linode://90601036\",\"taint\":\"karpenter.sh/unregistered\",\"error\":\"missing taint prevents registration-related race conditions on Karpenter-managed nodes\"}\n{\"level\":\"INFO\",\"time\":\"2026-01-26T19:44:22.705Z\",\"logger\":\"controller\",\"message\":\"registered nodeclaim\",\"commit\":\"237f3a9\",\"controller\":\"nodeclaim.lifecycle\",\"controllerGroup\":\"karpenter.sh\",\"controllerKind\":\"NodeClaim\",\"NodeClaim\":{\"name\":\"default-v2blg\"},\"namespace\":\"\",\"name\":\"default-v2blg\",\"reconcileID\":\"e3ab7681-c8fb-489a-9f6b-63036fa52090\",\"provider-id\":\"linode://90601036\",\"Node\":{\"name\":\"lke561146-819072-4a8e5fd50000\"}}\n```\n\n---\n\n### Source Attribution\n\nNotice: Files in this source code originated from a fork of https://github.com/aws/karpenter-provider-aws\nwhich is under an Apache 2.0 license. Those files have been modified to reflect environmental requirements in LKE and Linode.\n\n---\n### Community, discussion, contribution, and support\nThis project follows the [Linode Community Code of Conduct](https://www.linode.com/community/questions/conduct). \n\nCome discuss Karpenter in the [#karpenter](https://kubernetes.slack.com/archives/C02SFFZSA2K) channel in the [Kubernetes slack](https://slack.k8s.io/)!\n\nCheck out the [Docs](https://karpenter.sh/) to learn more.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinode%2Fkarpenter-provider-linode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinode%2Fkarpenter-provider-linode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinode%2Fkarpenter-provider-linode/lists"}