diff --git a/couchbase/Dockerfile b/couchbase/Dockerfile new file mode 100644 index 0000000..1bbcf7c --- /dev/null +++ b/couchbase/Dockerfile @@ -0,0 +1,6 @@ +FROM couchbase:community-7.6.1 +ENV RETRIES_INIT=50\ + RETRIES_ADDBUCKETS=10 +ADD ./entrypoint.sh /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] +CMD ["couchbase-server"] diff --git a/couchbase/docker-compose-example.yaml b/couchbase/docker-compose-example.yaml new file mode 100644 index 0000000..2733ba3 --- /dev/null +++ b/couchbase/docker-compose-example.yaml @@ -0,0 +1,15 @@ +version: '2' +services: + couchbase: + build: . + environment: + - CLUSTER=localhost + - USER=admin + - PASS=secret + - PORT=8091 + - RAMSIZEMB=2048 + - RAMSIZEINDEXMB=512 + - RAMSIZEFTSMB=512 + - BUCKETS= + - BUCKETSIZES= + - AUTOREBALANCE=true diff --git a/couchbase/entrypoint.sh b/couchbase/entrypoint.sh new file mode 100755 index 0000000..0d38dd0 --- /dev/null +++ b/couchbase/entrypoint.sh @@ -0,0 +1,248 @@ +#!/bin/bash + +####################################### +# function retry +# Runs a command for several times and gives up with +# an error message after max retries. +# +# Arguments: +# maxretries number of retries before giving up +# errormessage error message for each failed try +# command command to be executed +# +# Returns: +# 1 on failure. 0 on success +# +# Author: Christopher Hauser +####################################### +function retry(){ + maxretries=$1; shift + errormessage=$1; shift + command="$@" + + tries=0 + while (( $tries >= 0 )); do + $command + if [[ $? != 0 ]]; then + let tries+=1 + if (( $tries < $maxretries )); then + echo "$errormessage" + echo "$tries retries. retry in 5s." >&2 + sleep 5 + else + echo "$errormessage" + echo "$tries retries. Will give up." >&2 + return 1 + fi + else + tries=-1 # try success + return 0 + fi + done +} + +####################################### +# function initializeAddHost +# Inizialize a couchbase server: join a cluster +# +# Arguments: +# none +# +# Returns: +# 1 on failure. 0 on success +# +# Author: Christopher Hauser +####################################### +function initializeAddHost(){ + + # validate if host is part of cluster, then skip + local host_ip + host_ip="127.0.0.1" # $(hostname --ip-address) + if [[ $(couchbase-cli server-list -c $CLUSTER -u $USER -p $PASS | grep $host_ip:$PORT) ]]; then + echo "server is already part of the cluster. skipping." + return 0; + fi + + # add host to cluster + couchbase-cli server-add -c $CLUSTER -u $USER -p $PASS \ + --server-add=$(hostname --ip-address):$PORT \ + --server-add-username=$USER \ + --server-add-password=$PASS + if [[ $? != 0 ]]; then + echo "failed to add server to cluster." >&2 + return 1 + fi + + # if auto rebalance is activated, start rebalancing cluster + if [[ "$AUTOREBALANCE" == "true" ]]; then + couchbase-cli rebalance -c $CLUSTER -u $USER -p $PASS + if [[ $? != 0 ]]; then + echo "failed to rebalance cluster. please trigger again manually." >&2 + fi + fi +} + +####################################### +# function initializeAddBuckets +# Inizialize a couchbase server: add buckets to cluster +# +# Arguments: +# none +# +# Returns: +# 1 on failure. 0 on success +# +# Authors: Christopher Hauser , Jérôme Bertaux +####################################### +function initializeAddBuckets(){ + + # validate if all env vars are present + params=("BUCKETSIZES BUCKETS") + for var in $params ; do + if [ -z ${!var+x} ]; then + echo "$var is unset. skipping initialization of buckets." + return 0 + fi + done + + i=0 + sizes=($BUCKETSIZES) + for bucket in $BUCKETS; do + if [[ $(couchbase-cli bucket-list -c $CLUSTER -u $USER -p $PASS | grep -Fx $bucket) ]]; then + echo "bucket $bucket exists. skipping." + continue + fi + size=${sizes[$i]} + echo "create bucket $bucket with size $size" + couchbase-cli bucket-create -c $CLUSTER -u $USER -p $PASS \ + --bucket=$bucket \ + --bucket-type=couchbase \ + --bucket-ramsize=$size \ + --bucket-replica=1 \ + --wait + if [[ $? != 0 ]]; then + echo "failed to create buckets." >&2 + return 1 + fi + + echo "create user for bucket $bucket" + couchbase-cli user-manage -c $CLUSTER -u $USER -p $PASS \ + --set --rbac-username $bucket --rbac-password $PASS \ + --rbac-name $bucket --roles bucket_admin[$bucket],bucket_full_access[$bucket] \ + --auth-domain local + if [[ $? != 0 ]]; then + echo "failed to create user bucket." >&2 + return 1 + fi + + let i+=1 + done +} + +####################################### +# function initializeCluster +# Inizialize a couchbase server: create or join a cluster, +# create buckets if specified. +# +# Arguments: +# none +# +# Returns: +# 1 on failure. 0 on success +# +# Author: Christopher Hauser +####################################### +function initializeCluster(){ + + # validate if all env vars are present + params=("CLUSTER USER PASS PORT RAMSIZEMB RAMSIZEINDEXMB RAMSIZEFTSMB") + for var in $params ; do + if [ -z ${!var+x} ]; then + echo "$var is unset. skipping initialization of cluster." + return 0 + fi + done + + # initialize cluster + echo "try initialization" + initOutput=$(couchbase-cli cluster-init -c $CLUSTER -u $USER -p $PASS \ + --cluster-username=$USER \ + --cluster-password=$PASS \ + --cluster-port=$PORT \ + --services=data,index,query,fts \ + --cluster-ramsize=$RAMSIZEMB \ + --cluster-index-ramsize=$RAMSIZEINDEXMB \ + --cluster-fts-ramsize=$RAMSIZEFTSMB \ + --index-storage-setting=default) + if [[ $? != 0 ]]; then + echo $initOutput + echo "failed to initialize cluster." >&2 + return 1 + fi + echo $initOutput + + # add host to cluster + echo "try to add host (if not already added) to cluster" + retry 5 "failed to add host to cluster" initializeAddHost + if [[ $? != 0 ]]; then + echo "failed to add host to cluster." >&2 + return 1 + fi +} + +####################################### +# function main +# Main function to bootstrap Couchbase in a +# Docker container +# +# Arguments: +# none +# +# Returns: +# none +# +# Author: Christopher Hauser +####################################### +function main(){ + echo "Starting Couchbase Server -- Web UI available at http://:8091 and logs available in /opt/couchbase/var/lib/couchbase/logs" + exec /usr/sbin/runsvdir -P /etc/service & + if [[ $? != 0 ]]; then + echo "failed to start couchbase. exiting now." >&2 + exit 1 + fi + + # validate if all env vars are present + params=("RETRIES_INIT RETRIES_ADDBUCKETS") + for var in $params ; do + if [ -z ${!var+x} ]; then + echo "$var is unset. skipping initialization of cluster." + return 0 + fi + done + + echo "now initializing couchbase ..." + retry $RETRIES_INIT "cannot initialize couchbase" initializeCluster + if [[ $? != 0 ]]; then + echo "init failed. exiting now." >&2 + exit 1 + fi + + echo "try to create buckets" + retry $RETRIES_ADDBUCKETS "failed to add buckets" initializeAddBuckets + if [[ $? != 0 ]]; then + echo "failed to add buckets to cluster. please trigger again manually." >&2 + fi + + # wait for couchbase server + echo "now wait for couchbase forever" + wait +} + +####################################### +# Start the magic ... +####################################### +if [[ "$1" == "couchbase-server" ]]; then + main +else + exec "$@" +fi diff --git a/couchbase/readme.md b/couchbase/readme.md new file mode 100644 index 0000000..5af6e30 --- /dev/null +++ b/couchbase/readme.md @@ -0,0 +1,39 @@ +# Couchbase + +Based on https://github.com/cha87de/couchbase-docker-cloudnative + +```sh +docker run --rm -it \ + -e CLUSTER=localhost \ + -e USER=admin \ + -e PASS=public \ + -e PORT=8091 \ + -e RAMSIZEMB=2048 \ + -e RAMSIZEINDEXMB=512 \ + -e RAMSIZEFTSMB=512 \ + -e BUCKETS=mqtt \ + -e BUCKETSIZES=100 \ + -e AUTOREBALANCE=true \ + -p 8091-8093:8091-8093 \ + ghcr.io/emqx/couchbase:1.0.0 + +``` + +```sh +curl -v http://localhost:8093/query/service \ + -d 'statement=INSERT INTO mqtt (KEY, VALUE) VALUES ("1", {"id": 1}) + & args=[]' \ + -u admin:public | jq . + +curl -v http://localhost:8093/query/service \ + -d 'statement=INSERT INTO mqtt (KEY, VALUE) VALUES ("3", {"id": 33}), + VALUES ("10", {"name": "foo"}) + & args=[]' \ + -u admin:public | jq . + +curl -v http://localhost:8093/query/service \ + -d 'statement=SELECT * FROM mqtt + & args=[]' \ + -u admin:public | jq . + +``` diff --git a/couchbase/vsn b/couchbase/vsn new file mode 100644 index 0000000..3eefcb9 --- /dev/null +++ b/couchbase/vsn @@ -0,0 +1 @@ +1.0.0