github.com/microsoft/fabrikate@v1.0.0-alpha.1.0.20210115014322-dc09194d0885/testdata/generate-yaml/helm_repos/prometheus/REVIEW_GUIDELINES.md (about) 1 # Chart Review Guidelines 2 3 Anyone is welcome to review pull requests. Besides our [technical requirements](https://github.com/helm/charts/blob/master/CONTRIBUTING.md#technical-requirements) and [best practices](https://github.com/helm/helm/tree/master/docs/chart_best_practices), here's an overview of process and review guidelines. 4 5 ## Process 6 7 The process to get a pull request merged is fairly simple. First, all required tests need to pass and the contributor needs to have a signed [DCO](https://www.helm.sh/blog/helm-dco/index.html). See [Charts Testing](https://github.com/helm/charts/blob/master/test/README.md) for details on our CI system and how you can provide custom values for testing. If there is a problem with some part of the test, such as a timeout issue, please contact one of the charts repository maintainers by commenting `cc @helm/charts-maintainers`. 8 9 The charts repository uses the OWNERS files to provide merge access. If a chart has an OWNERS file, an approver listed in that file can approve the pull request. If the chart does not have an OWNERS file, an approver in the OWNERS file at the root of the repository can approve the pull request. 10 11 To approve the pull request, an approver needs to leave a comment of `/lgtm` on the pull request. Once this is in place some tags (`lgtm` and `approved`) will be added to the pull request and a bot will come along and perform the merge. 12 13 Note, if a reviewer who is not an approver in an OWNERS file leaves a comment of `/lgtm` a `lgtm` label will be added but a merge will not happen. 14 15 ## Immutability 16 17 Chart releases must be immutable. Any change to a chart warrants a chart version bump even if it is only changes to the documentation. 18 19 ## Chart Metadata 20 21 The `Chart.yaml` should be as complete as possible. The following fields are mandatory: 22 23 * name (same as chart's directory) 24 * home 25 * version 26 * appVersion 27 * description 28 * maintainers (name should be Github username) 29 30 ## Dependencies 31 32 Stable charts should not depend on charts in incubator. 33 34 ## Names and Labels 35 36 ### Metadata 37 Resources and labels should follow some conventions. The standard resource metadata (`metadata.labels` and `spec.template.metadata.labels`) should be this: 38 39 ```yaml 40 name: {{ include "myapp.fullname" . }} 41 labels: 42 app.kubernetes.io/name: {{ include "myapp.name" . }} 43 app.kubernetes.io/instance: {{ .Release.Name }} 44 app.kubernetes.io/managed-by: {{ .Release.Service }} 45 helm.sh/chart: {{ include "myapp.chart" . }} 46 ``` 47 48 If a chart has multiple components, a `app.kubernetes.io/component` label should be added (e. g. `app.kubernetes.io/component: server`). The resource name should get the component as suffix (e. g. `name: {{ include "myapp.fullname" . }}-server`). 49 50 Note that templates have to be namespaced. With Helm 2.7+, `helm create` does this out-of-the-box. The `app.kubernetes.io/name` label should use the `name` template, not `fullname` as is still the case with older charts. 51 52 ### Deployments, StatefulSets, DaemonSets Selectors 53 54 `spec.selector.matchLabels` must be specified should follow some conventions. The standard selector should be this: 55 56 ```yaml 57 selector: 58 matchLabels: 59 app.kubernetes.io/name: {{ include "myapp.name" . }} 60 app.kubernetes.io/instance: {{ .Release.Name }} 61 ``` 62 63 If a chart has multiple components, a `component` label should be added to the selector (see above). 64 65 `spec.selector.matchLabels` defined in `Deployments`/`StatefulSets`/`DaemonSets` `>=v1/beta2` **must not** contain `helm.sh/chart` label or any label containing a version of the chart, because the selector is immutable. 66 The chart label string contains the version, so if it is specified, whenever the the Chart.yaml version changes, Helm's attempt to change this immutable field would cause the upgrade to fail. 67 68 #### Fixing Selectors 69 70 ##### For Deployments, StatefulSets, DaemonSets apps/v1beta1 or extensions/v1beta1 71 72 - If it does not specify `spec.selector.matchLabels`, set it 73 - Remove `helm.sh/chart` label in `spec.selector.matchLabels` if it exists 74 - Bump patch version of the Chart 75 76 ##### For Deployments, StatefulSets, DaemonSets >=apps/v1beta2 77 78 - Remove `helm.sh/chart` label in `spec.selector.matchLabels` if it exists 79 - Bump major version of the Chart as it is a breaking change 80 81 ### Service Selectors 82 83 Label selectors for services must have both `app.kubernetes.io/name` and `app.kubernetes.io/instance` labels. 84 85 ```yaml 86 selector: 87 app.kubernetes.io/name: {{ include "myapp.name" . }} 88 app.kubernetes.io/instance: {{ .Release.Name }} 89 ``` 90 91 If a chart has multiple components, a `app.kubernetes.io/component` label should be added to the selector (see above). 92 93 ### Persistence Labels 94 95 ### StatefulSet 96 97 In case of a `Statefulset`, `spec.volumeClaimTemplates.metadata.labels` must have both `app.kubernetes.io/name` and `app.kubernetes.io/instance` labels, and **must not** contain `helm.sh/chart` label or any label containing a version of the chart, because `spec.volumeClaimTemplates` is immutable. 98 99 ```yaml 100 labels: 101 app.kubernetes.io/name: {{ include "myapp.name" . }} 102 app.kubernetes.io/instance: {{ .Release.Name }} 103 ``` 104 105 If a chart has multiple components, a `app.kubernetes.io/component` label should be added to the selector (see above). 106 107 ### PersistentVolumeClaim 108 109 In case of a `PersistentVolumeClaim`, unless special needs, `matchLabels` should not be specified 110 because it would prevent automatic `PersistentVolume` provisioning. 111 112 ## Formatting 113 114 * Yaml file should be indented with two spaces. 115 * List indentation style should be consistent. 116 * There should be a single space after `{{` and before `}}`. 117 118 ## Configuration 119 120 * Docker images should be configurable. Image tags should use stable versions. 121 122 ```yaml 123 image: 124 repository: myapp 125 tag: 1.2.3 126 pullPolicy: IfNotPresent 127 ``` 128 129 * The use of the `default` function should be avoided if possible in favor of defaults in `values.yaml`. 130 * It is usually best to not specify defaults for resources and to just provide sensible values that are commented out as a recommendation, especially when resources are rather high. This makes it easier to test charts on small clusters or Minikube. Setting resources should generally be a conscious choice of the user. 131 132 ## Persistence 133 134 * Persistence should be enabled by default 135 * PVCs should support specifying an existing claim 136 * Storage class should be empty by default so that the default storage class is used 137 * All options should be shown in README.md 138 * Example persistence section in values.yaml: 139 140 ```yaml 141 persistence: 142 enabled: true 143 ## If defined, storageClassName: <storageClass> 144 ## If set to "-", storageClassName: "", which disables dynamic provisioning 145 ## If undefined (the default) or set to null, no storageClassName spec is 146 ## set, choosing the default provisioner. (gp2 on AWS, standard on 147 ## GKE, AWS & OpenStack) 148 ## 149 storageClass: "" 150 accessMode: ReadWriteOnce 151 size: 10Gi 152 # existingClaim: "" 153 ``` 154 155 * Example pod spec within a deployment: 156 157 ```yaml 158 volumes: 159 - name: data 160 {{- if .Values.persistence.enabled }} 161 persistentVolumeClaim: 162 claimName: {{ .Values.persistence.existingClaim | default (include "myapp.fullname" .) }} 163 {{- else }} 164 emptyDir: {} 165 {{- end -}} 166 ``` 167 168 * Example pvc.yaml: 169 170 ```yaml 171 {{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} 172 kind: PersistentVolumeClaim 173 apiVersion: v1 174 metadata: 175 name: {{ include "myapp.fullname" . }} 176 labels: 177 app.kubernetes.io/name: {{ include "myapp.name" . }} 178 app.kubernetes.io/instance: {{ .Release.Name }} 179 app.kubernetes.io/managed-by: {{ .Release.Service }} 180 helm.sh/chart: {{ include "myapp.chart" . }} 181 spec: 182 accessModes: 183 - {{ .Values.persistence.accessMode | quote }} 184 resources: 185 requests: 186 storage: {{ .Values.persistence.size | quote }} 187 {{- if .Values.persistence.storageClass }} 188 {{- if (eq "-" .Values.persistence.storageClass) }} 189 storageClassName: "" 190 {{- else }} 191 storageClassName: "{{ .Values.persistence.storageClass }}" 192 {{- end }} 193 {{- end }} 194 {{- end }} 195 ``` 196 197 ## AutoScaling / HorizontalPodAutoscaler 198 199 * Autoscaling should be disabled by default 200 * All options should be shown in README.md 201 202 * Example autoscaling section in values.yaml: 203 204 ```yaml 205 autoscaling: 206 enabled: false 207 minReplicas: 1 208 maxReplicas: 5 209 targetCPUUtilizationPercentage: 50 210 targetMemoryUtilizationPercentage: 50 211 ``` 212 213 * Example hpa.yaml: 214 215 ```yaml 216 {{- if .Values.autoscaling.enabled }} 217 apiVersion: autoscaling/v2beta1 218 kind: HorizontalPodAutoscaler 219 metadata: 220 name: {{ include "myapp.fullname" . }} 221 labels: 222 app.kubernetes.io/name: {{ include "myapp.name" . }} 223 app.kubernetes.io/instance: {{ .Release.Name }} 224 app.kubernetes.io/managed-by: {{ .Release.Service }} 225 helm.sh/chart: {{ include "myapp.chart" . }} 226 app.kubernetes.io/component: "{{ .Values.name }}" 227 spec: 228 scaleTargetRef: 229 apiVersion: apps/v1 230 kind: Deployment 231 name: {{ include "myapp.fullname" . }} 232 minReplicas: {{ .Values.autoscaling.minReplicas }} 233 maxReplicas: {{ .Values.autoscaling.maxReplicas }} 234 metrics: 235 - type: Resource 236 resource: 237 name: cpu 238 targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 239 - type: Resource 240 resource: 241 name: memory 242 targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 243 {{- end }} 244 ``` 245 246 ## Ingress 247 248 * See the [Ingress resource documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/) for a broader concept overview 249 * Ingress should be disabled by default 250 * Example ingress section in values.yaml: 251 252 ```yaml 253 ingress: 254 enabled: false 255 annotations: {} 256 # kubernetes.io/ingress.class: nginx 257 # kubernetes.io/tls-acme: "true" 258 path: / 259 hosts: 260 - chart-example.test 261 tls: [] 262 # - secretName: chart-example-tls 263 # hosts: 264 # - chart-example.test 265 ``` 266 267 * Example ingress.yaml: 268 269 ```yaml 270 {{- if .Values.ingress.enabled -}} 271 apiVersion: extensions/v1beta1 272 kind: Ingress 273 metadata: 274 name: {{ include "myapp.fullname" }} 275 labels: 276 app.kubernetes.io/name: {{ include "myapp.name" . }} 277 app.kubernetes.io/instance: {{ .Release.Name }} 278 app.kubernetes.io/managed-by: {{ .Release.Service }} 279 helm.sh/chart: {{ include "myapp.chart" . }} 280 {{- with .Values.ingress.annotations }} 281 annotations: 282 {{ toYaml . | indent 4 }} 283 {{- end }} 284 spec: 285 {{- if .Values.ingress.tls }} 286 tls: 287 {{- range .Values.ingress.tls }} 288 - hosts: 289 {{- range .hosts }} 290 - {{ . | quote }} 291 {{- end }} 292 secretName: {{ .secretName }} 293 {{- end }} 294 {{- end }} 295 rules: 296 {{- range .Values.ingress.hosts }} 297 - host: {{ . | quote }} 298 http: 299 paths: 300 - path: {{ .Values.ingress.path }} 301 backend: 302 serviceName: {{ include "myapp.fullname" }} 303 servicePort: http 304 {{- end }} 305 {{- end }} 306 ``` 307 308 * Example prepend logic for getting an application URL in NOTES.txt: 309 310 ``` 311 {{- if .Values.ingress.enabled }} 312 {{- range .Values.ingress.hosts }} 313 http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }} 314 {{- end }} 315 ``` 316 317 ## Documentation 318 319 `README.md` and `NOTES.txt` are mandatory. `README.md` should contain a table listing all configuration options. `NOTES.txt` should provide accurate and useful information how the chart can be used/accessed. 320 321 ## Compatibility 322 323 We officially support compatibility with the current and the previous minor version of Kubernetes. Generated resources should use the latest possible API versions compatible with these versions. For extended backwards compatibility conditional logic based on capabilities may be used (see [built-in objects](https://github.com/helm/helm/blob/master/docs/chart_template_guide/builtin_objects.md)). 324 325 ## Kubernetes Native Workloads 326 327 While reviewing Charts that contain workloads such as [Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/), [StatefulSets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/), [DaemonSets](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) and [Jobs](https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/) the below points should be considered. These are to be seen as best practices rather than strict enforcement. 328 329 1. Any workload that are stateless and long running (servers) in nature are to be created as Deployments. Deployments in turn create ReplicaSets. 330 2. Unless there is a compelling reason, ReplicaSets or ReplicationControllers should be avoided as workload types. 331 3. Workloads that are stateful in nature such as databases, key-value stores, message queues, in-memory caches are to be created as StatefulSets 332 4. It is recommended that Deployments and StatefulSets configure their workloads with a [Pod Disruption Budget](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/) for high availability. 333 5. For workloads such as databases, KV stores, etc., that replicate data, it is recommended to configure interpod anti-affinity. 334 6. It is recommended to have a default workload update strategy configured that is suitable for this chart. 335 7. Batch workloads are to be created using Jobs. 336 8. It is best to always create workloads with the latest supported [api version](https://v1-8.docs.kubernetes.io/docs/api-reference/v1.8/) as older version are either deprecated or soon to be deprecated. 337 9. It is generally not advisable to provide hard [resource limits](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container) to workloads and leave it configurable unless the workload requires such quantity bare minimum to function. 338 10. As much as possible complex pre-app setups are configured using [init containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/). 339 340 More [configuration](https://kubernetes.io/docs/concepts/configuration/overview/) best practices.