Seven Story Rabbit Hole

Sometimes awesome things happen in deep rabbit holes. Or not.

   images

An Example of Using NSQ From Go

NSQ is a message queue, similar to RabbitMQ. I decided I’d give it a whirl.

Install Nsq

1
2
3
$ wget https://s3.amazonaws.com/bitly-downloads/nsq/nsq-0.2.31.darwin-amd64.go1.3.1.tar.gz
$ tar xvfz nsq-0.2.31.darwin-amd64.go1.3.1.tar.gz
$ sudo mv nsq-0.2.31.darwin-amd64.go1.3.1/bin/* /usr/local/bin

Launch Nsq

1
2
3
$ nsqlookupd & 
$ nsqd --lookupd-tcp-address=127.0.0.1:4160 &
$ nsqadmin --lookupd-http-address=127.0.0.1:4161 &

Get Go client library

1
$ go get -u -v github.com/bitly/go-nsq

Create a producer

Add the following code to main.go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import (
  "log"
  "github.com/bitly/go-nsq"
)

func main() {
  config := nsq.NewConfig()
  w, _ := nsq.NewProducer("127.0.0.1:4150", config)

  err := w.Publish("write_test", []byte("test"))
  if err != nil {
      log.Panic("Could not connect")
  }

  w.Stop()
}

and then run it with:

1
$ go run main.go

If you go to your NSQAdmin at http://localhost:4171, you should see a single message in the write_test topic.

NSQAdmin

Create a consumer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
  "log"
  "sync"

  "github.com/bitly/go-nsq"
)

func main() {

  wg := &sync.WaitGroup{}
  wg.Add(1)

  config := nsq.NewConfig()
  q, _ := nsq.NewConsumer("write_test", "ch", config)
  q.AddHandler(nsq.HandlerFunc(func(message *nsq.Message) error {
      log.Printf("Got a message: %v", message)
      wg.Done()
      return nil
  }))
  err := q.ConnectToNSQD("127.0.0.1:4150")
  if err != nil {
      log.Panic("Could not connect")
  }
  wg.Wait()

}

and then run it with:

1
$ go run main.go

You should see output:

1
2
2014/11/12 08:37:29 INF    1 [write_test/ch] (127.0.0.1:4150) connecting to nsqd
2014/11/12 08:37:29 Got a message: &{[48 55 54 52 48 57 51 56 50 100 50 56 101 48 48 55] [116 101 115 116] 1415810020571836511 2 0xc208042118 0 0}

Congratulations! You just pushed a message through NSQ.

Enhanced consumer: use NSQLookupd

The above example hardcoded the ip of nsqd into the consumer code, which is not a best practice. A better way to go about it is to point the consumer at nsqlookupd, which will transparently connect to the appropriate nsqd that happens to be publishing that topic.

In our example, we only have a single nsqd, so it’s an extraneous lookup. But it’s good to get into the right habits early, especially if you are a habitual copy/paster.

The consumer example only needs a one-line change to get this enhancement:

1
err := q.ConnectToNSQLookupd("127.0.0.1:4161")

Which will connect to the HTTP port of nsqlookupd.

CoreOS With Nvidia CUDA GPU Drivers

This will walk you through installing the Nvidia GPU kernel module and CUDA drivers on a docker container running inside of CoreOS.

architecture diagram

Launch CoreOS on an AWS GPU instance

  • Launch a new EC2 instance

  • Under “Community AMIs”, search for ami-f669f29e (CoreOS stable 494.4.0 (HVM))

  • Select the GPU instances: g2.2xlarge

  • Increase root EBS store from 8 GB –> 20 GB to give yourself some breathing room

ssh into CoreOS instance

Find the public ip of the EC2 instance launched above, and ssh into it:

1
$ ssh -A core@ec2-54-80-24-46.compute-1.amazonaws.com

Run Ubuntu 14 docker container in privileged mode

1
$ sudo docker run --privileged=true -i -t ubuntu:14.04 /bin/bash

After the above command, you should be inside a root shell in your docker container. The rest of the steps will assume this.

Install build tools + other required packages

In order to match the version of gcc that was used to build the CoreOS kernel. (gcc 4.7)

1
2
# apt-get update
# apt-get install gcc-4.7 g++-4.7 wget git make dpkg-dev

Set gcc 4.7 as default

1
2
3
# update-alternatives --remove gcc /usr/bin/gcc-4.8
# update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.7 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.7
# update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 40 --slave /usr/bin/g++ g++ /usr/bin/g++-4.8

Verify

1
# update-alternatives --config gcc

It should list gcc 4.7 with an asterisk next to it:

1
* 0            /usr/bin/gcc-4.7   60        auto mode

Prepare CoreOS kernel source

Clone CoreOS kernel repository

1
2
3
$ mkdir -p /usr/src/kernels
$ cd /usr/src/kernels
$ git clone https://github.com/coreos/linux.git

Find CoreOS kernel version

1
2
# uname -a
Linux ip-10-11-167-200.ec2.internal 3.17.2+ #2 SMP Tue Nov 4 04:15:48 UTC 2014 x86_64 Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz GenuineIntel GNU/Linux

The CoreOS kernel version is 3.17.2

Switch correct branch for this kernel version

1
2
# cd linux
# git checkout remotes/origin/coreos/v3.17.2

Create kernel configuration file

1
# zcat /proc/config.gz > /usr/src/kernels/linux/.config

Prepare kernel source for building modules

1
# make modules_prepare

Now you should be ready to install the nvidia driver.

Hack the kernel version

In order to avoid nvidia: version magic errors, the following hack is required:

1
# sed -i -e 's/3.17.2/3.17.2+/' include/generated/utsrelease.h

I’ve posted to the CoreOS Group to ask why this hack is needed.

Install nvidia driver

Download

1
2
3
# mkdir -p /opt/nvidia
# cd /opt/nvidia
# wget http://developer.download.nvidia.com/compute/cuda/6_5/rel/installers/cuda_6.5.14_linux_64.run

Unpack

1
2
3
# chmod +x cuda_6.5.14_linux_64.run
# mkdir nvidia_installers
# ./cuda_6.5.14_linux_64.run -extract=`pwd`/nvidia_installers

Install

1
2
# cd nvidia_installers
# ./NVIDIA-Linux-x86_64-340.29.run --kernel-source-path=/usr/src/kernels/linux/

Installer Questions

  • Install NVidia’s 32-bit compatibility libraries? YES
  • Would you like to run nvidia-xconfig? NO

If everything worked, you should see:

nvidia drivers installed

your /var/log/nvidia-installer.log should look something like this

Load nvidia kernel module

1
# modprobe nvidia

No errors should be returned. Verify it’s loaded by running:

1
# lsmod | grep -i nvidia

and you should see:

1
2
nvidia              10533711  0
i2c_core               41189  2 nvidia,i2c_piix4

Install CUDA

In order to fully verify that the kernel module is working correctly, install the CUDA drivers + library and run a device query.

To install CUDA:

1
2
# ./cuda-linux64-rel-6.5.14-18749181.run
# ./cuda-samples-linux-6.5.14-18745345.run

Verify CUDA

1
2
3
# cd /usr/local/cuda/samples/1_Utilities/deviceQuery
# make
# ./deviceQuery   

You should see the following output:

1
2
deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 6.5, CUDA Runtime Version = 6.5, NumDevs = 1, Device0 = GRID K520
Result = PASS

Congratulations! You now have a docker container running under CoreOS that can access the GPU.

Appendix: Expose GPU to other docker containers

If you need other docker containers on this CoreOS instance to be able to access the GPU, you can do the following steps.

Exit docker container

1
# exit

You should be back to your CoreOS shell.

Add nvidia device nodes

1
2
3
$ wget https://gist.githubusercontent.com/tleyden/74f593a0beea300de08c/raw/95ed93c5751a989e58153db6f88c35515b7af120/nvidia_devices.sh
$ chmod +x nvidia_devices.sh
$ sudo ./nvidia_devices.sh

Verify device nodes

1
2
3
4
$ ls -alh /dev | grep -i nvidia
crw-rw-rw-  1 root root  251,   0 Nov  5 16:37 nvidia-uvm
crw-rw-rw-  1 root root  195,   0 Nov  5 16:37 nvidia0
crw-rw-rw-  1 root root  195, 255 Nov  5 16:37 nvidiactl

Launch docker containers

When you launch other docker containers on the same CoreOS instance, to allow them to access the GPU device you will need to add the following arguments:

1
$ sudo docker run -ti --device /dev/nvidia0:/dev/nvidia0 --device /dev/nvidiactl:/dev/nvidiactl --device /dev/nvidia-uvm:/dev/nvidia-uvm tleyden5iwx/ubuntu-cuda /bin/bash

References

Goroutines vs Threads

Here are some of the advantages of Goroutines over threads:

  • You can run more goroutines on a typical system than you can threads.
  • Goroutines have growable segmented stacks.
  • Goroutines have a faster startup time than threads.
  • Goroutines come with built-in primitives to communicate safely between themselves (channels).
  • Goroutines allow you to avoid having to resort to mutex locking when sharing data structures.
  • Goroutines are multiplexed onto a small number of OS threads, rather than a 1:1 mapping.
  • You can write massively concurrent servers withouth having to resort to evented programming.

You can run more of them

On Java you can run 1000’s or tens of 1000’s threads. On Go you can run hundreds of thousands or millions of goroutines.

Java threads map directly to OS threads, and are relatively heavyweight. Part of the reason they are heavyweight is their rather large fixed stack size. This caps the number of them you can run in a single VM due to the increasing memory overhead.

Go OTOH has a segmented stack that grows as needed. They are “Green threads”, which means the Go runtime does the scheduling, not the OS. The runtime multiplexes the goroutines onto real OS threads, the number of which is controlled by GOMAXPROCS. Typically you’ll want to set this to the number of cores on your system, to maximize potential parellelism.

They let you avoid locking hell

One of the biggest drawback of threaded programming is the complexity and brittleness of many codebases that use threads to achieve high concurrency. There can be latent deadlocks and race conditions, and it can become near impossible to reason about the code.

Go OTOH gives you primitives that allow you to avoid locking completely. The mantra is don’t communicate by sharing memory, share memory by communicating. In other words, if two goroutines need to share data, they can do so safely over a channel. Go handles all of the synchronization for you, and it’s much harder to run into things like deadlocks.

No callback spaghetti, either

There are other approaches to achieving high concurrency with a small number of threads. Python Twisted was one of the early ones that got a lot of attention. Node.js is currently the most prominent evented frameworks out there.

The problem with these evented frameworks is that the code complexity is also high, and difficult to reason about. Rather than “straightline” coding, the programmer is forced to chain callbacks, which gets interleaved with error handling. While refactoring can help tame some of the mental load, it’s still an issue.

Running Caffe on AWS GPU Instance via Docker

This is a tutorial to help you get the Caffe deep learning framework up and running on a GPU-powered AWS instance running inside a Docker container.

Architecture

architecture diagram

Setup host

Before you can start your docker container, you will need to go deeper down the rabbit hole.

You’ll first need to complete the steps here:

Setting up an Ubuntu 14.04 box running on a GPU-enabled AWS instance

After you’re done, you’ll end up with a host OS with the following properties:

  • A GPU enabled AWS instance running Ubuntu 14.04
  • Nvidia kernel module
  • Nvidia device drivers
  • CUDA 6.5 installed and verified

Install Docker

Once your host OS is setup, you’re ready to install docker. (version 1.3 at the time of this writing)

Setup the key for the docker repo:

1
$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9

Add the docker repo:

1
2
$ sudo sh -c "echo deb https://get.docker.com/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
$ sudo apt-get update

Install docker:

1
$ sudo apt-get install lxc-docker

Run the docker container

Find your nvidia devices

1
$ ls -la /dev | grep nvidia

You should see:

1
2
3
crw-rw-rw-  1 root root    195,   0 Oct 25 19:37 nvidia0
crw-rw-rw-  1 root root    195, 255 Oct 25 19:37 nvidiactl
crw-rw-rw-  1 root root    251,   0 Oct 25 19:37 nvidia-uvm

You’ll have to adapt the DOCKER_NVIDIA_DEVICES variable below to match your particular devices.

Here’s how to start the docker container:

1
2
$ DOCKER_NVIDIA_DEVICES="--device /dev/nvidia0:/dev/nvidia0 --device /dev/nvidiactl:/dev/nvidiactl --device /dev/nvidia-uvm:/dev/nvidia-uvm"
$ sudo docker run -ti $DOCKER_NVIDIA_DEVICES tleyden5iwx/caffe-gpu-master /bin/bash

It’s a large docker image, so this might take a few minutes, depending on your network connection.

Run caffe test suite

After the above docker run command completes, your shell will now be inside a docker container that has Caffe installed.

You’ll want run the Caffe test suite and make sure it passes. This will validate your environment, including your GPU drivers.

1
2
$ cd /opt/caffe
$ make test && make runtest

Expected Result: ... [ PASSED ] 838 tests.

Run the MNIST LeNet example

A more comprehensive way to verify your environment is to train the MNIST LeNet example:

1
2
3
4
5
$ cd /opt/caffe/data/mnist
$ ./get_mnist.sh
$ cd /opt/caffe
$ ./examples/mnist/create_mnist.sh
$ ./examples/mnist/train_lenet.sh

This will take a few minutes.

Expected output:

1
2
3
4
5
libdc1394 error: Failed to initialize libdc1394 
I1018 17:02:23.552733    66 caffe.cpp:90] Starting Optimization 
I1018 17:02:23.553583    66 solver.cpp:32] Initializing solver from parameters:
... lots of output ...
I1018 17:17:58.684598    66 caffe.cpp:102] Optimization Done.

Congratulations, you’ve got GPU-powered Caffe running in a docker container — celebrate with a cup of Philz!

References

Docker on AWS GPU Ubuntu 14.04 / CUDA 6.5

Architecture

After going through the steps in this blog post, you’ll end up with this:

architecture diagram

Setup host

Before you can start your docker container, you will need to go deeper down the rabbit hole.

You’ll first need to complete the steps here:

Setting up an Ubuntu 14.04 box running on a GPU-enabled AWS instance

After you’re done, you’ll end up with a host OS with the following properties:

  • A GPU enabled AWS instance running Ubuntu 14.04
  • Nvidia kernel module
  • Nvidia device drivers
  • CUDA 6.5 installed and verified

Install Docker

Once your host OS is setup, you’re ready to install docker. The latest instructions are avaialable on the Docker website. Currently for Ubuntu 14.0.4 you need to:

1
2
$ sudo apt-get update && sudo apt-get install curl
$ curl -sSL https://get.docker.com/ | sh

As the post-install message suggests, enable docker for non-root users:

1
$ sudo usermod -aG docker ubuntu

Verify correct install via:

1
$ sudo docker run hello-world

Mount GPU devices

Mount

1
2
$ cd /usr/local/cuda/samples/1_Utilities/deviceQuery
$ ./deviceQuery

You should see something like this:

1
2
3
4
5
6
7
8
9
10
11
12
./deviceQuery Starting...

 CUDA Device Query (Runtime API) version (CUDART static linking)

Detected 1 CUDA Capable device(s)

Device 0: "GRID K520"
  CUDA Driver Version / Runtime Version          6.5 / 6.5
  ... snip ...

deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 6.5, CUDA Runtime Version = 6.5, NumDevs = 1, Device0 = GRID K520
Result = PASS

Verify: Find all your nvidia devices

1
$ ls -la /dev | grep nvidia

You should see:

1
2
3
crw-rw-rw-  1 root root    195,   0 Oct 25 19:37 nvidia0
crw-rw-rw-  1 root root    195, 255 Oct 25 19:37 nvidiactl
crw-rw-rw-  1 root root    251,   0 Oct 25 19:37 nvidia-uvm

Run GPU enabled docker image

Launch docker container

The easiest way to get going is to use this pre-built docker image that has the cuda drivers pre-installed. Or if you want to build your own, the accompanying dockerfile will be a useful starting point. (Update: Nvidia has released an official docker container which you should probably use, but I haven’t tried yet as of the time of this writing. Please post a comment if you get this to work)

You’ll have to adapt the DOCKER_NVIDIA_DEVICES variable below to match your particular devices.

To start the docker container, run:

1
2
$ DOCKER_NVIDIA_DEVICES="--device /dev/nvidia0:/dev/nvidia0 --device /dev/nvidiactl:/dev/nvidiactl --device /dev/nvidia-uvm:/dev/nvidia-uvm"
$ sudo docker run -ti $DOCKER_NVIDIA_DEVICES tleyden5iwx/ubuntu-cuda /bin/bash

After running the above command, you should be at a shell inside your docker container:

1
root@1149788c731c:# 

Verify CUDA access from inside the docker container

Install CUDA samples

1
2
$ cd /opt/nvidia_installers
$ ./cuda-samples-linux-6.5.14-18745345.run -noprompt -cudaprefix=/usr/local/cuda-6.5/

Build deviceQuery sample

1
2
3
$ cd /usr/local/cuda/samples/1_Utilities/deviceQuery
$ make
$ ./deviceQuery   

You should see the following output

1
2
deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 6.5, CUDA Runtime Version = 6.5, NumDevs = 1, Device0 = GRID K520
Result = PASS

References

CUDA 6.5 on AWS GPU Instance Running Ubuntu 14.04

Using a pre-built public AMI

Based on the instructions in this blog post, I’ve created an AMI and shared it publicly. So the easiest thing to do is just use that pre-built AMI:

  • Image: ami-2cbf3e44 for US-East or ami-c38babf3 for US-West (Ubuntu Server 14.04 LTS (HVM) – CUDA 6.5)
  • Instance type: g2.2xlarge (if you skip this step, you won’t have an nvidia device)
  • Storage: Use at least 8 GB, 20+ GB recommended

If you use the pre-built AMI, then you can skip down to the Verify CUDA is correctly installed section, since all of the rest of the steps are “baked in” to the AMI.

Note regarding AMI regions: the AMI only currently works in the US-East and US-West regions. If you need it added to another region, please post a comment below

Building from scratch

Or if you prefer to build your own instance from scratch, keep reading.

Create a new EC2 instance:

  • Image: ami-9eaa1cf6 (Ubuntu Server 14.04 LTS (HVM), SSD Volume Type)
  • Instance type: g2.2xlarge
  • Storage: Use at least 8 GB, 20+ GB recommended

Install build-essential:

1
$ apt-get update && apt-get install build-essential

Get CUDA installer:

1
$ wget http://developer.download.nvidia.com/compute/cuda/6_5/rel/installers/cuda_6.5.14_linux_64.run

Extract CUDA installer:

1
2
3
$ chmod +x cuda_6.5.14_linux_64.run
$ mkdir nvidia_installers
$ ./cuda_6.5.14_linux_64.run -extract=`pwd`/nvidia_installers

Run Nvidia driver installer:

1
2
$ cd nvidia_installers
$ ./NVIDIA-Linux-x86_64-340.29.run

At this point it will popup an 8-bit UI that will ask you to accept a license agreement, and then start installing.

screenshot

At this point, I got an error:

1
2
3
4
5
6
7
Unable to load the kernel module 'nvidia.ko'.  This happens most frequently when this kernel module was built against the wrong or
         improperly configured kernel sources, with a version of gcc that differs from the one used to build the target kernel, or if a driver
         such as rivafb, nvidiafb, or nouveau is present and prevents the NVIDIA kernel module from obtaining ownership of the NVIDIA graphics
         device(s), or no NVIDIA GPU installed in this system is supported by this NVIDIA Linux graphics driver release.

         Please see the log entries 'Kernel module load error' and 'Kernel messages' at the end of the file '/var/log/nvidia-installer.log'
         for more information.

After reading this forum post I installed:

1
$ sudo apt-get install linux-image-extra-virtual

When it prompted me what do to about the grub changes, I chose “choose package maintainers version”.

Reboot:

1
$ reboot

Disable nouveau

At this point you need to disable nouveau, since it conflicts with the nvidia kernel module.

Open a new file

1
$ vi /etc/modprobe.d/blacklist-nouveau.conf

and add these lines to it

1
2
3
4
5
blacklist nouveau
blacklist lbm-nouveau
options nouveau modeset=0
alias nouveau off
alias lbm-nouveau off

and then save the file.

Disable the Kernel Nouveau:

1
$ echo options nouveau modeset=0 | sudo tee -a /etc/modprobe.d/nouveau-kms.conf

Reboot:

1
2
$ update-initramfs -u
$ reboot

One more try — this time it works

Get Kernel source:

1
2
$ apt-get install linux-source
$ apt-get install linux-headers-3.13.0-37-generic

Rerun Nvidia driver installer:

1
2
$ cd nvidia_installers
$ ./NVIDIA-Linux-x86_64-340.29.run

Load nvidia kernel module:

1
$ modprobe nvidia

Run CUDA + samples installer:

1
2
$ ./cuda-linux64-rel-6.5.14-18749181.run
$ ./cuda-samples-linux-6.5.14-18745345.run

Verify CUDA is correctly installed

1
2
3
$ cd /usr/local/cuda/samples/1_Utilities/deviceQuery
$ make
$ ./deviceQuery   

You should see the following output:

1
2
deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 6.5, CUDA Runtime Version = 6.5, NumDevs = 1, Device0 = GRID K520
Result = PASS

References

Debugging Into Android Source

Debugging into the core Android source code can be useful. Here’s how to do it in Android Studio 0.8.2.

Starting out, if we hit a breakpoint where we have a sqlite database object:

screenshot

And if you step in, you get this, which isn’t very useful:

screenshot

To fix that, go to Android SDK, find the API level you are using, and check the Sources for Android SDK box.

screenshot

You must restart Android Studio at this point

Did you restart Android Studio? Now re-run your app in the debugger, and when you try to step into the database.execSQL() method, you should see this:

screenshot

It worked! Now you can debug into any Android code.

Running Couchbase Sync Gateway on Google Compute Engine

First, a quick refresh of what Couchbase Sync Gateway actually is.

So here’s a birds-eye-view of the Couchbase Mobile architecture:

diagram

Sync Gateway allows Couchbase Lite mobile apps to sync data between each other and the Couchbase Server running on the backend.

This blog post will walk you through how to run Sync Gateway in a Docker container on Google Compute Engine.

Create GCE instance and ssh in

Follow the instructions on Running Docker on Google Compute Engine.

At this point you should be ssh’d into your GCE instance

Create a configuration JSON

Here’s a sample example JSON configuration for Sync Gateway which uses walrus as it’s backing store, rather than Couchbase Server. Later we will swap in Couchbase Server as a backing store.

Run Sync Gateway docker container

1
gce:~$ sudo docker run -d -name sg -p 4984:4984 -p 4985:4985 tleyden5iwx/couchbase-sync-gateway sync_gateway "https://gist.githubusercontent.com/tleyden/d97d985eb1e0725e858e/raw"

This will return a container id, eg 8ffb83fd1f.

Check the logs to make sure there are no serious errors in the logs:

1
gce:~$ sudo docker logs 8ffb83fd1f

You should see something along the lines of:

1
2
3
4
5
6
02:23:58.905587 Enabling logging: [REST]
02:23:58.905818 ==== Couchbase Sync Gateway/1.00 (unofficial) ====
02:23:58.905863 Opening db /sync_gateway as bucket "sync_gateway", pool "default", server <walrus:/opt/sync_gateway/data>
02:23:58.905964 Opening Walrus database sync_gateway on <walrus:/opt/sync_gateway/data>
02:23:58.909659 Starting admin server on :4985
02:23:58.913260 Starting server on :4984 ...

Expose API port 4984 via Firewall rule

On your workstation with the gcloud tool installed, run:

1
$ gcloud compute firewalls create sg-4984 --allow tcp:4984

Verify that it’s running

Find out external ip address of instance

On your workstation with the gcloud tool installed, run:

1
2
3
$ gcloud compute instances list
name     status  zone          machineType internalIP   externalIP
couchbse RUNNING us-central1-a f1-micro    10.240.74.44 142.222.178.49

Your external ip is listed under the externalIP column, eg 142.222.178.49 in this example.

Run curl request

On your workstation, replace the ip below with your own ip, and run:

1
$ curl http://142.222.178.49:4984

You should get a response like:

1
{"couchdb":"Welcome","vendor":{"name":"Couchbase Sync Gateway","version":1},"version":"Couchbase Sync Gateway/1.00 (unofficial)"}

Re-run it with Couchbase Server backing store

OK, so we’ve gotten it working with walrus. But have you looked at the walrus website lately? One click and it’s pretty obvious that this thing is not exactly meant to be a scalable production ready backend, nor has it ever claimed to be.

Let’s dump walrus for now and use Couchbase Server from this point onwards.

Start Couchbase Server

Before moving on, you will need to go through the instructions in Running Couchbase Server on GCE in order to get a Couchbase Server instance running.

Stop Sync Gateway

Run this command to stop the Sync Gateway container and completely remove it, using the same container id you used earlier:

1
gce:~$ sudo docker stop 8ffb83fd1f && sudo docker rm 8ffb83fd1f

Update config

Copy this example JSON configuration, which expects a Couchbase Server running on http://172.17.0.2:8091, and update it with the ip address of the docker instance where your Couchbase Server is running. To get this ip address, follow the these instructions in the “Find the Docker instance IP address” section.

Now upload your modified JSON configuration to a website that is publicly accessible, for example in a Github Gist.

Run Sync Gateway

Run Sync Gateway again, this time using Couchbase Server as a backing store this time.

Replace http://yourserver.co/yourconfig.json with the URL where you’ve uploaded your JSON configuration from the previous step.

1
gce:~$ sudo docker run -d -name sg -p 4984:4984 -p 4985:4985 tleyden5iwx/couchbase-sync-gateway sync_gateway "http://yourserver.co/yourconfig.json"

This will return a container id, eg 9ffb83fd1f. Again, check the logs to make sure there are no serious errors in the logs:

1
gce:~$ sudo docker logs 9ffb83fd1f

You should see something along the lines of:

1
2
... 
02:23:58.913260 Starting server on :4984 ...

with no errors.

Verify it’s working

Save a document via curl

The easiest way to add a document is via the Admin port, since there is no authentication to worry about. Since we haven’t added a firewall rule to expose the admin port (4985), (and doing so without tight filtering would be a major security hole), the following command to create a new document must be run on the GCE instance.

1
gce:~$ curl -H "Content-Type: application/json" -d '{"such":"json"}' http://localhost:4985/sync_gateway/

If it worked, you should see a response like:

1
{"id":"3cbfbe43e76b7eb5c4c221a78b2cf0cc","ok":true,"rev":"1-cd809becc169215072fd567eebd8b8de"}

View document on Couchbase Server

To verify the document was successfully stored on Couchbase Server, you’ll need to login to the Couchbase Server Web Admin UI. There are instructions here on how to do that.

From there, navigate to Data Buckets / default / Documents, and you should see:

screenshot

Click on the document that has a UUID (eg, “29f8d7..” in the screenshot above), and you should see the document’s contents:

screenshot

The _sync metadata field is used internally by the Sync Gateway and can be ignored. The actual doc contents are towards the end of the file: .."such":"json"}

Running a Couchbase Cluster on Google Compute Engine

The easiest way to run Couchbase cluster on Google Compute Engine is to run all of the nodes in Docker containers.

Create GCE instance and ssh in

Follow the instructions on Running Docker on Google Compute Engine.

At this point you should be ssh’d into your GCE instance

Increase max number of files limit

If you try to run Couchbase Server at this point, you will get this warning because the file ulimit is too low.

Here’s how to fix it:

  • Edit /etc/default/docker
  • Add a new line in the file with:
1
ulimit -n 262144
  • Restart the GCE instance in the GCE web admin by going to Compute Engine / VM Instances / and hitting the “Reboot” button.

Note: in theory it should be possible to just restart docker via sudo service docker restart, however this didn’t work for me when I tried it, so I ended up restarting the whole GCE instance

Start Couchbase Server

1
gce:~$ sudo docker run -d -name cb1 -p 8091:8091 -p 8092:8092 -p 11210:11210 -p 11211:11211 ncolomer/couchbase

Verify it’s running

Find the Docker instance IP address

On the GCE instance, run:

1
gce:~$ sudo docker inspect -format '{{ .NetworkSettings.IPAddress }}' cb1

This should return an ip address, eg 172.17.0.2

Set it as an environment variable so we can use it in later steps:

1
gce:~$ export CB1_IP=172.17.0.2

Run couchbase-cli

To verify that couchbase server is running, use the couchbase-cli to ask for server info:

1
gce:~$ sudo docker run -rm ncolomer/couchbase couchbase-cli server-info -c ${CB1_IP} -u Administrator -p couchbase

If everything is working correctly, this should return a json response, eg:

1
2
3
4
5
6
7
{
  "availableStorage": {
    "hdd": [
      {
        "path": "/",
  ...
}

Start a 3-node cluster

On the GCE instance, run the following commands:

1
2
gce:~$ sudo docker run -d -name cb2 ncolomer/couchbase couchbase-start ${CB1_IP}
gce:~$ sudo docker run -d -name cb3 ncolomer/couchbase couchbase-start ${CB1_IP}

The nodes cb2 and cb3 will automatically join the cluster via cb1. The cluster needs a rebalance to be fully operational. To do so, run the following command:

1
gce:~$ sudo docker run -rm ncolomer/couchbase couchbase-cli rebalance -c ${CB1_IP} -u Administrator -p couchbase

Connect to admin web UI

The easiest way to manage a Couchbase Server cluster is via the built-in Web Admin UI.

In order to access it, we will need to make some network changes.

Expose port 8091 via firewall rule for your machine

Go to whatismyip.com or equivalent, and find your ip address. Eg, 67.161.66.7

On your workstation with the gcloud tool installed, run:

1
$ gcloud compute firewalls create cb-8091 --allow tcp:8091 --source-ranges 67.161.66.7/32

This will allow your machine, as well any other machine behind your internet router, to connect to the Couchbase Web UI running on GCE.

To increase security, you should use ipv6 and pass your workstation’s ipv6 hostname in the --source-ranges parameter.

Find out external ip address of instance

On your workstation with the gcloud tool installed, run:

1
2
3
$ gcloud compute instances list
name     status  zone          machineType internalIP   externalIP
couchbse RUNNING us-central1-a f1-micro    10.240.74.44 142.222.178.49

Your external ip is listed under the externalIP column, eg 142.222.178.49 in this example.

Go to admin in web browser

Go to http://142.222.178.49:8091 into your web browser (replacing w/ your external ip)

You should see a screen like this:

screenshot

Login with the default credentials:

  • Username: Administrator
  • Password: couchbase

And you should see the Web Admin dashboard:

screenshot

Increase default bucket size

The default bucket size is set to a very low number by default (128M in my case). To increase this:

  • In Web Admin UI, go to Data Buckets / Default / Edit
  • Change Per Node RAM Quota to 1024 MB
  • Hit “Save” button

References