diff --git a/charts/microservices/Chart.yaml b/charts/microservices/Chart.yaml new file mode 100644 index 00000000..1dafce4b --- /dev/null +++ b/charts/microservices/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +name: microservice +description: Basic helm chart for deploying microservices on kubernetes with best practices +type: application +version: 0.1.0 +appVersion: "0.1.2" +maintainers: + - name: Ashwani Singh + email: ashwani.singh@opstree.com + - name: Khushi Malhotra diff --git a/charts/microservices/README.md.gotmpl b/charts/microservices/README.md.gotmpl new file mode 100644 index 00000000..16f6a67c --- /dev/null +++ b/charts/microservices/README.md.gotmpl @@ -0,0 +1,22 @@ +{{ template "chart.header" . }} +{{ template "chart.description" . }} + +{{ template "chart.versionBadge" . }}{{ template "chart.typeBadge" . }}{{ template "chart.appVersionBadge" . }} + +{{ template "chart.maintainersSection" . }} + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```console +$ helm install my-release microservice/ +``` + +{{/* {{ template "chart.requirementsSection" . }} */}} + +{{ template "chart.valuesSection" . }} + +> **_NOTE:_** Please find the sample helm values yaml in example repository. + +{{/* {{ template "helm-docs.versionFooter" . }} */}} diff --git a/charts/microservices/examples/config.conf b/charts/microservices/examples/config.conf new file mode 100644 index 00000000..bc92ead9 --- /dev/null +++ b/charts/microservices/examples/config.conf @@ -0,0 +1,2 @@ +name=opstree +address=opstreesolution diff --git a/charts/microservices/examples/deploy-nginx.yaml b/charts/microservices/examples/deploy-nginx.yaml new file mode 100644 index 00000000..a488f9ec --- /dev/null +++ b/charts/microservices/examples/deploy-nginx.yaml @@ -0,0 +1,34 @@ +global: + namespace: "default" +# replicaCount: 5 + fullnameOverride: "webapp" + +deployment: + image: + name: nginx + tag: latest + pullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: "/" + port: http + readinessProbe: + httpGet: + path: "/" + port: http + resources: + requests: + memory: 100Mi + cpu: 100m + limits: + memory: 500Mi + cpu: 500m + volumes: + enabled: true + configMaps: + - name: index + mountPath: /usr/share/nginx/html + data: + index.html: | + Hello! Opstree + diff --git a/charts/microservices/templates/README.md b/charts/microservices/templates/README.md new file mode 100644 index 00000000..f9165a59 --- /dev/null +++ b/charts/microservices/templates/README.md @@ -0,0 +1,44 @@ +# microservice + +Basic helm chart for deploying microservices on kubernetes with best practices + +![Version: 0.1.3](https://img.shields.io/badge/Version-0.1.3-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.1.2](https://img.shields.io/badge/AppVersion-0.1.2-informational?style=flat-square) + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| Ashwani Singh | | | +| Khushi Malhotra | | | + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```console +helm install my-microservice -f ./values.yaml -f/examples/deploy-nginx.yaml +``` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| deployment | object | `{"affinity":{"podAntiAffinity"},"annotations":{},"environment":{},"image":{"name":"","pullPolicy":"IfNotPresent","tag":""},"livenessProbe":{"failureThreshold":5,"initialDelaySeconds":250,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"nodeSelector":{},"readinessProbe":{"failureThreshold":5,"initialDelaySeconds":30,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"resources":{},"tolerations":[],"volumeMounts":[],"volumes":{"configMaps":null,"enabled":true,"pvc":{"accessModes":["ReadWriteOnce"],"class":"default","enabled":false,"existing_claim":false,"mountPath":"/pv","name":"pvc","size":"1G"}}}` | Object that configures Deployment instance | +| deployment.image | object | `{"name":"","pullPolicy":"IfNotPresent","tag":""}` | Override default container image format | +| global | object | `{"environment":{},"fullnameOverride":"","imagePullSecrets":[],"nameOverride":"","namespace":"default","replicaCount":1}` | global variables | +| hpa.enabled | bool | `true` | | +| hpa.maxReplicas | int | `6` | | +| hpa.minReplicas | int | `5` | | +| hpa.targetCPU | int | `80` | | +| hpa.targetMemory | int | `80` | | +| kubeVersion | string | `""` | | +| service.annotations | object | `{}` | | +| service.specs[0].name | string | `"http"` | | +| service.specs[0].port | int | `80` | | +| service.type | string | `"ClusterIP"` | | +| serviceAccount.annotations | object | `{}` | | +| serviceAccount.automount | bool | `true` | | +| serviceAccount.create | bool | `false` | | +| serviceAccount.name | string | `""` | | + +> **_NOTE:_** Please find the sample helm values yaml in example repository. diff --git a/charts/microservices/templates/_capabiities.tpl b/charts/microservices/templates/_capabiities.tpl new file mode 100644 index 00000000..1998e762 --- /dev/null +++ b/charts/microservices/templates/_capabiities.tpl @@ -0,0 +1,36 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Return the target Kubernetes version +*/}} +{{- define "microservice.capabilities.kubeVersion" -}} +{{- default (default .Capabilities.KubeVersion.Version .Values.kubeVersion) ((.Values.global).kubeVersion) -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for Horizontal Pod Autoscaler. +*/}} +{{- define "microservice.capabilities.hpa.apiVersion" -}} +{{- $kubeVersion := include "microservice.capabilities.kubeVersion" .context -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} +{{- if .beta2 -}} +{{- print "autoscaling/v2beta2" -}} +{{- else -}} +{{- print "autoscaling/v2beta1" -}} +{{- end -}} +{{- else -}} +{{- print "autoscaling/v2" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for deployment. +*/}} +{{- define "microservice.capabilities.deployment.apiVersion" -}} +{{- $kubeVersion := include "microservice.capabilities.kubeVersion" . -}} +{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} diff --git a/charts/microservices/templates/_helpers.tpl b/charts/microservices/templates/_helpers.tpl new file mode 100644 index 00000000..8a2c02bb --- /dev/null +++ b/charts/microservices/templates/_helpers.tpl @@ -0,0 +1,54 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Create a defautl fully qualified app name +It will use the release name to give the app name +*/}} + +{{- define "microservice.name" -}} +{{- default .Chart.Name .Values.global.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 "microservice.fullname" -}} +{{- if .Values.global.fullnameOverride -}} +{{- .Values.global.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.global.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "microservice.labels" -}} +app: {{ include "microservice.fullname" . }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "microservice.selectorLabels" -}} +app: {{ include "microservice.fullname" . }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "microservice.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "microservice.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/microservices/templates/configmap.yaml b/charts/microservices/templates/configmap.yaml new file mode 100644 index 00000000..bdfbbeb8 --- /dev/null +++ b/charts/microservices/templates/configmap.yaml @@ -0,0 +1,30 @@ +#ConfigMap mounted as volumes +{{- if .Values.deployment.volumes.configMaps }} +{{- if .Values.deployment.volumes.enabled }} +{{ $header := .Values.deployment.volumes.configFileCommonHeader | default "" }} +{{ $root := . }} +{{ range $cm := .Values.deployment.volumes.configMaps}} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "microservice.fullname" $root }}-{{ $cm.name }}-cm + namespace: {{ $root.Values.global.namespace | quote }} +data: + {{- if $cm.data }} + {{- range $filename, $content := $cm.data }} + # property-like keys; each key maps to a simple value + {{ $filename }}: |- +{{ $content | toString | indent 4}} + {{- end }} + {{- end }} + {{- if $cm.files }} + {{- range $file := $cm.files }} + {{ $file.destination }}: | +{{ $header | toString | indent 4 }} + {{ $root.Files.Get "$file.source" }} + {{- end}} + {{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/microservices/templates/deployment.yaml b/charts/microservices/templates/deployment.yaml new file mode 100644 index 00000000..a79501cc --- /dev/null +++ b/charts/microservices/templates/deployment.yaml @@ -0,0 +1,129 @@ +{{ $root := . }} +--- +apiVersion: {{ include "microservice.capabilities.deployment.apiVersion" . }} +kind: Deployment +metadata: + name: {{ include "microservice.fullname" . }}-app + namespace: {{ .Values.global.namespace | quote }} + {{- if .Values.annotations }} + annotations: + {{- range $key, $value := .Values.annotations }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + labels: + {{- include "microservice.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.global.replicaCount }} + selector: + matchLabels: + {{- include "microservice.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "microservice.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "microservice.serviceAccountName" . }} + containers: + - name: {{ include "microservice.fullname" . }} + image: "{{ .Values.deployment.image.name }}:{{ .Values.deployment.image.tag }}" + imagePullPolicy: {{ .Values.deployment.image.pullPolicy }} + {{- if .Values.deployment.command }} + command: {{ .Values.deployment.command }} + {{- end }} + {{- if .Values.deployment.args }} + args: {{ .Values.deployment.args }} + {{- end }} + ports: + {{- range .Values.service.specs }} + - name: {{ .name }} + containerPort: {{ .targetPort | default .port }} + protocol: {{ .protocol | default "TCP" }} + {{- end }} + {{- if (merge .Values.global.environment .Values.deployment.environment) }} + env: + {{- range $name, $value := merge .Values.global.environment .Values.deployment.environment }} + - name: {{ $name | quote }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- if .Values.deployment.livenessProbe }} + livenessProbe: + {{- with .Values.deployment.livenessProbe }} + httpGet: + path: {{ .httpGet.path | quote }} + port: {{ .httpGet.port | quote }} + initialDelaySeconds: {{ .initialDelaySeconds }} + periodSeconds: {{ .periodSeconds }} + timeoutSeconds: {{ .timeoutSeconds }} + successThreshold: {{ .successThreshold }} + failureThreshold: {{ .failureThreshold }} + {{- end }} + {{- end }} + {{- if .Values.deployment.readinessProbe }} + readinessProbe: + {{- with .Values.deployment.readinessProbe }} + httpGet: + path: {{ .httpGet.path | quote }} + port: {{ .httpGet.port | quote }} + initialDelaySeconds: {{ .initialDelaySeconds }} + periodSeconds: {{ .periodSeconds }} + timeoutSeconds: {{ .timeoutSeconds }} + successThreshold: {{ .successThreshold }} + failureThreshold: {{ .failureThreshold }} + {{- end }} + {{- end }} + resources: + {{- toYaml .Values.deployment.resources | nindent 12 }} + {{- if .Values.deployment.volumes.enabled }} + volumeMounts: + {{- range $conf := .Values.deployment.volumes.configMaps }} + - mountPath: {{ $conf.mountPath }} + name: {{ include "microservice.fullname" $root }}-{{ $conf.name }}-cm + {{- end }} + {{- if .Values.deployment.volumes.pvc.enabled }} + - mountPath: {{ .Values.volumes.pvc.mountPath }} + name: {{ .Values.volumes.pvc.existing_claim | default .Values.volumes.pvc.name }}-volume + {{- end }} + {{- end }} + {{- if .Values.deployment.volumes.enabled }} + volumes: + {{- range $conf := .Values.deployment.volumes.configMaps }} + - name: {{ include "microservice.fullname" $root }}-{{ $conf.name }}-cm + configMap: + name: {{ include "microservice.fullname" $root }}-{{ $conf.name }}-cm + {{- end }} + {{- if .Values.deployment.volumes.pvc.enabled }} + - name: {{ .Values.deployment.volumes.pvc.existing_claim | default .Values.deployment.volumes.pvc.name }}-volume + persistentVolumeClaim: + claimName: {{ .Values.deployment.volumes.pvc.existing_claim | default .Values.deployment.volumes.pvc.name }} + {{- end }} + {{- end }} + {{- with .Values.deployment.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.deployment.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.deployment.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.deployment.topologySpreadConstraints }} + topologySpreadConstraints: + {{- range . }} + - maxSkew: {{ .maxSkew }} + topologyKey: {{ .topologyKey | quote }} # Ensure this is set and not empty + whenUnsatisfiable: {{ .whenUnsatisfiable }} + labelSelector: + matchLabels: + app: {{ include "microservice.fullname" $root }} + minDomains: {{ .minDomains }} + {{- end }} + {{- end }} diff --git a/charts/microservices/templates/hpa.yaml b/charts/microservices/templates/hpa.yaml new file mode 100644 index 00000000..02db2f41 --- /dev/null +++ b/charts/microservices/templates/hpa.yaml @@ -0,0 +1,41 @@ +{{- if .Values.hpa.enabled }} +apiVersion: {{ include "microservice.capabilities.hpa.apiVersion" ( dict "context" $ ) }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "microservice.fullname" . }}-hpa + namespace: {{ .Values.global.namespace | quote }} + labels: + {{- include "microservice.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: {{ include "microservice.capabilities.deployment.apiVersion" . }} + kind: Deployment + name: {{ include "microservice.fullname" . }}-app + minReplicas: {{ .Values.hpa.minReplicas }} + maxReplicas: {{ .Values.hpa.maxReplicas }} + metrics: + {{- if .Values.hpa.targetMemory }} + - type: Resource + resource: + name: memory + {{- if semverCompare "<1.23-0" (include "microservice.capabilities.kubeVersion" .) }} + targetAverageUtilization: {{ .Values.hpa.targetMemory }} + {{- else }} + target: + type: Utilization + averageUtilization: {{ .Values.hpa.targetMemory }} + {{- end }} + {{- end }} + {{- if .Values.hpa.targetCPU }} + - type: Resource + resource: + name: cpu + {{- if semverCompare "<1.23-0" (include "microservice.capabilities.kubeVersion" .) }} + targetAverageUtilization: {{ .Values.hpa.targetCPU }} + {{- else }} + target: + type: Utilization + averageUtilization: {{ .Values.hpa.targetCPU }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/microservices/templates/pvc.yaml b/charts/microservices/templates/pvc.yaml new file mode 100644 index 00000000..ce149caa --- /dev/null +++ b/charts/microservices/templates/pvc.yaml @@ -0,0 +1,21 @@ +{{- if .Values.deployment.volumes.pvc.enabled }} +{{- if .Values.deployment.volumes.pvc.existing_claim -}} +{{- else -}} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Values.deployment.volumes.pvc.name }} + namespace: {{ .Values.global.namespace | quote }} +spec: + {{- if .Values.deployment.volumes.pvc.class }} + storageClassName: {{ .Values.deployment.volumes.pvc.class }} + {{- end }} + accessModes: + {{- range $accessMode := .Values.deployment.volumes.pvc.accessModes }} + - {{ $accessMode }} + {{- end }} + resources: + requests: + storage: {{ .Values.deployment.volumes.pvc.size }} +{{- end }} +{{- end }} diff --git a/charts/microservices/templates/service.yaml b/charts/microservices/templates/service.yaml new file mode 100644 index 00000000..f9527c0f --- /dev/null +++ b/charts/microservices/templates/service.yaml @@ -0,0 +1,33 @@ +{{- $root:= . }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "microservice.fullname" . }}-svc + namespace: {{ .Values.global.namespace | quote }} + {{- if .Values.service.annotations }} + annotations: + {{- range $key, $value := .Values.service.annotations }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + labels: + {{- include "microservice.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + selector: + {{- include "microservice.selectorLabels" . | nindent 4 }} + ports: + {{- range $spec := .Values.service.specs }} + - name: {{ $spec.name }} + port: {{ $spec.port }} + protocol: {{ $spec.protocol | default "TCP" }} + {{- if $spec.targetPort }} + targetPort: {{ $spec.targetPort }} + {{- else }} + targetPort: {{ $spec.name }} + {{- end}} + {{- if $spec.nodePort }} + nodePort: {{ $spec.nodePort }} + {{- end }} + {{- end -}} diff --git a/charts/microservices/templates/serviceaccount.yaml b/charts/microservices/templates/serviceaccount.yaml new file mode 100644 index 00000000..d69c1171 --- /dev/null +++ b/charts/microservices/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "microservice.serviceAccountName" . }}-sa + namespace: {{ .Values.global.namespace | quote }} + labels: + {{- include "microservice.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/charts/microservices/values.yaml b/charts/microservices/values.yaml new file mode 100644 index 00000000..900d9f16 --- /dev/null +++ b/charts/microservices/values.yaml @@ -0,0 +1,108 @@ +# -- global variables +global: + namespace: "default" +# replicaCount: 5 + nameOverride: "" + fullnameOverride: "" + imagePullSecrets: + environment: {} + # list of key: value + # GLOBAL1: value + +## @param kubeVersion Override Kubernetes version +kubeVersion: "" + +# -- Object that configures Deployment instance +deployment: + # -- Override default container image format + image: + name: "" + tag: "" + pullPolicy: IfNotPresent + + # Annotation for the Deployment + annotations: {} + + livenessProbe: +# httpGet: +# path: "/health" +# port: http + initialDelaySeconds: 250 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + + readinessProbe: +# httpGet: +# path: "/readiness" +# port: http + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + + environment: {} + # VAR1: value1 + + resources: {} + + volumes: + enabled: true + pvc: + enabled: false + existing_claim: false + name: pvc + mountPath: /pv + size: 1G + class: "default" + accessModes: + - ReadWriteOnce + + configMaps: [] + + volumeMounts: [] + + nodeSelector: {} + + tolerations: [] + + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + app: "my-microservice" + topologyKey: topology.kubernetes.io/zone + + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: "topology.kubernetes.io/zone" # Ensure this key is valid + whenUnsatisfiable: "DoNotSchedule" + labelSelector: + matchLabels: + app: "my-microservice" + minDomains: 2 + +hpa: + enabled: true + minReplicas: 5 + maxReplicas: 6 + targetCPU: 80 + targetMemory: 80 + +service: + type: ClusterIP + annotations: {} + specs: + - port: 80 + name: http + +serviceAccount: + create: false + automount: true + annotations: {} + name: ""