1
0
mirror of https://github.com/containous/traefik.git synced 2025-09-22 13:44:25 +03:00

Compare commits

...

14 Commits

Author SHA1 Message Date
Vincent Demeester
fd234c683c Merge pull request #65 from EmileVauge/version-in-binary
Adds version in binary
2015-10-15 11:38:27 +02:00
Emile Vauge
67bc87dcda Merge branch 'master' into version-in-binary 2015-10-14 23:44:17 +02:00
Vincent Demeester
c452fd2195 Merge pull request #62 from EmileVauge/websockets-support
Websockets support
2015-10-14 23:13:07 +02:00
emile
8f38337757 Adds version in binary 2015-10-14 22:18:01 +02:00
emile
5454299bf0 update docs 2015-10-14 13:21:40 +02:00
emile
80f4884d50 Added websocket support https://github.com/EmileVauge/traefik/issues/8 2015-10-14 10:42:27 +02:00
emile
4ea48c2d19 Removed panicing spew https://github.com/EmileVauge/traefik/issues/56 2015-10-14 10:39:26 +02:00
Vincent Demeester
37438a6395 Merge pull request #63 from EmileVauge/no-more-godep-ever
Update package management with Glide
2015-10-13 23:38:27 +02:00
emile
784dc9ea62 update docs 2015-10-13 22:57:10 +02:00
emile
6362b1da7f Update package management with Glide 2015-10-13 22:56:44 +02:00
Emile Vauge
31c7aba8c4 Merge pull request #57 from vdemeester/no-more-sleep-in-integration
Update integration setups to use libcompose events
2015-10-12 15:43:08 +02:00
Vincent Demeester
45ea23ecc1 Update integration setups to use libcompose events
Now that docker/libcompose#55 is merged, use it \o/
No more sleeps !

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2015-10-12 08:44:56 +02:00
Vincent Demeester
661ac977d3 Merge pull request #55 from ldez/feature/json-case
refactor(rest) : add json annotation on configuration
2015-10-10 14:52:50 +02:00
Fernandez Ludovic
c11cf801ca refactor(rest) : add json annotation on configuration
- update Web UI
- update documentation
2015-10-10 14:24:36 +02:00
26 changed files with 670 additions and 570 deletions

3
.gitignore vendored
View File

@@ -6,5 +6,4 @@ log
traefik
traefik.toml
Godeps/_workspace/bin
Godeps/_workspace/pkg
vendor/

302
Godeps/Godeps.json generated
View File

@@ -1,302 +0,0 @@
{
"ImportPath": "github.com/emilevauge/traefik",
"GoVersion": "go1.4.2",
"Packages": [
"./..."
],
"Deps": [{
"ImportPath": "github.com/BurntSushi/toml",
"Rev": "bd2bdf7f18f849530ef7a1c29a4290217cab32a1"
}, {
"ImportPath": "github.com/BurntSushi/ty",
"Rev": "6add9cd6ad42d389d6ead1dde60b4ad71e46fd74"
}, {
"ImportPath": "github.com/Sirupsen/logrus",
"Comment": "v0.8.7",
"Rev": "418b41d23a1bf978c06faea5313ba194650ac088"
}, {
"ImportPath": "github.com/alecthomas/template",
"Rev": "b867cc6ab45cece8143cfcc6fc9c77cf3f2c23c0"
}, {
"ImportPath": "github.com/alecthomas/units",
"Rev": "6b4e7dc5e3143b85ea77909c72caf89416fc2915"
}, {
"ImportPath": "github.com/boltdb/bolt",
"Rev": "51f99c862475898df9773747d3accd05a7ca33c1"
}, {
"ImportPath": "github.com/cenkalti/backoff",
"Rev": "4dc77674aceaabba2c7e3da25d4c823edfb73f99"
}, {
"ImportPath": "github.com/codahale/hdrhistogram",
"Rev": "954f16e8b9ef0e5d5189456aa4c1202758e04f17"
}, {
"ImportPath": "github.com/codegangsta/negroni",
"Comment": "v0.1-70-gc7477ad",
"Rev": "c7477ad8e330bef55bf1ebe300cf8aa67c492d1b"
}, {
"ImportPath": "github.com/coreos/go-etcd/etcd",
"Comment": "v2.0.0-11-gcc90c7b",
"Rev": "cc90c7b091275e606ad0ca7102a23fb2072f3f5e"
}, {
"ImportPath": "github.com/davecgh/go-spew/spew",
"Rev": "2df174808ee097f90d259e432cc04442cf60be21"
}, {
"ImportPath": "github.com/docker/libkv",
"Rev": "3732f7ff1b56057c3158f10bceb1e79133025373"
}, {
"ImportPath": "github.com/docker/distribution",
"Comment": "v2.0.0-467-g9038e48",
"Rev": "9038e48c3b982f8e82281ea486f078a73731ac4e"
}, {
"ImportPath": "github.com/docker/docker/api",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/cliconfig",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/daemon/network",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/graph/tags",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/image",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/opts",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/archive",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/fileutils",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/homedir",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/httputils",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/ioutils",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/jsonmessage",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/mflag",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/nat",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/parsers",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/pools",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/promise",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/random",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/stdcopy",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/stringid",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/symlink",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/system",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/tarsum",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/term",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/timeutils",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/tlsconfig",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/ulimit",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/units",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/urlutil",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/useragent",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/pkg/version",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/registry",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/runconfig",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/utils",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/docker/volume",
"Comment": "v1.4.1-5200-gf39987a",
"Rev": "f39987afe8d611407887b3094c03d6ba6a766a67"
}, {
"ImportPath": "github.com/docker/libcompose/docker",
"Rev": "aad672800904307e96a2c21cad1420f3080e0f35"
}, {
"ImportPath": "github.com/docker/libcompose/logger",
"Rev": "aad672800904307e96a2c21cad1420f3080e0f35"
}, {
"ImportPath": "github.com/docker/libcompose/lookup",
"Rev": "aad672800904307e96a2c21cad1420f3080e0f35"
}, {
"ImportPath": "github.com/docker/libcompose/project",
"Rev": "aad672800904307e96a2c21cad1420f3080e0f35"
}, {
"ImportPath": "github.com/docker/libcompose/utils",
"Rev": "aad672800904307e96a2c21cad1420f3080e0f35"
}, {
"ImportPath": "github.com/docker/libtrust",
"Rev": "9cbd2a1374f46905c68a4eb3694a130610adc62a"
}, {
"ImportPath": "github.com/elazarl/go-bindata-assetfs",
"Rev": "d5cac425555ca5cf00694df246e04f05e6a55150"
}, {
"ImportPath": "github.com/flynn/go-shlex",
"Rev": "3f9db97f856818214da2e1057f8ad84803971cff"
}, {
"ImportPath": "github.com/fsouza/go-dockerclient",
"Rev": "0239034d42f665efa17fd77c39f891c2f9f32922"
}, {
"ImportPath": "github.com/gambol99/go-marathon",
"Rev": "0ba31bcb0d7633ba1888d744c42990eb15281cf1"
}, {
"ImportPath": "github.com/gorilla/context",
"Rev": "215affda49addc4c8ef7e2534915df2c8c35c6cd"
}, {
"ImportPath": "github.com/gorilla/handlers",
"Rev": "40694b40f4a928c062f56849989d3e9cd0570e5f"
}, {
"ImportPath": "github.com/gorilla/mux",
"Rev": "f15e0c49460fd49eebe2bcc8486b05d1bef68d3a"
}, {
"ImportPath": "github.com/hashicorp/consul/api",
"Comment": "v0.5.2-313-gde08067",
"Rev": "de080672fee9e6104572eeea89eccdca135bb918"
}, {
"ImportPath": "github.com/mailgun/log",
"Rev": "44874009257d4d47ba9806f1b7f72a32a015e4d8"
}, {
"ImportPath": "github.com/mailgun/manners",
"Comment": "0.3.1-30-g37136f7",
"Rev": "37136f736785d7c6aa3b9a27b4b2dd1028ca6d79"
}, {
"ImportPath": "github.com/mailgun/oxy/cbreaker",
"Rev": "547c334d658398c05b346c0b79d8f47ba2e1473b"
}, {
"ImportPath": "github.com/mailgun/oxy/forward",
"Rev": "547c334d658398c05b346c0b79d8f47ba2e1473b"
}, {
"ImportPath": "github.com/mailgun/oxy/memmetrics",
"Rev": "547c334d658398c05b346c0b79d8f47ba2e1473b"
}, {
"ImportPath": "github.com/mailgun/oxy/roundrobin",
"Rev": "547c334d658398c05b346c0b79d8f47ba2e1473b"
}, {
"ImportPath": "github.com/mailgun/oxy/utils",
"Rev": "547c334d658398c05b346c0b79d8f47ba2e1473b"
}, {
"ImportPath": "github.com/mailgun/predicate",
"Rev": "cb0bff91a7ab7cf7571e661ff883fc997bc554a3"
}, {
"ImportPath": "github.com/mailgun/timetools",
"Rev": "fd192d755b00c968d312d23f521eb0cdc6f66bd0"
}, {
"ImportPath": "github.com/samuel/go-zookeeper/zk",
"Rev": "fa6674abf3f4580b946a01bf7a1ce4ba8766205b"
}, {
"ImportPath": "github.com/opencontainers/runc/libcontainer/user",
"Comment": "v0.0.4-21-g4ab1324",
"Rev": "4ab132458fc3e9dbeea624153e0331952dc4c8d5"
}, {
"ImportPath": "github.com/samalba/dockerclient",
"Rev": "cfb489c624b635251a93e74e1e90eb0959c5367f"
}, {
"ImportPath": "github.com/thoas/stats",
"Rev": "54ed61c2b47e263ae2f01b86837b0c4bd1da28e8"
}, {
"ImportPath": "github.com/unrolled/render",
"Rev": "26b4e3aac686940fe29521545afad9966ddfc80c"
}, {
"ImportPath": "github.com/vdemeester/shakers",
"Rev": "8fe734f75f3a70b651cbfbf8a55a009da09e8dc5"
}, {
"ImportPath": "golang.org/x/net/context",
"Rev": "d9558e5c97f85372afee28cf2b6059d7d3818919"
}, {
"ImportPath": "gopkg.in/alecthomas/kingpin.v2",
"Comment": "v2.0.12",
"Rev": "639879d6110b1b0409410c7b737ef0bb18325038"
}, {
"ImportPath": "gopkg.in/check.v1",
"Rev": "11d3bc7aa68e238947792f30573146a3231fc0f1"
}, {
"ImportPath": "gopkg.in/fsnotify.v1",
"Comment": "v1.2.0",
"Rev": "96c060f6a6b7e0d6f75fddd10efeaca3e5d1bcb0"
}, {
"ImportPath": "gopkg.in/mgo.v2/bson",
"Comment": "r2015.06.03-5-g22287ba",
"Rev": "22287bab4379e1fbf6002fb4eb769888f3fb224c"
}, {
"ImportPath": "gopkg.in/yaml.v2",
"Rev": "7ad95dd0798a40da1ccdff6dff35fd177b5edf40"
}]
}

5
Godeps/Readme generated
View File

@@ -1,5 +0,0 @@
This directory tree is generated automatically by godep.
Please do not edit.
See https://github.com/tools/godep for more information.

3
Godeps/_workspace/.gitignore generated vendored
View File

@@ -1,3 +0,0 @@
/pkg
/bin
/src

View File

@@ -25,7 +25,8 @@ It supports several backends ([Docker :whale:](https://www.docker.com/), [Mesos/
- Tiny docker image included
- SSL backends support
- SSL frontend support
- WebUI
- Clean AngularJS Web UI
- Websocket support
## Demo
@@ -33,6 +34,13 @@ Here is a demo of Træfɪk using Docker backend, showing a load-balancing betwee
[![asciicast](https://asciinema.org/a/4tcyde7riou5vxulo6my3mtko.png)](https://asciinema.org/a/4tcyde7riou5vxulo6my3mtko)
## Web UI
You can access to a simple HTML frontend of Træfik.
![Web UI Providers](docs/img/web.frontend.png)
![Web UI Health](docs/img/traefik-health.png)
## Plumbing
- [Oxy](https://github.com/mailgun/oxy/): an awsome proxy library made by Mailgun guys
@@ -68,66 +76,61 @@ You can find the complete documentation [here](docs/index.md).
Refer to the [benchmarks section](docs/index.md#benchmarks) in the documentation.
## Web UI
You can access to a simple HTML frontend of Træfik.
![Web UI Providers](docs/img/web.frontend.png)
![Web UI Health](docs/img/traefik-health.png)
## Contributing
### Building
You need either [Docker](https://github.com/docker/docker) and `make`, or `go` and `godep` in order to build traefik.
You need either [Docker](https://github.com/docker/docker) and `make`, or `go` and `glide` in order to build traefik.
#### Using Docker and Makefile
#### Setting up your `go` environment
- You need `go` v1.5
- You need to set `export GO15VENDOREXPERIMENT=1` environment variable
- If you clone Træfɪk into something like `~/go/src/github.com/traefik`, your `GOPATH` variable will have to be set to `~/go`: export `GOPATH=~/go`.
#### Using `Docker` and `Makefile`
You need to run the `binary` target. This will create binaries for
linux and darwin platforms in the `dist` folder.
linux platform in the `dist` folder.
```bash
$ make binary
docker build -t "traefik-dev:your-feature-branch" -f build.Dockerfile .
# […]
docker run --rm -it -e OS_ARCH_ARG -e OS_PLATFORM_ARG -e TESTFLAGS -v "/home/vincent/src/github/vdemeester/traefik/dist:/go/src/github.com/emilevauge/traefik/dist" "traefik-dev:your-feature-branch" ./script/make.sh generate binary
docker build -t "traefik-dev:no-more-godep-ever" -f build.Dockerfile .
Sending build context to Docker daemon 295.3 MB
Step 0 : FROM golang:1.5
---> 8c6473912976
Step 1 : RUN go get github.com/Masterminds/glide
[...]
docker run --rm -v "/var/run/docker.sock:/var/run/docker.sock" -it -e OS_ARCH_ARG -e OS_PLATFORM_ARG -e TESTFLAGS -v "/home/emile/dev/go/src/github.com/emilevauge/traefik/"dist":/go/src/github.com/emilevauge/traefik/"dist"" "traefik-dev:no-more-godep-ever" ./script/make.sh generate binary
---> Making bundle: generate (in .)
removed 'gen.go'
---> Making bundle: binary (in .)
Number of parallel builds: 8
--> linux/arm: github.com/emilevauge/traefik
--> darwin/amd64: github.com/emilevauge/traefik
--> darwin/386: github.com/emilevauge/traefik
--> linux/386: github.com/emilevauge/traefik
--> linux/amd64: github.com/emilevauge/traefik
$ ls dist/
traefik* traefik_darwin-386* traefik_darwin-amd64* traefik_linux-386* traefik_linux-amd64* traefik_linux-arm*
traefik*
```
#### Using `godep`
#### Using `glide`
The idea behind `godep` is the following :
The idea behind `glide` is the following :
- when checkout(ing) a project, **run `godep restore`** to install
- when checkout(ing) a project, **run `glide up`** to install
(`go get …`) the dependencies in the `GOPATH`.
- if you need another dependency, `go get` it, import and use it in
the source, and **run `godep save ./...`** to save it in
`Godeps/Godeps.json`.
- if you need another dependency, import and use it in
the source, and **run `glide get github.com/Masterminds/cookoo`** to save it in
`vendor` and add it to your `glide.yaml`.
```bash
$ godep restore
# Generate
$ godep go generate
$ glide up --update-vendored
# generate
$ go generate
# Simple go build
$ godep go build
$ go build
# Using gox to build multiple platform
$ GOPATH=`godep path`:$GOPATH gox "linux darwin" "386 amd64 arm" \
$ gox "linux darwin" "386 amd64 arm" \
-output="dist/traefik_{{.OS}}-{{.Arch}}"
# run other commands like tests
$ godep go test ./...
$ go test ./...
ok _/home/vincent/src/github/vdemeester/traefik 0.004s
```

View File

@@ -1,12 +1,15 @@
FROM golang:1.5
RUN go get github.com/tools/godep
RUN go get github.com/Masterminds/glide
RUN go get github.com/mitchellh/gox
RUN go get github.com/tcnksm/ghr
# Which docker version to test on
ENV DOCKER_VERSION 1.6.2
# enable GO15VENDOREXPERIMENT
ENV GO15VENDOREXPERIMENT 1
# Download docker
RUN set -ex; \
curl https://get.docker.com/builds/Linux/x86_64/docker-${DOCKER_VERSION} -o /usr/local/bin/docker-${DOCKER_VERSION}; \
@@ -15,17 +18,9 @@ RUN set -ex; \
# Set the default Docker to be run
RUN ln -s /usr/local/bin/docker-${DOCKER_VERSION} /usr/local/bin/docker
ENV PATH /go/src/github.com/emilevauge/traefik/Godeps/_workspace/bin:$PATH
WORKDIR /go/src/github.com/emilevauge/traefik
# This is a hack (see libcompose#32) - will be removed when libcompose will be fixed
# (i.e go get able)
RUN mkdir -p /go/src/github.com/docker/docker/autogen/dockerversion/
COPY Godeps/_workspace/src/github.com/docker/docker/autogen/dockerversion/dockerversion.go /go/src/github.com/docker/docker/autogen/dockerversion/dockerversion.go
RUN mkdir Godeps
COPY Godeps/Godeps.json Godeps/
RUN godep restore
COPY glide.yaml glide.yaml
RUN glide up
COPY . /go/src/github.com/emilevauge/traefik

View File

@@ -6,6 +6,7 @@ machine:
environment:
REPO: $CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME
DOCKER_HOST: tcp://172.17.42.1:2375
VERSION: v1.0.alpha.$CIRCLE_BUILD_NUM
dependencies:
pre:
@@ -27,8 +28,8 @@ deployment:
hub:
branch: master
commands:
- ghr -t $GITHUB_TOKEN -u $CIRCLE_PROJECT_USERNAME -r $CIRCLE_PROJECT_REPONAME --prerelease v1.0.alpha.$CIRCLE_BUILD_NUM dist/
- ghr -t $GITHUB_TOKEN -u $CIRCLE_PROJECT_USERNAME -r $CIRCLE_PROJECT_REPONAME --prerelease ${VERSION} dist/
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
- docker push ${REPO,,}:latest
- docker tag ${REPO,,}:latest ${REPO,,}:v1.0.alpha.$CIRCLE_BUILD_NUM
- docker push ${REPO,,}:v1.0.alpha.$CIRCLE_BUILD_NUM
- docker tag ${REPO,,}:latest ${REPO,,}:${VERSION}
- docker push ${REPO,,}:${VERSION}

View File

@@ -32,38 +32,45 @@ func NewGlobalConfiguration() *GlobalConfiguration {
return globalConfiguration
}
// Backend configuration
type Backend struct {
Servers map[string]Server
CircuitBreaker *CircuitBreaker
LoadBalancer *LoadBalancer
Servers map[string]Server `json:"servers,omitempty"`
CircuitBreaker *CircuitBreaker `json:"circuitBreaker,omitempty"`
LoadBalancer *LoadBalancer `json:"loadBalancer,omitempty"`
}
// LoadBalancer configuration
type LoadBalancer struct {
Method string
Method string `json:"method,omitempty"`
}
// CircuitBreaker configuration
type CircuitBreaker struct {
Expression string
Expression string `json:"expression,omitempty"`
}
// Server configuration
type Server struct {
URL string
Weight int
URL string `json:"url,omitempty"`
Weight int `json:"weight,omitempty"`
}
// Route configuration
type Route struct {
Rule string
Value string
Rule string `json:"rule,omitempty"`
Value string `json:"value,omitempty"`
}
// Frontend configuration
type Frontend struct {
Backend string
Routes map[string]Route
Backend string `json:"backend,omitempty"`
Routes map[string]Route `json:"routes,omitempty"`
}
// Configuration of a provider
type Configuration struct {
Backends map[string]*Backend
Frontends map[string]*Frontend
Backends map[string]*Backend `json:"backends,omitempty"`
Frontends map[string]*Frontend `json:"frontends,omitempty"`
}
// Load Balancer Method

View File

@@ -4,17 +4,17 @@ ___
# <a id="top"></a> Documentation
* [Basics](#basics)
* [Global configuration](#global)
* [File backend](#file)
* [API backend](#api)
* [Docker backend](#docker)
* [Mesos/Marathon backend](#marathon)
* [Consul backend](#consul)
* [Etcd backend](#etcd)
* [Zookeeper backend](#zk)
* [Boltdb backend](#boltdb)
* [Benchmarks](#benchmarks)
- [Basics](#basics)
- [Global configuration](#global)
- [File backend](#file)
- [API backend](#api)
- [Docker backend](#docker)
- [Mesos/Marathon backend](#marathon)
- [Consul backend](#consul)
- [Etcd backend](#etcd)
- [Zookeeper backend](#zk)
- [Boltdb backend](#boltdb)
- [Benchmarks](#benchmarks)
## <a id="basics"></a> Basics
@@ -29,12 +29,12 @@ Basically, Træfɪk is a http router, which sends traffic from frontends to http
Frontends can be defined using the following rules:
* `Headers`: Headers adds a matcher for request header values. It accepts a sequence of key/value pairs to be matched. For example: `application/json`
* `HeadersRegexp`: Regular expressions can be used with headers as well. It accepts a sequence of key/value pairs, where the value has regex support. For example: `application/(text|json)`
* `Host`: Host adds a matcher for the URL host. It accepts a template with zero or more URL variables enclosed by `{}`. Variables can define an optional regexp pattern to be matched: `www.traefik.io`, `{subdomain:[a-z]+}.traefik.io`
* `Methods`: Methods adds a matcher for HTTP methods. It accepts a sequence of one or more methods to be matched, e.g.: `GET`, `POST`, `PUT`
* `Path`: Path adds a matcher for the URL path. It accepts a template with zero or more URL variables enclosed by `{}`. The template must start with a `/`. For exemple `/products/` `/articles/{category}/{id:[0-9]+}`
* `PathPrefix`: PathPrefix adds a matcher for the URL path prefix. This matches if the given template is a prefix of the full URL path.
- `Headers`: Headers adds a matcher for request header values. It accepts a sequence of key/value pairs to be matched. For example: `application/json`
- `HeadersRegexp`: Regular expressions can be used with headers as well. It accepts a sequence of key/value pairs, where the value has regex support. For example: `application/(text|json)`
- `Host`: Host adds a matcher for the URL host. It accepts a template with zero or more URL variables enclosed by `{}`. Variables can define an optional regexp pattern to be matched: `www.traefik.io`, `{subdomain:[a-z]+}.traefik.io`
- `Methods`: Methods adds a matcher for HTTP methods. It accepts a sequence of one or more methods to be matched, e.g.: `GET`, `POST`, `PUT`
- `Path`: Path adds a matcher for the URL path. It accepts a template with zero or more URL variables enclosed by `{}`. The template must start with a `/`. For exemple `/products/` `/articles/{category}/{id:[0-9]+}`
- `PathPrefix`: PathPrefix adds a matcher for the URL path prefix. This matches if the given template is a prefix of the full URL path.
A frontend is a set of rules that forwards the incoming http traffic to a backend.
@@ -44,19 +44,19 @@ Frontends can be defined using the following rules:
A backend is responsible to load-balance the traffic coming from one or more frontends to a set of http servers.
Various methods of load-balancing is supported:
* `wrr`: Weighted Round Robin
* `drr`: Dynamic Round Robin: increases weights on servers that perform better than others. It also rolls back to original weights if the servers have changed.
- `wrr`: Weighted Round Robin
- `drr`: Dynamic Round Robin: increases weights on servers that perform better than others. It also rolls back to original weights if the servers have changed.
A circuit breaker can also be applied to a backend, preventing high loads on failing servers.
It can be configured using:
* Methods: `LatencyAtQuantileMS`, `NetworkErrorRatio`, `ResponseCodeRatio`
* Operators: `AND`, `OR`, `EQ`, `NEQ`, `LT`, `LE`, `GT`, `GE`
- Methods: `LatencyAtQuantileMS`, `NetworkErrorRatio`, `ResponseCodeRatio`
- Operators: `AND`, `OR`, `EQ`, `NEQ`, `LT`, `LE`, `GT`, `GE`
For example:
* `NetworkErrorRatio() > 0.5`
* `LatencyAtQuantileMS(50.0) > 50`
* `ResponseCodeRatio(500, 600, 0, 600) > 0.5`
- `NetworkErrorRatio() > 0.5`
- `LatencyAtQuantileMS(50.0) > 50`
- `ResponseCodeRatio(500, 600, 0, 600) > 0.5`
## <a id="global"></a> Global configuration
@@ -114,7 +114,7 @@ For example:
Like any other reverse proxy, Træfɪk can be configured with a file. You have two choices:
* simply add your configuration at the end of the global configuration file `traefik.toml` :
- simply add your configuration at the end of the global configuration file `traefik.toml` :
```toml
# traefik.toml
@@ -158,7 +158,7 @@ logLevel = "DEBUG"
value = "/test"
```
* or put your rules in a separate file, for example `rules.tml`:
- or put your rules in a separate file, for example `rules.tml`:
```toml
# traefik.toml
@@ -230,12 +230,12 @@ address = ":8080"
# KeyFile = "traefik.key"
```
* `/`: provides a simple HTML frontend of Træfik
- `/`: provides a simple HTML frontend of Træfik
![Web UI Providers](img/web.frontend.png)
![Web UI Health](img/traefik-health.png)
* `/health`: `GET` json metrics
- `/health`: `GET` json metrics
```sh
$ curl -s "http://localhost:8080/health" | jq .
@@ -275,64 +275,63 @@ $ curl -s "http://localhost:8080/health" | jq .
}
```
* `/api`: `GET` configuration for all providers
- `/api`: `GET` configuration for all providers
```sh
$ curl -s "http://localhost:8080/api" | jq .
{
"file": {
"Frontends": {
"frontends": {
"frontend2": {
"Routes": {
"routes": {
"test_2": {
"Value": "/test",
"Rule": "Path"
"value": "/test",
"rule": "Path"
}
},
"Backend": "backend1"
"backend": "backend1"
},
"frontend1": {
"Routes": {
"routes": {
"test_1": {
"Value": "test.localhost",
"Rule": "Host"
"value": "test.localhost",
"rule": "Host"
}
},
"Backend": "backend2"
"backend": "backend2"
}
},
"Backends": {
"backends": {
"backend2": {
"LoadBalancer": {
"Method": "drr"
"loadBalancer": {
"method": "drr"
},
"CircuitBreaker": null,
"Servers": {
"servers": {
"server2": {
"Weight": 2,
"weight": 2,
"URL": "http://172.17.0.5:80"
},
"server1": {
"Weight": 1,
"URL": "http://172.17.0.4:80"
"weight": 1,
"url": "http://172.17.0.4:80"
}
}
},
"backend1": {
"LoadBalancer": {
"Method": "wrr"
"loadBalancer": {
"method": "wrr"
},
"CircuitBreaker": {
"Expression": "NetworkErrorRatio() > 0.5"
"circuitBreaker": {
"expression": "NetworkErrorRatio() > 0.5"
},
"Servers": {
"servers": {
"server2": {
"Weight": 1,
"URL": "http://172.17.0.3:80"
"weight": 1,
"url": "http://172.17.0.3:80"
},
"server1": {
"Weight": 10,
"URL": "http://172.17.0.2:80"
"weight": 10,
"url": "http://172.17.0.2:80"
}
}
}
@@ -394,14 +393,13 @@ watch = true
# filename = "docker.tmpl"
```
Labels can be used on containers to override default behaviour:
* `traefik.backend=foo`: assign the container to `foo` backend
* `traefik.port=80`: register this port. Useful when the container exposes multiples ports.
* `traefik.weight=10`: assign this weight to the container
* `traefik.enable=false`: disable this container in Træfɪk
* `traefik.host=bar`: override the default routing from {containerName}.{domain} to bar.{domain}
- `traefik.backend=foo`: assign the container to `foo` backend
- `traefik.port=80`: register this port. Useful when the container exposes multiples ports.
- `traefik.weight=10`: assign this weight to the container
- `traefik.enable=false`: disable this container in Træfɪk
- `traefik.host=bar`: override the default routing from `{containerName}.{domain}` to `bar.{domain}`
* `traefik.domain=traefik.localhost`: override the default domain
## <a id="marathon"></a> Marathon backend
@@ -456,12 +454,12 @@ domain = "marathon.localhost"
Labels can be used on containers to override default behaviour:
* `traefik.backend=foo`: assign the application to `foo` backend
* `traefik.port=80`: register this port. Useful when the application exposes multiples ports.
* `traefik.weight=10`: assign this weight to the application
* `traefik.enable=false`: disable this application in Træfɪk
* `traefik.host=bar`: override the default routing from {appName}.{domain} to bar.{domain}
* `traefik.prefixes=pf1,pf2`: use PathPrefix(es) instead of hostname for routing, use filename="providerTemplates/marathon-prefix.tmpl" with this option
- `traefik.backend=foo`: assign the application to `foo` backend
- `traefik.port=80`: register this port. Useful when the application exposes multiples ports.
- `traefik.weight=10`: assign this weight to the application
- `traefik.enable=false`: disable this application in Træfɪk
- `traefik.host=bar`: override the default routing from `{appName}.{domain}` to `bar.{domain}`
- `traefik.prefixes=pf1,pf2`: use `PathPrefix(es)` instead of hostname for routing, use `filename="providerTemplates/marathon-prefix.tmpl"` with this option
* `traefik.domain=traefik.localhost`: override the default domain
## <a id="consul"></a> Consul backend
@@ -508,39 +506,39 @@ The Keys-Values structure should look (using `prefix = "/traefik"`):
- backend 1
| Key | Value |
| ------------- | ----------- |
| /traefik/backends/backend1/circuitbreaker/expression | `NetworkErrorRatio() > 0.5` |
| /traefik/backends/backend1/servers/server1/url | `http://172.17.0.2:80` |
| /traefik/backends/backend1/servers/server1/weight | `10` |
| /traefik/backends/backend1/servers/server2/url | `http://172.17.0.3:80` |
| /traefik/backends/backend1/servers/server2/weight | `1` |
| Key | Value |
|--------------------------------------------------------|-----------------------------|
| `/traefik/backends/backend1/circuitbreaker/expression` | `NetworkErrorRatio() > 0.5` |
| `/traefik/backends/backend1/servers/server1/url` | `http://172.17.0.2:80` |
| `/traefik/backends/backend1/servers/server1/weight` | `10` |
| `/traefik/backends/backend1/servers/server2/url` | `http://172.17.0.3:80` |
| `/traefik/backends/backend1/servers/server2/weight` | `1` |
- backend 2
| Key | Value |
| ------------- | ----------- |
| /traefik/backends/backend2/loadbalancer/method | `drr` |
| /traefik/backends/backend2/servers/server1/url | `http://172.17.0.4:80` |
| /traefik/backends/backend2/servers/server1/weight | `1` |
| /traefik/backends/backend2/servers/server2/url | `http://172.17.0.5:80` |
| /traefik/backends/backend2/servers/server2/weight | `2` |
| Key | Value |
|-----------------------------------------------------|------------------------|
| `/traefik/backends/backend2/loadbalancer/method` | `drr` |
| `/traefik/backends/backend2/servers/server1/url` | `http://172.17.0.4:80` |
| `/traefik/backends/backend2/servers/server1/weight` | `1` |
| `/traefik/backends/backend2/servers/server2/url` | `http://172.17.0.5:80` |
| `/traefik/backends/backend2/servers/server2/weight` | `2` |
- frontend 1
| Key | Value |
| ------------- | ----------- |
| /traefik/frontends/frontend1/backend | `backend2` |
| /traefik/frontends/frontend1/routes/test_1/rule | `Host` |
| /traefik/frontends/frontend1/routes/test_1/value | `test.localhost` |
| Key | Value |
|----------------------------------------------------|------------------|
| `/traefik/frontends/frontend1/backend` | `backend2` |
| `/traefik/frontends/frontend1/routes/test_1/rule` | `Host` |
| `/traefik/frontends/frontend1/routes/test_1/value` | `test.localhost` |
- frontend 2
| Key | Value |
| ------------- | ----------- |
| /traefik/frontends/frontend2/backend | `backend1` |
| /traefik/frontends/frontend2/routes/test_2/rule | `Path` |
| /traefik/frontends/frontend2/routes/test_2/value | `/test` |
| Key | Value |
|----------------------------------------------------|------------|
| `/traefik/frontends/frontend2/backend` | `backend1` |
| `/traefik/frontends/frontend2/routes/test_2/rule` | `Path` |
| `/traefik/frontends/frontend2/routes/test_2/value` | `/test` |
## <a id="etcd"></a> Etcd backend
@@ -587,39 +585,39 @@ The Keys-Values structure should look (using `prefix = "/traefik"`):
- backend 1
| Key | Value |
| ------------- | ----------- |
| /traefik/backends/backend1/circuitbreaker/expression | `NetworkErrorRatio() > 0.5` |
| /traefik/backends/backend1/servers/server1/url | `http://172.17.0.2:80` |
| /traefik/backends/backend1/servers/server1/weight | `10` |
| /traefik/backends/backend1/servers/server2/url | `http://172.17.0.3:80` |
| /traefik/backends/backend1/servers/server2/weight | `1` |
| Key | Value |
|--------------------------------------------------------|-----------------------------|
| `/traefik/backends/backend1/circuitbreaker/expression` | `NetworkErrorRatio() > 0.5` |
| `/traefik/backends/backend1/servers/server1/url` | `http://172.17.0.2:80` |
| `/traefik/backends/backend1/servers/server1/weight` | `10` |
| `/traefik/backends/backend1/servers/server2/url` | `http://172.17.0.3:80` |
| `/traefik/backends/backend1/servers/server2/weight` | `1` |
- backend 2
| Key | Value |
| ------------- | ----------- |
| /traefik/backends/backend2/loadbalancer/method | `drr` |
| /traefik/backends/backend2/servers/server1/url | `http://172.17.0.4:80` |
| /traefik/backends/backend2/servers/server1/weight | `1` |
| /traefik/backends/backend2/servers/server2/url | `http://172.17.0.5:80` |
| /traefik/backends/backend2/servers/server2/weight | `2` |
| Key | Value |
|-----------------------------------------------------|------------------------|
| `/traefik/backends/backend2/loadbalancer/method` | `drr` |
| `/traefik/backends/backend2/servers/server1/url` | `http://172.17.0.4:80` |
| `/traefik/backends/backend2/servers/server1/weight` | `1` |
| `/traefik/backends/backend2/servers/server2/url` | `http://172.17.0.5:80` |
| `/traefik/backends/backend2/servers/server2/weight` | `2` |
- frontend 1
| Key | Value |
| ------------- | ----------- |
| /traefik/frontends/frontend1/backend | `backend2` |
| /traefik/frontends/frontend1/routes/test_1/rule | `Host` |
| /traefik/frontends/frontend1/routes/test_1/value | `test.localhost` |
| Key | Value |
|----------------------------------------------------|------------------|
| `/traefik/frontends/frontend1/backend` | `backend2` |
| `/traefik/frontends/frontend1/routes/test_1/rule` | `Host` |
| `/traefik/frontends/frontend1/routes/test_1/value` | `test.localhost` |
- frontend 2
| Key | Value |
| ------------- | ----------- |
| /traefik/frontends/frontend2/backend | `backend1` |
| /traefik/frontends/frontend2/routes/test_2/rule | `Path` |
| /traefik/frontends/frontend2/routes/test_2/value | `/test` |
| Key | Value |
|----------------------------------------------------|------------|
| `/traefik/frontends/frontend2/backend` | `backend1` |
| `/traefik/frontends/frontend2/routes/test_2/rule` | `Path` |
| `/traefik/frontends/frontend2/routes/test_2/value` | `/test` |
## <a id="zk"></a> Zookeeper backend
@@ -665,39 +663,39 @@ The Keys-Values structure should look (using `prefix = "/traefik"`):
- backend 1
| Key | Value |
| ------------- | ----------- |
| /traefik/backends/backend1/circuitbreaker/expression | `NetworkErrorRatio() > 0.5` |
| /traefik/backends/backend1/servers/server1/url | `http://172.17.0.2:80` |
| /traefik/backends/backend1/servers/server1/weight | `10` |
| /traefik/backends/backend1/servers/server2/url | `http://172.17.0.3:80` |
| /traefik/backends/backend1/servers/server2/weight | `1` |
| Key | Value |
|--------------------------------------------------------|-----------------------------|
| `/traefik/backends/backend1/circuitbreaker/expression` | `NetworkErrorRatio() > 0.5` |
| `/traefik/backends/backend1/servers/server1/url` | `http://172.17.0.2:80` |
| `/traefik/backends/backend1/servers/server1/weight` | `10` |
| `/traefik/backends/backend1/servers/server2/url` | `http://172.17.0.3:80` |
| `/traefik/backends/backend1/servers/server2/weight` | `1` |
- backend 2
| Key | Value |
| ------------- | ----------- |
| /traefik/backends/backend2/loadbalancer/method | `drr` |
| /traefik/backends/backend2/servers/server1/url | `http://172.17.0.4:80` |
| /traefik/backends/backend2/servers/server1/weight | `1` |
| /traefik/backends/backend2/servers/server2/url | `http://172.17.0.5:80` |
| /traefik/backends/backend2/servers/server2/weight | `2` |
| Key | Value |
|-----------------------------------------------------|------------------------|
| `/traefik/backends/backend2/loadbalancer/method` | `drr` |
| `/traefik/backends/backend2/servers/server1/url` | `http://172.17.0.4:80` |
| `/traefik/backends/backend2/servers/server1/weight` | `1` |
| `/traefik/backends/backend2/servers/server2/url` | `http://172.17.0.5:80` |
| `/traefik/backends/backend2/servers/server2/weight` | `2` |
- frontend 1
| Key | Value |
| ------------- | ----------- |
| /traefik/frontends/frontend1/backend | `backend2` |
| /traefik/frontends/frontend1/routes/test_1/rule | `Host` |
| /traefik/frontends/frontend1/routes/test_1/value | `test.localhost` |
| Key | Value |
|---------------------------------------------------|------------------|
| `/traefik/frontends/frontend1/backend | `backend2` |
| `/traefik/frontends/frontend1/routes/test_1/rule | `Host` |
| `/traefik/frontends/frontend1/routes/test_1/value | `test.localhost` |
- frontend 2
| Key | Value |
| ------------- | ----------- |
| /traefik/frontends/frontend2/backend | `backend1` |
| /traefik/frontends/frontend2/routes/test_2/rule | `Path` |
| /traefik/frontends/frontend2/routes/test_2/value | `/test` |
| Key | Value |
|----------------------------------------------------|------------|
| `/traefik/frontends/frontend2/backend` | `backend1` |
| `/traefik/frontends/frontend2/routes/test_2/rule` | `Path` |
| `/traefik/frontends/frontend2/routes/test_2/value` | `/test` |
## <a id="boltdb"></a> BoltDB backend
@@ -745,7 +743,7 @@ Træfɪk can be configured to use BoltDB as a backend configuration:
Here are some early Benchmarks between Nginx and Træfɪk acting as simple load balancers between two servers.
* Nginx:
- Nginx:
```sh
$ docker run -d -e VIRTUAL_HOST=test1.localhost emilevauge/whoami
@@ -805,10 +803,9 @@ Percentage of the requests served within a certain time (ms)
98% 12
99% 13
100% 36 (longest request)
```
* Træfɪk:
- Træfɪk:
```sh
$ docker run -d -l traefik.backend=test1 -l traefik.host=test1 emilevauge/whoami
@@ -868,5 +865,4 @@ Percentage of the requests served within a certain time (ms)
98% 11
99% 13
100% 22 (longest request)
```

144
glide.yaml Normal file
View File

@@ -0,0 +1,144 @@
package: main
import:
- package: github.com/coreos/go-etcd
ref: cc90c7b091275e606ad0ca7102a23fb2072f3f5e
subpackages:
- etcd
- package: github.com/docker/distribution
ref: 9038e48c3b982f8e82281ea486f078a73731ac4e
- package: github.com/mailgun/log
ref: 44874009257d4d47ba9806f1b7f72a32a015e4d8
- package: github.com/mailgun/oxy
ref: 547c334d658398c05b346c0b79d8f47ba2e1473b
subpackages:
- cbreaker
- forward
- memmetrics
- roundrobin
- utils
- package: github.com/hashicorp/consul
ref: de080672fee9e6104572eeea89eccdca135bb918
subpackages:
- api
- package: github.com/samuel/go-zookeeper
ref: fa6674abf3f4580b946a01bf7a1ce4ba8766205b
subpackages:
- zk
- package: github.com/docker/libtrust
ref: 9cbd2a1374f46905c68a4eb3694a130610adc62a
- package: gopkg.in/check.v1
ref: 11d3bc7aa68e238947792f30573146a3231fc0f1
- package: golang.org/x/net
ref: d9558e5c97f85372afee28cf2b6059d7d3818919
subpackages:
- context
- package: github.com/gorilla/handlers
ref: 40694b40f4a928c062f56849989d3e9cd0570e5f
- package: github.com/docker/libkv
ref: 3732f7ff1b56057c3158f10bceb1e79133025373
- package: github.com/alecthomas/template
ref: b867cc6ab45cece8143cfcc6fc9c77cf3f2c23c0
- package: github.com/vdemeester/shakers
ref: 8fe734f75f3a70b651cbfbf8a55a009da09e8dc5
- package: github.com/alecthomas/units
ref: 6b4e7dc5e3143b85ea77909c72caf89416fc2915
- package: github.com/gambol99/go-marathon
ref: 0ba31bcb0d7633ba1888d744c42990eb15281cf1
- package: github.com/mailgun/predicate
ref: cb0bff91a7ab7cf7571e661ff883fc997bc554a3
- package: github.com/thoas/stats
ref: 54ed61c2b47e263ae2f01b86837b0c4bd1da28e8
- package: github.com/samalba/dockerclient
ref: cfb489c624b635251a93e74e1e90eb0959c5367f
- package: github.com/Sirupsen/logrus
ref: 418b41d23a1bf978c06faea5313ba194650ac088
- package: github.com/unrolled/render
ref: 26b4e3aac686940fe29521545afad9966ddfc80c
- package: github.com/flynn/go-shlex
ref: 3f9db97f856818214da2e1057f8ad84803971cff
- package: github.com/fsouza/go-dockerclient
ref: 0239034d42f665efa17fd77c39f891c2f9f32922
- package: github.com/boltdb/bolt
ref: 51f99c862475898df9773747d3accd05a7ca33c1
- package: gopkg.in/mgo.v2
ref: 22287bab4379e1fbf6002fb4eb769888f3fb224c
subpackages:
- bson
- package: github.com/docker/docker
ref: f39987afe8d611407887b3094c03d6ba6a766a67
subpackages:
- autogen
- api
- cliconfig
- daemon/network
- graph/tags
- image
- opts
- pkg/archive
- pkg/fileutils
- pkg/homedir
- pkg/httputils
- pkg/ioutils
- pkg/jsonmessage
- pkg/mflag
- pkg/nat
- pkg/parsers
- pkg/pools
- pkg/promise
- pkg/random
- pkg/stdcopy
- pkg/stringid
- pkg/symlink
- pkg/system
- pkg/tarsum
- pkg/term
- pkg/timeutils
- pkg/tlsconfig
- pkg/ulimit
- pkg/units
- pkg/urlutil
- pkg/useragent
- pkg/version
- registry
- runconfig
- utils
- volume
- package: github.com/mailgun/timetools
ref: fd192d755b00c968d312d23f521eb0cdc6f66bd0
- package: github.com/codegangsta/negroni
ref: c7477ad8e330bef55bf1ebe300cf8aa67c492d1b
- package: gopkg.in/yaml.v2
ref: 7ad95dd0798a40da1ccdff6dff35fd177b5edf40
- package: github.com/opencontainers/runc
ref: 4ab132458fc3e9dbeea624153e0331952dc4c8d5
subpackages:
- libcontainer/user
- package: github.com/gorilla/mux
ref: f15e0c49460fd49eebe2bcc8486b05d1bef68d3a
- package: github.com/BurntSushi/ty
ref: 6add9cd6ad42d389d6ead1dde60b4ad71e46fd74
- package: github.com/elazarl/go-bindata-assetfs
ref: d5cac425555ca5cf00694df246e04f05e6a55150
- package: github.com/BurntSushi/toml
ref: bd2bdf7f18f849530ef7a1c29a4290217cab32a1
- package: gopkg.in/alecthomas/kingpin.v2
ref: 639879d6110b1b0409410c7b737ef0bb18325038
- package: github.com/docker/libcompose
ref: 79ef5d150f053a5b12f16b02d8844ed7cf33611a
subpackages:
- docker
- logger
- lookup
- project
- utils
- package: github.com/cenkalti/backoff
ref: 4dc77674aceaabba2c7e3da25d4c823edfb73f99
- package: gopkg.in/fsnotify.v1
ref: 96c060f6a6b7e0d6f75fddd10efeaca3e5d1bcb0
- package: github.com/mailgun/manners
ref: 37136f736785d7c6aa3b9a27b4b2dd1028ca6d79
- package: github.com/gorilla/context
ref: 215affda49addc4c8ef7e2534915df2c8c35c6cd
- package: github.com/codahale/hdrhistogram
ref: 954f16e8b9ef0e5d5189456aa4c1202758e04f17
- package: github.com/gorilla/websocket

View File

@@ -9,3 +9,36 @@
logLevel = "DEBUG"
[file]
# rules
[backends]
[backends.backend1]
[backends.backend1.circuitbreaker]
expression = "NetworkErrorRatio() > 0.5"
[backends.backend1.servers.server1]
url = "http://172.17.0.2:80"
weight = 10
[backends.backend1.servers.server2]
url = "http://172.17.0.3:80"
weight = 1
[backends.backend2]
[backends.backend2.LoadBalancer]
method = "drr"
[backends.backend2.servers.server1]
url = "http://172.17.0.4:80"
weight = 1
[backends.backend2.servers.server2]
url = "http://172.17.0.5:80"
weight = 2
[frontends]
[frontends.frontend1]
backend = "backend2"
[frontends.frontend1.routes.test_1]
rule = "Host"
value = "test.localhost"
[frontends.frontend2]
backend = "backend1"
[frontends.frontend2.routes.test_2]
rule = "Path"
value = "/test"

View File

@@ -9,7 +9,6 @@ import (
"path/filepath"
"testing"
"text/template"
"time"
"github.com/docker/libcompose/docker"
"github.com/docker/libcompose/project"
@@ -72,7 +71,7 @@ func (s *MarathonSuite) SetUpSuite(c *check.C) {
type BaseSuite struct {
composeProject *project.Project
listenChan chan project.ProjectEvent
listenChan chan project.Event
started chan bool
stopped chan bool
deleted chan bool
@@ -82,14 +81,12 @@ func (s *BaseSuite) TearDownSuite(c *check.C) {
// shutdown and delete compose project
if s.composeProject != nil {
s.composeProject.Down()
// Waiting for libcompose#55 to be merged
// <-s.stopped
time.Sleep(2 * time.Second)
<-s.stopped
defer close(s.stopped)
s.composeProject.Delete()
// Waiting for libcompose#55 to be merged
// <-s.deleted
time.Sleep(2 * time.Second)
<-s.deleted
defer close(s.deleted)
}
}
@@ -103,32 +100,32 @@ func (s *BaseSuite) createComposeProject(c *check.C, name string) {
c.Assert(err, checker.IsNil)
s.composeProject = composeProject
s.listenChan = make(chan project.ProjectEvent)
s.started = make(chan bool)
s.stopped = make(chan bool)
s.deleted = make(chan bool)
s.listenChan = make(chan project.Event)
go s.startListening(c)
composeProject.AddListener(s.listenChan)
composeProject.Start()
// FIXME Wait for compose to start
// Waiting for libcompose#55 to be merged
// <-s.started
time.Sleep(2 * time.Second)
// Wait for compose to start
<-s.started
defer close(s.started)
}
func (s *BaseSuite) startListening(c *check.C) {
for event := range s.listenChan {
// FIXME Remove this when it's working (libcompose#55)
// fmt.Fprintf(os.Stdout, "Event: %s (%v)\n", event.Event, event)
// FIXME Add a timeout on event
if event.Event == project.PROJECT_UP_DONE {
// FIXME Add a timeout on event ?
if event.EventType == project.EventProjectStartDone {
s.started <- true
}
if event.Event == project.PROJECT_DOWN_DONE {
if event.EventType == project.EventProjectDownDone {
s.stopped <- true
}
if event.Event == project.PROJECT_DELETE_DONE {
if event.EventType == project.EventProjectDeleteDone {
s.deleted <- true
}
}

52
middlewares/websocket.go Normal file
View File

@@ -0,0 +1,52 @@
/*
Copyright
*/
package middlewares
import (
log "github.com/Sirupsen/logrus"
"github.com/mailgun/oxy/roundrobin"
"net/http"
"strings"
"time"
)
type WebsocketUpgrader struct {
rr *roundrobin.RoundRobin
}
func NewWebsocketUpgrader(rr *roundrobin.RoundRobin) *WebsocketUpgrader {
wu := WebsocketUpgrader{
rr: rr,
}
return &wu
}
func (u *WebsocketUpgrader) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// If request is websocket, serve with golang websocket server to do protocol handshake
if strings.Join(req.Header["Upgrade"], "") == "websocket" {
start := time.Now().UTC()
url, err := u.rr.NextServer()
if err != nil {
log.Errorf("Can't round robin in websocket middleware")
return
}
log.Debugf("Websocket forward to %s", url.String())
NewProxy(url).ServeHTTP(w, req)
if req.TLS != nil {
log.Debugf("Round trip: %v, duration: %v tls:version: %x, tls:resume:%t, tls:csuite:%x, tls:server:%v",
req.URL, time.Now().UTC().Sub(start),
req.TLS.Version,
req.TLS.DidResume,
req.TLS.CipherSuite,
req.TLS.ServerName)
} else {
log.Debugf("Round trip: %v, duration: %v",
req.URL, time.Now().UTC().Sub(start))
}
return
}
u.rr.ServeHTTP(w, req)
}

View File

@@ -0,0 +1,170 @@
package middlewares
import (
"io"
"net"
"net/http"
"net/url"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/gorilla/websocket"
)
// Original developpement made by https://github.com/koding/websocketproxy
var (
// DefaultUpgrader specifies the parameters for upgrading an HTTP
// connection to a WebSocket connection.
DefaultUpgrader = &websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
// DefaultDialer is a dialer with all fields set to the default zero values.
DefaultDialer = websocket.DefaultDialer
)
// WebsocketProxy is an HTTP Handler that takes an incoming WebSocket
// connection and proxies it to another server.
type WebsocketProxy struct {
// Backend returns the backend URL which the proxy uses to reverse proxy
// the incoming WebSocket connection. Request is the initial incoming and
// unmodified request.
Backend func(*http.Request) *url.URL
// Upgrader specifies the parameters for upgrading a incoming HTTP
// connection to a WebSocket connection. If nil, DefaultUpgrader is used.
Upgrader *websocket.Upgrader
// Dialer contains options for connecting to the backend WebSocket server.
// If nil, DefaultDialer is used.
Dialer *websocket.Dialer
}
// ProxyHandler returns a new http.Handler interface that reverse proxies the
// request to the given target.
func ProxyHandler(target *url.URL) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
NewProxy(target).ServeHTTP(rw, req)
})
}
// NewProxy returns a new Websocket reverse proxy that rewrites the
// URL's to the scheme, host and base path provider in target.
func NewProxy(target *url.URL) *WebsocketProxy {
backend := func(r *http.Request) *url.URL {
// Shallow copy
u := *target
u.Fragment = r.URL.Fragment
u.Path = r.URL.Path
u.RawQuery = r.URL.RawQuery
rurl := u.String()
if strings.HasPrefix(rurl, "http") {
u.Scheme = "ws"
}
if strings.HasPrefix(rurl, "https") {
u.Scheme = "wss"
}
return &u
}
return &WebsocketProxy{Backend: backend}
}
// ServeHTTP implements the http.Handler that proxies WebSocket connections.
func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if w.Backend == nil {
log.Println("websocketproxy: backend function is not defined")
http.Error(rw, "internal server error (code: 1)", http.StatusInternalServerError)
return
}
backendURL := w.Backend(req)
if backendURL == nil {
log.Println("websocketproxy: backend URL is nil")
http.Error(rw, "internal server error (code: 2)", http.StatusInternalServerError)
return
}
dialer := w.Dialer
if w.Dialer == nil {
dialer = DefaultDialer
}
// Pass headers from the incoming request to the dialer to forward them to
// the final destinations.
requestHeader := http.Header{}
requestHeader.Add("Origin", req.Header.Get("Origin"))
for _, prot := range req.Header[http.CanonicalHeaderKey("Sec-WebSocket-Protocol")] {
requestHeader.Add("Sec-WebSocket-Protocol", prot)
}
for _, cookie := range req.Header[http.CanonicalHeaderKey("Cookie")] {
requestHeader.Add("Cookie", cookie)
}
// Pass X-Forwarded-For headers too, code below is a part of
// httputil.ReverseProxy. See http://en.wikipedia.org/wiki/X-Forwarded-For
// for more information
// TODO: use RFC7239 http://tools.ietf.org/html/rfc7239
if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
// If we aren't the first proxy retain prior
// X-Forwarded-For information as a comma+space
// separated list and fold multiple headers into one.
if prior, ok := req.Header["X-Forwarded-For"]; ok {
clientIP = strings.Join(prior, ", ") + ", " + clientIP
}
requestHeader.Set("X-Forwarded-For", clientIP)
}
// Set the originating protocol of the incoming HTTP request. The SSL might
// be terminated on our site and because we doing proxy adding this would
// be helpful for applications on the backend.
requestHeader.Set("X-Forwarded-Proto", "http")
if req.TLS != nil {
requestHeader.Set("X-Forwarded-Proto", "https")
}
// Connect to the backend URL, also pass the headers we get from the requst
// together with the Forwarded headers we prepared above.
// TODO: support multiplexing on the same backend connection instead of
// opening a new TCP connection time for each request. This should be
// optional:
// http://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing-01
connBackend, resp, err := dialer.Dial(backendURL.String(), nil)
if err != nil {
log.Printf("websocketproxy: couldn't dial to remote backend url %s, %s, %+v", backendURL.String(), err, resp)
return
}
defer connBackend.Close()
upgrader := w.Upgrader
if w.Upgrader == nil {
upgrader = DefaultUpgrader
}
// Only pass those headers to the upgrader.
upgradeHeader := http.Header{}
upgradeHeader.Set("Sec-WebSocket-Protocol",
resp.Header.Get(http.CanonicalHeaderKey("Sec-WebSocket-Protocol")))
upgradeHeader.Set("Set-Cookie",
resp.Header.Get(http.CanonicalHeaderKey("Set-Cookie")))
// Now upgrade the existing incoming request to a WebSocket connection.
// Also pass the header that we gathered from the Dial handshake.
connPub, err := upgrader.Upgrade(rw, req, upgradeHeader)
if err != nil {
log.Printf("websocketproxy: couldn't upgrade %s\n", err)
return
}
defer connPub.Close()
errc := make(chan error, 2)
cp := func(dst io.Writer, src io.Reader) {
_, err := io.Copy(dst, src)
errc <- err
}
// Start our proxy now, everything is ready...
go cp(connBackend.UnderlyingConn(), connPub.UnderlyingConn())
go cp(connPub.UnderlyingConn(), connBackend.UnderlyingConn())
<-errc
}

View File

@@ -7,8 +7,14 @@ if ! test -e gen.go; then
fi
rm -f dist/traefik
rm -rf Godeps/_workspace/pkg
if [ -z "$VERSION" ]; then
VERSION=$(git rev-parse HEAD)
fi
if [ -z "$DATE" ]; then
DATE=$(date -u '+%Y-%m-%d_%I:%M:%S%p')
fi
# Build binaries
CGO_ENABLED=0 godep go build -a -installsuffix nocgo -o dist/traefik .
CGO_ENABLED=0 go build -ldflags "-X main.Version=$VERSION -X main.BuildDate=$DATE" -a -installsuffix nocgo -o dist/traefik .

View File

@@ -20,11 +20,17 @@ else
OS_ARCH_ARG=($2)
fi
if [ -z "$VERSION" ]; then
VERSION=$(git rev-parse HEAD)
fi
if [ -z "$DATE" ]; then
DATE=$(date -u '+%Y-%m-%d_%I:%M:%S%p')
fi
# Get rid of existing binaries
rm -f dist/traefik_*
rm -rf Godeps/_workspace/pkg
# Build binaries
GOPATH=`godep path`:$GOPATH gox "${OS_PLATFORM_ARG[@]}" "${OS_ARCH_ARG[@]}" \
gox -ldflags "-X main.Version=$VERSION -X main.BuildDate=$DATE" "${OS_PLATFORM_ARG[@]}" "${OS_ARCH_ARG[@]}" \
-output="dist/traefik_{{.OS}}-{{.Arch}}"

View File

@@ -6,5 +6,5 @@ export DEST=.
TESTFLAGS="$TESTFLAGS -test.timeout=30m -check.v"
cd integration
GOPATH=`godep path`:$GOPATH go test $TESTFLAGS
go test $TESTFLAGS

View File

@@ -17,7 +17,7 @@ find_dirs() {
find . -not \( \
\( \
-path './integration/*' \
-o -path './Godeps/*' \
-o -path './vendor/*' \
-o -path './.git/*' \
\) \
-prune \
@@ -34,7 +34,7 @@ TESTS_FAILED=()
for dir in $TESTDIRS; do
echo '+ go test' $TESTFLAGS "${dir}"
godep go test ${TESTFLAGS} ${dir}
go test ${TESTFLAGS} ${dir}
if [ $? != 0 ]; then
TESTS_FAILED+=("$dir")
echo

View File

@@ -3,7 +3,7 @@
source "$(dirname "$BASH_SOURCE")/.validate"
IFS=$'\n'
files=( $(validate_diff --diff-filter=ACMR --name-only -- '*.go' | grep -v '^Godeps' || true) )
files=( $(validate_diff --diff-filter=ACMR --name-only -- '*.go' | grep -v '^vendor' || true) )
unset IFS
badFiles=()

View File

@@ -3,7 +3,7 @@
source "$(dirname "$BASH_SOURCE")/.validate"
IFS=$'\n'
files=( $(validate_diff --diff-filter=ACMR --name-only -- '*.go' | grep -v '^Godeps/' || true) )
files=( $(validate_diff --diff-filter=ACMR --name-only -- '*.go' | grep -v '^vendor/' || true) )
unset IFS
errors=()

View File

@@ -1,4 +1,4 @@
(function () {
(function (d3) {
'use strict';
angular.module('traefik.section.health')
@@ -9,7 +9,7 @@
vm.graph = {
averageResponseTime: {},
totalStatusCodeCount: {}
}
};
vm.graph.totalStatusCodeCount.options = {
"chart": {
@@ -71,7 +71,7 @@
vm.graph.totalStatusCodeCount.data[0].values.push({
label: code,
value: totalStatusCodeCount[code]
})
});
}
}
@@ -199,6 +199,6 @@
$interval.cancel(intervalId);
});
}]);
}]);
})();
})(d3);

View File

@@ -9,15 +9,15 @@
<td><em>URL</em></td>
<td><em>Weight</em></td>
</tr>
<tr data-ng-repeat="(serverId, server) in backendCtrl.backend.Servers">
<tr data-ng-repeat="(serverId, server) in backendCtrl.backend.servers">
<td>{{serverId}}</td>
<td><code><a data-ng-href="{{server.url}}">{{server.URL}}</a></code></td>
<td>{{server.Weight}}</td>
<td><code><a data-ng-href="{{server.url}}">{{server.url}}</a></code></td>
<td>{{server.weight}}</td>
</tr>
</table>
</div>
<div class="panel-footer" data-ng-show="backendCtrl.backend.LoadBalancer || backendCtrl.backend.CircuitBreaker">
<span data-ng-show="backendCtrl.backend.LoadBalancer" class="label label-success">Load Balancer: {{backendCtrl.backend.LoadBalancer.Method}}</span>
<span data-ng-show="backendCtrl.backend.CircuitBreaker" class="label label-success">Circuit Breaker: {{backendCtrl.backend.CircuitBreaker.Expression}}</span>
<div class="panel-footer" data-ng-show="backendCtrl.backend.loadBalancer || backendCtrl.backend.circuitBreaker">
<span data-ng-show="backendCtrl.backend.loadBalancer" class="label label-success">Load Balancer: {{backendCtrl.backend.loadBalancer.method}}</span>
<span data-ng-show="backendCtrl.backend.circuitBreaker" class="label label-success">Circuit Breaker: {{backendCtrl.backend.circuitBreaker.expression}}</span>
</div>
</div>

View File

@@ -9,14 +9,14 @@
<td><em>Rule</em></td>
<td><em>Value</em></td>
</tr>
<tr data-ng-repeat="(routeId, route) in frontendCtrl.frontend.Routes">
<tr data-ng-repeat="(routeId, route) in frontendCtrl.frontend.routes">
<td>{{routeId}}</td>
<td>{{route.Rule}}</td>
<td><code>{{route.Value}}</code></td>
<td>{{route.rule}}</td>
<td><code>{{route.value}}</code></td>
</tr>
</table>
</div>
<div data-bg-show="frontendCtrl.frontend.Backend" class="panel-footer">
<span class="label label-warning" role="button" data-toggle="collapse" href="#{{frontendCtrl.frontend.Backend}}" aria-expanded="false">{{frontendCtrl.frontend.Backend}}</span>
<div data-bg-show="frontendCtrl.frontend.backend" class="panel-footer">
<span class="label label-warning" role="button" data-toggle="collapse" href="#{{frontendCtrl.frontend.backend}}" aria-expanded="false">{{frontendCtrl.frontend.backend}}</span>
</div>
</div>

View File

@@ -4,12 +4,12 @@
<div class="row tabset-row__providers">
<div class="col-md-6">
<div data-ng-repeat="(frontendId, frontend) in provider.Frontends">
<div data-ng-repeat="(frontendId, frontend) in provider.frontends">
<frontend-monitor data-provider-id="providerId" data-frontend-id="frontendId" data-frontend="frontend"></frontend-monitor>
</div>
</div>
<div class="col-md-6">
<div data-ng-repeat="(backendId, backend) in provider.Backends">
<div data-ng-repeat="(backendId, backend) in provider.backends">
<backend-monitor data-provider-id="providerId" data-backend-id="backendId" data-backend="backend"></backend-monitor>
</div>
</div>

View File

@@ -16,7 +16,6 @@ import (
"github.com/BurntSushi/toml"
log "github.com/Sirupsen/logrus"
"github.com/codegangsta/negroni"
"github.com/davecgh/go-spew/spew"
"github.com/emilevauge/traefik/middlewares"
"github.com/gorilla/mux"
"github.com/mailgun/manners"
@@ -30,7 +29,10 @@ import (
)
var (
Version = ""
BuildDate = ""
globalConfigFile = kingpin.Arg("conf", "Main configration file.").Default("traefik.toml").String()
version = kingpin.Flag("version", "Get Version.").Short('v').Bool()
currentConfigurations = make(configs)
metrics = stats.New()
oxyLogger = &OxyLogger{}
@@ -50,6 +52,7 @@ type configs map[string]*Configuration
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
kingpin.Version(Version + " built on the " + BuildDate)
kingpin.Parse()
fmtlog.SetFlags(fmtlog.Lshortfile | fmtlog.LstdFlags)
var srv *manners.GracefulServer
@@ -88,7 +91,7 @@ func main() {
} else {
log.SetFormatter(&log.TextFormatter{FullTimestamp: true, DisableSorting: true})
}
log.Debugf("Global configuration loaded %s", spew.Sdump(globalConfiguration))
log.Debugf("Global configuration loaded %+v", globalConfiguration)
configurationRouter = LoadDefaultConfig(globalConfiguration)
// listen new configurations from providers
@@ -97,7 +100,6 @@ func main() {
for {
configMsg := <-configurationChan
log.Infof("Configuration receveived from provider %s: %#v", configMsg.providerName, configMsg.configuration)
log.Debugf("Configuration %s", spew.Sdump(configMsg.configuration))
if configMsg.configuration == nil {
log.Info("Skipping empty configuration")
} else if reflect.DeepEqual(currentConfigurations[configMsg.providerName], configMsg.configuration) {
@@ -191,7 +193,6 @@ func main() {
func startServer(srv *manners.GracefulServer, globalConfiguration *GlobalConfiguration) {
log.Info("Starting server")
log.Debugf("Server %s", spew.Sdump(srv))
if len(globalConfiguration.CertFile) > 0 && len(globalConfiguration.KeyFile) > 0 {
err := srv.ListenAndServeTLS(globalConfiguration.CertFile, globalConfiguration.KeyFile)
if err != nil {
@@ -281,7 +282,7 @@ func LoadConfig(configurations configs, globalConfiguration *GlobalConfiguration
}
case wrr:
log.Infof("Creating load-balancer wrr")
lb = rr
lb = middlewares.NewWebsocketUpgrader(rr)
for serverName, server := range configuration.Backends[frontend.Backend].Servers {
url, err := url.Parse(server.URL)
if err != nil {