Skip to content

Commit

Permalink
Add nodejs helm chart
Browse files Browse the repository at this point in the history
  • Loading branch information
WSMathias committed Jul 22, 2020
1 parent 4257d28 commit 034f725
Show file tree
Hide file tree
Showing 10 changed files with 687 additions and 0 deletions.
15 changes: 15 additions & 0 deletions starterkits/node-express-postgres/charts/node/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: v1
name: Node
version: 1.0.0
appVersion: 1.0.0
description: node helm charts .
keywords:
- node
- nodejs
home: https://nodejs.org/
sources:
- https://github.com/srijanone/vega/
maintainers:
- name: Srijan
email: platform@srijan.net
engine: gotpl
144 changes: 144 additions & 0 deletions starterkits/node-express-postgres/charts/node/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Node Helm Charts

## Introduction

This chart bootstraps a Nodejs deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.

It deploys a Node application. Optionally, you can set up an Ingress resource to access your application.

## Prerequisites

- Kubernetes 1.12+
- Helm 2.11+ or Helm 3.0-beta3+

## Installing the Chart (Helm3)

To install the chart with the release name `my-release`:

```console
$ helm install my-release .node
```


These commands deploy node on the Kubernetes cluster in the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation. Also includes support for MariaDB chart out of the box.

Due that the Helm Chart clones the application on the /app volume while the container is initializing, a persistent volume is not required.

> **Tip**: List all releases using `helm list`
## Uninstalling the Chart

To uninstall/delete the `my-release` deployment:

```console
$ helm delete my-release
```

The command removes all the Kubernetes components associated with the chart and deletes the release.

## Parameters

The following table lists the configurable parameters of the node chart and their default values.

| Parameter | Description | Default |
| --------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------- |
| `global.imageRegistry` | Global Docker image registry | `docker.io` |
| `node.registry` | Node image registry | `nil` |
| `node.repository` | Node image name | `srijanlabs/node:demo` |
| `node.pullPolicy` | Node image pull policy | `IfNotPresent` |
| `node.extraEnv` | Node container environment variables | `nill` |
| `node.command` | Node container entry point | from image |
| `node.arg` | Node container arguments | from image |
| `node.port` | Node container listing port | 9000 |
| `nameOverride` | String to partially override node.fullname template | `nil` |
| `fullnameOverride` | String to fully override node.fullname template | `nil` |
| `applicationKind` | Deployment or ReplicaSet | `Deployment` |
| `replicas` | Number of replicas for the application | `1` |
| `extraEnv` | Any extra environment variables to be pass to the pods | `{}` |
| `affinity` | Map of node/pod affinities | `{}` (The value is evaluated as a template) |
| `nodeSelector` | node labels for pod assignment | `{}` (The value is evaluated as a template) |
| `tolerations` | Tolerations for pod assignment | `[]` (The value is evaluated as a template) |
| `securityContext.enabled` | Enable security context | `true` |
| `securityContext.fsGroup` | Group ID for the container | `1001` |
| `securityContext.runAsUser` | User ID for the container | `1001` |
| `resources` | Resource requests and limits | `{}` |
| `service.type` | Kubernetes Service type | `NodePort` |
| `service.port` | Kubernetes Service port | `80` |
| `service.annotations` | Annotations for the Service | {} |
| `service.loadBalancerIP` | LoadBalancer IP if Service type is `LoadBalancer` | `nil` |
| `service.nodePort` | nodePort if Service type is `LoadBalancer` or `nodePort` | `nil` |
| `ingress.enabled` | Enable ingress controller resource | `false` |
| `ingress.hosts[0].name` | Hostname to your node installation | `node.local` |
| `ingress.hosts[0].path` | Path within the url structure | `/` |
| `ingress.hosts[0].tls` | Utilize TLS backend in ingress | `false` |
| `ingress.hosts[0].certManager` | Add annotations for cert-manager | `false` |
| `ingress.hosts[0].tlsSecret` | TLS Secret (certificates) | `node.local-tls-secret` |
| `ingress.hosts[0].annotations` | Annotations for this host's ingress record | `[]` |
| `ingress.secrets[0].name` | TLS Secret Name | `nil` |
| `ingress.secrets[0].certificate` | TLS Secret Certificate | `nil` |
| `ingress.secrets[0].key` | TLS Secret Key | `nil` |


Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,

```console
$ helm install my-release \
--set replicas=2 \
./node
```

The above command clones the remote git repository to the `/app/` directory of the container. Additionally it sets the number of `replicas` to `2`.

Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example,

```console
$ helm install my-release -f values.yaml ./node
```

> **Tip**: You can use the default [values.yaml](values.yaml)
## Configuration and installation details

### Set up an Ingress controller

First install the nginx-ingress controller and then deploy the node helm chart with the following parameters:

```console
ingress.enabled=true
ingress.host=example.com
service.type=ClusterIP
```

### Configure TLS termination for your ingress controller

You must manually create a secret containing the certificate and key for your domain. Then ensure you deploy the Helm chart with the following ingress configuration:

```yaml
ingress:
enabled: false
path: /
host: example.com
annotations:
kubernetes.io/ingress.class: nginx
tls:
hosts:
- example.com
```

### Steps to manually put the helm charts and values.yaml to S3 bucket

- Put the helm charts folder and values.yaml to Bastion host (or to a place from where s3 bucket is accessible).
- Make sure that current directory is having `charts.yaml`.
- Run below command to create a helm package
```
helm package .
```
- You should see a helm package named - `node-1.0.0.tgz`.
- Upload the `node-1.0.0.tgz` helm package to s3 bucket :
```
aws s3 cp node-1.0.0.tgz s3://s3-helm/node/node-1.0.0.tgz --sse=AES256 --region=ap-southeast-1
```
- Upload the `values.yaml` to s3 bucket :
```
aws s3 cp values-<env>.yaml s3://s3-helm/node/values/st-<env>-values.yaml --sse=AES256 --region=ap-southeast-1
```
23 changes: 23 additions & 0 deletions starterkits/node-express-postgres/charts/node/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

1. Get the URL of your Node app by running:

{{- if contains "NodePort" .Values.service.type }}

export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "node.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo "Node app URL: http://$NODE_IP:$NODE_PORT/"

{{- else if contains "LoadBalancer" .Values.service.type }}

NOTE: It may take a few minutes for the LoadBalancer IP to be available.
Watch the status with: 'kubectl get svc -w {{ template "node.fullname" . }} --namespace {{ .Release.Namespace }}'

export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "node.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo "Node app URL: http://$SERVICE_IP/"

{{- else if contains "ClusterIP" .Values.service.type }}

kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "node.fullname" . }} {{ .Values.service.port }}:{{ .Values.service.port }}
echo "Node app URL: http://127.0.0.1:{{ .Values.service.port }}/"

{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "node.appName" -}}
{{- 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).
*/}}
{{- define "node.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 "node.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Common labels
*/}}
{{- define "node.labels" -}}
app: {{ include "node.appName" . }}
chart: {{ include "node.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- end -}}

{{/*
Common labels for cron-jobs to be used for deletion
*/}}
{{- define "node.cronLabels" -}}
app: {{ include "node.appName" . }}
chart: {{ include "node.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
workload: cronjob
{{- end -}}

{{/*
Labels to use on deploy.spec.selector.matchLabels and svc.spec.selector
*/}}
{{- define "node.matchLabels" -}}
app: {{ include "node.appName" . }}
release: {{ .Release.Name }}
{{- end -}}

{{/*
Return the proper php-fpm image name
*/}}
{{- define "node.image" -}}
{{- $registryName := .Values.node.image.registry -}}
{{- $repositoryName := .Values.node.image.repository -}}
{{- $tag := .Values.node.image.tag | toString -}}
{{/*
Helm 2.11 supports the assignment of a value to a variable defined in a different scope,
but Helm 2.9 and 2.10 doesn't support it, so we need to implement this if-else logic.
Also, we can't use a single if because lazy evaluation is not an option
*/}}
{{- if .Values.global }}
{{- if .Values.global.imageRegistry }}
{{- printf "%s/%s" .Values.global.imageRegistry $repositoryName -}}
{{- else -}}
{{- printf "%s/%s" $registryName $repositoryName -}}
{{- end -}}
{{- else -}}
{{- printf "%s/%s" $registryName $repositoryName -}}
{{- end -}}
{{- end -}}



{{/*
Renders a value that contains template.
Usage:
{{ include "node.tplValue" (dict "value" .Values.path.to.the.Value "context" $) }}
*/}}
{{- define "node.tplValue" -}}
{{- if typeIs "string" .value }}
{{- tpl .value .context }}
{{- else }}
{{- tpl (.value | toYaml) .context }}
{{- end }}
{{- end -}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
apiVersion: apps/v1
kind: {{ .Values.applicationKind }}
metadata:
name: {{ template "node.fullname" . }}
labels: {{- include "node.labels" . | nindent 4 }}
spec:
selector:
matchLabels: {{- include "node.matchLabels" . | nindent 6 }}
replicas: {{ .Values.replicas }}
template:
metadata:
labels: {{- include "node.labels" . | nindent 8 }}
spec:
{{- if .Values.affinity }}
affinity: {{- include "node.tplValue" (dict "value" .Values.affinity "context" $) | nindent 8 }}
{{- end }}
{{- if .Values.nodeSelector }}
nodeSelector: {{- include "node.tplValue" (dict "value" .Values.nodeSelector "context" $) | nindent 8 }}
{{- end }}
{{- if .Values.tolerations }}
tolerations: {{- include "node.tplValue" (dict "value" .Values.tolerations "context" $) | nindent 8 }}
{{- end }}
{{- if .Values.securityContext.enabled }}
securityContext:
fsGroup: {{ .Values.securityContext.fsGroup }}
runAsUser: {{ .Values.securityContext.runAsUser }}
{{- end }}
containers:
- name: node
image: {{ template "node.image" . }}
imagePullPolicy: {{ .Values.node.image.pullPolicy | quote }}
envFrom:
- secretRef:
name: {{ template "node.fullname" . }}
{{- if .Values.node.extraEnv }}
env: {{- toYaml .Values.node.extraEnv | nindent 12 }}
{{- end }}
{{- if .Values.node.command }}
command: {{- toYaml .Values.node.command | nindent 12 }}
{{- end }}
{{- if .Values.node.args }}
args: {{- toYaml .Values.node.args | nindent 12 }}
{{- end }}
ports:
- name: node
containerPort: {{ .Values.node.port }}
livenessProbe:
{{ toYaml .Values.node.livenessProbe | indent 12 }}
readinessProbe:
{{ toYaml .Values.node.readinessProbe | indent 12 }}
{{- if .Values.node.resources }}
resources: {{- toYaml .Values.node.resources | nindent 12 }}
{{- end }}
14 changes: 14 additions & 0 deletions starterkits/node-express-postgres/charts/node/templates/hpa.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{{- if .Values.HPA.enabled }}
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: {{ template "node.fullname" . }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: {{ .Values.applicationKind }}
name: {{ template "node.fullname" . }}
minReplicas: {{ .Values.HPA.minReplicas }}
maxReplicas: {{ .Values.HPA.maxReplicas }}
targetCPUUtilizationPercentage: {{ .Values.HPA.targetCPUUtilizationPercentage }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ template "node.fullname" $ }}
labels: {{- include "node.labels" $ | nindent 4 }}
annotations:
{{- if .certManager }}
kubernetes.io/tls-acme: "true"
{{- end }}
{{- range $key, $value := .annotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
spec:
rules:
- host: {{ .name }}
http:
paths:
- path: /*
backend:
serviceName: ssl-redirect
servicePort: use-annotation
- path: {{ default "/" .path }}
backend:
serviceName: {{ template "node.fullname" $ }}
servicePort: {{ $.Values.service.port }}
{{- if .tls }}
tls:
- hosts:
- {{ .name }}
secretName: {{ .tlsSecret }}
{{- end }}
{{- end }}
{{- end }}

0 comments on commit 034f725

Please sign in to comment.