Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Using Docker to Develop With Couchbase

DZone's Guide to

Using Docker to Develop With Couchbase

In this article, I will explain how to create a modular Couchbase image that doesn’t require any Web UI interaction to have a ready-to-go database for you.

· Database Zone
Free Resource

Traditional relational databases weren’t designed for today’s customers. Learn about the world’s first NoSQL Engagement Database purpose-built for the new era of customer experience.

Docker is a great project that is helping developers around the world run applications in containers. This not only helps shipping software faster, but it also results with the famous “it works on my machine” phrase. In this article, I will explain how to create a modular Couchbase image that doesn’t require any Web UI interaction to have a ready-to-go database for you.

All the code is available online here.

Dockerfile

The first step is to create the Dockerfile.

Couchbase Version

FROM couchbase/server:enterprise-4.6.1

This example is based on Couchbase Server Enterprise 4.6.1, but you can feel free to change to the specific version you are running in your environment.

Memory Configuration

ENV MEMORY_QUOTA 256
ENV INDEX_MEMORY_QUOTA 256
ENV FTS_MEMORY_QUOTA 256

All the values here are in MB:

  • MEMORY_QUOTA: Per node data service ram quota.

  • INDEX_MEMORY_QUOTA: Per node index service ram quota.

  • FTS_MEMORY_QUOTA: Per node index service ram quota.

Services

ENV SERVICES "kv,n1ql,index,fts"

These are the services that will be available for the node created:

  • kv: Data.

  • n1ql: Query.

  • index: Index.

  • fts: Full-text search.

Credentials

ENV USERNAME "Administrator"
ENV PASSWORD "password"

Username and password to be used in Couchbase Server.

Cluster Options

ENV CLUSTER_HOST ""
ENV CLUSTER_REBALANCE ""

These options are only used if you want to add more than one node in the cluster.

  • CLUSTER_HOST: Hostname of the cluster for this node to join.

  • CLUSTER_REBALANCE: Set true if you want the cluster to rebalance after the node is joined.

Entrypoint

COPY entrypoint.sh /config-entrypoint.sh

ENTRYPOINT ["/config-entrypoint.sh"]

The Couchbase Server image already ships with an entrypoint.sh script and we don’t want to override it. The trick here is to copy our version of entrypoint.sh to /config-entrypoint.sh, run Couchbase Server entrypoint.sh in the background, and after configuring the node, attach the script back to the original ENTRYPOINT.

Entrypoint

The ENTRYPOINT is used in combination with the original script from the Couchbase Server image. Let’s go line-by-line to understand how it works.

Initialize Couchbase Server

# Monitor mode (used to attach into couchbase entrypoint)
set -m
# Send it to background
/entrypoint.sh couchbase-server &

First, we use set -m to enable job control and process running in the background (like the original ENTRYPOINT) run in a separate process group. This option is turned off by default in non-interactive mode, like scripts.

Util Functions

# Check if couchbase server is up
check_db() {
 curl --silent http://127.0.0.1:8091/pools > /dev/null
 echo $?
}

This function is used to check when Couchbase Server starts answering HTTP calls.

# Variable used in echo
i=1
# Echo with
numbered_echo() {
echo "[$i] $@"
i=`expr $i + 1`
}

This is just a util function. Add a number before any echo in the script to count the steps taken automatically.

# Parse JSON and get nodes from the cluster
read_nodes() {
cmd="import sys,json;"
cmd="${cmd} print(','.join([node['otpNode']"
cmd="${cmd} for node in json.load(sys.stdin)['nodes']"
cmd="${cmd} ]))"
python -c "${cmd}"
}

In order to parse the output of the nodes in Couchbase Server API, I’m using a function which runs ython to read STDIN, transform it to JSON and the Couchbase nodes. This is used for rebalancing.

Configure the Node

# Wait until it's ready
until [[ $(check_db) = 0 ]]; do
>&2 numbered_echo "Waiting for Couchbase Server to be available"
sleep 1
done

echo "# Couchbase Server Online"
echo "# Starting setup process"

The first step is to wait until the server is ready, then using the function numbered_echo you can see how long it took for Couchbase Server to have the API calls available.

HOSTNAME=`hostname -f`

# Reset steps
i=1

Then we set a variable HOSTNAME to be used in all the API calls we do and we also reset the counter from numbered_echo by setting it to 1.

numbered_echo "Initialize the node"
curl --silent "http://${HOSTNAME}:8091/nodes/self/controller/settings" \
-d path="/opt/couchbase/var/lib/couchbase/data" \
-d index_path="/opt/couchbase/var/lib/couchbase/data"

numbered_echo "Setting hostname"
curl --silent "http://${HOSTNAME}:8091/node/controller/rename" \
-d hostname=${HOSTNAME}

The first thing to do is to set up disk storage configuration and then we set the hostname.

Joining a Cluster

if [[ ${CLUSTER_HOST} ]];then
numbered_echo "Joining cluster ${CLUSTER_HOST}"
curl --silent -u ${USERNAME}:${PASSWORD} \
"http://${CLUSTER_HOST}:8091/controller/addNode" \
-d hostname="${HOSTNAME}" \
-d user="${USERNAME}" \
-d password="${PASSWORD}" \
-d services="${SERVICES}" > /dev/null

If CLUSTER_HOST is set, the script will try to add the current container to the cluster.

if [[ ${CLUSTER_REBALANCE} ]]; then
# "Unexpected server error without the sleep 2
sleep 2
numbered_echo "Retrieving nodes"
known_nodes=$(
curl --silent -u ${USERNAME}:${PASSWORD} http://${CLUSTER_HOST}:8091/pools/default | read_nodes
)

numbered_echo "Rebalancing cluster"
curl -u ${USERNAME}:${PASSWORD} \
"http://${CLUSTER_HOST}:8091/controller/rebalance" \
-d knownNodes="${known_nodes}"
fi

else

After adding the node into the cluster, the script can also check for the variable CLUSTER_REBALANCE to see if it needs to rebalance the cluster automatically. This is where we use the Python function to read the nodes from /pools/default endpoint.

Not Joining a Cluster

numbered_echo "Setting up memory"
curl --silent "http://${HOSTNAME}:8091/pools/default" \
-d memoryQuota=${MEMORY_QUOTA} \
-d indexMemoryQuota=${INDEX_MEMORY_QUOTA} \
-d ftsMemoryQuota=${FTS_MEMORY_QUOTA}

Memory settings for the services.

numbered_echo "Setting up services"
curl --silent "http://${HOSTNAME}:8091/node/controller/setupServices" \
-d services="${SERVICES}"

Services to be used by the node.

numbered_echo "Setting up user credentials"
curl --silent "http://${HOSTNAME}:8091/settings/web" \
-d port=8091 \
-d username=${USERNAME} \
-d password=${PASSWORD} > /dev/null

fi

Set up the credentials for the node.

Finalize

# Attach to couchbase entrypoint
numbered_echo "Attaching to couchbase-server entrypoint"
fg 1

To end the script, we attach it to the original ENTRYPOINT.

Example

To demonstrate how to use it, I will be using the image registered in Docker Hub with the code here.

Single Node

docker run -ti --name couchbase-server-nosetup \
-h node1.cluster \
-p 8091-8093:8091-8093 \
-p 11210:11210 \
-p 4369:4369 \
-p 21100-21299:21100-21299 \
rugolini/couchbase-server-nosetup

This runs a single node using the minimum required memory and the default credentials (Administrator/password) registered in the image. All the network ports Couchbase Server uses are exposed as well.

docker run -ti --name couchbase-server-nosetup \
-h node1.cluster \
-p 8091-8093:8091-8093 \
-p 11210:11210 \
-p 4369:4369 \
-e MEMORY_QUOTA=512 \
-e INDEX_MEMORY_QUOTA=512 \
-e FTS_MEMORY_QUOTA=512 \
-e USERNAME=admin \
-e PASSWORD=adminadmin \
-p 21100-21299:21100-21299 \
rugolini/couchbase-server-nosetup

The command above plays a little with the environment variables available in the Dockerfile.

Cluster

In this example, we will connect three nodes in the cluster.

docker network create couchbase

We must first create a network Couchbase where we will connect all nodes.

docker run -ti --name node1.cluster \
-p 8091-8093:8091-8093 \
-p 11210:11210 \
-p 4369:4369 \
-p 21100-21299:21100-21299 \
-h node1.cluster \
--network=couchbase \
rugolini/couchbase-server-nosetup

Then we create the first node.

docker run -ti --name node2.cluster \
--network=couchbase \
-h node2.cluster \
-e CLUSTER_HOST=node1.cluster \
-e CLUSTER_REBALANCE=true \
rugolini/couchbase-server-nosetup

Since all the network ports are exposed in the first node, it’s not necessary to expose them here.

Attention to the detail that CLUSTER_HOST is set to node1.cluster which is the hostname of the first node and CLUSTER_REBALANCE is also set to true. Once the node is added to the cluster, it will rebalance automatically.

docker run -ti --name node3.cluster \
--network=couchbase \
-h node3.cluster \
-e CLUSTER_HOST=node1.cluster \
rugolini/couchbase-server-nosetup

The node3 is also added to the cluster, but since CLUSTER_REBALANCE wasn’t set, it will require manual rebalance of the cluster for it to become available.

Learn how the world’s first NoSQL Engagement Database delivers unparalleled performance at any scale for customer experience innovation that never ends.

Topics:
docker ,couchbase ,database ,tutorial

Published at DZone with permission of Laura Czajkowski, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}