Version: v0.0.0-...-b425644 Latest Latest

This package is not in the latest version of its module.

Go to latest
Published: Nov 14, 2019 License: Apache-2.0 Imports: 21 Imported by: 0



wunderproxy is a tool to simply manage docker based deployments. It consists of two components:

  • proxy: Forward requests on a specified port to the currently deployed docker container.
  • manager: Manage docker containers via an API.

The Manager

The container manager is used to provide a simple API for handling docker containers and manage the proxy. It has the following actions:

  • /status: This action returns status information on the currently active container, like the number of requests served.
  • /launch: Will start a new container. The configuration identifier is read from the request body. The actual config file is fetched from S3. Using this information the container will be launched.
  • /switch: Switches the proxy port to the container given.

The launch action fetches the actual configuration from S3 using the requested identifier (it's the hash of the configuration file) as last part of the S3 key. The JSON config expected under this key contains the following information:

  • Docker image to launch
  • Docker configuration for launching the container (e.g. exports, environment variables, etc.)
  • Health check URL
  • S3 bucket for image artifacts

The manager expects the currently running configuration to also be available with the current.json key suffix on S3. This is the container configuration that will be launched on startup.

The Proxy

Using a reverse proxy approach the proxy will send incoming requests to a modifiable port. Some minor statistics are collected along the way, that can be retrieved using the manager's API.


The following options can be given to determine what happens when starting the wunderproxy:

  • ProxyAddress: The listen address of the proxy. The default is to use This is the port that will be forwarded to the docker containers.
  • ApiAddress: The listen address of the manager API. The default is
  • RegistryPort: The current version of the wunderproxy relies on a local docker registry/distribution (see here). The default is to expect the registry on port 8080.
  • ConfigFile: This is a simple key=value based file that can be used to give static environment variables to containers. This is optional of course.

Besides these options there are three arguments required:

  • The S3 bucket used to handle container launch configurations.
  • The path prefix to be used in the S3 bucket.
  • The name of the application handled. This is used as prefix for the containers images.

Possible Improvements (TODO)

502 Handling

If the load is distributed over multiple machines the local wunderproxy instance could try to defer handling a certain requests to one of the other instances if a 502 status code was returned (i.e. if the container wasn't started or doesn't run any more).

  • Those requests should get an extra header which mark them as fallback requests.
  • Those requests should not be proxied again.
  • The status action (used for health checks for example) shouldn't be forwarded of course.
Status Page

The manager's status action could be improved to contain:

  • the number of open connections by states
  • historic status codes
  • response times etc.
Compression, SSL, etc.

Currently the wunderproxy just does the default buffering provided by the Go http library (we measured that to be about 1MB). For unicorn deployments this isn't sufficient to handle slow clients (see unicorn philosophy). We decided to simply use a nginx instance in front of wunderproxy, what of course adds another layer but is sufficient for our case. The nginx layer could be made disposable with an improved request handling in wunderproxy.

Improved Container Switch

The old container should be kept around until all open connections are handled (or a timeout occurs).s




This section is empty.


View Source
var ErrorEmptyHistory = errors.New("container history is empty")
View Source
var ErrorLaunchConfigNotFound = fmt.Errorf("launch configuration not found")


This section is empty.


type ContainerHistory

type ContainerHistory struct {
	Events  []*ContainerHistoryEvent
	MaxSize int
	// contains filtered or unexported fields

A datastructure to manage the most recent containers that are/have been deployed. Including pointers to the launch configurations that were used for them.

func LoadContainerHistory

func LoadContainerHistory(s3c *s3.Client, bucket, prefix string) (*ContainerHistory, error)

Load the container history from S3.

func (*ContainerHistory) Add

Add a new entry to the history. This will add a new launch configuration and persist the launch configuration itself to S3. After a successful deployment (not part of this package) the changed history should be persisted, so that rollback and restart can rely on the current information.

func (*ContainerHistory) RollbackTo

Rollback to the container in the given history event. The history is changed to only contain events up to the given one, i.e. all successors are removed. Please note an explicit history.Save call must be done to persist the changed history.

func (*ContainerHistory) Save

func (ch *ContainerHistory) Save() error

Persist the container history to S3.

type ContainerHistoryEvent

type ContainerHistoryEvent struct {
	Revision   string
	DeployedAt time.Time
	DeployedBy string

	Hash string
	// contains filtered or unexported fields

func (*ContainerHistoryEvent) Load

func (che *ContainerHistoryEvent) Load() (*LaunchConfig, error)

Load the event's container configuration from S3.

type ContainerManager

type ContainerManager struct {
	S3Bucket     string
	S3Prefix     string
	Proxy        *Proxy
	RegistryPort int

	AppName string
	// contains filtered or unexported fields

func NewContainerManager

func NewContainerManager(s3Bucket, s3Prefix, appname string, proxy *Proxy, cfgFile string, rport int) (*ContainerManager, error)

func (*ContainerManager) StartContainer

func (cm *ContainerManager) StartContainer(hash string) (string, int, error)

func (*ContainerManager) Stats

func (cm *ContainerManager) Stats(stats map[string]interface{}) error

func (*ContainerManager) StopOldContainers

func (cm *ContainerManager) StopOldContainers() error

func (*ContainerManager) SwitchContainer

func (cm *ContainerManager) SwitchContainer(hash string) (string, int, error)

type LaunchConfig

type LaunchConfig struct {
	ContainerConfig *docker.ContainerConfig
	HostConfig      *docker.HostConfig
	HealthCheckPath string
	Revision        string
	ForceReload     bool
	// contains filtered or unexported fields

The launch configuration contains all the information required to start a container with the required environment, including all the environment variables required (like credentials).

func LoadCurrentLaunchConfig

func LoadCurrentLaunchConfig(s3c *s3.Client, bucket, prefix string) (*LaunchConfig, error)

Function to load the currently deployed container for the environment specified in the prefix. If history is empty the ErrorLaunchConfigNotFound error type will be returned.

func LoadLaunchConfig

func LoadLaunchConfig(s3c *s3.Client, bucket, prefix, hash string) (*LaunchConfig, error)

Function to load a given launch configuration from S3. This must be a public method to be able to load it when first deploying it (its not part of the history right then).

type Proxy

type Proxy struct {
	Mutex        *sync.Mutex
	ConnStates   map[net.Conn]http.ConnState
	RequestStats struct {
		Total     int64
		TotalTime time.Duration
	Address string
	// contains filtered or unexported fields

func NewProxy

func NewProxy() *Proxy

func (*Proxy) Director

func (p *Proxy) Director(req *http.Request)

func (*Proxy) ServeHTTP

func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*Proxy) Stats

func (p *Proxy) Stats(stats map[string]interface{}) error

func (*Proxy) Update

func (p *Proxy) Update(addr string)


Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL