diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..7388923 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,24 @@ +name: Release charts + +on: + push: + branches: + - main + +jobs: + release: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + + - name: Run chart-releaser + uses: helm/chart-releaser-action@v1.1.0 + env: + CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e4017eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.idea +.vscode + +charts/**/charts diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..528e8c0 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,8 @@ +repos: + - repo: https://github.com/norwoodj/helm-docs + rev: v1.2.0 + hooks: + - id: helm-docs + args: + - --chart-search-root=charts + - --template-files=../template/README.tpl.md diff --git a/README.md b/README.md index 2ba8c0c..2603bda 100644 --- a/README.md +++ b/README.md @@ -1 +1,43 @@ -# helm-charts +# Polyflix Helm Charts + +This repository contains the official Polyflix Helm charts. + +## Prerequisites + +- [helm-docs](https://github.com/norwoodj/helm-docs) +- [pre-commit](https://pre-commit.com/#install) + +Run the following commands to install the pre-commit hooks : + +```shell +pre-commit install +pre-commit install-hooks +``` + +## Install the repository + +To install the repository on your host and be able to pull charts from it, you'll need to execute the following command : + +```shell +$ helm repo add polyflix https://polyflix.github.io/helm-charts +``` + +You're now ready to work with the repository. **For detailed explanations about how to install a specific chart, please see the concerned chart directory**. + +## Documentation + +The chart documentation is important and needs to be maintained. To make easy this task, we use [helm-docs](https://github.com/norwoodj/helm-docs) to generate the documentation based on the chart `values.yml`. The repository provide a [template of README](./template/README.tpl.md), and [helm-docs](https://github.com/norwoodj/helm-docs) will generate a `README.md` into the chart folder if you have installed the [pre-commit](https://pre-commit.com/#install). + +If you wish to generate the documentation manually, simply run the following command from **the root of the project** : + +```shell +helm-docs --chart-search-root=charts --template-files template/README.tpl.md +``` + +## Contributing + +In order to make updates on one or more charts on the project, please follow the following instructions : + +- Make a branch and do your changes +- Run the [helm-docs](https://github.com/norwoodj/helm-docs) command to make sure the documentation is up to date. +- Once everything is ok, **don't forget to bump the chart(s) version(s) to trigger a new release when your PR will be merged.** diff --git a/charts/service/.helmignore b/charts/service/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/service/.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/charts/service/Chart.yaml b/charts/service/Chart.yaml new file mode 100644 index 0000000..4cd4894 --- /dev/null +++ b/charts/service/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: service +description: A base Helm chart that must be used as a dependency when creating Polyflix service charts. +type: application +version: 0.1.0 +appVersion: "X.X.X" diff --git a/charts/service/README.md b/charts/service/README.md new file mode 100644 index 0000000..03aa5ec --- /dev/null +++ b/charts/service/README.md @@ -0,0 +1,49 @@ +# service + +A base Helm chart that must be used as a dependency when creating Polyflix service charts. + +![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: X.X.X](https://img.shields.io/badge/AppVersion-X.X.X-informational?style=flat-square) + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```console +$ helm repo add polyflix https://polyflix.github.io/helm-charts +$ helm install my-release polyflix/service +``` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Pod affinity | +| autoscaling.enabled | bool | `false` | Enable the auto scaling of the deployment. | +| autoscaling.maxReplicas | int | `100` | The maximum replicas for the deployment. | +| autoscaling.minReplicas | int | `1` | The minimum replicas for the deployment. | +| autoscaling.targetCPUUtilizationPercentage | int | `80` | | +| extraEnvVars | list | `[]` | Extra env vars to pass to the migrations container | +| extraEnvVarsSecrets | list | `[]` | Extra secrets to use to populate the migration environment. | +| fullnameOverride | string | `""` | Override the entire release name | +| image.pullPolicy | string | `"Always"` | Define the image pulling behavior. Can be either Always or IfNotPresent. | +| image.repository | string | `"ghcr.io/polyflix/example"` | The repository of the image to deploy | +| image.tag | string | `"main"` | The image tag to deploy | +| imagePullSecrets | list | `[]` | A list of secrets that can be used by our deploymet to authenticate to registry. | +| migrations.enabled | bool | `false` | Set this to true if the service has PostgreSQL migrations to apply. We assume that the migrations are just another tag for the image. For example, if the image is : ghcr.io/polyflix/example:main the image migration should be located at : ghcr.io/polyflix/example:main-migrations | +| migrations.extraEnvVars | list | `[]` | | +| migrations.extraEnvVarsSecrets | list | `[]` | | +| nameOverride | string | `""` | Override the name of the release, by keeping the release name as suffix | +| nodeSelector | object | `{}` | A node selector configuration for our deployment | +| podAnnotations | object | `{}` | Annotations to add to the pod | +| podSecurityContext | object | `{}` | Security context of the pod | +| probes.liveness.path | string | `"/"` | The path for the Kubernetes liveness probe. | +| probes.readiness.path | string | `"/"` | The path for the Kubernetes readiness probe. | +| replicaCount | int | `1` | The number of replicas to deploy | +| resources | object | `{}` | The deployment resources | +| securityContext | object | `{}` | Security context of the deployment | +| service.port | int | `80` | The port of the service used to expose the deployment | +| service.type | string | `"ClusterIP"` | The type of service to expose the deployment | +| serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| 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 | `[]` | Tolerations for the pod | diff --git a/charts/service/templates/NOTES.txt b/charts/service/templates/NOTES.txt new file mode 100644 index 0000000..f5476e5 --- /dev/null +++ b/charts/service/templates/NOTES.txt @@ -0,0 +1 @@ +Microservices \ No newline at end of file diff --git a/charts/service/templates/_helpers.tpl b/charts/service/templates/_helpers.tpl new file mode 100644 index 0000000..4ace1c3 --- /dev/null +++ b/charts/service/templates/_helpers.tpl @@ -0,0 +1,104 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "microservice.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 "microservice.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 "microservice.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "microservice.labels" -}} +helm.sh/chart: {{ include "microservice.chart" . }} +{{ include "microservice.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "microservice.selectorLabels" -}} +app.kubernetes.io/name: {{ include "microservice.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- 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 }} + +{{- define "microservice.livenessProbe" -}} +failureThreshold: 3 +httpGet: + path: {{ hasKey .config "path" | ternary .config.path "/" }} + port: {{ hasKey .config "port" | ternary .config.port "http" }} +initialDelaySeconds: 15 +periodSeconds: 15 +successThreshold: 1 +timeoutSeconds: 15 +{{- end }} + +{{- define "microservice.readinessProbe" -}} +failureThreshold: 3 +httpGet: + path: {{ hasKey .config "path" | ternary .config.path "/" }} + port: {{ hasKey .config "port" | ternary .config.port "http" }} +initialDelaySeconds: 15 +periodSeconds: 15 +successThreshold: 3 +timeoutSeconds: 15 +{{- end }} + +{{- define "microservice.migrations" -}} +- name: migrations + imagePullPolicy: Always + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}-migrations" + envFrom: + {{- with .Values.migrations.extraEnvVarsSecrets }} + {{- range $secret := . }} + - secretRef: + name: {{ $secret.name }} + {{- end }} + {{- end }} + env: + {{- with .Values.migrations.extraEnvVars }} + {{- range $env := . }} + - name: {{ $env.name }} + value: {{ $env.value | quote }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/service/templates/deployment.yaml b/charts/service/templates/deployment.yaml new file mode 100644 index 0000000..bfebf35 --- /dev/null +++ b/charts/service/templates/deployment.yaml @@ -0,0 +1,84 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "microservice.fullname" . }} + labels: + {{- include "microservice.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "microservice.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "microservice.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "microservice.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + initContainers: + {{- if $.Values.migrations.enabled }} + {{ include "microservice.migrations" $ | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 8080 + protocol: TCP + livenessProbe: + {{ include "microservice.livenessProbe" (dict "config" ($.Values.probes.liveness | default dict)) | nindent 12 }} + readinessProbe: + {{ include "microservice.readinessProbe" (dict "config" ($.Values.probes.readiness | default dict)) | nindent 12 }} + envFrom: + {{- with $.Values.extraEnvVarsSecrets }} + {{- range $secret := . }} + - secretRef: + name: {{ $secret.name }} + {{- end }} + {{- end }} + env: + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- with $.Values.extraEnvVars }} + {{- range $env := . }} + - name: {{ $env.name }} + value: {{ $env.value | quote }} + {{- end }} + {{- end }} + + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/service/templates/hpa.yaml b/charts/service/templates/hpa.yaml new file mode 100644 index 0000000..dc773ae --- /dev/null +++ b/charts/service/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "microservice.fullname" . }} + labels: + {{- include "microservice.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "microservice.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 }} diff --git a/charts/service/templates/service.yaml b/charts/service/templates/service.yaml new file mode 100644 index 0000000..1ace41b --- /dev/null +++ b/charts/service/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "microservice.fullname" . }} + labels: + {{- include "microservice.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "microservice.selectorLabels" . | nindent 4 }} diff --git a/charts/service/templates/serviceaccount.yaml b/charts/service/templates/serviceaccount.yaml new file mode 100644 index 0000000..f341a6a --- /dev/null +++ b/charts/service/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "microservice.serviceAccountName" . }} + labels: + {{- include "microservice.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/service/values.yaml b/charts/service/values.yaml new file mode 100644 index 0000000..7174ace --- /dev/null +++ b/charts/service/values.yaml @@ -0,0 +1,109 @@ +# nameOverride -- Override the name of the release, by keeping the release name as suffix +nameOverride: "" +# fullnameOverride -- Override the entire release name +fullnameOverride: "" +# replicaCount -- The number of replicas to deploy +replicaCount: 1 + +image: + # image.repository -- The repository of the image to deploy + repository: ghcr.io/polyflix/example + # image.pullPolicy -- Define the image pulling behavior. Can be either Always or IfNotPresent. + pullPolicy: Always + # image.tag -- The image tag to deploy + tag: main + +# imagePullSecrets -- A list of secrets that can be used by our deploymet to authenticate to registry. +imagePullSecrets: [] + +# extraEnvVars -- Extra environment variables to pass to the container +extraEnvVars: [] + +# extraEnvVarsSecrets -- Extra secret used to populate the container environment +extraEnvVarsSecrets: [] + +migrations: + # migrations.enabled -- Set this to true if the service has PostgreSQL migrations to apply. + # We assume that the migrations are just another tag for the image. + # For example, if the image is : ghcr.io/polyflix/example:main + # the image migration should be located at : ghcr.io/polyflix/example:main-migrations + enabled: false + # extraEnvVars -- Extra env vars to pass to the migrations container + extraEnvVars: [] + # - name: POSTGRES_URL + # value: mysuperurl + # extraEnvVarsSecrets -- Extra secrets to use to populate the migration environment. + extraEnvVarsSecrets: [] + # - name: mysupersecret + +probes: + liveness: + # probes.liveness.path -- The path for the Kubernetes liveness probe. + path: / + readiness: + # probes.readiness.path -- The path for the Kubernetes readiness probe. + path: / + +serviceAccount: + # serviceAccount.create -- Specifies whether a service account should be created + create: 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: "" + +# podAnnotations -- Annotations to add to the pod +podAnnotations: {} + +# podSecurityContext -- Security context of the pod +podSecurityContext: {} + # fsGroup: 2000 + +# securityContext -- Security context of the deployment +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + # service.type -- The type of service to expose the deployment + type: ClusterIP + # service.port -- The port of the service used to expose the deployment + port: 80 + +# resources -- The deployment resources +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 + +autoscaling: + # autoscaling.enabled -- Enable the auto scaling of the deployment. + enabled: false + # autoscaling.minReplicas -- The minimum replicas for the deployment. + minReplicas: 1 + # autoscaling.maxReplicas -- The maximum replicas for the deployment. + maxReplicas: 100 + # autoscaling.targetCPUUtilizationPercentage -- + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +# nodeSelector -- A node selector configuration for our deployment +nodeSelector: {} + +# tolerations -- Tolerations for the pod +tolerations: [] + +# affinity -- Pod affinity +affinity: {} diff --git a/template/README.tpl.md b/template/README.tpl.md new file mode 100644 index 0000000..fabf453 --- /dev/null +++ b/template/README.tpl.md @@ -0,0 +1,17 @@ +{{ template "chart.header" . }} +{{ template "chart.description" . }} + +{{ template "chart.versionBadge" . }}{{ template "chart.typeBadge" . }}{{ template "chart.appVersionBadge" . }} + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```console +$ helm repo add polyflix https://polyflix.github.io/helm-charts +$ helm install my-release polyflix/{{ template "chart.name" . }} +``` + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }}