Take a good look at this site. Do you see something different? Well, to quote Captain Jack Sparrow, it's something not there to be noticed.
This site is now being deployed via Keter. In other words, it's alive!!! Keter is monitoring the yesodweb.com application process, handling logs and log rotation, configuring Nginx as necessary, and automatically deploying code updates. (If yesodweb.com used a database, Keter would handle that too.)
I've always believed heavily in dogfooding, which is why I'm rolling out Keter now. However, this should still be considered alpha quality code. I'll be keeping a close watch on the server to make sure nothing funny goes on. However, I think the code base is at the point where it makes sense to start some more serious testing.
I'm going to avoid going into the implementation details in this blog post, and instead focus on the end user. If people are interested in a post on the technical aspects of Keter itself, let me know and I'll try to write one.
Prepare the ServerYou'll need to install two things on the server: Nginx and PostgreSQL. To do so on a Debian based system, just run:
sudo apt-get install nginx postgresql
Build the Executable
Since Keter is just another package on Hackage, you can build it with a simple cabal install keter
. However, doing so on your server would entail installing an entire Haskell toolchain, which is not something we generally encourage. So for now, the recommended approach would be to do the cabal install
on a local system with the same architecture and distribution as your web server, and then copy the executable to the server. If you happen to be running Ubuntu 12.04 64-bit, I've made a copy of my executable available online.
Now, a few caveats:
/etc/nginx/sites-enabled/keter
) and the name of the user for running PostgreSQL admin activities (postgres
). This seems to work perfectly on Debian-based systems, but may not translate well elsewhere. If people are using other distributions on their servers and want to add support to Keter, please be in touch.Once you have the executable, place it in /usr/bin
on your server. (Of course, you can choose a different location, just keep in mind your changes as you continue.)
Next you'll want to make sure that keter is run on startup. This will depend again on your distribution. I'm going to assume using Ubuntu and Upstart. The following script works for me:
# /etc/init/keter.conf
start on (net-device-up and local-filesystems and runlevel [2345])
stop on runlevel [016]
respawn
console none
exec /usr/bin/keter /opt/keter
Notice that keter
takes a single argument: the folder to use as its base of operations. You can use whatever folder you want, but /opt/keter
seems like a good choice to me.
You can start running Keter immediately with sudo start keter
.
An application is sent to Keter as a keter bundle. This is a single GZIPed tarball with a .keter filename extension, and it contains your executable, resources, and your keter config file. This last file must be placed at config/keter.yaml
. Let's set up a simple example. Suppose you have the following inanely boring web application:
-- hello.hs
{-# LANGUAGE OverloadedStrings #-}
import System.Environment (getEnv)
import Network.Wai
import Network.Wai.Handler.Warp
import Network.HTTP.Types
import Control.Monad.IO.Class
import System.IO (hFlush, stdout)
main :: IO ()
main = do
putStrLn "Application is starting"
liftIO $ hFlush stdout
portS <- getEnv "PORT"
let port = read portS
run port $ \req -> do
liftIO $ putStrLn $ "Received a request at: " ++ show (pathInfo req)
liftIO $ hFlush stdout
return $ responseLBS status200 [("content-type", "text/plain")] "Hello World!"
There's one Keter-specific aspect to this code to mention: reading the PORT
environment variable. This is how an app is told where to listen for requests. Nginx will work as a front proxy and receive all requests from clients, and then pass them off to the appropriate web app based on hostname. This is the only change necessary to get an app to work with Keter. All Yesod scaffolded sites support this functionality already, and it should be trivial to add to Snap and Happstack applications too.
OK, now that we have our app, let's look at our keter.yaml file:
# config/keter.yaml
exec: ../hello
host: www.example.com
This is pretty simple. exec
says where to find the executable. This will be relative to the keter.yaml
file, which is inside the config
folder, so we use ../hello
. The host
setting says which hostname to listen on. As a side note, the hostname will also be provided to your app via the APPROOT
environment variable, which is how Yesod apps generate absolute URLs. This can be safely ignored: Yesod handles this automatically, and the data likely isn't necessary for other frameworks.
There are two other options you can specify in your keter.yaml file:
args
is a list of command line arguments to pass to your application.postgres
is a boolean indicating whether a PostgreSQL database should be created for this app. If true
, then the database parameters will be provided via environment variables. (Persistent can parse these automatically.)So a basic config file for a Yesod site called myawesomeapp
running on www.myawesomeapp.com
and using PostgreSQL would be:
exec: ../dist/build/myawesomeapp/myawesomeapp
args:
- production
host: www.myawesomeapp.com
postgres: true
Coming back to our simple hello world app, here's a shell script that can bundle up your executable and config file:
#!/bin/bash -ex
ghc --make -threaded hello.hs
strip hello
rm -f hello.keter
tar czfv hello.keter hello config/keter.yaml
This will produce a hello.keter bundle which is all ready to be deployed.
DeployingThis is the (relatively) easy part. Copy your bundle to /opt/keter/incoming
. That should be all there is to it. Now the caveats:
Oh, and obviously you'll need to set up your DNS to point to your server. Maybe we'll provide some ability to automate this via Amazon Route 53 in the future.
LogsKeter keeps fairly detailed logs of its own activities, plus logs all stdout and stderr output from each application. Logs each go into their own folder, and are automatically rotated. To see what's been happening with Keter, look in /opt/keter/log/keter/current.log
. For example, the log on yesodweb.com contains:
2012-05-17 11:16:35.08: Unpacking bundle '/opt/keter/incoming/yesodweb.keter' into folder: /opt/keter/temp/yesodweb-0
2012-05-17 11:16:35.29: Created process: config/../dist/build/yesodweb/yesodweb
Each app log gets placed in /opt/keter/log/app-<appname>
, with error output going in the err
subfolder. Keter does nothing to modify the contents of these files, it simply pipes directly from the app to the file.
The main thing now is testing: making sure it's working correctly under all circumstances. Keter will give fairly detailed diagnositcs about itself, and logs every single exception that gets thrown. This should make it easier to track down any problems. I've run a fair amount of testing myself, and everything seems to be in order, but obviously we won't know that for certain until more reports come in.
There are also some features I'd like to add:
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4