I built a SaaS and I shipped it – in an afternoon



I built a SaaS and I shipped it – in an afternoon

2 2


i-built-a-saas

presentation on building a SaaS in an afternoon with docker.io

On Github paulczar / i-built-a-saas

I built a SaaS and I shipped it

in an afternoon

and so could you!

Created by Paul Czarkowski / @pczarkowski

Australian...

Not a DevOp

what even is?

The Problem

I want an IRC

  • That is connected even when I'm not.
  • That I can connect from any of my machines.
  • That I can read back on conversations I wasn't around for.

to the googles!

There's a web app for that - http://ircrelay.com

But I don't want to pay $5 a month because I'm cheap.

There's an OSS App for that - http://wiki.znc.in/ZNC

But I would need to host it somewhere.

Shaving the Yak

I could do that myself!

in a docker container in the cloud.

behind a web app so my friends can use it too.

with a database to track who can access it.

Some chef cookbooks to manage the server and deploy the app.

...

...

...

First... Build a docker container to run ZNC

https://github.com/paulczar/docker-znc

Dockerfile

# This file creates a container that runs ZNC
#
# Author: Paul Czarkowski
# Date: 08/04/2013


FROM ubuntu:12.10
MAINTAINER Paul Czarkowski "paul@paulcz.net"

RUN apt-get update
RUN apt-get -y install znc

ADD start-znc /usr/local/bin/start-znc
ADD znc.pem /opt/znc/znc.pem
ADD znc.conf /opt/znc/configs/znc.conf

RUN chmod +x /usr/local/bin/start-znc

RUN useradd znc
RUN chown -R znc:znc /opt/znc

EXPOSE 6667

# Start znc
CMD ["start-znc"]
					

start-znc

#!/bin/bash

ZNC_USER=${ZNC_USER:-$(tr -dc "[:alpha:]" < /dev/urandom | head -c 8)}
ZNC_PASS=${ZNC_PASS:-$(tr -dc "[:alpha:]" < /dev/urandom | head -c 8)}
IRC_SERVER=${IRC_SERVER:-'irc.freenode.net'}
IRC_PORT=${IRC_PORT:-'6667'}


ZNC_SALT="$(dd if=/dev/urandom bs=16c count=1 | md5sum | awk '{print $1}')"
ZNC_HASH="sha256#$(echo -n ${ZNC_PASS}${ZNC_SALT} | sha256sum | awk '{print $1}')#$ZNC_SALT#"

sed -i "s/ZNC_USER/$ZNC_USER/" /opt/znc/configs/znc.conf
sed -i "s/ZNC_HASH/$ZNC_HASH/" /opt/znc/configs/znc.conf
sed -i "s/IRC_SERVER/$IRC_SERVER/" /opt/znc/configs/znc.conf
sed -i "s/IRC_PORT/$IRC_PORT/" /opt/znc/configs/znc.conf

znc -f -r -d /opt/znc
					

Run it!

$ docker run -e ZNC_USER=paultest -e ZNC_PASS=paultest \
      -p 6667 -u znc paulczar/znc start-znc
Connecting to IRC Server: irc.freenode.net:6667
ZNC User: paultest
ZNC Pass: paultest
Opening Config [/opt/znc/configs/znc.conf]...
Loading Global Module [lastseen]... [/usr/lib/znc/lastseen.so]
Binding to port [+6667] using ipv4...
Loading user [paultest]
Adding Server [irc.freenode.net 6667]...
					

That was easy ... now write a web app

I'm going to be ultra cool and use Node and Mongo!

Install Node.JS Install MongoDB Start writing code ... ... I just remembered ... I'm a shit programmer.

Back to the drawing board...

I vaguely remember seeing some guy did a 'try memcache' website using docker.

It's not stealing if you fork...

Opensource 101

If you fix something ... give it back!

Turns out its a fairly simply app

  • Ruby on Rails
  • Active Record
  • Calls docker CLI with backtick commands.

But it doesn't quite work...

  • learn how the site works while bugfixing.
  • If you fix a bug in forked code ... send a PR!
  • https://github.com/jbarbier/SaaS_Memcached/pull/2

Build a dev environment

require "vagrant"
Vagrant.configure("2") do |config|
  config.vm.define :SaasZNC do |config|
    config.vm.provision :chef_solo do |chef|
      chef.provisioning_path = "/tmp/vagrant-cache"
      chef.json = {
          "languages" => {
            "ruby" => {
              "default_version" => "1.9.1"
            }
          }
      }
      chef.run_list = [
        "recipe[apt::default]",
        "recipe[ruby::default]",
        "recipe[build-essential::default]",
        "recipe[git::default]",
        "recipe[docker::default]"
      ]
    end
    config.vm.provision :shell, :inline => <<-SCRIPT
      groupadd docker
      usermod -a -G docker vagrant
      apt-get -y -q install libxslt-dev libxml2-dev libpq-dev sqlite3 libsqlite3-dev
      gem install bundler --no-ri --no-rdoc
      cd /vagrant
      bundle install
      rake db:migrate
      rails server -d

    SCRIPT
  end
end

					

Vagrant+Chef = Dev Env as Code.

Vagrant is amazing. Use it.

Over the course of the next few hours...

  • Working prototype in Vagrant
  • Create Rackspace public cloud instance (free with dev promo)
  • add server to Chef Enterprise (5 servers free)
  • Write and upload chef cookbook to install ircaas app
  • bootstrap cloud instance from cookbook
  • http://znc.paulcz.net

Stress Test

for i in {1..100}; do
	docker run -e ZNC_USER=znctest$i -e ZNC_PASS=znctest$i -d -p 6667 -u znc paulczar/znc start-znc
done
				  

A 512mb instance runs 100 ZNC containers without stress... Would probably handle a lot more ...

but IRCops aren't amused...

you did a thing ... so what ?

  • increasing ecosystem of tools
  • Δt for idea -> product decreasing
  • reduce cost of failure
  • Get your (new or existing) product into users hands quicker!
    • trychef.com
    • tryconfluence.com
    • try[insert-your-product-here].com

Links

http://znc.paulcz.net

THE END

BY Paul Czarkowski / @pczarkowski