diff --git a/.github/workflows/helm-docs.yaml b/.github/workflows/helm-docs.yaml new file mode 100644 index 0000000..9ac416c --- /dev/null +++ b/.github/workflows/helm-docs.yaml @@ -0,0 +1,24 @@ +name: Generate Helm documentation +on: + pull_request: + paths: + - 'chart/**' +jobs: + generate: + permissions: + contents: write + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} + token: ${{ secrets.GITHUB_TOKEN }} + - name: Run helm-docs + uses: losisin/helm-docs-github-action@v1 + with: + fail-on-diff: true + version: v1.14.2 + # git-push-user-name: "github-actions[bot]" + # git-push-user-email: "github-actions[bot]@users.noreply.github.com" diff --git a/.github/workflows/helm-schema-gen.yaml b/.github/workflows/helm-schema-gen.yaml new file mode 100644 index 0000000..23b7b4e --- /dev/null +++ b/.github/workflows/helm-schema-gen.yaml @@ -0,0 +1,21 @@ +name: Generate values schema json +on: + pull_request: + paths: + - 'chart/**' +jobs: + generate: + permissions: + contents: write + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.ref }} + - name: Generate values schema json + uses: losisin/helm-values-schema-json-action@v2 + with: + values: chart/node-readiness-controller/values.yaml + output: chart/node-readiness-controller/values.schema.json + fail-on-diff: true diff --git a/chart/node-readiness-controller/.helmignore b/chart/node-readiness-controller/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/chart/node-readiness-controller/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/chart/node-readiness-controller/Chart.yaml b/chart/node-readiness-controller/Chart.yaml new file mode 100644 index 0000000..e68fa38 --- /dev/null +++ b/chart/node-readiness-controller/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: node-readiness-controller +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/chart/node-readiness-controller/README.md b/chart/node-readiness-controller/README.md new file mode 100644 index 0000000..1a30dfd --- /dev/null +++ b/chart/node-readiness-controller/README.md @@ -0,0 +1,41 @@ +# node-readiness-controller + +![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.16.0](https://img.shields.io/badge/AppVersion-1.16.0-informational?style=flat-square) + +A Helm chart for Kubernetes + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | This is for setting the affinity for the controller. More information can be found here: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity | +| enableWebhook | bool | `false` | Enables the validating webhook for the controller. More information can be found here: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/ | +| extraArgs | list | `[]` | This is for setting extra arguments to the controller | +| fullnameOverride | string | `""` | This is to override the full name of the resources created by this chart. More information can be found here: https://helm.sh/docs/chart_template_guide/naming_conventions/#full-name-override | +| healthCheckPort | int | `8081` | This is for setting the health check port for the controller. More information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ | +| image | object | `{"pullPolicy":"IfNotPresent","repository":"controller","tag":""}` | This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ | +| image.pullPolicy | string | `"IfNotPresent"` | This sets the pull policy for images. | +| image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | +| imagePullSecrets | list | `[]` | This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ | +| livenessProbe | object | `{"httpGet":{"path":"/healthz","port":"http"},"initialDelaySeconds":15,"periodSeconds":20}` | This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ | +| nameOverride | string | `""` | This is to override the chart name. | +| nodeSelector | object | `{}` | This is for setting the node selector for the controller. More information can be found here: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | +| podAnnotations | object | `{}` | This is for setting Kubernetes Annotations to a Pod. For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ | +| podLabels | object | `{}` | This is for setting Kubernetes Labels to a Pod. For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ | +| podSecurityContext | object | `{"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}` | This is for setting the security context for the pod. Set to a reasonable default. More information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ | +| priorityClassName | string | `"system-cluster-critical"` | This is for setting the priority class name for the controller. More information can be found here: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ | +| rbac | object | `{"create":true}` | Configures Roles, ClusterRoles, RoleBindings and ClusterRoleBindings required for node-readiness-controller to operate. | +| rbac.create | bool | `true` | Specifies whether RBAC resources should be created. | +| readinessProbe | object | `{"httpGet":{"path":"/healthz","port":"http"},"initialDelaySeconds":5,"periodSeconds":10}` | This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ | +| replicaCount | int | `1` | This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ | +| resources | object | `{}` | This is for setting the resource requests and limits for the container. A reeasonable default is commented out for guidance. More information can be found here: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | +| securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true}` | This is for setting the security context for the container. Set to a reasonable default. More information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ | +| serviceAccount | object | `{"annotations":{},"automount":true,"create":true,"name":""}` | This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/ | +| serviceAccount.annotations | object | `{}` | Annotations to add to the service account. | +| serviceAccount.automount | bool | `true` | Automatically mount a ServiceAccount's API credentials? | +| serviceAccount.create | bool | `true` | Specifies whether a service account should be created. | +| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template. | +| tolerations | list | `[]` | This is for setting the tolerations for the controller. More information can be found here: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/#concepts | +| volumeMounts | list | `[]` | Additional volumeMounts on the output Deployment definition. | +| volumes | list | `[]` | Additional volumes on the output Deployment definition. | + diff --git a/chart/node-readiness-controller/crds/crds.yaml b/chart/node-readiness-controller/crds/crds.yaml new file mode 100644 index 0000000..0ccf52a --- /dev/null +++ b/chart/node-readiness-controller/crds/crds.yaml @@ -0,0 +1,382 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: nodereadinessrules.readiness.node.x-k8s.io +spec: + group: readiness.node.x-k8s.io + names: + kind: NodeReadinessRule + listKind: NodeReadinessRuleList + plural: nodereadinessrules + shortNames: + - nrr + singular: nodereadinessrule + scope: Cluster + versions: + - additionalPrinterColumns: + - description: Continuous, Bootstrap or Dryrun - shows if the rule is in enforcement + or dryrun mode. + jsonPath: .spec.enforcementMode + name: Mode + type: string + - description: The readiness taint applied by this rule. + jsonPath: .spec.taint.key + name: Taint + type: string + - description: The age of this resource + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: NodeReadinessRule is the Schema for the NodeReadinessRules API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec defines the desired state of NodeReadinessRule + properties: + conditions: + description: |- + conditions contains a list of the Node conditions that defines the specific + criteria that must be met for taints to be managed on the target Node. + The presence or status of these conditions directly triggers the application or removal of Node taints. + items: + description: |- + ConditionRequirement defines a specific Node condition and the status value + required to trigger the controller's action. + properties: + requiredStatus: + description: requiredStatus is status of the condition, one + of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of Node condition + + Following kubebuilder validation is referred from https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Condition + maxLength: 316 + minLength: 1 + type: string + required: + - requiredStatus + - type + type: object + maxItems: 32 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + dryRun: + description: |- + dryRun when set to true, The controller will evaluate Node conditions and log intended taint modifications + without persisting changes to the cluster. Proposed actions are reflected in the resource status. + type: boolean + enforcementMode: + description: |- + enforcementMode specifies how the controller maintains the desired state. + enforcementMode is one of bootstrap-only, continuous. + "bootstrap-only" applies the configuration once during initial setup. + "continuous" ensures the state is monitored and corrected throughout the resource lifecycle. + enum: + - bootstrap-only + - continuous + type: string + nodeSelector: + description: nodeSelector limits the scope of this rule to a specific + subset of Nodes. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + taint: + description: |- + taint defines the specific Taint (Key, Value, and Effect) to be managed + on Nodes that meet the defined condition criteria. + properties: + effect: + description: |- + Required. The effect of the taint on pods + that do not tolerate the taint. + Valid effects are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Required. The taint key to be applied to a node. + type: string + timeAdded: + description: TimeAdded represents the time at which the taint + was added. + format: date-time + type: string + value: + description: The taint value corresponding to the taint key. + type: string + required: + - effect + - key + type: object + required: + - conditions + - enforcementMode + - nodeSelector + - taint + type: object + status: + description: status defines the observed state of NodeReadinessRule + minProperties: 1 + properties: + appliedNodes: + description: |- + appliedNodes lists the names of Nodes where the taint has been successfully managed. + This provides a quick reference to the scope of impact for this rule. + items: + maxLength: 253 + type: string + maxItems: 5000 + type: array + x-kubernetes-list-type: set + dryRunResults: + description: |- + dryRunResults captures the outcome of the rule evaluation when DryRun is enabled. + This field provides visibility into the actions the controller would have taken, + allowing users to preview taint changes before they are committed. + minProperties: 1 + properties: + affectedNodes: + description: affectedNodes is the total count of Nodes that match + the rule's criteria. + format: int32 + minimum: 0 + type: integer + riskyOperations: + description: |- + riskyOperations represents the count of Nodes where required conditions + are missing entirely, potentially indicating an ambiguous node state. + format: int32 + minimum: 0 + type: integer + summary: + description: |- + summary provides a human-readable overview of the dry run evaluation, + highlighting key findings or warnings. + maxLength: 4096 + minLength: 1 + type: string + taintsToAdd: + description: taintsToAdd is the number of Nodes that currently + lack the specified taint and would have it applied. + format: int32 + minimum: 0 + type: integer + taintsToRemove: + description: |- + taintsToRemove is the number of Nodes that currently possess the + taint but no longer meet the criteria, leading to its removal. + format: int32 + minimum: 0 + type: integer + required: + - summary + type: object + failedNodes: + description: |- + failedNodes lists the Nodes where the rule evaluation encountered an error. + This is used for troubleshooting configuration issues, such as invalid selectors during node lookup. + items: + description: NodeFailure provides diagnostic details for Nodes that + could not be successfully evaluated by the rule. + properties: + lastEvaluationTime: + description: lastEvaluationTime is the timestamp of the last + rule check failed for this Node. + format: date-time + type: string + message: + description: message is a human-readable message indicating + details about the evaluation. + maxLength: 10240 + minLength: 1 + type: string + nodeName: + description: |- + nodeName is the name of the failed Node. + + Following kubebuilder validation is referred from + https://github.com/kubernetes/apimachinery/blob/84d740c9e27f3ccc94c8bc4d13f1b17f60f7080b/pkg/util/validation/validation.go#L198 + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + reason: + description: reason provides a brief explanation of the evaluation + result. + maxLength: 256 + minLength: 1 + type: string + required: + - lastEvaluationTime + - nodeName + type: object + maxItems: 5000 + type: array + x-kubernetes-list-map-keys: + - nodeName + x-kubernetes-list-type: map + nodeEvaluations: + description: |- + nodeEvaluations provides detailed insight into the rule's assessment for individual Nodes. + This is primarily used for auditing and debugging why specific Nodes were or + were not targeted by the rule. + items: + description: NodeEvaluation provides a detailed audit of a single + Node's compliance with the rule. + properties: + conditionResults: + description: |- + conditionResults provides a detailed breakdown of each condition evaluation + for this Node. This allows for granular auditing of which specific + criteria passed or failed during the rule assessment. + items: + description: |- + ConditionEvaluationResult provides a detailed report of the comparison between + the Node's observed condition and the rule's requirement. + properties: + currentStatus: + description: currentStatus is the actual status value + observed on the Node, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + requiredStatus: + description: requiredStatus is the status value defined + in the rule that must be matched, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type corresponds to the Node condition type + being evaluated. + maxLength: 316 + minLength: 1 + type: string + required: + - currentStatus + - requiredStatus + - type + type: object + maxItems: 5000 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + lastEvaluationTime: + description: lastEvaluationTime is the timestamp when the controller + last assessed this Node. + format: date-time + type: string + nodeName: + description: nodeName is the name of the evaluated Node. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + taintStatus: + description: taintStatus represents the taint status on the + Node, one of Present, Absent. + enum: + - Present + - Absent + type: string + required: + - conditionResults + - lastEvaluationTime + - nodeName + - taintStatus + type: object + maxItems: 5000 + type: array + x-kubernetes-list-map-keys: + - nodeName + x-kubernetes-list-type: map + observedGeneration: + description: observedGeneration reflects the generation of the most + recently observed NodeReadinessRule by the controller. + format: int64 + minimum: 1 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/chart/node-readiness-controller/templates/_helpers.tpl b/chart/node-readiness-controller/templates/_helpers.tpl new file mode 100644 index 0000000..8ca8a0d --- /dev/null +++ b/chart/node-readiness-controller/templates/_helpers.tpl @@ -0,0 +1,81 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "node-readiness-controller.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "node-readiness-controller.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create a default short name for the application. +We truncate at 32 chars because some Kubernetes name fields are limited to this 63 characters (by the DNS naming spec) +and we add 29 characters maximum via a suffix for rbac +If release name contains chart name it will be used as a full name. +*/}} +{{- define "node-readiness-controller.shortname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 32 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 32 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 32 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "node-readiness-controller.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "node-readiness-controller.labels" -}} +helm.sh/chart: {{ include "node-readiness-controller.chart" . }} +{{ include "node-readiness-controller.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "node-readiness-controller.selectorLabels" -}} +app.kubernetes.io/name: {{ include "node-readiness-controller.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "node-readiness-controller.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "node-readiness-controller.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/chart/node-readiness-controller/templates/deployment.yaml b/chart/node-readiness-controller/templates/deployment.yaml new file mode 100644 index 0000000..3de6736 --- /dev/null +++ b/chart/node-readiness-controller/templates/deployment.yaml @@ -0,0 +1,88 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "node-readiness-controller.fullname" . }} + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "node-readiness-controller.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "node-readiness-controller.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "node-readiness-controller.serviceAccountName" . }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: manager + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: + - --leader-elect + - --health-probe-bind-address=:{{ .Values.healthCheckPort }} + - --enable-webhook={{ .Values.enableWebhook }} + {{- with .Values.extraArgs }} + {{- range . }} + - {{ . }} + {{- end }} + {{- end }} + ports: + - name: http + containerPort: {{ .Values.healthCheckPort }} + protocol: TCP + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/chart/node-readiness-controller/templates/rbac.yaml b/chart/node-readiness-controller/templates/rbac.yaml new file mode 100644 index 0000000..95b4be1 --- /dev/null +++ b/chart/node-readiness-controller/templates/rbac.yaml @@ -0,0 +1,251 @@ +{{- if .Values.rbac.create -}} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} + name: {{ include "node-readiness-controller.shortname" . }}-leader-election-role + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +... +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} + name: {{ include "node-readiness-controller.shortname" . }}-manager-role +rules: +- apiGroups: + - "" + resources: + - nodes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - nodes/finalizers + verbs: + - update +- apiGroups: + - "" + resources: + - nodes/status + verbs: + - get + - patch + - update +- apiGroups: + - readiness.node.x-k8s.io + resources: + - nodereadinessrules + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - readiness.node.x-k8s.io + resources: + - nodereadinessrules/finalizers + verbs: + - update +- apiGroups: + - readiness.node.x-k8s.io + resources: + - nodereadinessrules/status + verbs: + - get + - patch + - update +... +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} + name: {{ include "node-readiness-controller.shortname" . }}-metrics-auth-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +... +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} + name: {{ include "node-readiness-controller.shortname" . }}-metrics-reader +rules: +- nonResourceURLs: + - /metrics + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} + name: {{ include "node-readiness-controller.shortname" . }}-nodereadinessrule-admin-role +rules: +- apiGroups: + - readiness.node.x-k8s.io + resources: + - nodereadinessrules + verbs: + - '*' +- apiGroups: + - readiness.node.x-k8s.io + resources: + - nodereadinessrules/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} + name: {{ include "node-readiness-controller.shortname" . }}-nodereadinessrule-editor-role +rules: +- apiGroups: + - readiness.node.x-k8s.io + resources: + - nodereadinessrules + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - readiness.node.x-k8s.io + resources: + - nodereadinessrules/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} + name: {{ include "node-readiness-controller.shortname" . }}-nodereadinessrule-viewer-role +rules: +- apiGroups: + - readiness.node.x-k8s.io + resources: + - nodereadinessrules + verbs: + - get + - list + - watch +- apiGroups: + - readiness.node.x-k8s.io + resources: + - nodereadinessrules/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} + name: {{ include "node-readiness-controller.shortname" . }}-leader-election-rolebinding + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "node-readiness-controller.shortname" . }}-leader-election-role +subjects: +- kind: ServiceAccount + name: {{ include "node-readiness-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} + name: {{ include "node-readiness-controller.shortname" . }}-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "node-readiness-controller.shortname" . }}-manager-role +subjects: +- kind: ServiceAccount + name: {{ include "node-readiness-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} + name: {{ include "node-readiness-controller.shortname" . }}-metrics-auth-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "node-readiness-controller.shortname" . }}-metrics-auth-role +subjects: +- kind: ServiceAccount + name: {{ include "node-readiness-controller.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} \ No newline at end of file diff --git a/chart/node-readiness-controller/templates/serviceaccount.yaml b/chart/node-readiness-controller/templates/serviceaccount.yaml new file mode 100644 index 0000000..b64682d --- /dev/null +++ b/chart/node-readiness-controller/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "node-readiness-controller.serviceAccountName" . }} + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/chart/node-readiness-controller/values.schema.json b/chart/node-readiness-controller/values.schema.json new file mode 100644 index 0000000..90a83f1 --- /dev/null +++ b/chart/node-readiness-controller/values.schema.json @@ -0,0 +1,175 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "affinity": { + "type": "object" + }, + "enableWebhook": { + "type": "boolean" + }, + "extraArgs": { + "type": "array" + }, + "fullnameOverride": { + "type": "string" + }, + "healthCheckPort": { + "type": "integer" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "imagePullSecrets": { + "type": "array" + }, + "livenessProbe": { + "type": "object", + "properties": { + "httpGet": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "port": { + "type": "string" + } + } + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + } + } + }, + "nameOverride": { + "type": "string" + }, + "nodeSelector": { + "type": "object" + }, + "podAnnotations": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "podSecurityContext": { + "type": "object", + "properties": { + "runAsNonRoot": { + "type": "boolean" + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + } + } + } + }, + "priorityClassName": { + "type": "string" + }, + "rbac": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "httpGet": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "port": { + "type": "string" + } + } + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + } + } + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "securityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "readOnlyRootFilesystem": { + "type": "boolean" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "automount": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "tolerations": { + "type": "array" + }, + "volumeMounts": { + "type": "array" + }, + "volumes": { + "type": "array" + } + } +} diff --git a/chart/node-readiness-controller/values.yaml b/chart/node-readiness-controller/values.yaml new file mode 100644 index 0000000..c63f4fe --- /dev/null +++ b/chart/node-readiness-controller/values.yaml @@ -0,0 +1,127 @@ +# Default values for node-readiness-controller. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# replicaCount -- This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ +replicaCount: 1 + +# image -- This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ +image: + # image.repository + repository: controller + # image.pullPolicy -- This sets the pull policy for images. + pullPolicy: IfNotPresent + # image.tag -- Overrides the image tag whose default is the chart appVersion. + tag: "" + +# imagePullSecrets -- This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ +imagePullSecrets: [] + +# nameOverride -- This is to override the chart name. +nameOverride: "" + +# fullnameOverride -- This is to override the full name of the resources created by this chart. More information can be found here: https://helm.sh/docs/chart_template_guide/naming_conventions/#full-name-override +fullnameOverride: "" + +# enableWebhook -- Enables the validating webhook for the controller. More information can be found here: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/ +enableWebhook: false + +# healthCheckPort -- This is for setting the health check port for the controller. More information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ +healthCheckPort: 8081 + +# extraArgs -- This is for setting extra arguments to the controller +extraArgs: [] + +# priorityClassName -- This is for setting the priority class name for the controller. More information can be found here: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +priorityClassName: system-cluster-critical + +# serviceAccount -- This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/ +serviceAccount: + # serviceAccount.create -- Specifies whether a service account should be created. + create: true + # serviceAccount.automount -- Automatically mount a ServiceAccount's API credentials? + automount: true + # serviceAccount.annotations -- Annotations to add to the service account. + annotations: {} + # serviceAccount.name -- The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template. + name: "" + +# rbac -- Configures Roles, ClusterRoles, RoleBindings and ClusterRoleBindings required for node-readiness-controller to operate. +rbac: + # rbac.create -- Specifies whether RBAC resources should be created. + create: true + +# podAnnotations -- This is for setting Kubernetes Annotations to a Pod. +# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ +podAnnotations: {} + +# podLabels -- This is for setting Kubernetes Labels to a Pod. +# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ +podLabels: {} + +# podSecurityContext -- This is for setting the security context for the pod. Set to a reasonable default. More information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +podSecurityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + +# securityContext -- This is for setting the security context for the container. Set to a reasonable default. More information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + + +# resources -- This is for setting the resource requests and limits for the container. A reeasonable default is commented out for guidance. More information can be found here: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +resources: {} + # limits: + # cpu: 500m + # memory: 128Mi + # requests: + # cpu: 10m + # memory: 64Mi + +# livenessProbe -- This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ +livenessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 15 + periodSeconds: 20 + +# readinessProbe -- This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ +readinessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + + +# volumes -- Additional volumes on the output Deployment definition. +volumes: [] + # - name: foo + # secret: + # secretName: mysecret + # optional: false + +# volumeMounts -- Additional volumeMounts on the output Deployment definition. +volumeMounts: [] + # - name: foo + # mountPath: "/etc/foo" + # readOnly: true + +# nodeSelector -- This is for setting the node selector for the controller. More information can be found here: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector +nodeSelector: {} + # node-role.kubernetes.io/control-plane: "" + +# tolerations -- This is for setting the tolerations for the controller. More information can be found here: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/#concepts +tolerations: [] + # - key: node-role.kubernetes.io/control-plane + # operator: Exists + +# affinity -- This is for setting the affinity for the controller. More information can be found here: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity +affinity: {}