Skip to content
/ overseer Public
forked from jpillora/overseer

Monitorable, gracefully restarting, self-upgrading binaries in Go (golang)

License

Notifications You must be signed in to change notification settings

bnelz/overseer

Repository files navigation

overseer

GoDoc

Monitorable, gracefully restarting, self-upgrading binaries in Go (golang)

The main goal of this project is to facilitate the creation of self-upgrading binaries which play nice with standard process managers. The secondary goal is user simplicity. ⚠️ This is beta software.

Features

  • Simple
  • Works with process managers
  • Graceful, zero-down time restarts
  • Easy self-upgrading binaries

Install

go get github.com/jpillora/overseer

Quick example

package main

import (
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/jpillora/overseer"
	"github.com/jpillora/overseer/fetcher"
)

//create another main() to run the overseer process
//and then convert your old main() into a 'prog(state)'
func main() {
	overseer.Run(overseer.Config{
		Program: prog,
		Address: ":3000",
		Fetcher: &fetcher.HTTP{
			URL:      "http://localhost:4000/binaries/myapp",
			Interval: 1 * time.Second,
		},
		// Log: true, //display log of overseer actions
	})
}

//prog(state) runs in a child process
func prog(state overseer.State) {
	log.Printf("app (%s) listening...", state.ID)
	http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "app (%s) says hello\n", state.ID)
	}))
	http.Serve(state.Listener, nil)
}
$ cd example/
$ sh example.sh
serving . on port 4000
BUILT APP (1)
RUNNING APP
app#1 (96015cccdebcec119adad34f49b93e02552f3ad9) listening...
app#1 (96015cccdebcec119adad34f49b93e02552f3ad9) says hello
app#1 (96015cccdebcec119adad34f49b93e02552f3ad9) says hello
BUILT APP (2)
app#2 (ccc073a1c8e94fd4f2d76ebefb2bbc96790cb795) listening...
app#2 (ccc073a1c8e94fd4f2d76ebefb2bbc96790cb795) says hello
app#2 (ccc073a1c8e94fd4f2d76ebefb2bbc96790cb795) says hello
app#1 (96015cccdebcec119adad34f49b93e02552f3ad9) says hello
app#1 (96015cccdebcec119adad34f49b93e02552f3ad9) exiting...
BUILT APP (3)
app#3 (286848c2aefcd3f7321a65b5e4efae987fb17911) listening...
app#3 (286848c2aefcd3f7321a65b5e4efae987fb17911) says hello
app#3 (286848c2aefcd3f7321a65b5e4efae987fb17911) says hello
app#2 (ccc073a1c8e94fd4f2d76ebefb2bbc96790cb795) says hello
app#2 (ccc073a1c8e94fd4f2d76ebefb2bbc96790cb795) exiting...
app#3 (286848c2aefcd3f7321a65b5e4efae987fb17911) says hello
app#3 (286848c2aefcd3f7321a65b5e4efae987fb17911) exiting...

More examples

  • Only use graceful restarts

     func main() {
     	overseer.Run(overseer.Config{
     		Program: prog,
     		Address: ":3000",
     	})
     }

    Send main a SIGUSR2 to manually trigger a restart

  • Only use auto-upgrades, no restarts

     func main() {
     	overseer.Run(overseer.Config{
     		Program: prog,
     		NoRestartAfterFetch: true
     		Fetcher: &fetcher.HTTP{
     			URL:      "http://localhost:4000/binaries/myapp",
     			Interval: 1 * time.Second,
     		},
     	})
     }

    Your binary will be upgraded though it will require manual restart from the user

Warnings

  • Currently shells out to mv for moving files because mv handles cross-partition moves unlike os.Rename.
  • Bind Addresses can only be changed by restarting the main process.
  • Only supported on darwin and linux.

Documentation

Architecture overview

  • overseer uses the main process to check for and install upgrades and a child process to run Program
  • All child process pipes are connected back to the main process
  • All signals received on the main process are forwarded through to the child process
  • The provided fetcher.Interface will be used to Fetch() the latest build of the binary
  • The fetcher.HTTP accepts a URL, it polls this URL with HEAD requests and until it detects a change. On change, we GET the URL and stream it back out to overseer.
  • Once a binary is received, it is run with a simple echo token to confirm it is a overseer binary.
  • Except for scheduled upgrades, the child process exiting will cause the main process to exit with the same code. So, overseer is not a process manager.

Docker

  1. Compile your overseerable app to a /path/on/docker/host/dir/app

  2. Then run it with:

    docker run -d -v /path/on/docker/host/dir/:/home/ -w /home/ debian  -w /home/app
  3. For testing, swap out -d (daemonize) for --rm -it (remove on exit, input, terminal)

  4. app can use the current working directory as storage

  5. debian doesn't ship with TLS certs, you can mount them in with -v /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt

Alternatives

TODO

  • Log levels
  • Github fetcher (given a repo, poll releases)
  • etcd fetcher (given a cluster, watch key)
  • overseer CLI tool (TODO)
  • overseer package

About

Monitorable, gracefully restarting, self-upgrading binaries in Go (golang)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Go 95.6%
  • Shell 4.4%