From 68cc2ddd63b78ade697422885af66c7abca7ff6b Mon Sep 17 00:00:00 2001
From: Dominik Hebeler <dominik@suma-ev.de>
Date: Mon, 2 Sep 2019 11:54:00 +0200
Subject: [PATCH] Added custom charts

---
 charts/.gitignore                       |   1 +
 charts/.gitlab-ci.yml                   |  19 ++++
 charts/.helmignore                      |  21 +++++
 charts/CONTRIBUTING.md                  |  26 ++++++
 charts/Chart.yaml                       |   5 +
 charts/LICENSE                          |  19 ++++
 charts/README.md                        |  54 +++++++++++
 charts/requirements.lock                |   6 ++
 charts/requirements.yaml                |   5 +
 charts/templates/NOTES.txt              |   5 +
 charts/templates/_helpers.tpl           |  33 +++++++
 charts/templates/db-initialize-job.yaml |  39 ++++++++
 charts/templates/db-migrate-hook.yaml   |  39 ++++++++
 charts/templates/deployment.yaml        | 118 ++++++++++++++++++++++++
 charts/templates/hpa.yaml               |  19 ++++
 charts/templates/ingress.yaml           |  51 ++++++++++
 charts/templates/pdb.yaml               |  22 +++++
 charts/templates/service.yaml           |  44 +++++++++
 charts/templates/worker-deployment.yaml |  82 ++++++++++++++++
 charts/values.yaml                      |  87 +++++++++++++++++
 20 files changed, 695 insertions(+)
 create mode 100644 charts/.gitignore
 create mode 100644 charts/.gitlab-ci.yml
 create mode 100644 charts/.helmignore
 create mode 100644 charts/CONTRIBUTING.md
 create mode 100644 charts/Chart.yaml
 create mode 100644 charts/LICENSE
 create mode 100644 charts/README.md
 create mode 100644 charts/requirements.lock
 create mode 100644 charts/requirements.yaml
 create mode 100644 charts/templates/NOTES.txt
 create mode 100644 charts/templates/_helpers.tpl
 create mode 100644 charts/templates/db-initialize-job.yaml
 create mode 100644 charts/templates/db-migrate-hook.yaml
 create mode 100644 charts/templates/deployment.yaml
 create mode 100644 charts/templates/hpa.yaml
 create mode 100644 charts/templates/ingress.yaml
 create mode 100644 charts/templates/pdb.yaml
 create mode 100644 charts/templates/service.yaml
 create mode 100644 charts/templates/worker-deployment.yaml
 create mode 100644 charts/values.yaml

diff --git a/charts/.gitignore b/charts/.gitignore
new file mode 100644
index 0000000..e6b3ed6
--- /dev/null
+++ b/charts/.gitignore
@@ -0,0 +1 @@
+charts/*
diff --git a/charts/.gitlab-ci.yml b/charts/.gitlab-ci.yml
new file mode 100644
index 0000000..cb02d24
--- /dev/null
+++ b/charts/.gitlab-ci.yml
@@ -0,0 +1,19 @@
+image: registry.gitlab.com/charts/alpine-helm
+
+stages:
+  - test
+  - release
+
+lint:
+  stage: test
+  script:
+    - helm lint .
+  except:
+    - master
+
+release-chart:
+  stage: release
+  script:
+    - curl --fail --request POST --form "token=$CI_JOB_TOKEN" --form ref=master https://gitlab.com/api/v4/projects/2860651/trigger/pipeline
+  only:
+    - master
diff --git a/charts/.helmignore b/charts/.helmignore
new file mode 100644
index 0000000..f0c1319
--- /dev/null
+++ b/charts/.helmignore
@@ -0,0 +1,21 @@
+# 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
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
diff --git a/charts/CONTRIBUTING.md b/charts/CONTRIBUTING.md
new file mode 100644
index 0000000..589986f
--- /dev/null
+++ b/charts/CONTRIBUTING.md
@@ -0,0 +1,26 @@
+## Contributing
+
+Thank you for your interest in contributing to this GitLab project! We welcome
+all contributions. By participating in this project, you agree to abide by the
+[code of conduct](#code-of-conduct).
+
+
+## Developer Certificate of Origin + License
+
+By contributing to GitLab B.V., You accept and agree to the following terms and
+conditions for Your present and future Contributions submitted to GitLab B.V.
+Except for the license granted herein to GitLab B.V. and recipients of software
+distributed by GitLab B.V., You reserve all right, title, and interest in and to
+Your Contributions. All Contributions are subject to the following DCO + License
+terms.
+
+[DCO + License](https://gitlab.com/gitlab-org/dco/blob/master/README.md)
+
+_This notice should stay as the first item in the CONTRIBUTING.md file._
+
+## Code of conduct
+
+We want to create a welcoming environment for everyone who is interested
+in contributing. Please visit our [Code of Conduct
+page](https://about.gitlab.com/contributing/code-of-conduct) to learn
+more about our committment to an open and welcoming environment.
diff --git a/charts/Chart.yaml b/charts/Chart.yaml
new file mode 100644
index 0000000..e5a69ec
--- /dev/null
+++ b/charts/Chart.yaml
@@ -0,0 +1,5 @@
+apiVersion: v1
+description: GitLab's Auto-deploy Helm Chart
+name: auto-deploy-app
+version: 0.2.9
+icon: https://gitlab.com/gitlab-com/gitlab-artwork/raw/master/logo/logo-square.png
diff --git a/charts/LICENSE b/charts/LICENSE
new file mode 100644
index 0000000..a90ea93
--- /dev/null
+++ b/charts/LICENSE
@@ -0,0 +1,19 @@
+Copyright GitLab B.V.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/charts/README.md b/charts/README.md
new file mode 100644
index 0000000..c396cf2
--- /dev/null
+++ b/charts/README.md
@@ -0,0 +1,54 @@
+# GitLab's Auto-deploy Helm Chart
+
+## Requirements
+
+- Helm `2.9.0` and above is required in order support `"helm.sh/hook-delete-policy": before-hook-creation` for migrations
+
+## Configuration
+
+| Parameter                     | Description | Default                            |
+| ---                           | ---         | ---                                |
+| replicaCount                  |             | `1`                                |
+| image.repository              |             | `gitlab.example.com/group/project` |
+| image.tag                     |             | `stable`                           |
+| image.pullPolicy              |             | `Always`                           |
+| image.secrets                 |             | `[name: gitlab-registry]`          |
+| podAnnotations                | Pod annotations | `{}`                           |
+| application.track             |             | `stable`                           |
+| application.tier              |             | `web`                              |
+| application.migrateCommand    | If present, this variable will run as a shell command within an application Container as a Helm pre-upgrade Hook. Intended to run migration commands. | `nil` |
+| application.initializeCommand | If present, this variable will run as shall command within an application Container as a Helm post-install Hook. Intended to run database initialization commands. | `nil` |
+| application.secretName        | Pass in the name of a Secret which the deployment will [load all key-value pairs from the Secret as environment variables](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables) in the application container. | `nil` |
+| application.secretChecksum    | Pass in the checksum of the secrets referenced by `application.secretName`. | `nil` |
+| hpa.enabled                   | If true, enables horizontal pod autoscaler. A resource request is also required to be set, such as `resources.requests.cpu: 200m`.| `false` |
+| hpa.minReplicas               |             | `1`                                |
+| hpa.maxReplicas               |             | `5`                                |
+| hpa.targetCPUUtilizationPercentage | Percentage threshold when HPA begins scaling out pods | `80` |
+| gitlab.app                    | GitLab project slug. | `nil` |
+| gitlab.env                    | GitLab environment slug. | `nil` |
+| gitlab.envName                | GitLab environment name. | `nil` |
+| gitlab.envURL                 | GitLab environment URL.  | `nil` |
+| service.enabled               |             | `true`                             |
+| service.annotations           | Service annotations | `{}`                       |
+| service.name                  |             | `web`                              |
+| service.type                  |             | `ClusterIP`                        |
+| service.url                   |             | `http://my.host.com/`              |
+| service.additionalHosts       | If present, this list will add additional hostnames to the server configuration. | `nil` |
+| service.commonName            | If present, this will define the ssl certificate common name to be used by CertManager. `service.url` and `service.additionalHosts` will be added as Subject Alternative Names (SANs) | `nil` |
+| service.externalPort          |             | `5000`                             |
+| service.internalPort          |             | `5000`                             |
+| ingress.tls.enabled           | If true, enables SSL | `true`                    |
+| ingress.tls.secretName        | Name of the secret used to terminate SSL traffic | `""` |
+| ingress.annotations           | Ingress annotations | `{kubernetes.io/tls-acme: "true", kubernetes.io/ingress.class: "nginx"}` |
+| livenessProbe.path            | Path to access on the HTTP server on periodic probe of container liveness. | `/`                                |
+| livenessProbe.scheme          | Scheme to access the HTTP server (HTTP or HTTPS). | `HTTP`                                |
+| livenessProbe.initialDelaySeconds | # of seconds after the container has started before liveness probes are initiated. | `15`                               |
+| livenessProbe.timeoutSeconds  | # of seconds after which the liveness probe times out. | `15`                               |
+| readinessProbe.path           | Path to access on the HTTP server on periodic probe of container readiness. | `/`                                |
+| readinessProbe.scheme         | Scheme to access the HTTP server (HTTP or HTTPS). | `HTTP`                                |
+| readinessProbe.initialDelaySeconds | # of seconds after the container has started before readiness probes are initiated. | `5`                                |
+| readinessProbe.timeoutSeconds | # of seconds after which the readiness probe times out. | `3`                                |
+| postgresql.enabled            |             | `true`                             |
+| podDisruptionBudget.enabled   |             | `false`                            |
+| podDisruptionBudget.maxUnavailable |             | `1`                            |
+| podDisruptionBudget.minAvailable | If present, this variable will configure minAvailable in the PodDisruptionBudget. :warning: if you have `replicaCount: 1` and `podDisruptionBudget.minAvailable: 1` `kubectl drain` will be blocked.              | `nil`                            |
diff --git a/charts/requirements.lock b/charts/requirements.lock
new file mode 100644
index 0000000..c92fba5
--- /dev/null
+++ b/charts/requirements.lock
@@ -0,0 +1,6 @@
+dependencies:
+- name: postgresql
+  repository: https://kubernetes-charts.storage.googleapis.com/
+  version: 0.7.1
+digest: sha256:358ce85fe4d3461ea6bb96713470a80de9c1324214a2e6f97d800298c02530e2
+generated: 2017-08-28T15:22:30.690341342-05:00
diff --git a/charts/requirements.yaml b/charts/requirements.yaml
new file mode 100644
index 0000000..8d88384
--- /dev/null
+++ b/charts/requirements.yaml
@@ -0,0 +1,5 @@
+dependencies:
+  - name: postgresql
+    version: "0.7.1"
+    repository: "https://kubernetes-charts.storage.googleapis.com/"
+    condition: postgresql.enabled
diff --git a/charts/templates/NOTES.txt b/charts/templates/NOTES.txt
new file mode 100644
index 0000000..0ef42bb
--- /dev/null
+++ b/charts/templates/NOTES.txt
@@ -0,0 +1,5 @@
+{{- if .Values.service.enabled -}}
+Application should be accessible at: {{ .Values.service.url }}
+{{- else -}}
+Application will be accessible at: {{ .Values.service.url }} when you deploy stable track.
+{{- end -}}
diff --git a/charts/templates/_helpers.tpl b/charts/templates/_helpers.tpl
new file mode 100644
index 0000000..913145e
--- /dev/null
+++ b/charts/templates/_helpers.tpl
@@ -0,0 +1,33 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 24 | 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 "fullname" -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- printf "%s-%s" .Release.Name $name | trimSuffix "-app" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{- define "appname" -}}
+{{- $releaseName := default .Release.Name .Values.releaseOverride -}}
+{{- printf "%s" $releaseName | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{- define "trackableappname" -}}
+{{- $trackableName := printf "%s-%s" (include "appname" .) .Values.application.track -}}
+{{- $trackableName | trimSuffix "-stable" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Get a hostname from URL
+*/}}
+{{- define "hostname" -}}
+{{- . | trimPrefix "http://" |  trimPrefix "https://" | trimSuffix "/" | quote -}}
+{{- end -}}
diff --git a/charts/templates/db-initialize-job.yaml b/charts/templates/db-initialize-job.yaml
new file mode 100644
index 0000000..12fd511
--- /dev/null
+++ b/charts/templates/db-initialize-job.yaml
@@ -0,0 +1,39 @@
+{{- if .Values.application.initializeCommand -}}
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ template "trackableappname" . }}-db-initialize
+  labels:
+    app: {{ template "appname" . }}
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version| replace "+" "_" }}"
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+  annotations:
+    "helm.sh/hook": post-install
+    "helm.sh/hook-delete-policy": before-hook-creation
+    "helm.sh/hook-weight": "0"
+spec:
+  template:
+    metadata:
+      labels:
+        app: {{ template "appname" . }}
+        release: {{ .Release.Name }}
+    spec:
+      restartPolicy: Never
+      imagePullSecrets:
+{{ toYaml .Values.image.secrets | indent 10 }}
+      containers:
+      - name: {{ .Chart.Name }}
+        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+        command: ["/bin/sh"]
+        args: ["-c", "{{ .Values.application.initializeCommand }}"]
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        {{- if .Values.application.secretName }}
+        envFrom:
+        - secretRef:
+            name: {{ .Values.application.secretName }}
+        {{- end }}
+        env:
+        - name: DATABASE_URL
+          value: {{ .Values.application.database_url | quote }}
+{{- end -}}
diff --git a/charts/templates/db-migrate-hook.yaml b/charts/templates/db-migrate-hook.yaml
new file mode 100644
index 0000000..b2d5aa7
--- /dev/null
+++ b/charts/templates/db-migrate-hook.yaml
@@ -0,0 +1,39 @@
+{{- if .Values.application.migrateCommand -}}
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ template "trackableappname" . }}-db-migrate
+  labels:
+    app: {{ template "appname" . }}
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version| replace "+" "_" }}"
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+  annotations:
+    "helm.sh/hook": pre-upgrade
+    "helm.sh/hook-delete-policy": before-hook-creation
+    "helm.sh/hook-weight": "0"
+spec:
+  template:
+    metadata:
+      labels:
+        app: {{ template "appname" . }}
+        release: {{ .Release.Name }}
+    spec:
+      restartPolicy: Never
+      imagePullSecrets:
+{{ toYaml .Values.image.secrets | indent 10 }}
+      containers:
+      - name: {{ .Chart.Name }}
+        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+        command: ["/bin/sh"]
+        args: ["-c", "{{ .Values.application.migrateCommand }}"]
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        {{- if .Values.application.secretName }}
+        envFrom:
+        - secretRef:
+            name: {{ .Values.application.secretName }}
+        {{- end }}
+        env:
+        - name: DATABASE_URL
+          value: {{ .Values.application.database_url | quote }}
+{{- end -}}
diff --git a/charts/templates/deployment.yaml b/charts/templates/deployment.yaml
new file mode 100644
index 0000000..31f503e
--- /dev/null
+++ b/charts/templates/deployment.yaml
@@ -0,0 +1,118 @@
+{{- if not .Values.application.initializeCommand -}}
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+  name: {{ template "trackableappname" . }}
+  annotations:
+    {{ if .Values.gitlab.app }}app.gitlab.com/app: {{ .Values.gitlab.app | quote }}{{ end }}
+    {{ if .Values.gitlab.env }}app.gitlab.com/env: {{ .Values.gitlab.env | quote }}{{ end }}
+  labels:
+    app: {{ template "appname" . }}
+    track: "{{ .Values.application.track }}"
+    tier: "{{ .Values.application.tier }}"
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  template:
+    metadata:
+      annotations:
+        checksum/application-secrets: "{{ .Values.application.secretChecksum }}"
+        {{ if .Values.gitlab.app }}app.gitlab.com/app: {{ .Values.gitlab.app | quote }}{{ end }}
+        {{ if .Values.gitlab.env }}app.gitlab.com/env: {{ .Values.gitlab.env | quote }}{{ end }}
+{{- if .Values.podAnnotations }}
+{{ toYaml .Values.podAnnotations | indent 8 }}
+{{- end }}
+      labels:
+        app: {{ template "appname" . }}
+        track: "{{ .Values.application.track }}"
+        tier: "{{ .Values.application.tier }}"
+        release: {{ .Release.Name }}
+    spec:
+      imagePullSecrets:
+{{ toYaml .Values.image.secrets | indent 10 }}
+      containers:
+      - name: {{ .Chart.Name }}
+        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        {{- if .Values.application.secretName }}
+        envFrom:
+        - secretRef:
+            name: {{ .Values.application.secretName }}
+        {{- end }}
+        env:
+        - name: DATABASE_URL
+          value: {{ .Values.application.database_url | quote }}
+        - name: GITLAB_ENVIRONMENT_NAME
+          value: {{ .Values.gitlab.envName }}
+        - name: GITLAB_ENVIRONMENT_URL
+          value: {{ .Values.gitlab.envURL }}
+        ports:
+        - name: "{{ .Values.service.name }}"
+          containerPort: {{ .Values.service.internalPort }}
+        livenessProbe:
+          httpGet:
+            path: {{ .Values.livenessProbe.path }}
+            port: {{ .Values.service.internalPort }}
+            scheme: {{ .Values.livenessProbe.scheme }}
+          initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}
+          timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}
+        readinessProbe:
+          httpGet:
+            path: {{ .Values.readinessProbe.path }}
+            port: {{ .Values.service.internalPort }}
+            scheme: {{ .Values.readinessProbe.scheme }}
+          initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
+          timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}
+        resources:
+{{ toYaml .Values.resources | indent 12 }}
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+  name: {{ template "trackableappname" . }}-redis
+  annotations:
+    {{ if .Values.gitlab.app }}app.gitlab.com/app: {{ .Values.gitlab.app | quote }}{{ end }}
+    {{ if .Values.gitlab.env }}app.gitlab.com/env: {{ .Values.gitlab.env | quote }}{{ end }}
+  labels:
+    app: {{ template "appname" . }}-redis
+    track: "{{ .Values.application.track }}"
+    tier: "{{ .Values.application.tier }}"
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  template:
+    metadata:
+      labels:
+        app: {{ template "appname" . }}-redis
+        track: "{{ .Values.application.track }}"
+        tier: "{{ .Values.application.tier }}"
+        release: {{ .Release.Name }}
+    spec:
+      containers:
+      - name: {{ .Chart.Name }}-redis
+        image: "redis:latest"
+        ports:
+          - containerPort: 6379
+        livenessProbe:
+          exec:
+            command:
+            - sh
+            - -c
+            - redis-cli ping
+          initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}
+          timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}
+        readinessProbe:
+          exec:
+            command:
+            - sh
+            - -c
+            - redis-cli ping
+          initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
+          timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}
+        resources:
+{{ toYaml .Values.resources | indent 12 }}
+{{- end -}}
\ No newline at end of file
diff --git a/charts/templates/hpa.yaml b/charts/templates/hpa.yaml
new file mode 100644
index 0000000..f4cb3ad
--- /dev/null
+++ b/charts/templates/hpa.yaml
@@ -0,0 +1,19 @@
+{{- if and .Values.hpa.enabled .Values.resources.requests -}}
+apiVersion: autoscaling/v1
+kind: HorizontalPodAutoscaler
+metadata:
+  name: {{ template "fullname" . }}
+  labels:
+    app: {{ template "appname" . }}
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+spec:
+  scaleTargetRef:
+    kind: Deployment
+    name: {{ template "appname" . }}
+    apiVersion: apps/v1beta1
+  minReplicas: {{ .Values.hpa.minReplicas }}
+  maxReplicas: {{ .Values.hpa.maxReplicas }}
+  targetCPUUtilizationPercentage: {{ .Values.hpa.targetCPUUtilizationPercentage }}
+{{- end -}}
diff --git a/charts/templates/ingress.yaml b/charts/templates/ingress.yaml
new file mode 100644
index 0000000..8a1633c
--- /dev/null
+++ b/charts/templates/ingress.yaml
@@ -0,0 +1,51 @@
+{{- if .Values.service.enabled -}}
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  name: {{ template "fullname" . }}
+  labels:
+    app: {{ template "appname" . }}
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version| replace "+" "_" }}"
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+{{- if .Values.ingress.annotations }}
+  annotations:
+{{ toYaml .Values.ingress.annotations | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.ingress.tls.enabled }}
+  tls:
+  - hosts:
+{{- if .Values.service.commonName }}
+    - {{ template "hostname" .Values.service.commonName }}
+{{- end }}
+    - {{ template "hostname" .Values.service.url }}
+{{- if .Values.service.additionalHosts }}
+{{- range $host := .Values.service.additionalHosts }}
+    - {{ $host }}
+{{- end -}}
+{{- end }}
+    secretName: {{ .Values.ingress.tls.secretName | default (printf "%s-tls" (include "fullname" .)) }}
+{{- end }}
+  rules:
+  - host: {{ template "hostname" .Values.service.url }}
+    http:
+      &httpRule
+      paths:
+      - path: /
+        backend:
+          serviceName: {{ template "fullname" . }}
+          servicePort: {{ .Values.service.externalPort }}
+{{- if .Values.service.commonName }}
+  - host: {{ template "hostname" .Values.service.commonName }}
+    http:
+      <<: *httpRule
+{{- end -}}
+{{- if .Values.service.additionalHosts }}
+{{- range $host := .Values.service.additionalHosts }}
+  - host: {{ $host }}
+    http:
+      <<: *httpRule
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/templates/pdb.yaml b/charts/templates/pdb.yaml
new file mode 100644
index 0000000..69bb2ed
--- /dev/null
+++ b/charts/templates/pdb.yaml
@@ -0,0 +1,22 @@
+{{- if .Values.podDisruptionBudget.enabled }}
+apiVersion: policy/v1beta1
+kind: PodDisruptionBudget
+metadata:
+  name: {{ template "fullname" . }}
+  labels:
+    app: {{ template "appname" . }}
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+spec:
+{{- if .Values.podDisruptionBudget.minAvailable }}
+  minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
+{{- end }}
+{{- if .Values.podDisruptionBudget.maxUnavailable }}
+  maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
+{{- end }}
+  selector:
+    matchLabels:
+      app: {{ template "appname" . }}
+      release: {{ .Release.Name }}
+{{- end }}
diff --git a/charts/templates/service.yaml b/charts/templates/service.yaml
new file mode 100644
index 0000000..c03f069
--- /dev/null
+++ b/charts/templates/service.yaml
@@ -0,0 +1,44 @@
+{{- if .Values.service.enabled -}}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ template "fullname" . }}
+{{- if .Values.service.annotations }}
+  annotations:
+{{ toYaml .Values.service.annotations | indent 4 }}
+{{- end }}
+  labels:
+    app: {{ template "appname" . }}
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+spec:
+  type: {{ .Values.service.type }}
+  ports:
+  - port: {{ .Values.service.externalPort }}
+    targetPort: {{ .Values.service.internalPort }}
+    protocol: TCP
+    name: {{ .Values.service.name }}
+  selector:
+    app: {{ template "appname" . }}
+    tier: "{{ .Values.application.tier }}"
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ template "fullname" . }}-redis
+  labels:
+    app: {{ template "appname" . }}-redis
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+spec:
+  ports:
+  - port: 6379
+    targetPort: 6379
+    protocol: TCP
+    name: {{ .Values.service.name }}
+  selector:
+    app: {{ template "appname" . }}-redis
+    tier: "{{ .Values.application.tier }}"
+{{- end -}}
diff --git a/charts/templates/worker-deployment.yaml b/charts/templates/worker-deployment.yaml
new file mode 100644
index 0000000..56618ee
--- /dev/null
+++ b/charts/templates/worker-deployment.yaml
@@ -0,0 +1,82 @@
+{{- if and (not .Values.application.initializeCommand) .Values.workers -}}
+apiVersion: v1
+kind: List
+items:
+{{- range $workerName, $workerConfig :=  .Values.workers }}
+- apiVersion: extensions/v1beta1
+  kind: Deployment
+  metadata:
+    name: {{ template "trackableappname" $ }}-{{ $workerName }}
+    annotations:
+      {{ if $.Values.gitlab.app }}app.gitlab.com/app: {{ $.Values.gitlab.app | quote }}{{ end }}
+      {{ if $.Values.gitlab.env }}app.gitlab.com/env: {{ $.Values.gitlab.env | quote }}{{ end }}
+    labels:
+      track: "{{ $.Values.application.track }}"
+      tier: worker
+      chart: "{{ $.Chart.Name }}-{{ $.Chart.Version | replace "+" "_" }}"
+      release: {{ $.Release.Name }}
+      heritage: {{ $.Release.Service }}
+  spec:
+    replicas: {{ $workerConfig.replicaCount }}
+    template:
+      metadata:
+        annotations:
+          checksum/application-secrets: "{{ $.Values.application.secretChecksum }}"
+          {{ if $.Values.gitlab.app }}app.gitlab.com/app: {{ $.Values.gitlab.app | quote }}{{ end }}
+          {{ if $.Values.gitlab.env }}app.gitlab.com/env: {{ $.Values.gitlab.env | quote }}{{ end }}
+  {{- if $.Values.podAnnotations }}
+  {{ toYaml $.Values.podAnnotations | indent 10 }}
+  {{- end }}
+        labels:
+          track: "{{ $.Values.application.track }}"
+          tier: worker
+          release: {{ $.Release.Name }}
+      spec:
+        imagePullSecrets:
+  {{ toYaml $.Values.image.secrets | indent 12 }}
+        terminationGracePeriodSeconds: {{ $workerConfig.terminationGracePeriodSeconds }}
+        containers:
+        - name: {{ $.Chart.Name }}-{{ $workerName }}
+          image: "{{ $.Values.image.repository }}:{{ $.Values.image.tag }}"
+          command:
+          {{- range $workerConfig.command }}
+          - {{ . }}
+          {{- end }}
+          imagePullPolicy: {{ $.Values.image.pullPolicy }}
+          {{- if $.Values.application.secretName }}
+          envFrom:
+          - secretRef:
+              name: {{ $.Values.application.secretName }}
+          {{- end }}
+          env:
+          - name: DATABASE_URL
+            value: {{ $.Values.application.database_url | quote }}
+          - name: GITLAB_ENVIRONMENT_NAME
+            value: {{ $.Values.gitlab.envName }}
+          livenessProbe:
+            httpGet:
+              path: {{ $.Values.livenessProbe.path }}
+              port: {{ $.Values.service.internalPort }}
+              scheme: {{ $.Values.livenessProbe.scheme }}
+            initialDelaySeconds: {{ $.Values.livenessProbe.initialDelaySeconds }}
+            timeoutSeconds: {{ $.Values.livenessProbe.timeoutSeconds }}
+          readinessProbe:
+            httpGet:
+              path: {{ $.Values.readinessProbe.path }}
+              port: {{ $.Values.service.internalPort }}
+              scheme: {{ $.Values.readinessProbe.scheme }}
+            initialDelaySeconds: {{ $.Values.readinessProbe.initialDelaySeconds }}
+            timeoutSeconds: {{ $.Values.readinessProbe.timeoutSeconds }}
+          {{- if $workerConfig.preStopCommand }}
+          lifecycle:
+            preStop:
+              exec:
+                command:
+                {{- range $workerConfig.preStopCommand }}
+                - {{ . }}
+                {{- end }}
+          {{- end }}
+          resources:
+  {{ toYaml $.Values.resources | indent 14 }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/values.yaml b/charts/values.yaml
new file mode 100644
index 0000000..a53604d
--- /dev/null
+++ b/charts/values.yaml
@@ -0,0 +1,87 @@
+# Default values for chart.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+replicaCount: 1
+image:
+  repository: gitlab.example.com/group/project
+  tag: stable
+  pullPolicy: Always
+  secrets:
+    - name: gitlab-registry
+podAnnotations: {}
+application:
+  track: stable
+  tier: web
+  migrateCommand:
+  initializeCommand:
+  secretName:
+  secretChecksum:
+hpa:
+  enabled: false
+  minReplicas: 1
+  maxReplicas: 5
+  targetCPUUtilizationPercentage: 80
+gitlab:
+  app:
+  env:
+  envName:
+  envURL:
+service:
+  enabled: true
+  annotations: {}
+  name: web
+  type: ClusterIP
+  url: http://my.host.com/
+  additionalHosts:
+  commonName:
+  externalPort: 5000
+  internalPort: 5000
+ingress:
+  tls:
+    enabled: true
+    secretName: ""
+  annotations:
+    kubernetes.io/tls-acme: "true"
+    kubernetes.io/ingress.class: "nginx"
+livenessProbe:
+  path: "/"
+  initialDelaySeconds: 15
+  timeoutSeconds: 15
+  scheme: "HTTP"
+readinessProbe:
+  path: "/"
+  initialDelaySeconds: 5
+  timeoutSeconds: 3
+  scheme: "HTTP"
+postgresql:
+  enabled: true
+resources:
+#  limits:
+#    cpu: 100m
+#    memory: 128Mi
+  requests:
+#    cpu: 100m
+#    memory: 128Mi
+
+## Configure PodDisruptionBudget
+## ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/
+#
+podDisruptionBudget:
+  enabled: false
+  # minAvailable: 1
+  maxUnavailable: 1
+
+workers:
+  # worker:
+  #   replicaCount: 1
+  #   terminationGracePeriodSeconds: 60
+  #   command:
+  #   - /bin/herokuish
+  #   - procfile
+  #   - start
+  #   - worker
+  #   preStopCommand:
+  #   - /bin/herokuish
+  #   - procfile
+  #   - start
+  #   - stop_worker
-- 
GitLab