mirror of
https://github.com/containous/traefik.git
synced 2025-09-22 13:44:25 +03:00
Compare commits
14 Commits
v1.0.alpha
...
v1.0.alpha
Author | SHA1 | Date | |
---|---|---|---|
|
fd234c683c | ||
|
67bc87dcda | ||
|
c452fd2195 | ||
|
8f38337757 | ||
|
5454299bf0 | ||
|
80f4884d50 | ||
|
4ea48c2d19 | ||
|
37438a6395 | ||
|
784dc9ea62 | ||
|
6362b1da7f | ||
|
31c7aba8c4 | ||
|
45ea23ecc1 | ||
|
661ac977d3 | ||
|
c11cf801ca |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,5 +6,4 @@ log
|
||||
traefik
|
||||
traefik.toml
|
||||
|
||||
Godeps/_workspace/bin
|
||||
Godeps/_workspace/pkg
|
||||
vendor/
|
||||
|
302
Godeps/Godeps.json
generated
302
Godeps/Godeps.json
generated
@@ -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
5
Godeps/Readme
generated
@@ -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
3
Godeps/_workspace/.gitignore
generated
vendored
@@ -1,3 +0,0 @@
|
||||
/pkg
|
||||
/bin
|
||||
/src
|
71
README.md
71
README.md
@@ -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
|
||||
|
||||
[](https://asciinema.org/a/4tcyde7riou5vxulo6my3mtko)
|
||||
|
||||
## Web UI
|
||||
|
||||
You can access to a simple HTML frontend of Træfik.
|
||||
|
||||

|
||||

|
||||
|
||||
## 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.
|
||||
|
||||

|
||||

|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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}
|
||||
|
@@ -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
|
||||
|
282
docs/index.md
282
docs/index.md
@@ -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
|
||||
|
||||

|
||||

|
||||
|
||||
* `/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
144
glide.yaml
Normal 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
|
@@ -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"
|
||||
|
@@ -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
52
middlewares/websocket.go
Normal 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)
|
||||
}
|
170
middlewares/websocketproxy.go
Normal file
170
middlewares/websocketproxy.go
Normal 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
|
||||
}
|
@@ -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 .
|
||||
|
@@ -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}}"
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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=()
|
||||
|
@@ -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=()
|
||||
|
@@ -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);
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
11
traefik.go
11
traefik.go
@@ -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 {
|
||||
|
Reference in New Issue
Block a user