diff --git a/chart/.helmignore b/chart/.helmignore
new file mode 100644
index 0000000000000000000000000000000000000000..0e8a0eb36f4ca2c939201c0d54b5d82a1ea34778
--- /dev/null
+++ b/chart/.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/chart/Chart.yaml b/chart/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a91297c616414c858d7b8e9ec74d1c5489920578
--- /dev/null
+++ b/chart/Chart.yaml
@@ -0,0 +1,18 @@
+apiVersion: v2
+name: vs
+description: A Helm chart for Kubernetes of the View Server (VS)
+
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 0.1.0-beta.1
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application.
+appVersion: 1.0.0-beta.1
+
+maintainers:
+  - name: EOX IT Services GmbH
+    url: https://eox.at
diff --git a/chart/README.md b/chart/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9ef273a0dd4f0b748b5a55425f4f47ec66bb6fea
--- /dev/null
+++ b/chart/README.md
@@ -0,0 +1 @@
+Chart for the View Server (VS) bundling all services
diff --git a/chart/templates/_helpers.tpl b/chart/templates/_helpers.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..64cea4aac060290ea742a2a95fe0371a87fb55ca
--- /dev/null
+++ b/chart/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "vs.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 53 chars leaving space for 10 additional 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 "vs.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 53 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 53 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 53 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "vs.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "vs.labels" -}}
+helm.sh/chart: {{ include "vs.chart" . }}
+{{ include "vs.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "vs.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "vs.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "vs.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "vs.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/chart/templates/init-db-configmap.yaml b/chart/templates/init-db-configmap.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c012c5c66be6134b255b8c30d206db3ecfd2587c
--- /dev/null
+++ b/chart/templates/init-db-configmap.yaml
@@ -0,0 +1,7 @@
+apiVersion: v1
+data:
+  init-db.sh: |
+    {{- .Values.initDb }}
+kind: ConfigMap
+metadata:
+  name: {{ include "vs.fullname" . }}-init-db
diff --git a/chart/templates/renderer-deployment.yaml b/chart/templates/renderer-deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d8a8f83a0ecaec0431fcb7d9aa487440136e25f2
--- /dev/null
+++ b/chart/templates/renderer-deployment.yaml
@@ -0,0 +1,93 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "vs.fullname" . }}-renderer
+  labels:
+    {{- include "vs.labels" . | nindent 4 }}
+    app.kubernetes.io/service: renderer
+spec:
+{{- if not .Values.autoscaling.enabled }}
+  replicas: {{ .Values.renderer.replicaCount }}
+{{- end }}
+  selector:
+    matchLabels:
+      {{- include "vs.selectorLabels" . | nindent 6 }}
+      app.kubernetes.io/service: renderer
+  strategy:
+    rollingUpdate:
+      maxUnavailable: 0
+    type: RollingUpdate
+  template:
+    metadata:
+      annotations:
+        prometheus.io/scrape: "false"
+      labels:
+        {{- include "vs.selectorLabels" . | nindent 8 }}
+        app.kubernetes.io/service: renderer
+    spec:
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      containers:
+        - name: {{ .Chart.Name }}-renderer
+          image: "registry.gitlab.eox.at/esa/prism/vs/pvs_core:{{ .Values.image.tag | default .Chart.AppVersion }}"
+          imagePullPolicy: {{ .Values.image.pullPolicy }}
+          ports:
+            - name: http
+              containerPort: 80
+              protocol: TCP
+          livenessProbe:
+            httpGet:
+              path: /
+              port: http
+          readinessProbe:
+            httpGet:
+              path: /
+              port: http
+          resources:
+            {{- toYaml .Values.renderer.resources | nindent 12 }}
+          args:
+            - /run-httpd.sh
+          env:
+            {{- range $key, $value := .Values.config.general }}
+            - name: {{ $key }}
+              value: {{ $value | quote }}
+            {{- end }}
+            {{- range $key, $value := .Values.config.database }}
+            - name: {{ $key }}
+              value: {{ $value | quote }}
+            {{- end }}
+            {{- range $key, $value := .Values.config.django }}
+            - name: {{ $key }}
+              value: {{ $value | quote }}
+            {{- end }}
+            {{- range $key, $value := .Values.config.objectStorage.data }}
+            - name: {{ $key }}
+              value: {{ $value | quote }}
+            {{- end }}
+            - name: INIT_SCRIPTS
+              value: /configure.sh /init-db.sh /initialized.sh
+            - name: INSTALL_DIR
+              value: /var/www/pvs/dev/
+            - name: INSTANCE_ID
+              value: prism-view-server_renderer
+            - name: STARTUP_SCRIPTS
+              value: /wait-initialized.sh
+            - name: WAIT_SERVICES
+              value: {{ .Values.config.database.DB_HOST }}:{{ .Values.config.database.DB_PORT }}
+          volumeMounts:
+            - mountPath: /init-db.sh
+              name: init-db
+              subPath: init-db.sh
+      {{- with .Values.renderer.affinity | default .Values.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      volumes:
+        - configMap:
+            items:
+              - key: vhr18_init-db.sh
+                path: init-db.sh
+            name: init-db
+          name: {{ include "vs.fullname" . }}-init-db
diff --git a/chart/values-init-db.yaml b/chart/values-init-db.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..23118ada6f0d4f841dddcb38a7710d4c72344bf9
--- /dev/null
+++ b/chart/values-init-db.yaml
@@ -0,0 +1,80 @@
+initDb: |
+    # Check if collection exits in database and initialize database only if not
+    if python3 manage.py id check "${COLLECTION}"; then
+        echo "Initialize database"
+
+        python3 manage.py coveragetype import /rgbnir_definition.json --traceback
+
+        if [ "${COLLECTION}" == "VHR_IMAGE_2018" ]; then
+            echo "Initializing collection '${COLLECTION}'."
+
+            # PL00
+            python3 manage.py producttype create "${COLLECTION}"_Product_PL00 --traceback \
+                --coverage-type "RGBNir"
+            python3 manage.py browsetype create "${COLLECTION}"_Product_PL00 --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1000 15000 \
+                --green-range 1000 15000 \
+                --blue-range 1000 15000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python3 manage.py browsetype create "${COLLECTION}"_Product_PL00 "TRUE_COLOR" --traceback \
+                --red "red" \
+                --green "green" \
+                --blue "blue" \
+                --red-range 1000 15000 \
+                --green-range 1000 15000 \
+                --blue-range 1000 15000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python3 manage.py browsetype create "${COLLECTION}"_Product_PL00 "FALSE_COLOR" --traceback \
+                --red "nir" \
+                --green "red" \
+                --blue "green" \
+                --red-range 1000 15000 \
+                --green-range 1000 15000 \
+                --blue-range 1000 15000 \
+                --red-nodata 0 \
+                --green-nodata 0 \
+                --blue-nodata 0
+            python3 manage.py browsetype create "${COLLECTION}"_Product_PL00 "NDVI" --traceback \
+                --grey "(nir-red)/(nir+red)" --grey-range -1 1
+
+
+            python3 manage.py collectiontype create "${COLLECTION}"_Collection --traceback \
+                --coverage-type "RGBNir" \
+                --product-type "${COLLECTION}"_Product_PL00
+
+            # Create collections for all products
+            python3 manage.py collection create "${COLLECTION}" --type "${COLLECTION}"_Collection --traceback
+
+            # Register mask type
+            python3 manage.py masktype create --validity "${COLLECTION}"_Product_PL00 validity
+
+        else
+            echo "Provided collection '${COLLECTION}' not valid."
+        fi
+
+        python3 manage.py storageauth create auth-cloud-ovh "${OS_AUTH_URL_SHORT}" \
+            --type keystone \
+            -p auth-version "${ST_AUTH_VERSION}" \
+            -p identity-api-version="${ST_AUTH_VERSION}" \
+            -p username "${OS_USERNAME}" \
+            -p password "${OS_PASSWORD}" \
+            -p tenant-name "${OS_TENANT_NAME}" \
+            -p tenant-id "${OS_TENANT_ID}" \
+            -p region-name "${OS_REGION_NAME}"
+
+        python3 manage.py storage create \
+            ${UPLOAD_CONTAINER} ${UPLOAD_CONTAINER} \
+            --type swift \
+            --storage-auth auth-cloud-ovh
+
+
+    else
+        echo "Using existing database"
+    fi
diff --git a/chart/values.yaml b/chart/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..75b000cd10bd6f342cff44c388941ce07b4aea38
--- /dev/null
+++ b/chart/values.yaml
@@ -0,0 +1,96 @@
+config:
+  general:
+    COLLECTION: COLLECTION
+    CPL_VSIL_CURL_ALLOWED_EXTENSIONS: .TIF,.tif,.xml
+    GDAL_DISABLE_READDIR_ON_OPEN: "TRUE"
+    COLLECT_STATIC: "false"
+  database:
+    DB_HOST: database
+    DB_NAME: dbname
+    DB_PORT: "5432"
+    DB_PW: dbpw
+    DB_USER: dbuser
+    POSTGRES_DB: dbname
+    POSTGRES_PASSWORD: dbpw
+    POSTGRES_USER: dbuser
+  django:
+    DJANGO_MAIL: office@eox.at
+    DJANGO_PASSWORD: djangopw
+    DJANGO_USER: djangouser
+  objectStorage:
+    download:
+      OS_AUTH_URL_DOWNLOAD: https://auth.cloud.ovh.net/
+      OS_PASSWORD_DOWNLOAD: ospw
+      OS_REGION_NAME_DOWNLOAD: SERCO-DIAS1
+      OS_TENANT_ID_DOWNLOAD: tenantid
+      OS_TENANT_NAME_DOWNLOAD: "tenantname"
+      OS_USERNAME_DOWNLOAD: osuser
+      ST_AUTH_VERSION_DOWNLOAD: "3"
+    data:
+      OS_AUTH_URL: https://auth.cloud.ovh.net/v3/
+      OS_AUTH_URL_SHORT: https://auth.cloud.ovh.net/
+      OS_PASSWORD: ospw
+      OS_REGION_NAME: SERCO-DIAS1
+      OS_TENANT_ID: tenantid
+      OS_TENANT_NAME: "tenantname"
+      OS_USER_DOMAIN_NAME: default
+      OS_USERNAME: osuser
+      ST_AUTH_VERSION: "3"
+    cache:
+      S3_BUCKET: s3bucket
+      S3_ID: s3id
+      S3_SECRET: s3secret
+      S3_REGION: eu-central-1
+  preprocessing:
+    UPLOAD_CONTAINER: container
+    ENFORCE_FOUR_BANDS: "True"
+    SPLIT_PARTS_CHECK: "False"
+  redis:
+    REDIS_HOST: redis
+    REDIS_PORT: "6379"
+    REDIS_PREPROCESS_QUEUE_KEY: preprocess_queue
+    REDIS_QUEUE_KEY: seed_queue
+    REDIS_REGISTER_QUEUE_KEY: register_queue
+    REDIS_REGISTERED_SET_KEY: registered_set
+    REDIS_SEED_QUEUE_KEY: seed_queue
+    REDIS_SET_KEY: registered_set
+
+renderer:
+  replicaCount: 1
+  resources:
+    limits:
+      cpu: 1.5
+      memory: 6Gi
+    requests:
+      cpu: 0.5
+      memory: 2Gi
+  affinity: {}
+
+replicaCount: 1
+
+image:
+  repository: registry.gitlab.eox.at/esa/prism/vs
+  pullPolicy: IfNotPresent
+  tag: ""
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+service:
+  type: ClusterIP
+  port: 80
+
+ingress:
+  enabled: false
+  annotations:
+    kubernetes.io/ingress.class: nginx
+    kubernetes.io/tls-acme: "true"
+    nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
+    nginx.ingress.kubernetes.io/enable-cors: "true"
+  hosts:
+    - host: chart-example.local
+      paths: []
+  tls: []
+
+affinity: {}