Add Neo4j chart (#1559)

This commit is contained in:
Mark Needham
2017-09-09 22:57:20 +02:00
committed by Reinhard Nägele
parent c09662101a
commit 990dfca268
10 changed files with 442 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
name: neo4j
home: https://www.neo4j.com
version: 0.1.0
appVersion: 3.2.3
description: Neo4j is the world's leading graph database
icon: http://info.neo4j.com/rs/773-GON-065/images/neo4j_logo.png
sources:
- https://github.com/neo4j/neo4j
- https://github.com/neo4j/docker-neo4j
- https://github.com/mneedham/k8s-kubectl
maintainers:
- name: mneedham
email: mark.needham@neo4j.com
+75
View File
@@ -0,0 +1,75 @@
# Neo4j
[Neo4j](https://neo4j.com/) is a highly scalable native graph database that leverages data relationships as first-class entities, helping enterprises build intelligent applications to meet todays evolving data challenges.
## TL;DR;
```bash
$ helm install incubator/neo4j
```
## Introduction
This chart bootstraps a [Neo4j](https://github.com/neo4j/docker-neo4j) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
## Prerequisites
- Kubernetes 1.6+ with Beta APIs enabled
- PV provisioner support in the underlying infrastructure
## Installing the Chart
To install the chart with the release name `neo4j-helm`:
```bash
$ helm install --name neo4j-helm incubator/neo4j
```
The command deploys Neo4j on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation.
> **Tip**: List all releases using `helm list`
## Uninstalling the Chart
To uninstall/delete the `neo4j-helm` deployment:
```bash
$ helm delete neo4j-helm --purge
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
## Configuration
The following tables lists the configurable parameters of the Neo4j chart and their default values.
| Parameter | Description | Default |
|--------------------------------------|------------------------------------------------|----------------------------------------------------------|
| `image` | Neo4j image | `neo4j` |
| `imageTag` | Neo4j version | `{VERSION}` |
| `imagePullPolicy` | Image pull policy | `IfNotPresent` |
| `core.numberOfServers` | Number of machines in CORE mode | `3` |
| `core.persistentVolume.storageClass` | Storage class of backing PVC | `standard` (uses beta storage class annotation) |
| `core.persistentVolume.size` | Size of data volume | `10Gi` |
| `core.persistentVolume.mountPath` | Persistent Volume mount root path | `/data` |
| `core.persistentVolume.annotations` | Persistent Volume Claim annotations | `{}` |
| `readReplica.numberOfServers` | Number of machines in READ_REPLICA mode | `0` |
| `resources` | Resources required (e.g. CPU, memory) | `{}` |
The above parameters map to the env variables defined in the [Neo4j docker image](https://github.com/neo4j/docker-neo4j).
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
```bash
$ helm install --name neo4j-helm --set core.numberOfServers=5,readReplica.numberOfServers=3 incubator/neo4j
```
The above command creates a cluster containing 5 core servers and 3 read replicas.
Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example,
```bash
$ helm install --name neo4j-helm -f values.yaml incubator/neo4j
```
> **Tip**: You can use the default [values.yaml](values.yaml)
+9
View File
@@ -0,0 +1,9 @@
You can connect to the cluster using the Cypher shell by running:
kubectl run -it --rm cypher-shell \
--image=neo4j:3.2.1-enterprise \
--restart=Never \
--namespace {{ .Release.Namespace }} \
--command -- ./bin/cypher-shell -u neo4j -p neo4j --a {{ printf "%s-%s" .Release.Name .Values.name | trunc 56 }}.default.svc.cluster.local "call dbms.cluster.overview()"
This will print out the addresses of the members of the cluster.
+19
View File
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "neo4j.fullname" . }}
labels:
heritage: {{ .Release.Service | quote }}
release: {{ .Release.Name | quote }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
app: {{ template "neo4j.name" . }}
component: core
spec:
clusterIP: None
ports:
- port: 7474
targetPort: 7474
selector:
app: {{ template "neo4j.name" . }}
release: {{ .Release.Name }}
component: core
@@ -0,0 +1,80 @@
apiVersion: "apps/v1beta1"
kind: StatefulSet
metadata:
name: "{{ template "neo4j.core.fullname" . }}"
spec:
serviceName: {{ template "neo4j.fullname" . }}
replicas: {{ .Values.core.numberOfServers }}
template:
metadata:
labels:
heritage: {{ .Release.Service | quote }}
release: {{ .Release.Name | quote }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
app: {{ template "neo4j.name" . }}
component: core
spec:
containers:
- name: {{ template "neo4j.fullname" . }}
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
imagePullPolicy: "{{ .Values.imagePullPolicy }}"
env:
- name: NEO4J_dbms_mode
value: CORE
- name: NUMBER_OF_CORES
value: "{{ .Values.core.numberOfServers }}"
- name: NEO4J_dbms_security_auth__enabled
value: "false"
- name: NEO4J_causal__clustering_discovery__type
value: DNS
- name: NEO4J_causal__clustering_initial__discovery__members
value: "{{ template "neo4j.fullname" . }}.default.svc.cluster.local:5000"
command:
- "/bin/bash"
- "-ecx"
- |
export NEO4J_dbms_connectors_default__advertised__address=$(hostname -f)
export NEO4J_causal__clustering_discovery__advertised__address=$(hostname -f):5000
export NEO4J_causal__clustering_transaction__advertised__address=$(hostname -f):6000
export NEO4J_causal__clustering_raft__advertised__address=$(hostname -f):7000
exec /docker-entrypoint.sh "neo4j"
ports:
- containerPort: 5000
name: discovery
- containerPort: 7000
name: raft
- containerPort: 6000
name: tx
- containerPort: 7474
name: browser
- containerPort: 7687
name: bolt
securityContext:
privileged: true
volumeMounts:
- name: datadir
mountPath: "{{ .Values.core.persistentVolume.mountPath }}"
subPath: "{{ .Values.core.persistentVolume.subPath }}"
resources:
{{ toYaml .Values.resources | indent 10 }}
volumeClaimTemplates:
- metadata:
name: datadir
annotations:
{{- if .Values.core.persistentVolume.annotations }}
{{ toYaml .Values.core.persistentVolume.annotations | indent 12 }}
{{- end }}
spec:
accessModes:
- ReadWriteOnce
{{- if .Values.core.persistentVolume.storageClass }}
{{- if (eq "-" .Values.core.persistentVolume.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: "{{ .Values.core.persistentVolume.storageClass }}"
{{- end }}
{{- end }}
resources:
requests:
storage: "{{ .Values.core.persistentVolume.size }}"
@@ -0,0 +1,48 @@
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: "{{ template "neo4j.replica.fullname" . }}"
labels:
heritage: {{ .Release.Service | quote }}
release: {{ .Release.Name | quote }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "neo4j.name" . }}
component: replica
spec:
replicas: {{ .Values.readReplica.numberOfServers }}
template:
metadata:
labels:
app: {{ template "neo4j.name" . }}
release: {{ .Release.Name | quote }}
component: replica
spec:
containers:
- name: neo4j
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
imagePullPolicy: "{{ .Values.imagePullPolicy }}"
env:
- name: NEO4J_dbms_mode
value: READ_REPLICA
- name: NEO4J_dbms_security_auth__enabled
value: "false"
- name: NEO4J_causal__clustering_discovery__type
value: DNS
- name: NEO4J_causal__clustering_initial__discovery__members
value: "{{ template "neo4j.fullname" . }}.default.svc.cluster.local:5000"
command:
- "/bin/bash"
- "-ecx"
- |
export NEO4J_dbms_connectors_default__advertised__address=$(hostname -f)
export NEO4J_causal__clustering_transaction__advertised__address=$(hostname -f):6000
exec /docker-entrypoint.sh "neo4j"
ports:
- containerPort: 7474
name: browser
- containerPort: 7687
name: bolt
- containerPort: 6000
name: tx
securityContext:
privileged: true
@@ -0,0 +1,34 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "neo4j.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).
*/}}
{{- define "neo4j.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name for core servers.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "neo4j.core.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s-core" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name for read replica servers.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "neo4j.replica.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s-replica" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
@@ -0,0 +1,72 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "neo4j.fullname" . }}-tests
labels:
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "neo4j.name" . }}
data:
run.sh: |-
@test "Testing Neo4j cluster has quorum" {
echo "checking if the cluster is up"
check_machine() {
name=$1
end="$((SECONDS+90))"
while true; do
echo "testing http://$name:7474/db/data"
out=`wget http://$name:7474/db/data -O - 2>&1`
echo "out: $out"
wget http://$name:7474/db/data -O - 2>&1
response_code=$?
echo "response: $response_code"
[[ "0" = "$response_code" ]] && break
[[ "${SECONDS}" -ge "${end}" ]] && exit 1
sleep 1
done
}
for id in {0..2}; do
name="${STATEFULSET_NAME}-core-$id.${STATEFULSET_NAME}.default.svc.cluster.local"
echo "checking $name"
run check_machine $name
echo $status
echo $output
[ "$status" -eq 0 ]
done
}
@test "Testing we can get the cluster role of each server" {
check_role() {
name=$1
end="$((SECONDS+90))"
while true; do
echo "checking cluster role: $name"
kubectl exec $name -- bin/cypher-shell "call dbms.cluster.role()"
response_code=$?
echo "response: $response_code"
[[ "0" = "$response_code" ]] && break
[[ "${SECONDS}" -ge "${end}" ]] && exit 1
sleep 1
done
}
for id in {0..2}; do
name="${STATEFULSET_NAME}-core-$id"
echo "checking role of $name"
run check_role $name
echo $status
echo $output
[ "$status" -eq 0 ]
done
# kill a machine and make sure it comes back again
machine_to_kill="${STATEFULSET_NAME}-core-0"
kubectl delete pod ${machine_to_kill}
run check_role ${machine_to_kill}
echo $status
echo $output
[ "$status" -eq 0 ]
}
@@ -0,0 +1,39 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ template "neo4j.fullname" . }}-service-test-{{ randAlphaNum 5 | lower }}"
labels:
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app: {{ template "neo4j.name" . }}
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: {{ .Release.Name }}-ui-test
image: {{ .Values.testImage }}:{{ .Values.testImageTag }}
env:
- name: "STATEFULSET_NAME"
value: "{{ template "neo4j.fullname" . }}"
command: ["/tools/bats/bats", "-t", "/tests/run.sh"]
volumeMounts:
- mountPath: /tests
name: tests
readOnly: true
- mountPath: /tools
name: tools
initContainers:
- name: test-framework
image: "dduportal/bats:0.4.0"
command: ["bash", "-c", "set -ex\ncp -R /usr/local/libexec/ /tools/bats/"]
volumeMounts:
- mountPath: "/tools"
name: tools
volumes:
- name: tests
configMap:
name: {{ template "neo4j.fullname" . }}-tests
- name: tools
emptyDir: {}
restartPolicy: Never
+53
View File
@@ -0,0 +1,53 @@
# Default values for Neo4j.
# This is a YAML-formatted file.
# Declare name/value pairs to be passed into your templates.
# name: value
name: "neo4j"
# Specs for the Neo4j docker image
image: "neo4j"
imageTag: "3.2.3-enterprise"
imagePullPolicy: "IfNotPresent"
# Specs for the images used for running tests against the Helm package
testImage: "markhneedham/k8s-kubectl"
testImageTag: "master"
# Cores
core:
numberOfServers: 3
persistentVolume:
## core server data Persistent Volume mount root path
##
mountPath: /data
## core server data Persistent Volume size
##
size: 10Gi
## core server data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##storageClass: "-"
## Subdirectory of core server data Persistent Volume to mount
## Useful if the volume's root directory is not empty
##
subPath: ""
# Read Replicas
readReplica:
numberOfServers: 0
resources: {}
# limits:
# cpu: 100m
# memory: 512Mi
# requests:
# cpu: 100m
# memory: 512Mi