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
## Configuration ## Configuration
The following tables lists the configurable parameters of the mongodb chart and their default values. The following table lists the configurable parameters of the mongodb chart and their default values.
| Parameter | Description | Default | | Parameter | Description | Default |
| ----------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------- | | ----------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------- |
...@@ -8,56 +8,87 @@ The following tables lists the configurable parameters of the mongodb chart and ...@@ -8,56 +8,87 @@ The following tables lists the configurable parameters of the mongodb chart and
| `replicaSetName` | The name of the replica set | `rs0` | | `replicaSetName` | The name of the replica set | `rs0` |
| `podDisruptionBudget` | Pod disruption budget | `{}` | | `podDisruptionBudget` | Pod disruption budget | `{}` |
| `port` | MongoDB port | `27017` | | `port` | MongoDB port | `27017` |
| `installImage.repository` | Image name for the install container | `k8s.gcr.io/mongodb-install` | | `imagePullSecrets` | Image pull secrets | `[]` |
| `installImage.tag` | Image tag for the install container | `0.5` | | `installImage.repository` | Image name for the install container | `unguiculus/mongodb-install` |
| `installImage.tag` | Image tag for the install container | `0.7` |
| `installImage.pullPolicy` | Image pull policy for the init container that establishes the replica set | `IfNotPresent` | | `installImage.pullPolicy` | Image pull policy for the init container that establishes the replica set | `IfNotPresent` |
| `copyConfigImage.repository` | Image name for the copy config init container | `busybox` |
| `copyConfigImage.tag` | Image tag for the copy config init container | `1.29.3` |
| `copyConfigImage.pullPolicy` | Image pull policy for the copy config init container | `IfNotPresent` |
| `image.repository` | MongoDB image name | `mongo` | | `image.repository` | MongoDB image name | `mongo` |
| `image.tag` | MongoDB image tag | `3.6` | | `image.tag` | MongoDB image tag | `3.6` |
| `image.pullPolicy` | MongoDB image pull policy | `IfNotPresent` | | `image.pullPolicy` | MongoDB image pull policy | `IfNotPresent` |
| `podAnnotations` | Annotations to be added to MongoDB pods | `{}` | | `podAnnotations` | Annotations to be added to MongoDB pods | `{}` |
| `securityContext` | Security context for the pod | `{runAsUser: 999, fsGroup: 999, runAsNonRoot: true}`| | `securityContext.enabled` | Enable security context | `true` |
| `securityContext.fsGroup` | Group ID for the container | `999` |
| `securityContext.runAsUser` | User ID for the container | `999` |
| `securityContext.runAsNonRoot` | | `true` |
| `resources` | Pod resource requests and limits | `{}` | | `resources` | Pod resource requests and limits | `{}` |
| `persistentVolume.enabled` | If `true`, persistent volume claims are created | `true` | | `persistentVolume.enabled` | If `true`, persistent volume claims are created | `true` |
| `persistentVolume.storageClass` | Persistent volume storage class | `` | | `persistentVolume.storageClass` | Persistent volume storage class | `` |
| `persistentVolume.accessMode` | Persistent volume access modes | `[ReadWriteOnce]` | | `persistentVolume.accessModes` | Persistent volume access modes | `[ReadWriteOnce]` |
| `persistentVolume.size` | Persistent volume size | `10Gi` | | `persistentVolume.size` | Persistent volume size | `10Gi` |
| `persistentVolume.annotations` | Persistent volume annotations | `{}` | | `persistentVolume.annotations` | Persistent volume annotations | `{}` |
| `terminationGracePeriodSeconds` | Duration in seconds the pod needs to terminate gracefully | `30` |
| `tls.enabled` | Enable MongoDB TLS support including authentication | `false` | | `tls.enabled` | Enable MongoDB TLS support including authentication | `false` |
| `tls.cacert` | The CA certificate used for the members | Our self signed CA certificate | | `tls.cacert` | The CA certificate used for the members | Our self signed CA certificate |
| `tls.cakey` | The CA key used for the members | Our key for the self signed CA certificate | | `tls.cakey` | The CA key used for the members | Our key for the self signed CA certificate |
| `init.resources` | Pod resource requests and limits (for init containers) | `{}` |
| `init.timeout` | The amount of time in seconds to wait for bootstrap to finish | `900` |
| `metrics.enabled` | Enable Prometheus compatible metrics for pods and replicasets | `false` |
| `metrics.image.repository` | Image name for metrics exporter | `ssalaues/mongodb-exporter` |
| `metrics.image.tag` | Image tag for metrics exporter | `0.6.1` |
| `metrics.image.pullPolicy` | Image pull policy for metrics exporter | `IfNotPresent` |
| `metrics.port` | Port for metrics exporter | `9216` |
| `metrics.path` | URL Path to expose metics | `/metrics` |
| `metrics.resources` | Metrics pod resource requests and limits | `{}` |
| `metrics.socketTimeout` | Time to wait for a non-responding socket | `3s` |
| `metrics.syncTimeout` | Time an operation with this session will wait before returning an error | `1m` |
| `metrics.prometheusServiceDiscovery`| Adds annotations for Prometheus ServiceDiscovery | `true` |
| `auth.enabled` | If `true`, keyfile access control is enabled | `false` | | `auth.enabled` | If `true`, keyfile access control is enabled | `false` |
| `auth.key` | Key for internal authentication | `` | | `auth.key` | Key for internal authentication | `` |
| `auth.existingKeySecret` | If set, an existing secret with this name for the key is used | `` | | `auth.existingKeySecret` | If set, an existing secret with this name for the key is used | `` |
| `auth.adminUser` | MongoDB admin user | `` | | `auth.adminUser` | MongoDB admin user | `` |
| `auth.adminPassword` | MongoDB admin password | `` | | `auth.adminPassword` | MongoDB admin password | `` |
| `auth.metricsUser` | MongoDB clusterMonitor user | `` |
| `auth.metricsPassword` | MongoDB clusterMonitor password | `` |
| `auth.existingMetricsSecret` | If set, and existing secret with this name is used for the metrics user | `` |
| `auth.existingAdminSecret` | If set, and existing secret with this name is used for the admin user | `` | | `auth.existingAdminSecret` | If set, and existing secret with this name is used for the admin user | `` |
| `serviceAnnotations` | Annotations to be added to the service | `{}` | | `serviceAnnotations` | Annotations to be added to the service | `{}` |
| `configmap` | Content of the MongoDB config file | `` | | `configmap` | Content of the MongoDB config file | `` |
| `initMongodStandalone` | If set, initContainer executes script in standalone mode | `` |
| `nodeSelector` | Node labels for pod assignment | `{}` | | `nodeSelector` | Node labels for pod assignment | `{}` |
| `affinity` | Node/pod affinities | `{}` | | `affinity` | Node/pod affinities | `{}` |
| `tolerations` | List of node taints to tolerate | `[]` | | `tolerations` | List of node taints to tolerate | `[]` |
| `livenessProbe` | Liveness probe configuration | See below | | `priorityClassName` | Pod priority class name | `` |
| `readinessProbe` | Readiness probe configuration | See below | | `livenessProbe.failureThreshold` | Liveness probe failure threshold | `3` |
| `livenessProbe.initialDelaySeconds` | Liveness probe initial delay seconds | `30` |
| `livenessProbe.periodSeconds` | Liveness probe period seconds | `10` |
| `livenessProbe.successThreshold` | Liveness probe success threshold | `1` |
| `livenessProbe.timeoutSeconds` | Liveness probe timeout seconds | `5` |
| `readinessProbe.failureThreshold` | Readiness probe failure threshold | `3` |
| `readinessProbe.initialDelaySeconds`| Readiness probe initial delay seconds | `5` |
| `readinessProbe.periodSeconds` | Readiness probe period seconds | `10` |
| `readinessProbe.successThreshold` | Readiness probe success threshold | `1` |
| `readinessProbe.timeoutSeconds` | Readiness probe timeout seconds | `1` |
| `extraVars` | Set environment variables for the main container | `{}` | | `extraVars` | Set environment variables for the main container | `{}` |
| `extraLabels` | Additional labels to add to resources | `{}` |
*MongoDB config file* *MongoDB config file*
All options that depended on the chart configuration are supplied as command-line arguments to `mongod`. By default, All options that depended on the chart configuration are supplied as command-line arguments to `mongod`. By default, the chart creates an empty config file. Entries may be added via the `configmap` configuration value.
the chart creates an empty config file. Entries may be added via the `configmap` configuration value.
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`.
Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example,
```console ``` console
$ helm install --name my-release -f values.yaml stable/mongodb-replicaset helm install --name my-release -f values.yaml stable/mongodb-replicaset
``` ```
> **Tip**: You can use the default [values.yaml](values.yaml) > **Tip**: You can use the default [values.yaml](values.yaml)
Once you have all 3 nodes in running, you can run the "test.sh" script in this directory, which will insert a key into Once you have all 3 nodes in running, you can run the "test.sh" script in this directory, which will insert a key into the primary and check the secondaries for output. This script requires that the `$RELEASE_NAME` environment variable be set, in order to access the pods.
the primary and check the secondaries for output. This script requires that the `$RELEASE_NAME` environment variable
be set, in order to access the pods.
## Authentication ## Authentication
...@@ -69,13 +100,19 @@ keys `user` and `password`, that for the key file must contain `key.txt`. The u ...@@ -69,13 +100,19 @@ keys `user` and `password`, that for the key file must contain `key.txt`. The u
full `root` permissions but is restricted to the `admin` database for security purposes. It can be full `root` permissions but is restricted to the `admin` database for security purposes. It can be
used to create additional users with more specific permissions. used to create additional users with more specific permissions.
To connect to the mongo shell with authentication enabled, use a command similar to the following (substituting values as appropriate):
```shell
kubectl exec -it mongodb-replicaset-0 -- mongo mydb -u admin -p password --authenticationDatabase admin
```
## TLS support ## TLS support
To enable full TLS encryption set `tls.enabled` to `true`. It is recommended to create your own CA by executing: To enable full TLS encryption set `tls.enabled` to `true`. It is recommended to create your own CA by executing:
```console ```console
$ openssl genrsa -out ca.key 2048 openssl genrsa -out ca.key 2048
$ openssl req -x509 -new -nodes -key ca.key -days 10000 -out ca.crt -subj "/CN=mydomain.com" openssl req -x509 -new -nodes -key ca.key -days 10000 -out ca.crt -subj "/CN=mydomain.com"
``` ```
After that paste the base64 encoded (`cat ca.key | base64 -w0`) cert and key into the fields `tls.cacert` and After that paste the base64 encoded (`cat ca.key | base64 -w0`) cert and key into the fields `tls.cacert` and
...@@ -89,13 +126,16 @@ configmap: ...@@ -89,13 +126,16 @@ configmap:
port: 27017 port: 27017
ssl: ssl:
mode: requireSSL mode: requireSSL
CAFile: /ca/tls.crt CAFile: /data/configdb/tls.crt
PEMKeyFile: /work-dir/mongo.pem PEMKeyFile: /work-dir/mongo.pem
# Set to false to require mutual TLS encryption
allowConnectionsWithoutCertificates: true
replication: replication:
replSetName: rs0 replSetName: rs0
security: security:
authorization: enabled authorization: enabled
clusterAuthMode: x509 # # Uncomment to enable mutual TLS encryption
# clusterAuthMode: x509
keyFile: /keydir/key.txt keyFile: /keydir/key.txt
``` ```
...@@ -131,37 +171,35 @@ alternative hostnames you want to allow access to the MongoDB replicaset. You sh ...@@ -131,37 +171,35 @@ alternative hostnames you want to allow access to the MongoDB replicaset. You sh
mongodb with your `mongo.pem` certificate: mongodb with your `mongo.pem` certificate:
```console ```console
$ mongo --ssl --sslCAFile=ca.crt --sslPEMKeyFile=mongo.pem --eval "db.adminCommand('ping')" mongo --ssl --sslCAFile=ca.crt --sslPEMKeyFile=mongo.pem --eval "db.adminCommand('ping')"
``` ```
## Readiness probe
The default values for the readiness probe are:
```yaml ## Promethus metrics
readinessProbe:
initialDelaySeconds: 5
timeoutSeconds: 1
failureThreshold: 3
periodSeconds: 10
successThreshold: 1
```
## Liveness probe Enabling the metrics as follows will allow for each replicaset pod to export Prometheus compatible metrics
The default values for the liveness probe are: on server status, individual replicaset information, replication oplogs, and storage engine.
```yaml ```yaml
livenessProbe: metrics:
initialDelaySeconds: 30 enabled: true
timeoutSeconds: 5 image:
failureThreshold: 3 repository: ssalaues/mongodb-exporter
periodSeconds: 10 tag: 0.6.1
successThreshold: 1 pullPolicy: IfNotPresent
port: 9216
path: "/metrics"
socketTimeout: 3s
syncTimeout: 1m
prometheusServiceDiscovery: true
resources: {}
``` ```
More information on [MongoDB Exporter](https://github.com/percona/mongodb_exporter) metrics available.
## Deep dive ## Deep dive
Because the pod names are dependent on the name chosen for it, the following examples use the Because the pod names are dependent on the name chosen for it, the following examples use the
environment variable `RELEASENAME`. For example, if the helm release name is `messy-hydra`, one would need to set the environment variable `RELEASENAME`. For example, if the helm release name is `messy-hydra`, one would need to set the following before proceeding. The example scripts below assume 3 pods only.
following before proceeding. The example scripts below assume 3 pods only.
```console ```console
export RELEASE_NAME=messy-hydra export RELEASE_NAME=messy-hydra
...@@ -170,12 +208,13 @@ export RELEASE_NAME=messy-hydra ...@@ -170,12 +208,13 @@ export RELEASE_NAME=messy-hydra
### Cluster Health ### Cluster Health
```console ```console
$ for i in 0 1 2; do kubectl exec $RELEASE_NAME-mongodb-replicaset-$i -- sh -c 'mongo --eval="printjson(db.serverStatus())"'; done for i in 0 1 2; do kubectl exec $RELEASE_NAME-mongodb-replicaset-$i -- sh -c 'mongo --eval="printjson(db.serverStatus())"'; done
``` ```
### Failover ### Failover
One can check the roles being played by each node by using the following: One can check the roles being played by each node by using the following:
```console ```console
$ for i in 0 1 2; do kubectl exec $RELEASE_NAME-mongodb-replicaset-$i -- sh -c 'mongo --eval="printjson(rs.isMaster())"'; done $ for i in 0 1 2; do kubectl exec $RELEASE_NAME-mongodb-replicaset-$i -- sh -c 'mongo --eval="printjson(rs.isMaster())"'; done
...@@ -183,32 +222,32 @@ MongoDB shell version: 3.6.3 ...@@ -183,32 +222,32 @@ MongoDB shell version: 3.6.3
connecting to: mongodb://127.0.0.1:27017 connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3 MongoDB server version: 3.6.3
{ {
"hosts" : [ "hosts" : [
"messy-hydra-mongodb-0.messy-hydra-mongodb.default.svc.cluster.local:27017", "messy-hydra-mongodb-0.messy-hydra-mongodb.default.svc.cluster.local:27017",
"messy-hydra-mongodb-1.messy-hydra-mongodb.default.svc.cluster.local:27017", "messy-hydra-mongodb-1.messy-hydra-mongodb.default.svc.cluster.local:27017",
"messy-hydra-mongodb-2.messy-hydra-mongodb.default.svc.cluster.local:27017" "messy-hydra-mongodb-2.messy-hydra-mongodb.default.svc.cluster.local:27017"
], ],
"setName" : "rs0", "setName" : "rs0",
"setVersion" : 3, "setVersion" : 3,
"ismaster" : true, "ismaster" : true,
"secondary" : false, "secondary" : false,
"primary" : "messy-hydra-mongodb-0.messy-hydra-mongodb.default.svc.cluster.local:27017", "primary" : "messy-hydra-mongodb-0.messy-hydra-mongodb.default.svc.cluster.local:27017",
"me" : "messy-hydra-mongodb-0.messy-hydra-mongodb.default.svc.cluster.local:27017", "me" : "messy-hydra-mongodb-0.messy-hydra-mongodb.default.svc.cluster.local:27017",
"electionId" : ObjectId("7fffffff0000000000000001"), "electionId" : ObjectId("7fffffff0000000000000001"),
"maxBsonObjectSize" : 16777216, "maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000, "maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 1000, "maxWriteBatchSize" : 1000,
"localTime" : ISODate("2016-09-13T01:10:12.680Z"), "localTime" : ISODate("2016-09-13T01:10:12.680Z"),
"maxWireVersion" : 4, "maxWireVersion" : 4,
"minWireVersion" : 0, "minWireVersion" : 0,
"ok" : 1 "ok" : 1
} }
``` ```
This lets us see which member is primary. This lets us see which member is primary.
Let us now test persistence and failover. First, we insert a key (in the below example, we assume pod 0 is the master): Let us now test persistence and failover. First, we insert a key (in the below example, we assume pod 0 is the master):
```console ```console
$ kubectl exec $RELEASE_NAME-mongodb-replicaset-0 -- mongo --eval="printjson(db.test.insert({key1: 'value1'}))" $ kubectl exec $RELEASE_NAME-mongodb-replicaset-0 -- mongo --eval="printjson(db.test.insert({key1: 'value1'}))"
...@@ -218,6 +257,7 @@ connecting to: mongodb://127.0.0.1:27017 ...@@ -218,6 +257,7 @@ connecting to: mongodb://127.0.0.1:27017
``` ```
Watch existing members: Watch existing members:
```console ```console
$ kubectl run --attach bbox --image=mongo:3.6 --restart=Never --env="RELEASE_NAME=$RELEASE_NAME" -- sh -c 'while true; do for i in 0 1 2; do echo $RELEASE_NAME-mongodb-replicaset-$i $(mongo --host=$RELEASE_NAME-mongodb-replicaset-$i.$RELEASE_NAME-mongodb-replicaset --eval="printjson(rs.isMaster())" | grep primary); sleep 1; done; done'; $ kubectl run --attach bbox --image=mongo:3.6 --restart=Never --env="RELEASE_NAME=$RELEASE_NAME" -- sh -c 'while true; do for i in 0 1 2; do echo $RELEASE_NAME-mongodb-replicaset-$i $(mongo --host=$RELEASE_NAME-mongodb-replicaset-$i.$RELEASE_NAME-mongodb-replicaset --eval="printjson(rs.isMaster())" | grep primary); sleep 1; done; done';
...@@ -232,6 +272,7 @@ messy-hydra-mongodb-0 "primary" : "messy-hydra-mongodb-0.messy-hydra-mongodb.def ...@@ -232,6 +272,7 @@ messy-hydra-mongodb-0 "primary" : "messy-hydra-mongodb-0.messy-hydra-mongodb.def
``` ```
Kill the primary and watch as a new master getting elected. Kill the primary and watch as a new master getting elected.
```console ```console
$ kubectl delete pod $RELEASE_NAME-mongodb-replicaset-0 $ kubectl delete pod $RELEASE_NAME-mongodb-replicaset-0
...@@ -239,6 +280,7 @@ pod "messy-hydra-mongodb-0" deleted ...@@ -239,6 +280,7 @@ pod "messy-hydra-mongodb-0" deleted
``` ```
Delete all pods and let the statefulset controller bring it up. Delete all pods and let the statefulset controller bring it up.
```console ```console
$ kubectl delete po -l "app=mongodb-replicaset,release=$RELEASE_NAME" $ kubectl delete po -l "app=mongodb-replicaset,release=$RELEASE_NAME"
$ kubectl get po --watch-only $ kubectl get po --watch-only
...@@ -277,6 +319,7 @@ messy-hydra-mongodb-2 "primary" : "messy-hydra-mongodb-0.messy-hydra-mongodb.def ...@@ -277,6 +319,7 @@ messy-hydra-mongodb-2 "primary" : "messy-hydra-mongodb-0.messy-hydra-mongodb.def
``` ```
Check the previously inserted key: Check the previously inserted key:
```console ```console
$ kubectl exec $RELEASE_NAME-mongodb-replicaset-1 -- mongo --eval="rs.slaveOk(); db.test.find({key1:{\$exists:true}}).forEach(printjson)" $ kubectl exec $RELEASE_NAME-mongodb-replicaset-1 -- mongo --eval="rs.slaveOk(); db.test.find({key1:{\$exists:true}}).forEach(printjson)"
...@@ -288,3 +331,22 @@ connecting to: mongodb://127.0.0.1:27017 ...@@ -288,3 +331,22 @@ connecting to: mongodb://127.0.0.1:27017
### Scaling ### Scaling
Scaling should be managed by `helm upgrade`, which is the recommended way. Scaling should be managed by `helm upgrade`, which is the recommended way.
### Indexes and Maintenance
You can run Mongo in standalone mode and execute Javascript code on each replica at initContainer time using `initMongodStandalone`.
This allows you to create indexes on replicasets following [best practices](https://docs.mongodb.com/manual/tutorial/build-indexes-on-replica-sets/).
#### Example: Creating Indexes
```js
initMongodStandalone: |+
db = db.getSiblingDB("mydb")
db.my_users.createIndex({email: 1})
```
Tail the logs to debug running indexes or to follow their progress
```sh
kubectl exec -it $RELEASE-mongodb-replicaset-0 -c bootstrap -- tail -f /work-dir/log.txt
```
# 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