Cody Bunch Some Random IT Guy - OpenStack, DevOps, Cloud, Things with vSphere

Packer isn’t exactly a new tool. In fact, I’ve covered using packer to build Vagrant boxes a little while ago. This time around, I’m going to share some notes and the json file I used to get this to build and upload properly to vSphere.

My Build Environment:

I am running these builds from OSX 10.12.3 with:

  • VMware Fusion 8.5.3
  • 0.12.3
  • vSphere 6.5
    • ESXi 6.5a
    • VCSA 6.5

Packer json template.

The entire json I use is here. I have copied the relevant sections below. First, the variables section. You will want to swap these with values specific to your environment. The values I’ve supplied came from the vGhetto lab builder.

    "variables": {
        "vsphere_host": "vcenter65-1.vghetto.local",
        "vsphere_user": "administrator@vghetto.local",
        "vsphere_pass": "VMware1!",
        "vsphere_datacenter": "Datacenter",
        "vsphere_cluster": "\"VSAN-Cluster\"",
        "vsphere_datastore": "virtual_machines",
        "vsphere_network": "\"VM Network\""

Next, post-processors. Here be the magic.


Some highlights:

  • type - tells packer we’re uploading to vsphere
  • keep_input_artifact - setting this to true helps troubleshooting
  • only - tells packer to only run this post-processor for the named builds.
  • the remaining lines - the vSphere specific variables from the prior section.

Note: Only change the variables rather than specifying names directly. Otherwise, OVFTool will get stupid angry about escaping characters.

The Packer to vSphere Build

Once you have all the parts in place, you can run the following command to kick off the packer build that will dump it’s artifacts into vSphere:

packer build -parallel=false ubuntu-14.04.json

Now, the packer command will produce a LOT of output, even without debugging enabled. If you would like to review said output or dump it to a file in case sometehing goes sideways:

time { packer build -parallel=false ubuntu-14.04.json; } 2>&1 | tee -a /tmp/packer.log

This will time how long packer takes to do it’s thing and dumps all output to /tmp/packer.log

When the command finishes you’ll see the following output:

==> ubuntu-14.04.amd64.vmware: Running post-processor: vsphere
    ubuntu-14.04.amd64.vmware (vsphere): Uploading output-ubuntu-14.04.amd64.vmware/packer-ubuntu-14.04.amd64.vmware.vmx to vSphere
Build 'ubuntu-14.04.amd64.vmware' finished.

vSphere client

With that, all should be in working order.

A Simple Terraform on vSphere Build

This post will talk a bit about how to use Terraform to deploy a simple config against vSphere. Simple? Here’s what we’re building:

  • VMs -
    • OpenSUSE 42.2
      • 2 vCPU
      • 8GB Ram
      • 20GB Disk
    • CentOS7
      • 2 vCPU
      • 8GB Ram
      • 20GB Disk

As with prior posts, I am building this on top of a vSphere lab from here. Along with the following:

  • VMware Fusion 8.5.3
  • Terraform 0.8.8
  • vSphere 6.5
    • ESXi 6.5a
    • VCSA 6.5

Defining the Environment

To build our two VM environment, we need to create three files at the root of the directory you plan to build from. These files are:

$ ls -l
-rw-r--r--  1 bunchc  staff  1788 Mar  8 16:02
-rw-r--r--  1 bunchc  staff   172 Mar  8 15:01 terraform.tfvars
-rw-r--r--  1 bunchc  staff   162 Mar  8 15:01

Each of these files has the following use:

  • - defines the infrastructure to build. This includes definitions for VMs, networks, storage, which files to copy where, and then some.
  • - defines any variables to be used in
  • terraform.tfvars - supplies the actual values for the variables

In the following sections we review each file as it pertains to our environment.

Below I have broken out the sections of that are of interest to us. If you are following along, you will want to copy/paste each section into a single file.

This first section tells terraform how to connect to vSphere. You will notice there are no actual values provided. These come from and terraform.tfvars

# Configure the VMware vSphere Provider
provider "vsphere" {
    vsphere_server = "${var.vsphere_vcenter}"
    user = "${var.vsphere_user}"
    password = "${var.vsphere_password}"
    allow_unverified_ssl = true

The second section defines the OpenSUSE VM. We do this by telling Terraform to create a resource, and then providing the type and name of said resource. The only other thing I will call out in this section is the ‘disk’ clause. When using ‘template’ inside the disk clause, you do not need to specify a disk size.

# Build openSUSE
resource "vsphere_virtual_machine" "opensuse-openstack" {
    name   = "opensuse-openstack"
    vcpu   = 2
    memory = 8192
    domain = "vghetto.local"
    datacenter = "${var.vsphere_datacenter}"
    cluster = "${var.vsphere_cluster}"

    # Define the Networking settings for the VM
    network_interface {
        label = "VM Network"
        ipv4_gateway = ""
        ipv4_address = ""
        ipv4_prefix_length = "24"

    dns_servers = ["", ""]

    # Define the Disks and resources. The first disk should include the template.
    disk {
        template = "openSUSE-Leap-42.2-NET-x86_64.vmware"
        datastore = "virtual_machines"
        type ="thin"

    # Define Time Zone
    time_zone = "America/Chicago"

The third section that follows, defines the second VM. You will see it’s a repeat of the first.

# Build CentOS
resource "vsphere_virtual_machine" "centos-openstack" {
    name   = "centos-openstack"
    vcpu   = 2
    memory = 8192
    domain = "vghetto.local"
    datacenter = "${var.vsphere_datacenter}"
    cluster = "${var.vsphere_cluster}"

    # Define the Networking settings for the VM
    network_interface {
        label = "VM Network"
        ipv4_gateway = ""
        ipv4_address = ""
        ipv4_prefix_length = "24"

    dns_servers = ["", ""]

    # Define the Disks and resources. The first disk should include the template.
    disk {
        template = "CentOS-7-x86_64.vmware"
        datastore = "virtual_machines"
        type ="thin"

    # Define Time Zone
    time_zone = "America/Chicago"

Next up in the files we need to make is I’ve provided in wholesale below:

# Variables
variable "vsphere_vcenter" {}
variable "vsphere_user" {}
variable "vsphere_password" {}
variable "vsphere_datacenter" {}
variable "vsphere_cluster" {}

Note: We are only defining things here, not providing them values just yet.


Here’s the good stuff. That is, this is the file that maps values to the variables, and in our case, stores credentials. You will want to add this to .gitignore (or whatever your source control uses):

vsphere_vcenter = ""
vsphere_user = "administrator@vghetto.local"
vsphere_password = "VMware1!"
vsphere_datacenter = "Datacenter"
vsphere_cluster = "VSAN-Cluster"

Yes, yes, I left my creds in. These are, after-all the default creds for the vGhetto autobuilder.

Building the Infrastructure

Now that you have all the config files in place there are two steps left, validate and deploy. Fist, we validate:

terraform plan

If you have everything correct so far, you will see the following:

terraform plan

Neat! Let’s build:

terraform apply

If you glance in vCenter, you will notice the build has indeed kicked off:

vCenter screenshot

Terraform also produces the following output when successful:

terraform build

.screenrc tricks

I’m not a tmux user.

There, I said it. I guess as tmux was becoming the thing to use to have lots of terminals open, I’d moved on to being Admin for a while. Who knows. screen 4lyfe.

With that said, here’s a bit of my screenrc that makes life easier:

# Status bar
hardstatus always # activates window caption
hardstatus string '%{= wk}[ %{k}%H %{k}][%= %{= wk}%?%-Lw%?%{r}(%{r}%n*%f%t%?(%u)%?%{r})%{k}%?%+Lw%?%?%= %{k}][%{b} %Y-%m-%d %{k}%c %{k}]'

# Terminal options
term "xterm"
attrcolor b ".I"

# Turn off startup messaage
startup_message off

# Set the OSX term name to the current window
termcapinfo xterm* 'hs:ts=\\E]2;:fs=\\007:ds=\\E]2;screen\\007'

# In case of ssh disconnect or any weirdness, the screen will auto detach
autodetach on

The first line tells the status bar to always display. The second one, tells screen what this status should looklike. In this case, current user, windows with names, and date/time:

[ bunchc ][ 0$ irssi  (1*$vagrant)  2$ rbac-testing  3-$ docker-01 ][ 2017-02-22 15:35 ]

The next lines tell screen to:

  • Set the term type to xterm for nested ssh
  • Use bright colors for bold items
  • Turn off the boiler plate when starting
  • Set the OSX window title
  • Autodetach if ssh breaks

Getting remote hostnames as window names

This is not so much a screen thing as an ssh thing. First pull down this script somewhere local. For me that’s /home/bunchc/scripts/

Then add these two lines to your .ssh/config:

# Screen prompts to the remote hostname
Host *
    PermitLocalCommand yes
    LocalCommand /home/bunchc/scripts/

Reloading the config from within screen

Now that you’ve got these settings, reload the screenrc file: ctrl-a : source ~/.screenrc


This post comes about after having collected these settings over a while. I’d love to give credit to all the original authors, finding posts from 2007 - 2009… well.

Extended Github Like Service on rPI

The good folks over at Hypriot have a wonderful tutorial on how to run your own GitHub like service. To do this, they use Gogs on a raspian image. A great starting point, but, well, what if you wanted to scale it some?

Yes yes, we’re running on a Raspberry PI, ‘scale’ in this case just means build it a bit more like you’d deploy on real hardware.

Forgiving my ascii, the following depicts what we will build:

|                        |
|      nginx             |
|                        |
|                        |
|      gogs              |
|                        |
|                        |
|     postgres           |
|                        |

This build is involved, so, lets dive in.

Before Starting

To complete the lab as described, you’ll need at least one Raspberry Pi running Hypriot 1.x and a recent version of Docker and docker-compose.

Everything that follows was adapted for rPI, meaning, with some work, could be run on an x86 Docker as well.

What we’re building

In this lab we will build 3 containers:

  • nginx - A reverse proxy that handles incoming requests to our git server
  • gogs - The GoGit service
  • postgres - a SQL backend for gogs.

Ok, maybe not entirely production, but, a few steps closer.

Getting Started

To get started, we’ll make the directory structure. The end result should look similar to this:

$ tree -d
├── gogs
│   ├── custom
│   │   └── conf
│   └── data
├── nginx
│   └── conf
└── postgres
    └── docker-entrypoint-initdb.d

You can create this with the following command:

mkdir gogs-project; cd gogs-project
mkdir -p gogs/custom/conf gogs/data \
    nginx/conf postgres/docker-entrypoint-initdb.d

Next, at the root of the project folder, create a file called ‘env’. This will be the environment file in which we store info about our database.

cat > env <<EOF

Define the hosts in docker-compose.yaml

Next up, we define all of the hosts in a docker-compose.yaml file. I’ll explain each as we get into their respective sections:

  restart: always
  build: ./nginx/
    - "80:80"
    - gogs:gogs

  restart: always
  build: ./gogs/
    - "3000"
    - postgres:postgres
    - ./gogs/data:/data
  command: gogs/gogs web

  restart: always
  image: rotschopf/rpi-postgres
    - ./postgres/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
    - env
    - "5432"

Build the Reverse Proxy

Repeated here, is the nginx section of the docker-compose.yaml file.

  restart: always
  build: ./nginx/
    - "80:80"
    - gogs:gogs
  • restart - This container should always be running. Docker will restart this container if it crashes.
  • build - Specifies a directory where the Dockerfile for this container lives.
  • ports - Tells docker to map an external port to this container
  • links - Creates a link between the containers and creates an /etc/hosts entry for name resolution

You’ll notice we told docker-compose we wanted to build this container rather than recycle one. To do that, you will need to place a Dockerfile into the ./nginx/ folder we created earlier. The Dockerfile should have the following contents:

FROM hypriot/rpi-alpine-scratch:v3.4
RUN apk add --update nginx \
    && rm -rf /var/cache/apk/*

COPY conf/nginx.conf /etc/nginx/nginx.conf
COPY conf/default.conf /etc/nginx/conf.d/default.conf

CMD ["nginx", "-g", "daemon off;"]
  • FROM - sets our base image.
  • RUN - installs nginx and cleans out the apk cache to save space.
  • COPY - these two lines pull in nginx configurations
  • CMD - sets nginx to run when the container gets launched

Finally, we need to provide the configurations specified in the copy commands. The contents of which follow. These should be placed into ./nginx/config/

$ cat nginx/conf/nginx.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/;

events {
    worker_connections  1024;

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        off;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;

This first config provides a very basic setup for nginx, and then pulls additional configuration in using the include line.

$ cat nginx/conf/default.conf
server {

    listen 80;
    charset utf-8;

    location / {
        proxy_pass http://gogs:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;


This file tells nginx to listen on port 80, and to serve all requests to / back to our gogs instance over port 3000.

Let’s look at what we’ve got so far:

$ pwd

$ tree
├── conf
│   ├── default.conf
│   └── nginx.conf
└── Dockerfile

Building the Go Git service

What follows is how we build our Go Git container. A reminder of what this looks like in docker-compose.yaml:

  restart: always
  build: ./gogs/
    - "3000"
    - postgres:postgres
    - ./gogs/data:/data
  command: gogs/gogs web
  • restart - We’d like this running, all the time
  • build - Build our gogs image from the Dockerfile in ./gogs/
  • expose - Tells docker to expose port 3000 on the container
  • links - Ties us in to our database server
  • volumes - Tells docker we want to map ./gogs/data to /data in the container for our repo storage
  • command - launches the gogs web service

Neat, right? Now let’s take a look inside the ./gogs/Dockerfile:

FROM hypriot/rpi-alpine-scratch:v3.4

# Install the packages we need
RUN apk --update add \
    openssl \
    linux-pam-dev \
    build-base \
    coreutils \
    libc6-compat \
    git \
    && wget -O \ \
    && unzip ./ \
    && mkdir -p /gogs/custom/http /gogs/custom/conf \
    && /gogs/gogs cert \
    -ca=true \
    -duration=8760h0m0s \
    -host=git.isa.fuckingsshat.local \
    && mv *.pem /gogs/custom/http/ \
    && rm -f /*.zip \
    && rm -rf /var/cache/apk/*

COPY custom/conf/app.ini /gogs/custom/conf/

CMD ["gogs/gogs" "web"]

Unlike the nginx file, there is a LOT going on here.

  • FROM - Same alpine source image. Tiny, quick, and does what we need.
  • RUN - This is actually a bunch of commands tied together into a single line to reduce the number of Docker build steps. This breaks down as follows:
    • apk –update add - install the required packages
    • wget - pull down the latest gogs binary for pi.
    • unzip - decompress it
    • mkdir - create a folder for our config and ssl certs
    • /gogs/gogs cert - creates the ssl certificates
    • mv *.pem - puts the certificates into the right spot
    • rm - these two clean up our image so we stay small
  • COPY - This pulls our app.ini file into our container
  • EXPOSE - tells docker to expose these ports
  • CMD - launch the gogs web service

Still with me? We have one last file to create, the app.ini file. To do that, we will pull down a generic app.ini from the gogs project and then add our specific details.

First, pull in the file:

$ curl -L \
    > ./gogs/custom/conf/app.ini

Next, find the database section, and provide the data from your env file:

; Either "mysql", "postgres" or "sqlite3", it's your choice
DB_TYPE = postgres
HOST = postgres:5432
NAME = myproject_web
USER = myproject_web
PASSWD = shoov3Phezaimahsh7eb2Tii4ohkah8k
; For "postgres" only, either "disable", "require" or "verify-full"
SSL_MODE = disable
; For "sqlite3" and "tidb", use absolute path when you start as service
PATH = data/gogs.db

That’s it for this section. Which should now look like this:

$ pwd
HypriotOS/armv7: pirate@node-01 in ~/rpi-gogs-docker-alpine/gogs
$ tree
├── custom
│   └── conf
│       └── app.ini
├── data
└── Dockerfile

Setting up Postgres

Unlike the last two, postgres is fairly simple to setup, as instead of building it from scratch, we’re running a community supplied image. Let’s take a look at the postgres section of docker-compose.yaml:

  restart: always
  image: rotschopf/rpi-postgres
    - ./postgres/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
    - env
    - "5432"
  • restart - like our other containers, we want this one to run, all the time.
  • image - specifies the postgres image to use
  • volumes - This is a special volume for our postgres container. The container will run script contained within. You’ll see how we use this next.
  • env_file - turns our env file into environment variables within the container
  • expose - makes port 5432 available for connections

Now, in your ./postgres/docker-entrypoint-initdb.d/ directory, we’re going to place a script that will create our database user and database:

$ cat ./postgres/docker-entrypoint-initdb.d/
#!/bin/env sh
psql -U postgres -c "CREATE USER $DB_USER PASSWORD '$DB_PASS'"

Cool, once you’ve done that, you have finished the prep work. Now we can make the magic!

Make the Magic!

Ok, so, that was a lot of work. With that in place, you can now build and launch the gogs environment:

docker-compose build --no-cache
docker-compose up -d

Once that completes, point a web browser to your raspberry pi on port 80, and enjoy your own github service.


Long post is long. We used docker compose to build two docker images and launch a third. All three of which are tied together to provide a github like service.


Kube Dashboard on Master Node

Putting this here so I don’t forget.

First we need to make it so we can schedule pods to master. So, let’s taint the node (thanks Sam!)

kubectl taint nodes --all dedicated-

Then add this to the kubernetes-dashboard.yaml, replacing master-node for your environment.

      - name: kubernetes-dashboard
*** some stuff ***
      nodeSelector: master-node

Disabling / Enabling OSX Finder Tabs

Here’s to hoping Google picks this up, I couldn’t find it elsewhere:

To tell Finder you don’t want tabs when you open a folder:

$ defaults write FinderSpawnTab -bool false

To put things back to normal:

$ defaults write FinderSpawnTab -bool true

To figure out what a particular setting is:

$ defaults read > ~/before.list

# Make the change

$ defaults read > ~/before.list
$ diff ~/before.list ~/after.list

Seti@home on Raspberry Pi with Kubernetes

In this post we take our Raspberry PI cluster, deploy Kubernetes to it, and then use a deployment set to launch the Boinc client to churn seti@home data.

The cluster

Prep The Cluster

First things first, we need to flash all 8 nodes with the latest hypriot image. We do this using their flash tool, a bash for loop, and some flash card switching:

for i in {1..8}; do flash --hostname node0$i; done

Once you have the cards flashed, install them into your Pi’s and boot them up, we’ve got some more prep to do.

Copy SSH Keys

The first thing to do is enable keybased logins. You’ll be prompted for the password each time. Password: hypriot

for i in {1..8}; do ssh-copy-id pirate@node0$i; done

Run updates

for i in {1..8}; do ssh pirate@node0$i -t 'sudo apt-get update -qq && sudo apt-get upgrade -qqy --force-yes'

Build the cluster

Here is where the fun starts. On each node, you’re going to want to install Kubernetes as described here.

Fire Up BOINC & Seti@Home

For this I used the kubernetes dashboard, tho the command line would work just as well.

Click create to launch the creation wizard. You’ll see something like this where you can provide a name, image, and number of pods. My settings are captured in the image:

k8s new deployment

Next, we need to open the advanced settings. This is where we specify the environment variables, again captured in the following image:

Environment variables

For reference these are:





Finally, save & deploy it, this’ll take a minute or two.

All done:

all done


In this post, you flashed a bunch of Raspberry Pi’s with Hypriot and built a Kubernetes cluster with them. From there you logged into the dashboard and deployed seti@home.


My First Django App

Having had some time over the winter break, I took some time to watch the excellent Django Webcast on O’Reilly’s Safari. What follows here are the commands used in said video cast used to get started with an app:

Setting up a virtual environment

My first instinct to keep the development environment separate from my working world was to fire up a VM and go with it. Turns out, in Python you can still work locally without much fear of breaking your box. You do this with virtualenv’s, and manage those with virtualenvwrapper.

Note: One can use virtual environments without virtualenvwrapper. virtualenvwrapper made things a bit easier for me.

Install virtualenvwrapper on OSX

For this, I assume you have a working homebrew:

brew update
brew install pyenv-virtualenvwrapper

Install virtualenvwrapper on Ubuntu 16.04

Thankfully, it’s a happy little apt-package for us here:

sudo apt-get update
sudo apt-get install virtualenvwrapper

Configuring virtualenvwrapper

Now that you have it installed on your system, the following .bash_profile settings set up some specific behaviors in virtualenvwrapper. These work on both OSX and Ubuntu:

echo "export WORKON_HOME=$HOME/.virtualenvs" >> ~/.bashrc
echo "export PROJECT_HOME=$HOME/projects" >> ~/.bashrc

source ~/.bashrc

The first line tells virtualenvwrapper where you would like it to store all of the files (python, pip, and all their parts) for said virtualenv. The second line tells virtualenvwrapper where your code lives. Finally, we pull said values into out working bash shell.

Create and enter your virtual env

Now that’s all sorted, let’s make a virtual environment to work on:

mkvirtualenv -p /usr/bin/python3 newProject

Breaking this down, the -p /usr/bin/python3 tells virtualenv to install python3 into our virtualenv. The name newProject is well, the new project name. This command will produce output like the following:

$ mkvirtualenv -p /usr/bin/python3 newProject
Already using interpreter /usr/bin/python3
Using base prefix '/usr'
New python executable in newProject/bin/python3
Also creating executable in newProject/bin/python
Installing setuptools, pip...done.

To enter your virtual environment and start working on things:

$ cd ~/projects/
$ mkdir newProject
$ cd newProject/
$ workon newProject

Installing and Getting Started with Django

Ok, so that was a lot of setup to get to this point, but, here we are, it’s time to install Django, create the structure of our application, and finally start Django’s built in webserver to make sure it is all working.

To install Django inside your virtual environment:

$ pip install django
Downloading/unpacking django
  Downloading Django-1.10.5-py2.py3-none-any.whl (6.8MB): 6.8MB downloaded
Installing collected packages: django
Successfully installed django
Cleaning up...

Now let’s install the skeleton of our app:

django-admin startproject newProject

This will create a directory structure like this:

$ tree
└── newProject
    └── newProject

2 directories, 5 files

Next up, we will want to fire up django’s built in server and validate our install:

$ cd newProject
$ python migrate

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying sessions.0001_initial... OK

$ python runserver
Performing system checks...

System check identified no issues (0 silenced).
January 07, 2017 - 23:52:17
Django version 1.10.5, using settings 'newProject.settings'
Starting development server at
Quit the server with CONTROL-C.

Taking a look at what we did there:

  • migrate - preforms the initial migration & population of a sqlite database so our shell application will work.
  • runserver - started Django’s built in webserver

While there is a lot more to actually writing a Django app, this is essentially how you get started on a net-new application.


In this post we installed virtualenvwrapper and used it to crate a new virtual environment. We then installed Django, performed an initial database migration and run Django’s built in server so we could browse to and test the shell application.

Some MS Resources

After a conversation with a friend who has a relative recently diagnosed, I felt compelled to share a bunch of the same links with the greater readership both on the blog and via Twitter. Mayhaps you’ve already seen the tweet storm, but I thought I’d collect the resources here a bit longer form.

I have taken the time to read and vet each one of these resources. Meaning I have spent some time distilling a lot of the crap out there into this list. If you’re newly diagnosed, know someone who was, or want to come up to speed fast, start here.

Note: This list is only a starting point. If you have a resource you’ve found useful, please drop me a note or @cody_bunch on twttier.


I start with diet rather than disease, because it was the single thing we did that has had the greatest impact. Taking the approach that you or someone you know may be newly diagnosed, I know you have questions, but trust me, start here.

The one thing that has had the single biggest impact for us on our MS journey has been Terry Wahls. Mind, we’re super inconsistent in the application of the Wahls diet(s), and still have had great effect.

  • Terry Wahls Tedx
  • Terry Wahls - Minding My Mitochondria Terry Wahls has two books out. This was the first, and reads more like a research scientist than new-age treatment. Read this after watching the TedX
  • Terry Wahls - Wahls Protocol This one reads a bit more turbo Paleo hipster. Still, totally worth it, as between the first book and this one, there have been a number of actual scientific studies done on variants of the Wahls protocol and to good effect. This book reports those findings.


Next up, some information on the disease itself. These links can be dry / more scientific reading. If you’re comfortable with that, they will bring you up to date with where MS related research and knowledge are as of 2015/2016.

  • For Nurses and Nurse Practitioners (MS Society) Read all of them. Start with the quick reference and follow that up with the handbook (3 & 4).
  • National MS Society Resource page This page helped us not only find a Dr who understands MS, but also helped us coordinate a transition from FL to TX back in the day. They have links to local support groups, education, and more.
  • MS Society Research page Here you will find links to both how the MS Society spends it’s money on research, as well as links to said research studies. If you’ve heard of a treatment, maybe Dr. OZ recommended a thing, read about the research behind it here.
  • A comprehensive research review It’s getting a bit older (a 2014 book), but research takes time, and it’s still a good primer. It won’t hold your hand however. Be prepared for science.

The Human Side

The disease, like others, has a human component. Below are two of the blogs that have helped me figure out what that means for other folks and incorporate some of that into our family.


This post, like the twitter rant before it, isn’t to garner sy/empathy. Rather, it’s to help others who find themselves in the same boat. You aren’t alone, and if you’d like, feel free to reach out to chat.

Seti@Home with Docker on Raspberry Pi

A little while back Tim from CERN commented related to my HomeLab. Specifically he was wanting me to run LHC@Home workloads. While I promise those are coming, they do not currently support ARM CPU’s. There is an @home citizen science project that does however. Seti. You know, the one that started it all.


To get started with this on docker on rPI you need to do a few things:

Don’t worry about any of the values the first time around, we’re only getting it going enough to get our authenticator code

docker run -d -t --env BOINC_CONFIG_CONTENTS="<account>
</account>" --env -i boinc

Next attach to the container and get your authenticator code:

docker exec -i -t /bin/bash <id of container>
boinccmd --lookup_account <your_email> <your_password>

Copy the authenticator code it gives you, and kill the container:

docker kill <id of container>

Finally restart it with the correct auth code: Science!

docker run -d -t --env BOINC_CONFIG_CONTENTS="<account>
</account>" --env -i boinc

Once done, you can fire up htop and confirm all your CPU’s have maxed out.