Giter Site home page Giter Site logo

plumber-cd / kubernetes-dynamic-reclaimable-pvc-controllers Goto Github PK

View Code? Open in Web Editor NEW
35.0 5.0 5.0 128 KB

Dynamic PVC provisioner for pods requesting it via annotations. Automatic PV releaser.

License: Apache License 2.0

Go 98.64% Dockerfile 1.36%
kubernetes persistent-volume-claim provisioner persistent-volume pvc pv controller

kubernetes-dynamic-reclaimable-pvc-controllers's Introduction

kubernetes-dynamic-reclaimable-pvc-controllers

Automatic PV releaser.

Features

  • PV Releaser
    • Deletes claimRef from PVs that belong to Storage Class annotated for this Releaser ID (-controller-id) to move their status from Released to Available without deleting any data.

Disclaimers

Releaser Controller is by design automatically makes PVs with reclaimPolicy: Retain available to be reclaimed by other consumers without cleaning up any data. Use it with caution - this behavior might not be desirable in most cases. Any data left on the PV after the previous consumer will be available to all the following consumers. You may want to use StatefulSets instead. This controller might be ideal for something like build cache - insensitive data by design required to be shared among different consumers. There is many use cases for this, one of them is documented in examples/jenkins-kubernetes-plugin-with-build-cache.

Why do I need this?

Essentially Releaser controller allows you to have a storage pool of reusable PVs that retain data between consumers.

The problem statement for creating it was - I needed a pool of CI/CD build caches that can be re-used by my build pods but not allowed to be used concurrently. Normally, similar functionality is performed by a StatefulSet controller, but build pods (such as Jenkins) are not managed by StatefulSet controller.

Why reclaimPolicy: Retain is not enough?

When PVC that were using PV with reclaimPolicy: Retain is deleted - Kubernetes marks this PV Released. Fortunately, this will not let any other PVC to use it. I say fortunately because imagine if it did - meaning all the data on the volume could be accessed by a new consumer. This is not what reclaimPolicy: Retain is designed for - it only allows cluster administrators to recover the data after accidental PVC deletion. Even now deprecated reclaimPolicy: Recycle was performing a cleanup before making PV Available again. Unfortunately, this just doesn't work for something like a CI/CD build cache, where you intentionally want to reuse data from the previous consumer.

Why not a static PVC?

One way to approach this problem statement would be just to create a static PVC with accessModes: ["ReadWriteMany"] - and it would work in most of the cases. But it has certain limitations - let's start with the fact ReadWriteMany is not supported by many storage types (example: EBS). The ones that do support it (another popular choice - EFS) most likely based on NFS which does not support an FS-level locking. Even if you got a storage type that supports both ReadWriteMany and FS level locking - many tools just doesn't seem to use FS level locking (or have other bugs related to concurrent cache usage). All this can lead to various race conditions failing your builds. That can be solved by making different builds to isolate themselves into a different sub-folders, but that reduces overall cache hit ratio - performance gain will be smaller and you'll have a lot of duplicated cache for commonly used transitive build dependencies.

Why not StatefulSets?

StatefulSets are idiomatic way to reuse PVs and preserve data in Kubernetes. It works great for most of the stateful workload types - unfortunately it doesn't fit very well for CI/CD. Build pods are most likely dynamically generated in CI/CD, each pod is crafted for a specific project, with containers to bring in tools that are needed for this specific project. A simple example - one project might need a MySQL container for its unit tests while another might need a PostgreSQL container - but both are Maven projects so both need a Maven cache. You can't do this with StatefulSets where all the pods are exactly the same. Not to mention, that most of the times - using StatefulSets is just not an option (hello, Jenkins).

PV Releaser Controller

Associate

Releaser considers PVs associated when their Storage Class is annotated with metadata.annotations."reclaimable-pv-releaser.kubernetes.io/controller-id" pointing to this -controller-id.

Release

Releaser watches for PVs to be released. The following conditions must be met for a PV to be made Available:

  • metadata.annotations."reclaimable-pv-releaser.kubernetes.io/controller-id" on Storage Class must be set to this Controller ID.
  • status.phase must be Released.

If these conditions are met, Releaser will set spec.claimRef to null. That will make Kubernetes eventually to mark status.phase of this PV as Available - making other PVCs able to reclaim this PV.

Usage

Usage of reclaimable-pv-releaser:
  -add_dir_header
    	If true, adds the file directory to the header of the log messages
  -alsologtostderr
    	log to standard error as well as files
  -controller-id string
    	this controller identity name - use the same string for both provisioner and releaser
  -kubeconfig string
    	optional, absolute path to the kubeconfig file
  -lease-lock-id string
    	optional, the lease lock holder identity name (default <computed>)
  -lease-lock-name string
    	the lease lock resource name
  -lease-lock-namespace string
    	optional, the lease lock resource namespace; default to -namespace
  -log_backtrace_at value
    	when logging hits line file:N, emit a stack trace
  -log_dir string
    	If non-empty, write log files in this directory
  -log_file string
    	If non-empty, use this log file
  -log_file_max_size uint
    	Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
  -logtostderr
    	log to standard error instead of files (default true)
  -namespace string
    	limit to a specific namespace - only for provisioner
  -one_output
    	If true, only write logs to their native severity level (vs also writing to each lower severity level)
  -skip_headers
    	If true, avoid header prefixes in the log messages
  -skip_log_headers
    	If true, avoid headers when opening log files
  -stderrthreshold value
    	logs at or above this threshold go to stderr (default 2)
  -v value
    	number for the log level verbosity
  -vmodule value
    	comma-separated list of pattern=N settings for file-filtered logging

Example:

reclaimable-pv-releaser \
  -controller-id reclaimable-pvc-test \
  -lease-lock-name reclaimable-pvc-releaser-test \
  -lease-lock-namespace default

Helm

You can deploy Releaser controller using Helm:

helm repo add plumber-cd https://plumber-cd.github.io/helm/
helm repo update
helm install releaser plumber-cd/reclaimable-pv-releaser

See https://github.com/plumber-cd/helm.

Values:

kubernetes-dynamic-reclaimable-pvc-controllers's People

Contributors

dee-kryvenko avatar jglick avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

kubernetes-dynamic-reclaimable-pvc-controllers's Issues

[Request] Update `examples/jenkins-kubernetes-plugin-with-build-cache` with ephemeral volume usage

I came here from your comments on the https://issues.jenkins.io/browse/JENKINS-42422 issue.

I also read that Provisioner Controller is deprecated in favor of the Ephemeral Volumes.

But I am recently entering the Jenkins using Kubernetes world, and I am struggling to understand more or less how everything is tied.

I have seen the example jenkins-kubernetes-plugin-with-build-cache which still make use of the provisioner. Could be possible to update that example (or create a new one) with the usage of the releaser along with the ephemeral volumes?

panic in releaser.go:189

I tried this out on Kubernetes 1.21.10 cluster (RKE, VMware vSphere).
I followed the examples, and the first pod starts nicely, with the generated PVC, and VSphere CSI dynamically provisioned a volume.
However, after removing the pod, and starting a new one, a new volume is created instead of the old one reused.
The first volume is retained in state 'Released'.

The releaser logs show the error below. Am I missing something ?

I0426 15:22:50.780443       1 leaderelection.go:243] attempting to acquire leader lease default/releaser-reclaimable-pv-releaser...
I0426 15:23:54.735339       1 leaderelection.go:253] successfully acquired lease default/releaser-reclaimable-pv-releaser
I0426 15:23:54.735447       1 leader.go:82] I am the leader now: 34b83774-3474-4921-bc81-cd3c9bbe6d31
I0426 15:23:54.735549       1 releaser.go:60] Releaser starting...
I0426 15:23:54.735780       1 controller.go:243] Starting reclaimable-pv-releaser controller
I0426 15:23:54.836498       1 controller.go:252] Started reclaimable-pv-releaser controller
E0426 15:29:08.814156       1 runtime.go:78] Observed a panic: "assignment to entry in nil map" (assignment to entry in nil map)
goroutine 79 [running]:
k8s.io/apimachinery/pkg/util/runtime.logPanic(0x160a5a0, 0x198d150)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/runtime/runtime.go:74 +0x95
k8s.io/apimachinery/pkg/util/runtime.HandleCrash(0x0, 0x0, 0x0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/runtime/runtime.go:48 +0x86
panic(0x160a5a0, 0x198d150)
	/usr/local/go/src/runtime/panic.go:965 +0x1b9
github.com/plumber-cd/kubernetes-dynamic-reclaimable-pvc-controllers/releaser.(*Releaser).pvAssociateHandler(0xc0003fd540, 0xc00025e500, 0x17fea71, 0x22)
	/go/delivery/releaser/releaser.go:189 +0x87e
github.com/plumber-cd/kubernetes-dynamic-reclaimable-pvc-controllers/releaser.(*Releaser).pvSyncHandler(0xc0003fd540, 0x0, 0x0, 0xc00012c0f0, 0x28, 0x1565340, 0xc00051a210)
	/go/delivery/releaser/releaser.go:150 +0x4c5
github.com/plumber-cd/kubernetes-dynamic-reclaimable-pvc-controllers.(*BasicController).ProcessNextWorkItem.func1(0x19e16f8, 0xc0004089a0, 0xc00017cc90, 0x1565340, 0xc00051a120, 0x0, 0x0)
	/go/delivery/controller.go:312 +0x138
github.com/plumber-cd/kubernetes-dynamic-reclaimable-pvc-controllers.(*BasicController).ProcessNextWorkItem(0xc0003fd540, 0x17e267b, 0x2, 0x19e16f8, 0xc0004089a0, 0xc00017cc90, 0x203001)
	/go/delivery/controller.go:323 +0x1da
github.com/plumber-cd/kubernetes-dynamic-reclaimable-pvc-controllers.(*BasicController).RunWorker.func1()
	/go/delivery/controller.go:280 +0x99
k8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1(0xc00035c5c0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:155 +0x5f
k8s.io/apimachinery/pkg/util/wait.BackoffUntil(0xc00035c5c0, 0x19a13a0, 0xc0001b6420, 0x1, 0xc00009aea0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:156 +0x9b
k8s.io/apimachinery/pkg/util/wait.JitterUntil(0xc00035c5c0, 0x3b9aca00, 0x0, 0x1, 0xc00009aea0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:133 +0x98
k8s.io/apimachinery/pkg/util/wait.Until(0xc00035c5c0, 0x3b9aca00, 0xc00009aea0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:90 +0x4d
created by github.com/plumber-cd/kubernetes-dynamic-reclaimable-pvc-controllers/releaser.(*Releaser).Run.func1
	/go/delivery/releaser/releaser.go:107 +0x22f
panic: assignment to entry in nil map [recovered]
	panic: assignment to entry in nil map

goroutine 79 [running]:
k8s.io/apimachinery/pkg/util/runtime.HandleCrash(0x0, 0x0, 0x0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/runtime/runtime.go:55 +0x109
panic(0x160a5a0, 0x198d150)
	/usr/local/go/src/runtime/panic.go:965 +0x1b9
github.com/plumber-cd/kubernetes-dynamic-reclaimable-pvc-controllers/releaser.(*Releaser).pvAssociateHandler(0xc0003fd540, 0xc00025e500, 0x17fea71, 0x22)
	/go/delivery/releaser/releaser.go:189 +0x87e
github.com/plumber-cd/kubernetes-dynamic-reclaimable-pvc-controllers/releaser.(*Releaser).pvSyncHandler(0xc0003fd540, 0x0, 0x0, 0xc00012c0f0, 0x28, 0x1565340, 0xc00051a210)
	/go/delivery/releaser/releaser.go:150 +0x4c5
github.com/plumber-cd/kubernetes-dynamic-reclaimable-pvc-controllers.(*BasicController).ProcessNextWorkItem.func1(0x19e16f8, 0xc0004089a0, 0xc00017cc90, 0x1565340, 0xc00051a120, 0x0, 0x0)
	/go/delivery/controller.go:312 +0x138
github.com/plumber-cd/kubernetes-dynamic-reclaimable-pvc-controllers.(*BasicController).ProcessNextWorkItem(0xc0003fd540, 0x17e267b, 0x2, 0x19e16f8, 0xc0004089a0, 0xc00017cc90, 0x203001)
	/go/delivery/controller.go:323 +0x1da
github.com/plumber-cd/kubernetes-dynamic-reclaimable-pvc-controllers.(*BasicController).RunWorker.func1()
	/go/delivery/controller.go:280 +0x99
k8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1(0xc00035c5c0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:155 +0x5f
k8s.io/apimachinery/pkg/util/wait.BackoffUntil(0xc00035c5c0, 0x19a13a0, 0xc0001b6420, 0x1, 0xc00009aea0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:156 +0x9b
k8s.io/apimachinery/pkg/util/wait.JitterUntil(0xc00035c5c0, 0x3b9aca00, 0x0, 0x1, 0xc00009aea0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:133 +0x98
k8s.io/apimachinery/pkg/util/wait.Until(0xc00035c5c0, 0x3b9aca00, 0xc00009aea0)
	/go/pkg/mod/k8s.io/[email protected]/pkg/util/wait/wait.go:90 +0x4d
created by github.com/plumber-cd/kubernetes-dynamic-reclaimable-pvc-controllers/releaser.(*Releaser).Run.func1
	/go/delivery/releaser/releaser.go:107 +0x22f

Better association mechanism

From the README:

Once Released - PVs doesn't have any indication that they were once associated with a PVC that had association with this Controller ID. To establish this relation - we must catch it while PVC still exists and mark it with our label. If Releaser was down the whole time PVC existed - PV could never be associated making it now orphaned and it will stay as Released - Releaser can't know it have to make it Available.

This seems to become an issue. I am starting to get orphaned volumes because informers are not firing off until after PVC is already gone. There may be a bug in the informers code, but I had an idea to get a more reliable association mechanism that would not rely on a chance.

Can use annotation on the Storage Class to notify Releaser that the volume is up for release.

Latest application version isn't pushed to Helm

Hey there!

I noticed it's been a little bit since a new release was pushed to the Helm repository:

❯ helm repo add plumber-cd https://plumber-cd.github.io/helm/

❯ helm search repo plumber-cd --versions
NAME                              	CHART VERSION	APP VERSION	DESCRIPTION
plumber-cd/dynamic-pvc-provisioner	0.1.0        	0.2.0      	A Helm chart for Kubernetes
plumber-cd/dynamic-pvc-provisioner	0.0.3        	0.1.1      	A Helm chart for Kubernetes
plumber-cd/dynamic-pvc-provisioner	0.0.2        	0.0.4      	A Helm chart for Kubernetes
plumber-cd/dynamic-pvc-provisioner	0.0.1        	0.0.2      	A Helm chart for Kubernetes
plumber-cd/reclaimable-pv-releaser	0.1.0        	0.2.0      	A Helm chart for Kubernetes
plumber-cd/reclaimable-pv-releaser	0.0.3        	0.1.1      	A Helm chart for Kubernetes
plumber-cd/reclaimable-pv-releaser	0.0.2        	0.0.4      	A Helm chart for Kubernetes
plumber-cd/reclaimable-pv-releaser	0.0.1        	0.0.2      	A Helm chart for Kubernetes

Would it be possible to push v0.2.3 to the Helm repo?

Thanks much!

linux/arm64 support

Hey there!

Are there plans to push multiarch images with linux/amd64 and linux/arm64? I can build and host that myself if need be, but it would be nice to pull the official images from your Github registry.

Thanks much!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.