2012-05-06 08:03:35 +04:00
|
|
|
Deployment system for Yesod (and other Haskell) web apps.
|
|
|
|
|
2012-05-18 09:50:51 +04:00
|
|
|
## Setup
|
|
|
|
|
|
|
|
Instructions are for an Ubuntu system. Eventually, I hope to provide a PPA for
|
|
|
|
this (please contact me if you would like to assist with this). For now, the
|
|
|
|
following steps should be sufficient:
|
|
|
|
|
2012-09-14 07:26:47 +04:00
|
|
|
First, install PostgreSQL
|
2012-05-18 09:50:51 +04:00
|
|
|
|
2012-09-14 07:26:47 +04:00
|
|
|
sudo apt-get install postgresql
|
2012-05-18 09:50:51 +04:00
|
|
|
|
2012-10-23 22:48:55 +04:00
|
|
|
Second, build the `keter` binary and place it at `/opt/keter/bin`.
|
2012-05-18 09:50:51 +04:00
|
|
|
|
2012-09-14 07:26:47 +04:00
|
|
|
Third, create a Keter config file:
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
# /opt/keter/etc/keter-config.yaml
|
|
|
|
root: ..
|
|
|
|
# host: host to bind to
|
|
|
|
# port: port to listen on
|
|
|
|
# ssl:
|
|
|
|
# host:
|
|
|
|
# port:
|
|
|
|
# key:
|
|
|
|
# certificate:
|
|
|
|
```
|
|
|
|
|
|
|
|
Fourth, set up an Upstart job to start `keter` when your system boots.
|
2012-05-18 09:50:51 +04:00
|
|
|
|
|
|
|
```
|
|
|
|
# /etc/init/keter.conf
|
|
|
|
start on (net-device-up and local-filesystems and runlevel [2345])
|
|
|
|
stop on runlevel [016]
|
|
|
|
respawn
|
|
|
|
|
|
|
|
console none
|
|
|
|
|
2012-10-23 22:48:55 +04:00
|
|
|
exec /opt/keter/bin/keter /opt/keter/etc/keter-config.yaml
|
2012-05-18 09:50:51 +04:00
|
|
|
```
|
|
|
|
|
|
|
|
Finally, start the job for the first time:
|
|
|
|
|
|
|
|
sudo start keter
|
|
|
|
|
|
|
|
## Bundles
|
|
|
|
|
|
|
|
An application needs to be set up as a keter bundle. This is a GZIPed tarball
|
|
|
|
with a `.keter` filename extension and which has one special file:
|
|
|
|
`config/keter.yaml`. A sample file is:
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
exec: ../dist/build/yesodweb/yesodweb
|
|
|
|
args:
|
|
|
|
- production
|
|
|
|
host: www.yesodweb.com
|
2012-09-14 07:29:03 +04:00
|
|
|
ssl: false # true would use https scheme for approot
|
2012-10-14 20:17:01 +04:00
|
|
|
|
|
|
|
# Additional hosts your app will listen on, without affecting approot.
|
|
|
|
extra-hosts:
|
|
|
|
- www1.yesodweb.com
|
|
|
|
|
|
|
|
# Static file hosts. Keter handles the serving for you.
|
|
|
|
static-hosts:
|
|
|
|
- host: static.yesodweb.com
|
|
|
|
root: ../static # relative to config file, just like the executable
|
2012-10-21 09:07:26 +04:00
|
|
|
|
|
|
|
# Host name redirects.
|
|
|
|
redirects:
|
|
|
|
- from: yesodweb.com
|
|
|
|
to: www.yesodweb.com
|
2012-05-18 09:50:51 +04:00
|
|
|
```
|
|
|
|
|
2012-09-14 07:26:47 +04:00
|
|
|
A sample Bash script for producing a Keter bundle is:
|
2012-05-18 09:50:51 +04:00
|
|
|
|
|
|
|
```bash
|
|
|
|
#!/bin/bash -ex
|
|
|
|
|
|
|
|
cabal build
|
|
|
|
strip dist/build/yesodweb/yesodweb
|
|
|
|
rm -rf static/tmp
|
|
|
|
tar czfv yesodweb.keter dist/build/yesodweb/yesodweb config static
|
|
|
|
```
|
|
|
|
|
2012-09-14 07:26:47 +04:00
|
|
|
For users of Yesod, The `yesod` executable provides a `keter` command for
|
|
|
|
creating the bundle, and the scaffolded site provides a `keter.yaml` file.
|
|
|
|
|
2012-05-18 09:50:51 +04:00
|
|
|
## Deploying
|
|
|
|
|
|
|
|
In order to deploy, you simply copy the keter bundle to `/opt/keter/incoming`.
|
|
|
|
To update an app, copy in the new version. The old process will only be
|
|
|
|
terminated after the new process has started answering requests. To stop an
|
|
|
|
application, delete the file from incoming.
|
|
|
|
|
|
|
|
## Technical Details
|
|
|
|
|
2012-05-06 08:03:35 +04:00
|
|
|
Components:
|
|
|
|
|
|
|
|
* Logger: provides a file descriptor to redirect output to. Takes the name of
|
|
|
|
the app.
|
|
|
|
|
|
|
|
* Process: Give it all the information (executable, working directory,
|
|
|
|
environment, args) for a process, and it will start the process and monitor
|
|
|
|
it. If the process dies, it will restart. Binds the output to the logger.
|
|
|
|
Allows you to terminate the process.
|
|
|
|
|
|
|
|
* Postgres: Ask it for database information for an app. If no information is
|
|
|
|
available, it will create a database/user.
|
|
|
|
|
2012-05-08 16:18:06 +04:00
|
|
|
* TempFolder: Wipes out a folder on startup, then assigns random, unique
|
|
|
|
folders inside it on request.
|
|
|
|
|
2012-05-06 08:03:35 +04:00
|
|
|
* App: Started with a path to an app bundle. Unpacks into a random folder
|
|
|
|
inside the temp folder, gets a random port, starts a Process, updates Nginx,
|
|
|
|
and waits for commands. Accepts two commands: reload and terminate.
|
|
|
|
|
|
|
|
* Terminate kills the existing process, removes from Nginx, and deletes the
|
|
|
|
folder.
|
|
|
|
|
|
|
|
* Reload gets a new random port, unpacks to a new folder in the temp
|
|
|
|
folder, starts a Process, waits till the process is "ready" (checks with
|
|
|
|
an HTTP request)- canceling after a certain timeout.
|
|
|
|
|
|
|
|
* If process is not ready within timeout, terminate the new process and
|
|
|
|
delete the new folder.
|
|
|
|
|
|
|
|
* If a process *is* ready, tell Nginx to use the new port, wait some
|
|
|
|
amount of time (20 seconds?), send a TERM to the old process, wait
|
|
|
|
some more (1 minute?) and delete the old folder.
|
|
|
|
|
|
|
|
* Keter: Delete temp folder, start the Nginx, logger, and port assigner. Start
|
|
|
|
a new App for each app in the incoming folder. Monitor for file changes in
|
|
|
|
the incoming folder, and appropriately start a new app, reload an existing app,
|
|
|
|
or delete an existing app. Also provide a web interface based on logger.
|