Commit 2578effd by Guangbo Chen

Bump mongodb replicatset to v3.9.6

parent 24418e2a
apiVersion: v1
name: mongodb-replicaset name: mongodb-replicaset
home: https://github.com/mongodb/mongo home: https://github.com/mongodb/mongo
version: 3.3.1 version: 3.9.6
appVersion: 3.6 appVersion: 3.6
description: NoSQL document-oriented database that stores JSON-like documents with description: NoSQL document-oriented database that stores JSON-like documents with
dynamic schemas, simplifying the integration of data in content-driven applications. dynamic schemas, simplifying the integration of data in content-driven applications.
icon: https://webassets.mongodb.com/_com_assets/cms/mongodb-logo-rgb-j6w271g1xn.jpg icon: file://../mongo-logo.jpg
sources: sources:
- https://github.com/mongodb/mongo - https://github.com/mongodb/mongo
- https://github.com/percona/mongodb_exporter
maintainers: maintainers:
- name: foxish
email: ramanathana@google.com
- name: unguiculus - name: unguiculus
email: unguiculus@gmail.com email: unguiculus@gmail.com
- name: steven-sheehy
email: ssheehy@firescope.com
approvers: approvers:
- foxish
- unguiculus - unguiculus
- steven-sheehy
reviewers: reviewers:
- foxish
- unguiculus - unguiculus
- steven-sheehy
# MongoDB Helm Chart # MongoDB Helm Chart
## Prerequisites Details ## Prerequisites Details
* Kubernetes 1.8+ with Beta APIs enabled.
* PV support on the underlying infrastructure. * Kubernetes 1.9+
* Kubernetes beta APIs enabled only if `podDisruptionBudget` is enabled
* PV support on the underlying infrastructure
## Chart Details ## Chart Details
This chart implements a dynamically scalable [MongoDB replica set](https://docs.mongodb.com/manual/tutorial/deploy-replica-set/) This chart implements a dynamically scalable [MongoDB replica set](https://docs.mongodb.com/manual/tutorial/deploy-replica-set/)
using Kubernetes StatefulSets and Init Containers. using Kubernetes StatefulSets and Init Containers.
\ No newline at end of file
#!/usr/bin/env bash #!/usr/bin/env bash
# Copyright 2016 The Kubernetes Authors. All rights reserved. # Copyright 2018 The Kubernetes Authors. All rights reserved.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
...@@ -14,31 +14,88 @@ ...@@ -14,31 +14,88 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
set -e pipefail
port=27017
replica_set="$REPLICA_SET" replica_set="$REPLICA_SET"
script_name=${0##*/} script_name=${0##*/}
SECONDS=0
timeout="${TIMEOUT:-900}"
if [[ "$AUTH" == "true" ]]; then if [[ "$AUTH" == "true" ]]; then
admin_user="$ADMIN_USER" admin_user="$ADMIN_USER"
admin_password="$ADMIN_PASSWORD" admin_password="$ADMIN_PASSWORD"
admin_creds=(-u "$admin_user" -p "$admin_password") admin_creds=(-u "$admin_user" -p "$admin_password")
auth_args=(--auth --keyFile=/data/configdb/key.txt) if [[ "$METRICS" == "true" ]]; then
metrics_user="$METRICS_USER"
metrics_password="$METRICS_PASSWORD"
fi
auth_args=("--auth" "--keyFile=/data/configdb/key.txt")
fi fi
function log() { log() {
local msg="$1" local msg="$1"
local timestamp local timestamp
timestamp=$(date --iso-8601=ns) timestamp=$(date --iso-8601=ns)
echo "[$timestamp] [$script_name] $msg" >> /work-dir/log.txt echo "[$timestamp] [$script_name] $msg" 2>&1 | tee -a /work-dir/log.txt 1>&2
} }
function shutdown_mongo() { retry_until() {
if [[ $# -eq 1 ]]; then local host="${1}"
args="timeoutSecs: $1" local command="${2}"
else local expected="${3}"
args='force: true' local creds=("${admin_creds[@]}")
# Don't need credentials for admin user creation and pings that run on localhost
if [[ "${host}" =~ ^localhost ]]; then
creds=()
fi fi
until [[ $(mongo admin --host "${host}" "${creds[@]}" "${ssl_args[@]}" --quiet --eval "${command}") == "${expected}" ]]; do
sleep 1
if (! ps "${pid}" &>/dev/null); then
log "mongod shutdown unexpectedly"
exit 1
fi
if [[ "${SECONDS}" -ge "${timeout}" ]]; then
log "Timed out after ${timeout}s attempting to bootstrap mongod"
exit 1
fi
log "Retrying ${command} on ${host}"
done
}
shutdown_mongo() {
local host="${1:-localhost}"
local args='force: true'
log "Shutting down MongoDB ($args)..." log "Shutting down MongoDB ($args)..."
mongo admin "${admin_creds[@]}" "${ssl_args[@]}" --eval "db.shutdownServer({$args})" if (! mongo admin --host "${host}" "${admin_creds[@]}" "${ssl_args[@]}" --eval "db.shutdownServer({$args})"); then
log "db.shutdownServer() failed, sending the terminate signal"
kill -TERM "${pid}"
fi
}
init_mongod_standalone() {
if [[ ! -f /init/initMongodStandalone.js ]]; then
log "Skipping init mongod standalone script"
return 0
elif [[ -z "$(ls -1A /data/db)" ]]; then
log "mongod standalone script currently not supported on initial install"
return 0
fi
local port="27018"
log "Starting a MongoDB instance as standalone..."
mongod --config /data/configdb/mongod.conf --dbpath=/data/db "${auth_args[@]}" --port "${port}" --bind_ip=0.0.0.0 2>&1 | tee -a /work-dir/log.txt 1>&2 &
export pid=$!
trap shutdown_mongo EXIT
log "Waiting for MongoDB to be ready..."
retry_until "localhost:${port}" "db.adminCommand('ping').ok" "1"
log "Running init js script on standalone mongod"
mongo admin --port "${port}" "${admin_creds[@]}" "${ssl_args[@]}" /init/initMongodStandalone.js
shutdown_mongo "localhost:${port}"
} }
my_hostname=$(hostname) my_hostname=$(hostname)
...@@ -48,7 +105,6 @@ log "Reading standard input..." ...@@ -48,7 +105,6 @@ log "Reading standard input..."
while read -ra line; do while read -ra line; do
if [[ "${line}" == *"${my_hostname}"* ]]; then if [[ "${line}" == *"${my_hostname}"* ]]; then
service_name="$line" service_name="$line"
continue
fi fi
peers=("${peers[@]}" "$line") peers=("${peers[@]}" "$line")
done done
...@@ -61,6 +117,9 @@ if [ -f "$ca_crt" ]; then ...@@ -61,6 +117,9 @@ if [ -f "$ca_crt" ]; then
pem=/work-dir/mongo.pem pem=/work-dir/mongo.pem
ssl_args=(--ssl --sslCAFile "$ca_crt" --sslPEMKeyFile "$pem") ssl_args=(--ssl --sslCAFile "$ca_crt" --sslPEMKeyFile "$pem")
# Move into /work-dir
pushd /work-dir
cat >openssl.cnf <<EOL cat >openssl.cnf <<EOL
[req] [req]
req_extensions = v3_req req_extensions = v3_req
...@@ -80,7 +139,7 @@ EOL ...@@ -80,7 +139,7 @@ EOL
# Generate the certs # Generate the certs
openssl genrsa -out mongo.key 2048 openssl genrsa -out mongo.key 2048
openssl req -new -key mongo.key -out mongo.csr -subj "/CN=$my_hostname" -config openssl.cnf openssl req -new -key mongo.key -out mongo.csr -subj "/OU=MongoDB/CN=$my_hostname" -config openssl.cnf
openssl x509 -req -in mongo.csr \ openssl x509 -req -in mongo.csr \
-CA "$ca_crt" -CAkey "$ca_key" -CAcreateserial \ -CA "$ca_crt" -CAkey "$ca_key" -CAcreateserial \
-out mongo.crt -days 3650 -extensions v3_req -extfile openssl.cnf -out mongo.crt -days 3650 -extensions v3_req -extfile openssl.cnf
...@@ -90,63 +149,71 @@ EOL ...@@ -90,63 +149,71 @@ EOL
rm mongo.key mongo.crt rm mongo.key mongo.crt
fi fi
init_mongod_standalone
log "Peers: ${peers[*]}" log "Peers: ${peers[*]}"
log "Starting a MongoDB replica"
log "Starting a MongoDB instance..." mongod --config /data/configdb/mongod.conf --dbpath=/data/db --replSet="$replica_set" --port="${port}" "${auth_args[@]}" --bind_ip=0.0.0.0 2>&1 | tee -a /work-dir/log.txt 1>&2 &
mongod --config /data/configdb/mongod.conf --dbpath=/data/db --replSet="$replica_set" --port=27017 "${auth_args[@]}" --bind_ip_all >> /work-dir/log.txt 2>&1 & pid=$!
trap shutdown_mongo EXIT
log "Waiting for MongoDB to be ready..." log "Waiting for MongoDB to be ready..."
until mongo "${ssl_args[@]}" --eval "db.adminCommand('ping')"; do retry_until "localhost" "db.adminCommand('ping').ok" "1"
log "Retrying..."
sleep 2
done
log "Initialized." log "Initialized."
# try to find a master and add yourself to its replica set. # try to find a master
for peer in "${peers[@]}"; do for peer in "${peers[@]}"; do
if mongo admin --host "$peer" "${admin_creds[@]}" "${ssl_args[@]}" --eval "rs.isMaster()" | grep '"ismaster" : true'; then log "Checking if ${peer} is primary"
log "Found master: $peer" # Check rs.status() first since it could be in primary catch up mode which db.isMaster() doesn't show
log "Adding myself ($service_name) to replica set..." if [[ $(mongo admin --host "${peer}" "${admin_creds[@]}" "${ssl_args[@]}" --quiet --eval "rs.status().myState") == "1" ]]; then
mongo admin --host "$peer" "${admin_creds[@]}" "${ssl_args[@]}" --eval "rs.add('$service_name')" retry_until "${peer}" "db.isMaster().ismaster" "true"
log "Found primary: ${peer}"
sleep 3 primary="${peer}"
break
log 'Waiting for replica to reach SECONDARY state...'
until printf '.' && [[ $(mongo admin "${admin_creds[@]}" "${ssl_args[@]}" --quiet --eval "rs.status().myState") == '2' ]]; do
sleep 1
done
log '✓ Replica reached SECONDARY state.'
shutdown_mongo "60"
log "Good bye."
exit 0
fi fi
done done
# else initiate a replica set with yourself. if [[ "${primary}" = "${service_name}" ]]; then
if mongo "${ssl_args[@]}" --eval "rs.status()" | grep "no replset config has been received"; then log "This replica is already PRIMARY"
elif [[ -n "${primary}" ]]; then
if [[ $(mongo admin --host "${primary}" "${admin_creds[@]}" "${ssl_args[@]}" --quiet --eval "rs.conf().members.findIndex(m => m.host == '${service_name}:${port}')") == "-1" ]]; then
log "Adding myself (${service_name}) to replica set..."
if (mongo admin --host "${primary}" "${admin_creds[@]}" "${ssl_args[@]}" --eval "rs.add('${service_name}')" | grep 'Quorum check failed'); then
log 'Quorum check failed, unable to join replicaset. Exiting prematurely.'
exit 1
fi
fi
sleep 3
log 'Waiting for replica to reach SECONDARY state...'
retry_until "${service_name}" "rs.status().myState" "2"
log '✓ Replica reached SECONDARY state.'
elif (mongo "${ssl_args[@]}" --eval "rs.status()" | grep "no replset config has been received"); then
log "Initiating a new replica set with myself ($service_name)..." log "Initiating a new replica set with myself ($service_name)..."
mongo "${ssl_args[@]}" --eval "rs.initiate({'_id': '$replica_set', 'members': [{'_id': 0, 'host': '$service_name'}]})" mongo "${ssl_args[@]}" --eval "rs.initiate({'_id': '$replica_set', 'members': [{'_id': 0, 'host': '$service_name'}]})"
sleep 3 sleep 3
log 'Waiting for replica to reach PRIMARY state...' log 'Waiting for replica to reach PRIMARY state...'
until printf '.' && [[ $(mongo "${ssl_args[@]}" --quiet --eval "rs.status().myState") == '1' ]]; do retry_until "localhost" "db.isMaster().ismaster" "true"
sleep 1 primary="${service_name}"
done
log '✓ Replica reached PRIMARY state.' log '✓ Replica reached PRIMARY state.'
if [[ "$AUTH" == "true" ]]; then if [[ "${AUTH}" == "true" ]]; then
log "Creating admin user..." log "Creating admin user..."
mongo admin "${ssl_args[@]}" --eval "db.createUser({user: '$admin_user', pwd: '$admin_password', roles: [{role: 'root', db: 'admin'}]})" mongo admin "${ssl_args[@]}" --eval "db.createUser({user: '${admin_user}', pwd: '${admin_password}', roles: [{role: 'root', db: 'admin'}]})"
fi fi
fi
log "Done." # User creation
if [[ -n "${primary}" && "$AUTH" == "true" && "$METRICS" == "true" ]]; then
metric_user_count=$(mongo admin --host "${primary}" "${admin_creds[@]}" "${ssl_args[@]}" --eval "db.system.users.find({user: '${metrics_user}'}).count()" --quiet)
if [[ "${metric_user_count}" == "0" ]]; then
log "Creating clusterMonitor user..."
mongo admin --host "${primary}" "${admin_creds[@]}" "${ssl_args[@]}" --eval "db.createUser({user: '${metrics_user}', pwd: '${metrics_password}', roles: [{role: 'clusterMonitor', db: 'admin'}, {role: 'read', db: 'local'}]})"
fi
fi fi
shutdown_mongo log "MongoDB bootstrap complete"
log "Good bye." exit 0
...@@ -12,8 +12,9 @@ ...@@ -12,8 +12,9 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
FROM alpine:3.7 FROM alpine:3.8
MAINTAINER Anirudh Ramanathan <foxish@google.com>
LABEL maintainer="Reinhard Nägele <unguiculus@gmail.com>"
RUN apk update && apk add bash openssl && wget -qO /peer-finder http://storage.googleapis.com/kubernetes-release/pets/peer-finder RUN apk update && apk add bash openssl && wget -qO /peer-finder http://storage.googleapis.com/kubernetes-release/pets/peer-finder
......
...@@ -14,14 +14,14 @@ ...@@ -14,14 +14,14 @@
all: push all: push
TAG = 0.6 TAG = 0.7
PREFIX = staging-k8s.gcr.io/mongodb-install PREFIX = unguiculus/mongodb-install
container: build:
docker build -t $(PREFIX):$(TAG) . docker build -t $(PREFIX):$(TAG) .
push: container push: build
gcloud docker -- push $(PREFIX):$(TAG) docker push $(PREFIX):$(TAG)
clean: clean:
docker rmi $(PREFIX):$(TAG) docker rmi $(PREFIX):$(TAG)
categories: categories:
- Database - Database
- NoSQL - NoSQL
labels:
io.cattle.role: project # options are cluster/project
questions: questions:
- variable: defaultImage - variable: defaultImage
default: true default: true
...@@ -10,26 +12,36 @@ questions: ...@@ -10,26 +12,36 @@ questions:
show_subquestion_if: false show_subquestion_if: false
group: "Container Images" group: "Container Images"
subquestions: subquestions:
- variable: image.repository
default: "ranchercharts/mongo"
description: "MongoDB image name"
type: string
label: MongoDB Image Name
- variable: image.tag
default: "3.6"
description: "MongoDB image tag"
type: string
label: Image Tag
- variable: installImage.repository - variable: installImage.repository
default: "k8s.gcr.io/mongodb-install" default: "ranchercharts/unguiculus-mongodb-install"
description: "Image name for the install container" description: "Image name for the install container"
type: string type: string
label: Init-Container Image Name label: Init-Container Image Name
- variable: installImage.tag - variable: installImage.tag
default: "0.6" default: "0.7"
description: "Image tag for the install container" description: "Image tag for the install container"
type: string type: string
label: Init-Container Image Tag label: Init-Container Image Tag
- variable: image.repository - variable: copyConfigImage.repository
default: "mongo" default: "ranchercharts/busybox"
description: "MongoDB image name" description: "Image name for the CopyConfig container"
type: string type: string
label: MongoDB Image Name label: Copy Config Image Name
- variable: image.tag - variable: copyConfigImage.tag
default: "3.6" default: "1.29.3"
description: "MongoDB image tag" description: "Image tag for the CopyConfig container"
type: string type: string
label: Image Tag label: Copy Config Image Tag
- variable: replicas - variable: replicas
default: 3 default: 3
description: "Number of replicas in the replica set" description: "Number of replicas in the replica set"
......
...@@ -42,6 +42,15 @@ Create the name for the admin secret. ...@@ -42,6 +42,15 @@ Create the name for the admin secret.
{{- end -}} {{- end -}}
{{- end -}} {{- end -}}
{{- define "mongodb-replicaset.metricsSecret" -}}
{{- if .Values.auth.existingMetricsSecret -}}
{{- .Values.auth.existingMetricsSecret -}}
{{- else -}}
{{- template "mongodb-replicaset.fullname" . -}}-metrics
{{- end -}}
{{- end -}}
{{/* {{/*
Create the name for the key secret. Create the name for the key secret.
*/}} */}}
......
...@@ -7,6 +7,9 @@ metadata: ...@@ -7,6 +7,9 @@ metadata:
chart: {{ template "mongodb-replicaset.chart" . }} chart: {{ template "mongodb-replicaset.chart" . }}
heritage: {{ .Release.Service }} heritage: {{ .Release.Service }}
release: {{ .Release.Name }} release: {{ .Release.Name }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 4 }}
{{- end }}
name: {{ template "mongodb-replicaset.adminSecret" . }} name: {{ template "mongodb-replicaset.adminSecret" . }}
type: Opaque type: Opaque
data: data:
......
...@@ -8,6 +8,9 @@ metadata: ...@@ -8,6 +8,9 @@ metadata:
chart: {{ template "mongodb-replicaset.chart" . }} chart: {{ template "mongodb-replicaset.chart" . }}
heritage: {{ .Release.Service }} heritage: {{ .Release.Service }}
release: {{ .Release.Name }} release: {{ .Release.Name }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 4 }}
{{- end }}
name: {{ template "mongodb-replicaset.fullname" . }}-ca name: {{ template "mongodb-replicaset.fullname" . }}-ca
data: data:
tls.key: {{ .Values.tls.cakey }} tls.key: {{ .Values.tls.cakey }}
......
...@@ -6,7 +6,15 @@ metadata: ...@@ -6,7 +6,15 @@ metadata:
chart: {{ template "mongodb-replicaset.chart" . }} chart: {{ template "mongodb-replicaset.chart" . }}
heritage: {{ .Release.Service }} heritage: {{ .Release.Service }}
release: {{ .Release.Name }} release: {{ .Release.Name }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 4 }}
{{- end }}
name: {{ template "mongodb-replicaset.fullname" . }}-init name: {{ template "mongodb-replicaset.fullname" . }}-init
data: data:
on-start.sh: | on-start.sh: |
{{ .Files.Get "init/on-start.sh" | indent 4 }} {{ .Files.Get "init/on-start.sh" | indent 4 }}
{{- if .Values.initMongodStandalone }}
initMongodStandalone.js: |
{{ .Values.initMongodStandalone | indent 4 }}
{{- end }}
...@@ -7,6 +7,9 @@ metadata: ...@@ -7,6 +7,9 @@ metadata:
chart: {{ template "mongodb-replicaset.chart" . }} chart: {{ template "mongodb-replicaset.chart" . }}
heritage: {{ .Release.Service }} heritage: {{ .Release.Service }}
release: {{ .Release.Name }} release: {{ .Release.Name }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 4 }}
{{- end }}
name: {{ template "mongodb-replicaset.keySecret" . }} name: {{ template "mongodb-replicaset.keySecret" . }}
type: Opaque type: Opaque
data: data:
......
{{- if and (.Values.auth.enabled) (not .Values.auth.existingMetricsSecret) (.Values.metrics.enabled) -}}
apiVersion: v1
kind: Secret
metadata:
labels:
app: {{ template "mongodb-replicaset.name" . }}
chart: {{ template "mongodb-replicaset.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 4 }}
{{- end }}
name: {{ template "mongodb-replicaset.metricsSecret" . }}
type: Opaque
data:
user: {{ .Values.auth.metricsUser | b64enc }}
password: {{ .Values.auth.metricsPassword | b64enc }}
{{- end -}}
...@@ -6,6 +6,9 @@ metadata: ...@@ -6,6 +6,9 @@ metadata:
chart: {{ template "mongodb-replicaset.chart" . }} chart: {{ template "mongodb-replicaset.chart" . }}
heritage: {{ .Release.Service }} heritage: {{ .Release.Service }}
release: {{ .Release.Name }} release: {{ .Release.Name }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 4 }}
{{- end }}
name: {{ template "mongodb-replicaset.fullname" . }}-mongodb name: {{ template "mongodb-replicaset.fullname" . }}-mongodb
data: data:
mongod.conf: | mongod.conf: |
......
...@@ -7,6 +7,9 @@ metadata: ...@@ -7,6 +7,9 @@ metadata:
chart: {{ template "mongodb-replicaset.chart" . }} chart: {{ template "mongodb-replicaset.chart" . }}
heritage: {{ .Release.Service }} heritage: {{ .Release.Service }}
release: {{ .Release.Name }} release: {{ .Release.Name }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 4 }}
{{- end }}
name: {{ template "mongodb-replicaset.fullname" . }} name: {{ template "mongodb-replicaset.fullname" . }}
spec: spec:
selector: selector:
......
# A headless service for client applications to use
apiVersion: v1
kind: Service
metadata:
annotations:
{{- if .Values.serviceAnnotations }}
{{ toYaml .Values.serviceAnnotations | indent 4 }}
{{- end }}
labels:
app: {{ template "mongodb-replicaset.name" . }}
chart: {{ template "mongodb-replicaset.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 4 }}
{{- end }}
name: {{ template "mongodb-replicaset.fullname" . }}-client
spec:
type: ClusterIP
clusterIP: None
ports:
- name: mongodb
port: {{ .Values.port }}
{{- if .Values.metrics.enabled }}
- name: metrics
port: {{ .Values.metrics.port }}
targetPort: metrics
{{- end }}
selector:
app: {{ template "mongodb-replicaset.name" . }}
release: {{ .Release.Name }}
# A headless service to create DNS records # A headless service to create DNS records for discovery purposes. Use the -client service to connect applications
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
annotations: annotations:
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
{{- if .Values.serviceAnnotations }}
{{ toYaml .Values.serviceAnnotations | indent 4 }}
{{- end }}
labels: labels:
app: {{ template "mongodb-replicaset.name" . }} app: {{ template "mongodb-replicaset.name" . }}
chart: {{ template "mongodb-replicaset.chart" . }} chart: {{ template "mongodb-replicaset.chart" . }}
heritage: {{ .Release.Service }} heritage: {{ .Release.Service }}
release: {{ .Release.Name }} release: {{ .Release.Name }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 4 }}
{{- end }}
name: {{ template "mongodb-replicaset.fullname" . }} name: {{ template "mongodb-replicaset.fullname" . }}
spec: spec:
type: ClusterIP type: ClusterIP
clusterIP: None clusterIP: None
ports: ports:
- name: peer - name: mongodb
port: {{ .Values.port }} port: {{ .Values.port }}
publishNotReadyAddresses: true
selector: selector:
app: {{ template "mongodb-replicaset.name" . }} app: {{ template "mongodb-replicaset.name" . }}
release: {{ .Release.Name }} release: {{ .Release.Name }}
apiVersion: apps/v1beta1 apiVersion: apps/v1
kind: StatefulSet kind: StatefulSet
metadata: metadata:
labels: labels:
...@@ -6,9 +6,11 @@ metadata: ...@@ -6,9 +6,11 @@ metadata:
chart: {{ template "mongodb-replicaset.chart" . }} chart: {{ template "mongodb-replicaset.chart" . }}
heritage: {{ .Release.Service }} heritage: {{ .Release.Service }}
release: {{ .Release.Name }} release: {{ .Release.Name }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 4 }}
{{- end }}
name: {{ template "mongodb-replicaset.fullname" . }} name: {{ template "mongodb-replicaset.fullname" . }}
spec: spec:
podManagementPolicy: {{ .Values.podManagementPolicy }}
selector: selector:
matchLabels: matchLabels:
app: {{ template "mongodb-replicaset.name" . }} app: {{ template "mongodb-replicaset.name" . }}
...@@ -20,16 +22,40 @@ spec: ...@@ -20,16 +22,40 @@ spec:
labels: labels:
app: {{ template "mongodb-replicaset.name" . }} app: {{ template "mongodb-replicaset.name" . }}
release: {{ .Release.Name }} release: {{ .Release.Name }}
{{- if .Values.extraLabels }}
{{ toYaml .Values.extraLabels | indent 8 }}
{{- end }}
annotations: annotations:
checksum/config: {{ include (print $.Template.BasePath "/mongodb-mongodb-configmap.yaml") . | sha256sum }}
{{- if and (.Values.metrics.prometheusServiceDiscovery) (.Values.metrics.enabled) }}
prometheus.io/scrape: "true"
prometheus.io/port: {{ .Values.metrics.port | quote }}
prometheus.io/path: {{ .Values.metrics.path | quote }}
{{- end }}
{{- if .Values.podAnnotations }} {{- if .Values.podAnnotations }}
{{ toYaml .Values.podAnnotations | indent 8 }} {{ toYaml .Values.podAnnotations | indent 8 }}
{{- end }} {{- end }}
spec: spec:
{{- if .Values.priorityClassName }}
priorityClassName: {{ .Values.priorityClassName }}
{{- end }}
{{- if .Values.imagePullSecrets }}
imagePullSecrets:
{{- range .Values.imagePullSecrets }}
- name: {{ . }}
{{- end}}
{{- end }}
{{- if .Values.securityContext.enabled }}
securityContext: securityContext:
{{ toYaml .Values.securityContext | indent 8 }} runAsUser: {{ .Values.securityContext.runAsUser }}
fsGroup: {{ .Values.securityContext.fsGroup }}
runAsNonRoot: {{ .Values.securityContext.runAsNonRoot }}
{{- end }}
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
initContainers: initContainers:
- name: copy-config - name: copy-config
image: busybox image: "{{ .Values.copyConfigImage.repository }}:{{ .Values.copyConfigImage.tag }}"
imagePullPolicy: {{ .Values.copyConfigImage.pullPolicy | quote }}
command: command:
- "sh" - "sh"
args: args:
...@@ -64,6 +90,8 @@ spec: ...@@ -64,6 +90,8 @@ spec:
- name: keydir - name: keydir
mountPath: /keydir-readonly mountPath: /keydir-readonly
{{- end }} {{- end }}
resources:
{{ toYaml .Values.init.resources | indent 12 }}
- name: install - name: install
image: "{{ .Values.installImage.repository }}:{{ .Values.installImage.tag }}" image: "{{ .Values.installImage.repository }}:{{ .Values.installImage.tag }}"
args: args:
...@@ -72,6 +100,8 @@ spec: ...@@ -72,6 +100,8 @@ spec:
volumeMounts: volumeMounts:
- name: workdir - name: workdir
mountPath: /work-dir mountPath: /work-dir
resources:
{{ toYaml .Values.init.resources | indent 12 }}
- name: bootstrap - name: bootstrap
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
command: command:
...@@ -88,6 +118,8 @@ spec: ...@@ -88,6 +118,8 @@ spec:
fieldPath: metadata.namespace fieldPath: metadata.namespace
- name: REPLICA_SET - name: REPLICA_SET
value: {{ .Values.replicaSetName }} value: {{ .Values.replicaSetName }}
- name: TIMEOUT
value: "{{ .Values.init.timeout }}"
{{- if .Values.auth.enabled }} {{- if .Values.auth.enabled }}
- name: AUTH - name: AUTH
value: "true" value: "true"
...@@ -101,6 +133,20 @@ spec: ...@@ -101,6 +133,20 @@ spec:
secretKeyRef: secretKeyRef:
name: "{{ template "mongodb-replicaset.adminSecret" . }}" name: "{{ template "mongodb-replicaset.adminSecret" . }}"
key: password key: password
{{- if .Values.metrics.enabled }}
- name: METRICS
value: "true"
- name: METRICS_USER
valueFrom:
secretKeyRef:
name: "{{ template "mongodb-replicaset.metricsSecret" . }}"
key: user
- name: METRICS_PASSWORD
valueFrom:
secretKeyRef:
name: "{{ template "mongodb-replicaset.metricsSecret" . }}"
key: password
{{- end }}
{{- end }} {{- end }}
volumeMounts: volumeMounts:
- name: workdir - name: workdir
...@@ -111,6 +157,8 @@ spec: ...@@ -111,6 +157,8 @@ spec:
mountPath: /data/configdb mountPath: /data/configdb
- name: datadir - name: datadir
mountPath: /data/db mountPath: /data/db
resources:
{{ toYaml .Values.init.resources | indent 12 }}
containers: containers:
- name: {{ template "mongodb-replicaset.name" . }} - name: {{ template "mongodb-replicaset.name" . }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
...@@ -120,7 +168,7 @@ spec: ...@@ -120,7 +168,7 @@ spec:
{{ toYaml .Values.extraVars | indent 12 }} {{ toYaml .Values.extraVars | indent 12 }}
{{- end }} {{- end }}
ports: ports:
- name: peer - name: mongodb
containerPort: 27017 containerPort: 27017
resources: resources:
{{ toYaml .Values.resources | indent 12 }} {{ toYaml .Values.resources | indent 12 }}
...@@ -137,7 +185,7 @@ spec: ...@@ -137,7 +185,7 @@ spec:
- --keyFile=/data/configdb/key.txt - --keyFile=/data/configdb/key.txt
{{- end }} {{- end }}
{{- if .Values.tls.enabled }} {{- if .Values.tls.enabled }}
- --ssl - --sslMode=requireSSL
- --sslCAFile=/data/configdb/tls.crt - --sslCAFile=/data/configdb/tls.crt
- --sslPEMKeyFile=/work-dir/mongo.pem - --sslPEMKeyFile=/work-dir/mongo.pem
{{- end }} {{- end }}
...@@ -180,7 +228,78 @@ spec: ...@@ -180,7 +228,78 @@ spec:
mountPath: /data/configdb mountPath: /data/configdb
- name: workdir - name: workdir
mountPath: /work-dir mountPath: /work-dir
{{- with .Values.nodeSelector }} {{ if .Values.metrics.enabled }}
- name: metrics
image: "{{ .Values.metrics.image.repository }}:{{ .Values.metrics.image.tag }}"
imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }}
command:
- sh
- -ec
- >-
/bin/mongodb_exporter
{{- if .Values.auth.enabled }}
-mongodb.uri mongodb://$METRICS_USER:$METRICS_PASSWORD@localhost:{{ .Values.port }}
{{- else }}
-mongodb.uri mongodb://localhost:{{ .Values.port }}
{{- end }}
{{- if .Values.tls.enabled }}
-mongodb.tls
-mongodb.tls-ca=/ca/tls.crt
-mongodb.tls-cert=/work-dir/mongo.pem
{{- end }}
-mongodb.socket-timeout={{ .Values.metrics.socketTimeout }}
-mongodb.sync-timeout={{ .Values.metrics.syncTimeout }}
-web.metrics-path={{ .Values.metrics.path }}
-web.listen-address=:{{ .Values.metrics.port }}
volumeMounts:
{{- if and (.Values.tls.enabled) }}
- name: ca
mountPath: /ca
readOnly: true
{{- end }}
- name: workdir
mountPath: /work-dir
readOnly: true
env:
{{- if .Values.auth.enabled }}
- name: METRICS_USER
valueFrom:
secretKeyRef:
name: "{{ template "mongodb-replicaset.metricsSecret" . }}"
key: user
- name: METRICS_PASSWORD
valueFrom:
secretKeyRef:
name: "{{ template "mongodb-replicaset.metricsSecret" . }}"
key: password
{{- end }}
ports:
- name: metrics
containerPort: {{ .Values.metrics.port }}
resources:
{{ toYaml .Values.metrics.resources | indent 12 }}
livenessProbe:
exec:
command:
- sh
- -ec
- >-
/bin/mongodb_exporter
{{- if .Values.auth.enabled }}
-mongodb.uri mongodb://$METRICS_USER:$METRICS_PASSWORD@localhost:{{ .Values.port }}
{{- else }}
-mongodb.uri mongodb://localhost:{{ .Values.port }}
{{- end }}
{{- if .Values.tls.enabled }}
-mongodb.tls
-mongodb.tls-ca=/ca/tls.crt
-mongodb.tls-cert=/work-dir/mongo.pem
{{- end }}
-test
initialDelaySeconds: 30
periodSeconds: 10
{{ end }}
{{- with .Values.nodeSelector }}
nodeSelector: nodeSelector:
{{ toYaml . | indent 8 }} {{ toYaml . | indent 8 }}
{{- end }} {{- end }}
...@@ -216,32 +335,30 @@ spec: ...@@ -216,32 +335,30 @@ spec:
emptyDir: {} emptyDir: {}
- name: configdir - name: configdir
emptyDir: {} emptyDir: {}
{{- if not .Values.persistentVolume.enabled }}
- name: datadir
emptyDir: {}
{{- end }}
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
{{- if .Values.persistentVolume.enabled }} {{- if .Values.persistentVolume.enabled }}
volumeClaimTemplates: volumeClaimTemplates:
- metadata: - metadata:
name: datadir name: datadir
annotations: annotations:
{{- range $key, $value := .Values.persistentVolume.annotations }} {{- range $key, $value := .Values.persistentVolume.annotations }}
{{ $key }}: {{ $value }} {{ $key }}: "{{ $value }}"
{{- end }}
spec:
accessModes:
{{- range .Values.persistentVolume.accessModes }}
- {{ . | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistentVolume.size | quote }}
{{- if .Values.persistentVolume.storageClass }}
{{- if (eq "-" .Values.persistentVolume.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: "{{ .Values.persistentVolume.storageClass }}"
{{- end }} {{- end }}
spec:
accessModes:
{{- range .Values.persistentVolume.accessModes }}
- {{ . | quote }}
{{- end }} {{- end }}
resources: {{- else }}
requests: - name: datadir
storage: {{ .Values.persistentVolume.size | quote }} emptyDir: {}
{{- if .Values.persistentVolume.storageClass }}
{{- if (eq "-" .Values.persistentVolume.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: "{{ .Values.persistentVolume.storageClass }}"
{{- end }}
{{- end }}
{{- end }} {{- end }}
{{- if .Values.runtest }}
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
...@@ -11,4 +10,3 @@ metadata: ...@@ -11,4 +10,3 @@ metadata:
data: data:
mongodb-up-test.sh: | mongodb-up-test.sh: |
{{ .Files.Get "tests/mongodb-up-test.sh" | indent 4 }} {{ .Files.Get "tests/mongodb-up-test.sh" | indent 4 }}
{{- end }}
{{- if .Values.runtest }}
apiVersion: v1 apiVersion: v1
kind: Pod kind: Pod
metadata: metadata:
...@@ -36,6 +35,20 @@ spec: ...@@ -36,6 +35,20 @@ spec:
value: {{ template "mongodb-replicaset.fullname" . }} value: {{ template "mongodb-replicaset.fullname" . }}
- name: REPLICAS - name: REPLICAS
value: "{{ .Values.replicas }}" value: "{{ .Values.replicas }}"
{{- if .Values.auth.enabled }}
- name: AUTH
value: "true"
- name: ADMIN_USER
valueFrom:
secretKeyRef:
name: "{{ template "mongodb-replicaset.adminSecret" . }}"
key: user
- name: ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: "{{ template "mongodb-replicaset.adminSecret" . }}"
key: password
{{- end }}
volumeMounts: volumeMounts:
- name: tools - name: tools
mountPath: /tools mountPath: /tools
...@@ -48,4 +61,3 @@ spec: ...@@ -48,4 +61,3 @@ spec:
configMap: configMap:
name: {{ template "mongodb-replicaset.fullname" . }}-tests name: {{ template "mongodb-replicaset.fullname" . }}-tests
restartPolicy: Never restartPolicy: Never
{{- end }}
...@@ -3,8 +3,14 @@ ...@@ -3,8 +3,14 @@
MONGOCACRT=/ca/tls.crt MONGOCACRT=/ca/tls.crt
MONGOPEM=/work-dir/mongo.pem MONGOPEM=/work-dir/mongo.pem
MONGOARGS="--quiet"
if [ -f "$MONGOPEM" ]; then if [ -f "$MONGOPEM" ]; then
MONGOARGS="--ssl --sslCAFile $MONGOCACRT --sslPEMKeyFile $MONGOPEM" MONGOARGS="$MONGOARGS --ssl --sslCAFile $MONGOCACRT --sslPEMKeyFile $MONGOPEM"
fi
if [[ "${AUTH}" == "true" ]]; then
MONGOARGS="$MONGOARGS --username $ADMIN_USER --password $ADMIN_PASSWORD --authenticationDatabase admin"
fi fi
pod_name() { pod_name() {
...@@ -19,8 +25,8 @@ replicas() { ...@@ -19,8 +25,8 @@ replicas() {
master_pod() { master_pod() {
for ((i = 0; i < $(replicas); ++i)); do for ((i = 0; i < $(replicas); ++i)); do
response=$(mongo "$MONGOARGS" "--host=$(pod_name "$i")" "--eval=rs.isMaster().ismaster") response=$(mongo $MONGOARGS "--host=$(pod_name "$i")" "--eval=rs.isMaster().ismaster")
if [[ "$response" =~ "true" ]]; then if [[ "$response" == "true" ]]; then
pod_name "$i" pod_name "$i"
break break
fi fi
...@@ -34,31 +40,31 @@ setup() { ...@@ -34,31 +40,31 @@ setup() {
sleep 1 sleep 1
for ((i = 0; i < $(replicas); ++i)); do for ((i = 0; i < $(replicas); ++i)); do
response=$(mongo "$MONGOARGS" "--host=$(pod_name "$i")" "--eval=rs.status()" || true) response=$(mongo $MONGOARGS "--host=$(pod_name "$i")" "--eval=rs.status().ok" || true)
if [[ "$response" =~ .*ok.* ]]; then if [[ "$response" -eq 1 ]]; then
ready=$((ready + 1)) ready=$((ready + 1))
fi fi
done done
done done
} }
@test "Testing mongodb client is accessible" { @test "Testing mongodb client is executable" {
mongo -h mongo -h
[ "$?" -eq 0 ] [ "$?" -eq 0 ]
} }
@test "Connect mongodb client to mongodb pods" { @test "Connect mongodb client to mongodb pods" {
for ((i = 0; i < $(replicas); ++i)); do for ((i = 0; i < $(replicas); ++i)); do
response=$(mongo "$MONGOARGS" "--host=$(pod_name "$i")" "--eval=rs.status()") response=$(mongo $MONGOARGS "--host=$(pod_name "$i")" "--eval=rs.status().ok")
if [[ ! "$response" =~ .*ok.* ]]; then if [[ ! "$response" -eq 1 ]]; then
exit 1 exit 1
fi fi
done done
} }
@test "Write key to master" { @test "Write key to primary" {
response=$(mongo "$MONGOARGS" --host=$(master_pod) "--eval=db.test.insert({\"abc\": \"def\"}).nInserted") response=$(mongo $MONGOARGS --host=$(master_pod) "--eval=db.test.insert({\"abc\": \"def\"}).nInserted")
if [[ ! "$response" =~ "1" ]]; then if [[ ! "$response" -eq 1 ]]; then
exit 1 exit 1
fi fi
} }
...@@ -68,9 +74,12 @@ setup() { ...@@ -68,9 +74,12 @@ setup() {
sleep 10 sleep 10
for ((i = 0; i < $(replicas); ++i)); do for ((i = 0; i < $(replicas); ++i)); do
response=$(mongo "$MONGOARGS" --host=$(pod_name "$i") "--eval=rs.slaveOk(); db.test.find({\"abc\":\"def\"})") response=$(mongo $MONGOARGS --host=$(pod_name "$i") "--eval=rs.slaveOk(); db.test.find({\"abc\":\"def\"})")
if [[ ! "$response" =~ .*def.* ]]; then if [[ ! "$response" =~ .*def.* ]]; then
exit 1 exit 1
fi fi
done done
# Clean up a document after test
mongo $MONGOARGS --host=$(master_pod) "--eval=db.test.deleteMany({\"abc\": \"def\"})"
} }
...@@ -7,27 +7,39 @@ podDisruptionBudget: {} ...@@ -7,27 +7,39 @@ podDisruptionBudget: {}
# maxUnavailable: 1 # maxUnavailable: 1
# minAvailable: 2 # minAvailable: 2
## Start and stop pods in Parallel or OrderedReady (one-by-one.) Note - Can not change after first release.
## ref: https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/#pod-management-policy
podManagementPolicy: OrderedReady
auth: auth:
enabled: false enabled: false
# adminUser: username # adminUser: username
# adminPassword: password # adminPassword: password
# metricsUser: metrics
# metricsPassword: password
# key: keycontent # key: keycontent
# existingKeySecret: # existingKeySecret:
# existingAdminSecret: # existingAdminSecret:
# existingMetricsSecret:
## Optionally specify an array of imagePullSecrets.
## Secrets must be manually created in the namespace.
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
##
imagePullSecrets: []
# - myRegistrKeySecretName
# Specs for the Docker image for the init container that establishes the replica set # Specs for the Docker image for the init container that establishes the replica set
installImage: installImage:
repository: k8s.gcr.io/mongodb-install repository: ranchercharts/unguiculus-mongodb-install
tag: 0.6 tag: 0.7
pullPolicy: IfNotPresent
# Specs for the Docker image for the copyConfig init container
copyConfigImage:
repository: ranchercharts/busybox
tag: 1.29.3
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
# Specs for the MongoDB image # Specs for the MongoDB image
image: image:
repository: mongo repository: ranchercharts/mongo
tag: 3.6 tag: 3.6
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
...@@ -36,14 +48,33 @@ extraVars: {} ...@@ -36,14 +48,33 @@ extraVars: {}
# - name: TCMALLOC_AGGRESSIVE_DECOMMIT # - name: TCMALLOC_AGGRESSIVE_DECOMMIT
# value: "true" # value: "true"
# Prometheus Metrics Exporter
metrics:
enabled: false
image:
repository: ranchercharts/ssalaues-mongodb-exporter
tag: 0.6.1
pullPolicy: IfNotPresent
port: 9216
path: "/metrics"
socketTimeout: 3s
syncTimeout: 1m
prometheusServiceDiscovery: true
resources: {}
# Annotations to be added to MongoDB pods # Annotations to be added to MongoDB pods
podAnnotations: {} podAnnotations: {}
securityContext: securityContext:
enabled: true
runAsUser: 999 runAsUser: 999
fsGroup: 999 fsGroup: 999
runAsNonRoot: true runAsNonRoot: true
init:
resources: {}
timeout: 900
resources: {} resources: {}
# limits: # limits:
# cpu: 500m # cpu: 500m
...@@ -60,6 +91,10 @@ affinity: {} ...@@ -60,6 +91,10 @@ affinity: {}
tolerations: [] tolerations: []
extraLabels: {}
# priorityClassName: ""
persistentVolume: persistentVolume:
enabled: true enabled: true
## mongodb-replicaset data Persistent Volume Storage Class ## mongodb-replicaset data Persistent Volume Storage Class
...@@ -78,6 +113,8 @@ persistentVolume: ...@@ -78,6 +113,8 @@ persistentVolume:
# Annotations to be added to the service # Annotations to be added to the service
serviceAnnotations: {} serviceAnnotations: {}
terminationGracePeriodSeconds: 30
tls: tls:
# Enable or disable MongoDB TLS support # Enable or disable MongoDB TLS support
enabled: false enabled: false
...@@ -90,12 +127,15 @@ tls: ...@@ -90,12 +127,15 @@ tls:
# cakey: # cakey:
# Entries for the MongoDB config file # Entries for the MongoDB config file
configmap: configmap: {}
## Period to wait for broker graceful shutdown (sigterm) before pod is killed (sigkill) # Javascript code to execute on each replica at initContainer time
## ref: https://kubernetes-v1-4.github.io/docs/user-guide/production-pods/#lifecycle-hooks-and-termination-notice # This is the recommended way to create indexes on replicasets.
## ref: https://kafka.apache.org/10/documentation.html#brokerconfigs controlled.shutdown.* # Below is an example that creates indexes in foreground on each replica in standalone mode.
terminationGracePeriodSeconds: 30 # ref: https://docs.mongodb.com/manual/tutorial/build-indexes-on-replica-sets/
# initMongodStandalone: |+
# db = db.getSiblingDB("mydb")
# db.my_users.createIndex({email: 1})
# Readiness probe # Readiness probe
readinessProbe: readinessProbe:
...@@ -112,6 +152,3 @@ livenessProbe: ...@@ -112,6 +152,3 @@ livenessProbe:
failureThreshold: 3 failureThreshold: 3
periodSeconds: 10 periodSeconds: 10
successThreshold: 1 successThreshold: 1
# whether run helm test or nnot
runtest: false
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment