Fast Deployment Using Docker

By Mark Bloomer on

Quick Start

NOTE: This article is confined to installation and operation on a Raspberry Pi 3.

From SD Card image

Size: ~4.5 GB (~29 GB extracted - yikes! There is room for improvement here) Checksum: SHA256 f0f87941482485d4e35dab8ed869c50b

Using Windows

  1. Format the SD Card using SD Formatter (this will erase ALL data)
  2. Download, install and run Win32DiskImager
  3. Select the SD Card device, choose the downloaded .img file and click Write.

It takes about a couple of minutes.

Once complete, insert the SD Card into the Pi slot and plug in a compatible USB camera along with the network cable.

Start the Pi and locate it on your network (How to find your Pi) and then simply navigate to it using your browser:


From Docker image

  1. Download from the Hypriot downloads page and write it to the SD Card as described above and insert it into the Pi.
  2. Start the Pi and locate it on your network (How to find your Pi). Connect to it using a Terminal Emulator (such as PuTTy) and enter the Hypriot image default username/password: pi/raspberry.
  3. Execute the following:
docker \
    run -d --name snack-db \
    -p 27017:27017 \
    -p 28017:28017 \
    -v ~/snack-db/data:/data/db \
    -e AUTH=no \
docker \
    run -d --name snack-web \
    --privileged \
    -p 80:8000 \
    -v snack-web-images:/opt/snack/SnackWatcher/static/images \
    -v ~/snack-web/logs:/opt/snack/SnackWatcher/logs \
    -v /dev/video0:/dev/video0 \
    --link snack-db:snack-db \

NOTE: Docker will start downloading all of the necessary image layers from our public Docker Hub repository to run Snack Watcher on top of. The size is approximately ~1.2 GB so it could take some time. If you encounter the error x509: certificate has expired or is not yet valid, a simple workaround is execute sudo date 113017402015 which will reset the clock.

Once it is complete, the application will be up and running and ready to start Snack Watching!

Simply navigate to it in your browser:


NOTE: Refer to the below Operations section for a more detailed explanation of the Docker commands being executed and all of the scripts to control it.


We have created a few scripts to control the main functions.

Here is how they work:


To build a fresh Docker image of snack-web and snack-db, we invoke the docker build command and supply a name. Simple!

docker build -t snackwatcher/snack-db snack-db
docker build -t snackwatcher/snack-web snack-web


To install snack-db and snack-web, we simply pull them from our Docker Hub repository and it will download the necessary image layers.

docker pull snackwatcher/snack-db
docker pull snackwatcher/snack-web


To start, we simply call the same docker run commands as in the Quick Start section. The one caveat is that snack-db requires that you delete the Mongo DB mongod.lock file from previous runs otherwise it will fail to start.

There are a few options we need to set in order to wire them up correctly. We specify the -d option so that it runs in the background, and then provide a --name to reference it. Then we define the ports that each Docker image will use using the -p option which maps the container port to the local port in the form -p <local_port>:<container_port>. snack-web maps to the default port of 80 so that we don’t need to specify it in the browser. After that, there is the -v option which maps the volumes (or filesystem folders) between the environments. When the container starts, the files on Docker hosted operating system are copied into the container and then written back and persisted for the next container launch. The snack-web-images we treat as a virtual volume since there are multi-use files in that folder (this will likely be changed in a later release). Finally, we use the --link option to expose the snack-db container to the snack-web container so that they can communicate.

sudo rm -f ~/snack-db/data/mongod.lock
docker \
    run -d --name snack-db \
    -p 27017:27017 \
    -p 28017:28017 \
    -v ~/snack-db/data:/data/db \
    -e AUTH=no \
docker \
    run -d --name snack-web \
    --privileged \
    -p 80:8000 \
    -v snack-web-images:/opt/snack/SnackWatcher/static/images \
    -v ~/snack-web/logs:/opt/snack/SnackWatcher/logs \
    -v /dev/video0:/dev/video0 \
    --link snack-db:snack-db \


To stop, we simply remove the running containers (if any) and any related spawned siblings by calling the docker rm command.

docker ps -aq -f ancester=snack-db | xargs -r -I % docker rm -f %
docker ps -aq -f ancester=snack-web | xargs -r -I % docker rm -f %


To reset, we delete both the virtual volume by using the command docker rm and the mapped volume by deleting the folders.

sudo rm -rf ~/snack-db/data
sudo rm -rf ~/snack-web/logs
docker volume rm snack-web-images


To uninstall, we simply call the docker rmi command with the -f option to force destruction of it.

docker rmi -f snackwatcher/snack-db
docker rmi -f snackwatcher/snack-web


Docker enables SnackWatcher to be packaged into distinct containers by running them atop the Docker Daemon with the configured particulars baked in! The daemon exposes and routes the ports between the containers and utilizes aliases to allow them to reference each other where ever they may reside - on a Raspberry Pi or a distributed cluster of daemons.

Building the Dockerfile

There are 2 Dockerfiles used to run the basic functionality of Snack Watcher: snack-web and snack-db


First, we start from a recent version of Fedora (compiled for ARM architecture) as the base.

FROM armv7/armhf-fedora:latest

Then we install the Simple CV layer using the instructions for installing Simple CV on Fedora (nice and simple!).

RUN sudo yum -y install python-SimpleCV

That will take a little while. Once complete, we proceed to install Git.

RUN sudo yum -y install git-all

With those installed, we now move onto Snack Watcher!

Let’s make some working directories…

RUN mkdir /opt/snack
WORKDIR /opt/snack

Followed by cloning SnackWatcher from the Git repository, but only the most recent files, not the entire history. We then set SnackWatcher as the new working directory and reset to a specific commit. It’s explicitly defined so that if we change the version, Docker will know to build a new layer.

RUN git clone --depth 1 -q
WORKDIR /opt/snack/SnackWatcher
RUN git reset --hard 3ef096d793438c6faee3f6db9e56e926455b536f

Now we install the application dependencies. For the purposes of our Docker image, we don’t care about iPython, so we remove it first, then install the rest of the required Python libraries.

RUN sed -i "s/ipython//" requirements.txt
RUN sudo pip install -r requirements.txt

There are a few extra modifications we need to make in order for the application and database to communicate with each other. To facilitate that, we change the connection string to use the snack-db alias instead of the raw IP or device name, because they are not resolvable from within the container - Docker handles the routing for you!

RUN sed -i "s/DB_CONNECT_STRING = .*/DB_CONNECT_STRING = mongodb\:\/\/snack-db\:27017/" configuration/environment.ini

We also set the debugging to false so that we can use the plugged in USB camera.

RUN sed -i "s/DEBUG = .*/DEBUG = False/" configuration/environment.ini

Now it’s just a matter of exposing the port that SnackWatcher will be served on. By default, that’s 8000.


Finally, we want to persist some of the data to the file system that the Docker Daemon is running on. To do this, we define VOLUME’s within the Docker container. In our case, these are the static/images and logs folders.

VOLUME /opt/snack/SnackWatcher/static/images
RUN mkdir logs
VOLUME /opt/snack/SnackWatcher/logs

The final step is setting up the Supervisor which will ensure that SnackWatcher remains up or restarts in the case of a network interruption or other uncontrollable service downtime. The final CMD will be the primary process that runs in the container when it is launched. We specify option -n so that it runs the process in the foreground (otherwise the container will immediately shut down).

RUN sudo pip install supervisor
CMD ["supervisord", "-n", "-c", "deployment/supervisor/snack-web.conf"]


This image is simply built on top of mangoraft/mongodb-arm which is a Mongo DB instance built on the ARM architecture.

FROM mangoraft/mongodb-arm


Fork me on GitHub