Repository: helm/helm (go)

Issue:
[helm create] Add autoscaling(hpa) boilerplate
Elasticity is an important feature for cloud native stateless apps such as the one deployed out of the box with helm create.  Allowing users to easily autoscale newly created apps would be beneficial.

I propose we add a disabled by default hpa, with default values of 1 to 100 replicas and 80% cpu utilization threshold.

cc @helm/chart-maintainers





Pull request description:
[helm create] Add hpa boilerplate
Adds hpa boilerplate with following properties which imho are most sane:

* disabled by default
* if enabled:
  * 1 to 100 replicas by default
  * 80% cpu average threshold by default
  * commented out and thus disabled 80% memory average threshold

Fixes #7369 

Patch:
diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go
index 390f12f4c..90bf4ec48 100644
--- a/pkg/chartutil/create.go
+++ b/pkg/chartutil/create.go
@@ -53,6 +53,8 @@ const (
 	ServiceName = TemplatesDir + sep + "service.yaml"
 	// ServiceAccountName is the name of the example serviceaccount file.
 	ServiceAccountName = TemplatesDir + sep + "serviceaccount.yaml"
+	// HorizontalPodAutoscalerName is the name of the example hpa file.
+	HorizontalPodAutoscalerName = TemplatesDir + sep + "hpa.yaml"
 	// NotesName is the name of the example NOTES.txt file.
 	NotesName = TemplatesDir + sep + "NOTES.txt"
 	// HelpersName is the name of the example helpers file.
@@ -149,6 +151,13 @@ resources: {}
   #   cpu: 100m
   #   memory: 128Mi
 
+autoscaling:
+  enabled: false
+  minReplicas: 1
+  maxReplicas: 100
+  targetCPUUtilizationPercentage: 80
+  # targetMemoryUtilizationPercentage: 80
+
 nodeSelector: {}
 
 tolerations: []
@@ -231,7 +240,9 @@ metadata:
   labels:
     {{- include "<CHARTNAME>.labels" . | nindent 4 }}
 spec:
+{{- if not .Values.autoscaling.enabled }}
   replicas: {{ .Values.replicaCount }}
+{{- end }}
   selector:
     matchLabels:
       {{- include "<CHARTNAME>.selectorLabels" . | nindent 6 }}
@@ -312,6 +323,36 @@ metadata:
 {{- end -}}
 `
 
+const defaultHorizontalPodAutoscaler = `{{- if .Values.autoscaling.enabled }}
+apiVersion: autoscaling/v2beta1
+kind: HorizontalPodAutoscaler
+metadata:
+  name: {{ include "<CHARTNAME>.fullname" . }}
+  labels:
+    {{- include "<CHARTNAME>.labels" . | nindent 4 }}
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: {{ include "<CHARTNAME>.fullname" . }}
+  minReplicas: {{ .Values.autoscaling.minReplicas }}
+  maxReplicas: {{ .Values.autoscaling.maxReplicas }}
+  metrics:
+  {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
+    - type: Resource
+      resource:
+        name: cpu
+        targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
+  {{- end }}
+  {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
+    - type: Resource
+      resource:
+        name: memory
+        targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
+  {{- end }}
+{{- end }}
+`
+
 const defaultNotes = `1. Get the application URL by running these commands:
 {{- if .Values.ingress.enabled }}
 {{- range $host := .Values.ingress.hosts }}
@@ -517,6 +558,11 @@ func Create(name, dir string) (string, error) {
 			path:    filepath.Join(cdir, ServiceAccountName),
 			content: transform(defaultServiceAccount, name),
 		},
+		{
+			// hpa.yaml
+			path:    filepath.Join(cdir, HorizontalPodAutoscalerName),
+			content: transform(defaultHorizontalPodAutoscaler, name),
+		},
 		{
 			// NOTES.txt
 			path:    filepath.Join(cdir, NotesName),


Test patch:
diff --git a/cmd/helm/create_test.go b/cmd/helm/create_test.go
index 0a9b7b9a5..bbb8d394a 100644
--- a/cmd/helm/create_test.go
+++ b/cmd/helm/create_test.go
@@ -106,7 +106,7 @@ func TestCreateStarterCmd(t *testing.T) {
 		t.Errorf("Wrong API version: %q", c.Metadata.APIVersion)
 	}
 
-	expectedNumberOfTemplates := 8
+	expectedNumberOfTemplates := 9
 	if l := len(c.Templates); l != expectedNumberOfTemplates {
 		t.Errorf("Expected %d templates, got %d", expectedNumberOfTemplates, l)
 	}
@@ -174,7 +174,7 @@ func TestCreateStarterAbsoluteCmd(t *testing.T) {
 		t.Errorf("Wrong API version: %q", c.Metadata.APIVersion)
 	}
 
-	expectedNumberOfTemplates := 8
+	expectedNumberOfTemplates := 9
 	if l := len(c.Templates); l != expectedNumberOfTemplates {
 		t.Errorf("Expected %d templates, got %d", expectedNumberOfTemplates, l)
 	}