helm: Add a basic helm chart for zuul-operator

This change introduces a basic helm chart for the zuul-operator to
make it easier to (un)install is from a given Kubernetes cluster.  The
chart is a combination of the trimmed down output from 'helm create'
combined with some details from the existing Kubernetes templates in
the repository.

Notable differences from the existing templates are as follows:

- ClusterRole, ClusterRoleBinding, and ServiceAccount are all in
  separate template files

- we use the named role in the binding instead of using the
  cluster-admin role, which provides greater access than an operator
  should require

- any references to namespaces are removed as they will be controlled
  by 'helm install'

Notable deficiencies are as follows:

- no readiness probe or liveness probe (this was a pre-existing
  problem in the Kubernetes templates)

- not 100% clear if the listed role permissions are exactly what's
  required

Depends-on: https://review.opendev.org/c/zuul/zuul-jobs/+/861799
Change-Id: I4c31d2e59f140277afe02077551544458c141412
This commit is contained in:
Michael Kelly 2022-10-14 17:17:58 -07:00
parent ae83e678b2
commit 5694e0921b
No known key found for this signature in database
GPG Key ID: 77F7FE93040ECF3E
10 changed files with 551 additions and 0 deletions

View File

@ -94,11 +94,22 @@
nodes: []
vars: *image_vars
- job:
description: Run Helm lint against operator chart
name: zuul-operator-helm-lint
parent: helm-lint
files:
- helm/.*
vars:
helm_charts: [helm/zuul-operator]
helm_version: 3.10.1
- project:
check:
jobs:
- nox-linters
- zuul-nox-docs
- zuul-operator-helm-lint
- zuul-operator-build-image
- zuul-operator-functional-k8s:
dependencies: zuul-operator-build-image
@ -106,6 +117,7 @@
jobs:
- nox-linters
- zuul-nox-docs
- zuul-operator-helm-lint
- zuul-operator-upload-image
- zuul-operator-functional-k8s:
dependencies: zuul-operator-upload-image

View File

@ -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/

View File

@ -0,0 +1,9 @@
apiVersion: v2
name: zuul-operator
description: "An operator for running Zuul CI on Kubernetes"
type: application
version: 0.1.0
appVersion: "8.0.0"
maintainers:
- name: michael_kelly
email: mkelly@arista.com

View File

@ -0,0 +1,184 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: zuuls.operator.zuul-ci.org
spec:
group: operator.zuul-ci.org
names:
kind: Zuul
listKind: ZuulList
plural: zuuls
singular: zuul
shortNames:
- zuul
scope: Namespaced
versions:
- name: v1alpha1
served: false
storage: false
schema:
openAPIV3Schema:
type: object
- name: v1alpha2
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
imagePrefix:
type: string
imagePullSecrets:
type: array
items:
type: string
zuulImageVersion:
type: string
zuulPreviewImageVersion:
type: string
zuulRegistryImageVersion:
type: string
nodepoolImageVersion:
type: string
database:
type: object
properties:
secretName:
type: string
allowUnsafeConfig:
type: boolean
default: false
zookeeper:
type: object
properties:
hosts:
type: string
secretName:
type: string
storageClassName:
type: string
env:
type: object
x-kubernetes-preserve-unknown-fields: true
scheduler:
type: object
properties:
config:
type: object
properties:
secretName:
type: string
count:
type: integer
default: 1
minimum: 1
storageClassName:
type: string
launcher:
type: object
properties:
config:
type: object
properties:
secretName:
type: string
executor:
type: object
properties:
count:
type: integer
default: 1
minimum: 1
sshkey:
type: object
properties:
secretName:
type: string
terminationGracePeriodSeconds:
type: integer
default: 21600
minimum: 0
merger:
type: object
properties:
count:
type: integer
git_user_email:
type: string
git_user_name:
type: string
web:
type: object
properties:
count:
type: integer
default: 1
status_url:
type: string
fingergw:
type: object
properties:
count:
type: integer
default: 1
connections:
type: object
x-kubernetes-preserve-unknown-fields: true
externalConfig:
type: object
x-kubernetes-preserve-unknown-fields: true
jobVolumes:
type: array
items:
type: object
properties:
context:
type: string
pattern: ^(trusted|untrusted)$
access:
type: string
pattern: ^(rw|ro)$
path:
type: string
volume:
type: object
properties:
name:
type: string
hostPath:
type: object
properties:
path:
type: string
type:
type: string
preview:
type: object
properties:
count:
type: integer
default: 0
registry:
type: object
properties:
count:
type: integer
default: 0
volumeSize:
type: string
default: "80G"
tls:
type: object
properties:
secretName:
type: string
config:
type: object
properties:
secretName:
type: string
storageClassName:
type: string

View File

@ -0,0 +1,12 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "zuul-operator.serviceAccountName" . }}
labels:
{{- include "zuul-operator.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,133 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "zuul-operator.serviceAccountName" . }}
rules:
- apiGroups:
- ""
resources:
- pods
- pods/exec
- services
- services/finalizers
- endpoints
- persistentvolumeclaims
- events
- configmaps
- secrets
- ingresses
- namespaces
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- apps
resources:
- deployments
- daemonsets
- replicasets
- statefulsets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- get
- list
- apiGroups:
- batch
resources:
- jobs
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- policy
resources:
- poddisruptionbudgets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- apps
resourceNames:
- zuul-operator
resources:
- deployments/finalizers
verbs:
- update
- apiGroups:
- apps
resources:
- replicasets
- deployments
verbs:
- get
- apiGroups:
- cert-manager.io
- pxc.percona.com
resources:
- '*'
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- operator.zuul-ci.org
resources:
- zuuls
- zuuls/status
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- monitoring.coreos.com
resources:
- servicemonitors
verbs:
- get
- create

View File

@ -0,0 +1,12 @@
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ include "zuul-operator.serviceAccountName" . }}
subjects:
- kind: ServiceAccount
name: {{ include "zuul-operator.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
roleRef:
kind: ClusterRole
name: {{ include "zuul-operator.serviceAccountName" . }}
apiGroup: rbac.authorization.k8s.io

View File

@ -0,0 +1,53 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "zuul-operator.fullname" . }}
labels:
{{- include "zuul-operator.labels" . | nindent 4 }}
spec:
replicas: 1
selector:
matchLabels:
{{- include "zuul-operator.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "zuul-operator.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "zuul-operator.serviceAccountName" . }}
{{- if .Values.podSecurityContext }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
{{- if .Values.securityContext }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
{{- end }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- if .Values.resources }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "zuul-operator.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 "zuul-operator.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 chart name and version as used by the chart label.
*/}}
{{- define "zuul-operator.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "zuul-operator.labels" -}}
helm.sh/chart: {{ include "zuul-operator.chart" . }}
{{ include "zuul-operator.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "zuul-operator.selectorLabels" -}}
app.kubernetes.io/name: {{ include "zuul-operator.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "zuul-operator.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "zuul-operator.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,51 @@
# Default values for zuul-operator.
image:
repository: docker.io/zuul/zuul-operator
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}