├── rancher-compose.yml ├── Dockerfile ├── initiate.sh ├── scaling.sh ├── lowest_idx.sh ├── docker-compose.yml ├── connect.sh ├── entrypoint.sh └── README.md /rancher-compose.yml: -------------------------------------------------------------------------------- 1 | mongo-cluster: 2 | scale: 3 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | MAINTAINER Hussein Galal 3 | 4 | ENV MONGO_SERVICE_NAME mongo 5 | 6 | ADD ./*.sh /opt/rancher/bin/ 7 | RUN chmod u+x /opt/rancher/bin/*.sh 8 | 9 | VOLUME /opt/rancher/bin 10 | 11 | ENTRYPOINT ["/bin/true"] 12 | -------------------------------------------------------------------------------- /initiate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # Run cluster init script 5 | /opt/rancher/bin/connect.sh & 6 | 7 | # Start mongodb 8 | if [ $? -ne 0 ] 9 | then 10 | echo "Error Occurred.." 11 | fi 12 | 13 | set -e 14 | 15 | if [ "${1:0:1}" = '-' ]; then 16 | set -- mongod "$@" 17 | fi 18 | 19 | if [ "$1" = 'mongod' ]; then 20 | chown -R mongodb /data/db 21 | 22 | numa='numactl --interleave=all' 23 | if $numa true &> /dev/null; then 24 | set -- $numa "$@" 25 | fi 26 | 27 | exec gosu mongodb "$@" 28 | fi 29 | -------------------------------------------------------------------------------- /scaling.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sleep 5 3 | DIG=/usr/bin/dig 4 | 5 | function scaleup { 6 | MYIP=$(ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1 | sed -n 2p) 7 | $DIG A $MONGO_SERVICE_NAME +short > ips.tmp 8 | for IP in $(cat ips.tmp); do 9 | IS_MASTER=$(mongo --host $IP --eval "printjson(db.isMaster())" | grep 'ismaster') 10 | if echo $IS_MASTER | grep "true"; then 11 | mongo --host $IP --eval "printjson(rs.add('$MYIP:27017'))" 12 | return 0 13 | fi 14 | done 15 | return 1 16 | } 17 | 18 | # Script starts here 19 | if [ $($DIG A $MONGO_SERVICE_NAME +short | wc -l) -gt 3 ]; then 20 | scaleup 21 | fi 22 | -------------------------------------------------------------------------------- /lowest_idx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ### 3 | # Detect if this container has the lowest create ID 4 | ### 5 | 6 | META_URL="http://rancher-metadata/2015-07-25" 7 | 8 | ALLMETA=$(curl -s -H 'Accept: application/json' ${META_URL}) 9 | MY_CREATE_INDEX="$(echo ${ALLMETA} | jq -r .self.container.create_index)" 10 | 11 | get_create_index() 12 | { 13 | echo $(echo ${ALLMETA}| jq -r ".containers[]| select(.name==\"${1}\")| .create_index") 14 | } 15 | 16 | SMALLEST="${MY_CREATE_INDEX}" 17 | for container in $(echo ${ALLMETA}| jq -r .self.service.containers[]); do 18 | IDX=$(get_create_index "${container}") 19 | if [ "${IDX}" -lt "${SMALLEST}" ]; then 20 | SMALLEST=${IDX} 21 | fi 22 | done 23 | 24 | if [ "${MY_CREATE_INDEX}" -eq "${SMALLEST}" ]; then 25 | exit 0 26 | fi 27 | 28 | exit 1 29 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | mongo-cluster: 2 | restart: always 3 | environment: 4 | MONGO_SERVICE_NAME: mongo-cluster 5 | tty: true 6 | entrypoint: /opt/rancher/bin/entrypoint.sh 7 | command: 8 | - --replSet 9 | - "rs0" 10 | image: mongo:3.0 11 | labels: 12 | io.rancher.container.hostname_override: container_name 13 | io.rancher.sidekicks: mongo-base, mongo-datavolume 14 | volumes_from: 15 | - mongo-datavolume 16 | - mongo-base 17 | mongo-base: 18 | restart: always 19 | tty: true 20 | labels: 21 | io.rancher.container.hostname_override: container_name 22 | io.rancher.container.start_once: true 23 | build: ./ 24 | stdin_open: true 25 | entrypoint: /bin/true 26 | mongo-datavolume: 27 | net: none 28 | labels: 29 | io.rancher.container.hostname_override: container_name 30 | io.rancher.container.start_once: true 31 | volumes: 32 | - /data/db 33 | entrypoint: /bin/true 34 | image: busybox 35 | -------------------------------------------------------------------------------- /connect.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DIG=/usr/bin/dig 3 | 4 | function cluster_init { 5 | sleep 10 6 | MYIP=$(ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1 | sed -n 2p) 7 | $DIG A $MONGO_SERVICE_NAME +short > ips.tmp 8 | mongo --eval "printjson(rs.initiate())" 9 | for member in $(cat ips.tmp); do 10 | if [ $member != $MYIP ]; then 11 | mongo --eval "printjson(rs.add('$member:27017'))" 12 | sleep 5 13 | fi 14 | done 15 | 16 | } 17 | 18 | function find_master { 19 | $DIG A $MONGO_SERVICE_NAME +short > ips.tmp 20 | for IP in $(cat ips.tmp); do 21 | IS_MASTER=`mongo --host $IP --eval "printjson(db.isMaster())" | grep 'ismaster'` 22 | if echo $IS_MASTER | grep "true"; then 23 | return 0 24 | fi 25 | done 26 | return 1 27 | } 28 | # Script starts here 29 | # wait for mongo to start 30 | while [ `$DIG A $MONGO_SERVICE_NAME +short | wc -l` -lt 3 ]; do 31 | echo 'mongo instances are less than 3.. waiting!' 32 | sleep 5 33 | done 34 | 35 | # Wait until all services are up 36 | sleep 10 37 | find_master 38 | if [ $? -eq 0 ]; then 39 | echo 'Master is already initated.. nothing to do!' 40 | else 41 | echo 'Initiating the cluster!' 42 | cluster_init 43 | fi 44 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Installing dnsutils and jq 4 | echo "deb http://http.debian.net/debian wheezy-backports main" | tee /etc/apt/sources.list.d/wheezy-backports.list > /dev/null 5 | echo "deb http://security.debian.org/ wheezy/updates main contrib non-free " | tee /etc/apt/sources.list.d/wheezy-security.list > /dev/null 6 | echo "deb-src http://security.debian.org/ wheezy/updates main contrib non-free" | tee /etc/apt/sources.list.d/wheezy-security.list > /dev/null 7 | apt-get -q update > /dev/null 8 | apt-get install -qqy dnsutils jq > /dev/null 2>&1 9 | 10 | # Check for lowest ID 11 | /opt/rancher/bin/lowest_idx.sh 12 | if [ "$?" -eq "0" ]; then 13 | echo "This is the lowest numbered contianer.. Handling the initiation." 14 | /opt/rancher/bin/initiate.sh $@ 15 | else 16 | 17 | # Run the scaling script 18 | /opt/rancher/bin/scaling.sh & 19 | 20 | # Start mongodb 21 | if [ $? -ne 0 ] 22 | then 23 | echo "Error Occurred.." 24 | fi 25 | 26 | set -e 27 | 28 | if [ "${1:0:1}" = '-' ]; then 29 | set -- mongod "$@" 30 | fi 31 | 32 | if [ "$1" = 'mongod' ]; then 33 | chown -R mongodb /data/db 34 | 35 | numa='numactl --interleave=all' 36 | if $numa true &> /dev/null; then 37 | set -- $numa "$@" 38 | fi 39 | 40 | exec gosu mongodb "$@" 41 | fi 42 | 43 | exec "$@" 44 | 45 | fi 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rancher-mongo-config 2 | A base Docker image to be used as a sidekick for MongoDB container, the scripts in this container will create replica set when you create a service in Rancher environment (at least 3 containers). 3 | 4 | ## Requirements 5 | - Docker engine. 6 | - Rancher server. 7 | - rancher-compose. 8 | 9 | ## Usage 10 | 11 | After installing rancher-compose, you can create a service that contain the following: 12 | 13 | **docker-compose.yml** 14 | ``` 15 | mongo-cluster: 16 | restart: always 17 | environment: 18 | MONGO_SERVICE_NAME: mongo-cluster 19 | tty: true 20 | entrypoint: /opt/rancher/bin/entrypoint.sh 21 | command: 22 | - --replSet 23 | - "rs0" 24 | image: mongo:3.0 25 | labels: 26 | io.rancher.container.hostname_override: container_name 27 | io.rancher.sidekicks: mongo-base, mongo-datavolume 28 | volumes_from: 29 | - mongo-datavolume 30 | - mongo-base 31 | mongo-base: 32 | restart: always 33 | tty: true 34 | labels: 35 | io.rancher.container.hostname_override: container_name 36 | io.rancher.container.start_once: true 37 | build: ./ 38 | stdin_open: true 39 | entrypoint: /bin/true 40 | mongo-datavolume: 41 | net: none 42 | labels: 43 | io.rancher.container.hostname_override: container_name 44 | io.rancher.container.start_once: true 45 | volumes: 46 | - /data/db 47 | entrypoint: /bin/true 48 | image: busybox 49 | ``` 50 | **rancher-compose.yml** 51 | ``` 52 | mongo-cluster: 53 | scale: 3 54 | ``` 55 | 56 | And now to run the service run the following: 57 | 58 | ``` 59 | # rancher-compose up 60 | ``` 61 | As an added bonus the service can scale up as you go, just change the settings in rancher-compose.yml or use the Web UI to scale the serivce and the container will connect to the replicaset and be attached. 62 | --------------------------------------------------------------------------------