3.9 KB
Newer Older
Daniel Quinn's avatar
Daniel Quinn committed
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
# Pizza Place

Sure you could figure out how to get [Dokku](
to work, but this is much simpler: a quick & dirty way to automate the process
of creating an instance of your application based on a published branch,
triggered by way of a web hook.

There are two parts to this: the webhook listener (dispatcher) and the
instance-builder (kitchen).

## How it Works

Everything is tied in with your web hooks.  If you push a branch to GitLab,
and that branch isn't `master` or `develop`, PizzaPlace will spin up a fresh
instance of your application at `https://your-branch-name.yourdomain.tld`.  The
time between push and ready is mostly dependent on how heavy your application

Sending additional pushes will blow away the old one and replace it with the
new one, complete with a fresh database every time.  You can even rebase or
reset and overwrite your entire branch history with `push -f` and PizzaPlace
will handle it just fine.

## Installation

As this is intended to be installed on a single-purpose cloud server, the installation is basically a shell script that does a bunch of things to your system to configure it to do the job.  Do not run this on your laptop:

# wget --output-document /install
# chmod 755 /install
# /install

The install script is interactive, asking you a bunch of questions, generating
keys and asking you to install said keys on your repo.  For the most part
though, it's pretty straightforward.

## Components

### Dispatcher

The dumb workhorse of the system, this is a crude Flask app that has one one
endpoint, `/dispatcher` which simply authenticates the request, decides whether
it's something we'll want to build an instance for, and if yes, creates a file
in the "add queue" directory.

The name of the file will be a URL-friendly name, and the contents of the file
will be the name of the branch in question.

The dispatcher runs as an unprivileged user: `pizzaplace`.

### Kitchen

Doing nearly all of the work, the kitchen is a much more complicated script,
but at its core the process is simple:

1. Look for a file in the `add` queue
2. If there's one there:
    1. Check out that branch into `/var/www/pizzaplace/NAME`
    2. Pick a random port number
    3. Create a Docker instance for this branch and have it listen on that port
    4. Create an Nginx config for it, pointing at our port
    5. Restart Nginx
3. GOTO 1.

As it modifies server configurations and restarts Nginx, `kitchen` must run as
**root**, however about 60% of the system calls it makes are done as the
`pizzaplace` user.

## Potentially Useful Information

### SSL

We manage all the SSL stuff with LetsEncrypt, which uses notoriously
82 83 84 85 86 87 88 89 90 91
short-lived certificates.  Unfortunately, since we're using a *wildcard
certificate*, the typical method of automatically updating your cert isn't
available without [considerable effort](

In the absence of that effort (say for example you're using a DNS provider
that doesn't have an API for changes), then you'll have to run this command
every 3 months or so.  Just remember to replace `${PARENT_DOMAIN}` with
whatever you specified above:

    certbot certonly --manual --preferred-challenges=dns -d "${PARENT_DOMAIN},*.${PARENT_DOMAIN}"

Daniel Quinn's avatar
Daniel Quinn committed
93 94 95 96

### Git

We speed up the process of checking out instances of the repo by using a git
97 98 99
reference directory at `/opt/git-reference`.  For the most part, you don't
need to worry about this, just don't delete this directory or Bad Things might
Daniel Quinn's avatar
Daniel Quinn committed
100 101 102 103 104 105 106 107 108

## Colophon

I was looking for a rough analogy for something that takes a job an spins up
new stuff according to instructions and a pizza place is what came to mind.

Credit for the adorable pizza icon goes to [u/CodexOfMaya](
found [here](