From 4f3b06472bf56881fb9e69e05ba55b5418b55f08 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Tue, 13 Feb 2018 23:42:03 +0100 Subject: [PATCH 1/9] Check ping configuration. --- cmd/traefik/healthcheck.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/cmd/traefik/healthcheck.go b/cmd/traefik/healthcheck.go index 9f926dd6f..67ee6cd98 100644 --- a/cmd/traefik/healthcheck.go +++ b/cmd/traefik/healthcheck.go @@ -29,11 +29,6 @@ func runHealthCheck(traefikConfiguration *TraefikConfiguration) func() error { return func() error { traefikConfiguration.GlobalConfiguration.SetEffectiveConfiguration(traefikConfiguration.ConfigFile) - if traefikConfiguration.Ping == nil { - fmt.Println("Please enable `ping` to use healtcheck.") - os.Exit(1) - } - resp, errPing := healthCheck(traefikConfiguration.GlobalConfiguration) if errPing != nil { fmt.Printf("Error calling healthcheck: %s\n", errPing) @@ -50,9 +45,13 @@ func runHealthCheck(traefikConfiguration *TraefikConfiguration) func() error { } func healthCheck(globalConfiguration configuration.GlobalConfiguration) (*http.Response, error) { + if globalConfiguration.Ping == nil { + return nil, errors.New("please enable `ping` to use health check") + } + pingEntryPoint, ok := globalConfiguration.EntryPoints[globalConfiguration.Ping.EntryPoint] if !ok { - return nil, errors.New("missing ping entrypoint") + return nil, errors.New("missing `ping` entrypoint") } client := &http.Client{Timeout: 5 * time.Second} From d54777236ccd54b247defcdd48d9e0735d6fde8a Mon Sep 17 00:00:00 2001 From: SALLEYRON Julien Date: Fri, 16 Feb 2018 10:32:03 +0100 Subject: [PATCH 2/9] Update documentation on onHostRule, ping examples, and web deprecation --- docs/configuration/acme.md | 21 +++--- docs/configuration/api.md | 9 ++- docs/configuration/backends/web.md | 107 +++++++++++++++++++++++------ docs/configuration/entrypoints.md | 10 +-- docs/configuration/ping.md | 4 +- docs/user-guide/examples.md | 79 ++++++++------------- 6 files changed, 144 insertions(+), 86 deletions(-) diff --git a/docs/configuration/acme.md b/docs/configuration/acme.md index 3248ecc6b..83bcc9eac 100644 --- a/docs/configuration/acme.md +++ b/docs/configuration/acme.md @@ -113,7 +113,7 @@ entryPoint = "https" # Required # entryPoint = "http" - + # Use a DNS-01 acme challenge rather than TLS-SNI-01 challenge # # Optional @@ -135,6 +135,7 @@ entryPoint = "https" # # delayBeforeCheck = 0 ``` + !!! note Even if `TLS-SNI-01` challenge is [disabled](https://community.letsencrypt.org/t/2018-01-11-update-regarding-acme-tls-sni-and-shared-hosting-infrastructure/50188) for the moment, it stays the _by default_ ACME Challenge in Træfik. If `TLS-SNI-01` challenge is not re-enabled in the future, it we will be removed from Træfik. @@ -149,12 +150,13 @@ entryPoint = "https" Let's Encrypt functionality will be limited until Træfik is restarted. If Let's Encrypt is not reachable, these certificates will be used : + - ACME certificates already generated before downtime - Expired ACME certificates - Provided certificates !!! note - Default Træfik certificate will be used instead of ACME certificates for new (sub)domains (which need Let's Encrypt challenge). + Default Træfik certificate will be used instead of ACME certificates for new (sub)domains (which need Let's Encrypt challenge). ### `storage` @@ -168,6 +170,7 @@ storage = "acme.json" The `storage` option sets where are stored your ACME certificates. There are two kind of `storage` : + - a JSON file, - a KV store entry. @@ -182,7 +185,7 @@ There are two kind of `storage` : #### Store data in a file -ACME certificates can be stored in a JSON file which with the `600` right mode. +ACME certificates can be stored in a JSON file which with the `600` right mode. There are two ways to store ACME certificates in a file from Docker: @@ -240,6 +243,8 @@ entryPoint = "https" Specify the entryPoint to use during the challenges. ```toml +defaultEntryPoints = ["http", "http"] + [entryPoints] [entryPoints.http] address = ":80" @@ -272,7 +277,7 @@ Use `DNS-01` challenge to generate/renew ACME certificates. # ... ``` -#### `provider` +#### `provider` Select the provider that matches the DNS domain that will host the challenge TXT record, and provide environment variables to enable setting it: @@ -326,11 +331,11 @@ onDemand = true Enable on demand certificate. -This will request a certificate from Let's Encrypt during the first TLS handshake for a hostname that does not yet have a certificate. +This will request a certificate from Let's Encrypt during the first TLS handshake for a host name that does not yet have a certificate. !!! warning - TLS handshakes will be slow when requesting a hostname certificate for the first time, this can lead to DoS attacks. - + TLS handshakes will be slow when requesting a host name certificate for the first time, this can lead to DoS attacks. + !!! warning Take note that Let's Encrypt have [rate limiting](https://letsencrypt.org/docs/rate-limits). @@ -343,7 +348,7 @@ onHostRule = true # ... ``` -Enable certificate generation on frontends Host rules. +Enable certificate generation on frontends `Host` rules (for frontends wired on the `acme.entryPoint`). This will request a certificate from Let's Encrypt for each frontend with a Host rule. diff --git a/docs/configuration/api.md b/docs/configuration/api.md index ac6afd7dc..298812f3b 100644 --- a/docs/configuration/api.md +++ b/docs/configuration/api.md @@ -1,5 +1,7 @@ # API Definition +## Configuration + ```toml # API definition [api] @@ -28,6 +30,8 @@ debug = true ``` +For more customization, see [entry points](/configuration/entrypoints/) documentation and [examples](/user-guide/examples/#ping-health-check). + ## Web UI ![Web UI Providers](/img/web.frontend.png) @@ -42,7 +46,7 @@ | `/health` | `GET` | json health metrics | | `/api` | `GET` | Configuration for all providers | | `/api/providers` | `GET` | Providers | -| `/api/providers/{provider}` | `GET`, `PUT` | Get or update provider | +| `/api/providers/{provider}` | `GET`, `PUT` | Get or update provider (1) | | `/api/providers/{provider}/backends` | `GET` | List backends | | `/api/providers/{provider}/backends/{backend}` | `GET` | Get backend | | `/api/providers/{provider}/backends/{backend}/servers` | `GET` | List servers in backend | @@ -52,6 +56,8 @@ | `/api/providers/{provider}/frontends/{frontend}/routes` | `GET` | List routes in a frontend | | `/api/providers/{provider}/frontends/{frontend}/routes/{route}` | `GET` | Get a route in a frontend | +<1> See [Rest](/configuration/backends/rest/#api) for more information. + !!! warning For compatibility reason, when you activate the rest provider, you can use `web` or `rest` as `provider` value. But be careful, in the configuration for all providers the key is still `web`. @@ -185,6 +191,7 @@ curl -s "http://localhost:8080/health" | jq . ## Metrics You can enable Traefik to export internal metrics to different monitoring systems. + ```toml [api] # ... diff --git a/docs/configuration/backends/web.md b/docs/configuration/backends/web.md index a5e185560..6e3b2852c 100644 --- a/docs/configuration/backends/web.md +++ b/docs/configuration/backends/web.md @@ -36,7 +36,6 @@ address = ":8080" # readOnly = true - # Set the root path for webui and API # # Deprecated @@ -55,13 +54,13 @@ readOnly = true ### Authentication !!! note - The `/ping` path of the api is excluded from authentication (since 1.4). + The `/ping` path of the API is excluded from authentication (since 1.4). #### Basic Authentication Passwords can be encoded in MD5, SHA1 and BCrypt: you can use `htpasswd` to generate those ones. -Users can be specified directly in the toml file, or indirectly by referencing an external file; +Users can be specified directly in the TOML file, or indirectly by referencing an external file; if both are provided, the two are merged, with external file contents having precedence. ```toml @@ -80,7 +79,7 @@ usersFile = "/path/to/.htpasswd" You can use `htdigest` to generate those ones. -Users can be specified directly in the toml file, or indirectly by referencing an external file; +Users can be specified directly in the TOML file, or indirectly by referencing an external file; if both are provided, the two are merged, with external file contents having precedence ```toml @@ -98,7 +97,7 @@ usersFile = "/path/to/.htdigest" ## Metrics -You can enable Traefik to export internal metrics to different monitoring systems. +You can enable Træfik to export internal metrics to different monitoring systems. ### Prometheus @@ -114,7 +113,7 @@ You can enable Traefik to export internal metrics to different monitoring system # Optional # Default: [0.1, 0.3, 1.2, 5] buckets=[0.1,0.3,1.2,5.0] - + # ... ``` @@ -221,7 +220,7 @@ recentErrors = 10 |-----------------------------------------------------------------|:-------------:|----------------------------------------------------------------------------------------------------| | `/` | `GET` | Provides a simple HTML frontend of Træfik | | `/ping` | `GET`, `HEAD` | A simple endpoint to check for Træfik process liveness. Return a code `200` with the content: `OK` | -| `/health` | `GET` | json health metrics | +| `/health` | `GET` | JSON health metrics | | `/api` | `GET` | Configuration for all providers | | `/api/providers` | `GET` | Providers | | `/api/providers/{provider}` | `GET`, `PUT` | Get or update provider | @@ -244,7 +243,7 @@ curl -sv "http://localhost:8080/ping" ``` ```shell * Trying ::1... -* Connected to localhost (::1) port 8080 (#0) +* Connected to localhost (::1) port 8080 (\#0) > GET /ping HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.43.0 @@ -255,7 +254,7 @@ curl -sv "http://localhost:8080/ping" < Content-Length: 2 < Content-Type: text/plain; charset=utf-8 < -* Connection #0 to host localhost left intact +* Connection \#0 to host localhost left intact OK ``` @@ -309,7 +308,7 @@ curl -s "http://localhost:8080/health" | jq . "status": "Internal Server Error", // request HTTP method "method": "GET", - // request hostname + // request host name "host": "localhost", // request path "path": "/path", @@ -385,23 +384,28 @@ curl -s "http://localhost:8080/api" | jq . } ``` -## Path +### Deprecation compatibility -As web is deprecated, you can handle the `Path` option like this +#### Path + +As the web provider is deprecated, you can handle the `Path` option like this: ```toml -[entrypoints.http] -address=":80" +defaultEntryPoints = ["http"] -[entrypoints.dashboard] -address=":8080" +[entryPoints] + [entryPoints.http] + address = ":80" -[entrypoints.api] -address=":8081" + [entryPoints.dashboard] + address = ":8080" -#Activate API and Dashboard + [entryPoints.api] + address = ":8081" + +# Activate API and Dashboard [api] -entrypoint="api" +entryPoint = "api" [file] [backends] @@ -411,8 +415,67 @@ entrypoint="api" [frontends] [frontends.frontend1] - entrypoints=["dashboard"] + entryPoints = ["dashboard"] backend = "backend1" [frontends.frontend1.routes.test_1] rule = "PathPrefixStrip:/yourprefix;PathPrefix:/yourprefix" -``` \ No newline at end of file +``` + +#### Address + +As the web provider is deprecated, you can handle the `Address` option like this: + +```toml +defaultEntryPoints = ["http"] + +[entryPoints] + [entryPoints.http] + address = ":80" + + [entryPoints.ping] + address = ":8082" + + [entryPoints.api] + address = ":8083" + +[ping] +entryPoint = "ping" + +[api] +entryPoint = "api" +``` + +In the above example, you would access a regular path, administration panel, and health-check as follows: + +* Regular path: `http://hostname:80/foo` +* Admin Panel: `http://hostname:8083/` +* Ping URL: `http://hostname:8082/ping` + +In the above example, it is _very_ important to create a named dedicated entry point, and do **not** include it in `defaultEntryPoints`. +Otherwise, you are likely to expose _all_ services via that entry point. + +#### Authentication + +As the web provider is deprecated, you can handle the `auth` option like this: + +```toml +defaultEntryPoints = ["http"] + +[entryPoints] + [entryPoints.http] + address = ":80" + + [entryPoints.api] + address=":8080" + [entryPoints.api.auth] + [entryPoints.api.auth.basic] + users = [ + "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", + "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", + ] + +[api] +entrypoint="api" +``` + +For more information, see [entry points](/configuration/entrypoints/) . diff --git a/docs/configuration/entrypoints.md b/docs/configuration/entrypoints.md index a8f7eefcc..9ec90931b 100644 --- a/docs/configuration/entrypoints.md +++ b/docs/configuration/entrypoints.md @@ -234,9 +234,9 @@ In the example below both `snitest.com` and `snitest.org` will require client ce ### Basic Authentication -Passwords can be encoded in MD5, SHA1 and BCrypt: you can use `htpasswd` to generate those ones. +Passwords can be encoded in MD5, SHA1 and BCrypt: you can use `htpasswd` to generate them. -Users can be specified directly in the toml file, or indirectly by referencing an external file; +Users can be specified directly in the TOML file, or indirectly by referencing an external file; if both are provided, the two are merged, with external file contents having precedence. ```toml @@ -251,9 +251,9 @@ Users can be specified directly in the toml file, or indirectly by referencing a ### Digest Authentication -You can use `htdigest` to generate those ones. +You can use `htdigest` to generate them. -Users can be specified directly in the toml file, or indirectly by referencing an external file; +Users can be specified directly in the TOML file, or indirectly by referencing an external file; if both are provided, the two are merged, with external file contents having precedence ```toml @@ -271,7 +271,7 @@ Users can be specified directly in the toml file, or indirectly by referencing a This configuration will first forward the request to `http://authserver.com/auth`. If the response code is 2XX, access is granted and the original request is performed. -Otherwise, the response from the auth server is returned. +Otherwise, the response from the authentication server is returned. ```toml [entryPoints] diff --git a/docs/configuration/ping.md b/docs/configuration/ping.md index bfe27b79a..de1d805e5 100644 --- a/docs/configuration/ping.md +++ b/docs/configuration/ping.md @@ -1,5 +1,7 @@ # Ping Definition +## Configuration + ```toml # Ping definition [ping] @@ -19,7 +21,7 @@ !!! warning Even if you have authentication configured on entry point, the `/ping` path of the api is excluded from authentication. -### Example +## Example ```shell curl -sv "http://localhost:8080/ping" diff --git a/docs/user-guide/examples.md b/docs/user-guide/examples.md index ff2813a6c..c7f6f4c86 100644 --- a/docs/user-guide/examples.md +++ b/docs/user-guide/examples.md @@ -91,7 +91,7 @@ entryPoint = "https" This configuration allows generating Let's Encrypt certificates (thanks to `HTTP-01` challenge) for the four domains `local[1-4].com` with described SANs. -Traefik generates these certificates when it starts and it needs to be restart if new domains are added. +Træfik generates these certificates when it starts and it needs to be restart if new domains are added. ### OnHostRule option (with HTTP challenge) @@ -126,9 +126,9 @@ entryPoint = "https" This configuration allows generating Let's Encrypt certificates (thanks to `HTTP-01` challenge) for the four domains `local[1-4].com`. -Traefik generates these certificates when it starts. +Træfik generates these certificates when it starts. -If a backend is added with a `onHost` rule, Traefik will automatically generate the Let's Encrypt certificate for the new domain. +If a backend is added with a `onHost` rule, Træfik will automatically generate the Let's Encrypt certificate for the new domain (for frontends wired on the `acme.entryPoint`). ### OnDemand option (with HTTP challenge) @@ -152,11 +152,10 @@ entryPoint = "https" This configuration allows generating a Let's Encrypt certificate (thanks to `HTTP-01` challenge) during the first HTTPS request on a new domain. - !!! note This option simplifies the configuration but : - * TLS handshakes will be slow when requesting a hostname certificate for the first time, this can leads to DDoS attacks. + * TLS handshakes will be slow when requesting a host name certificate for the first time, this can leads to DDoS attacks. * Let's Encrypt have rate limiting: https://letsencrypt.org/docs/rate-limits That's why, it's better to use the `onHostRule` option if possible. @@ -191,7 +190,7 @@ entryPoint = "https" ``` DNS challenge needs environment variables to be executed. -This variables have to be set on the machine/container which host Traefik. +These variables have to be set on the machine/container which host Træfik. These variables are described [in this section](/configuration/acme/#provider). @@ -218,7 +217,7 @@ entryPoint = "https" entryPoint = "http" ``` -Traefik will only try to generate a Let's encrypt certificate (thanks to `HTTP-01` challenge) if the domain cannot be checked by the provided certificates. +Træfik will only try to generate a Let's encrypt certificate (thanks to `HTTP-01` challenge) if the domain cannot be checked by the provided certificates. ### Cluster mode @@ -292,14 +291,14 @@ The `consul` provider contains the configuration. rule = "Path:/test" ``` -## Enable Basic authentication in an entrypoint +## Enable Basic authentication in an entry point With two user/pass: - `test`:`test` - `test2`:`test2` -Passwords are encoded in MD5: you can use htpasswd to generate those ones. +Passwords are encoded in MD5: you can use `htpasswd` to generate them. ```toml defaultEntryPoints = ["http"] @@ -337,7 +336,7 @@ providersThrottleDuration = "5s" idleTimeout = "360s" ``` -## Securing Ping Health Check +## Ping Health Check The `/ping` health-check URL is enabled with the command-line `--ping` or config file option `[ping]`. Thus, if you have a regular path for `/foo` and an entrypoint on `:80`, you would access them as follows: @@ -346,40 +345,36 @@ Thus, if you have a regular path for `/foo` and an entrypoint on `:80`, you woul * Admin panel: `http://hostname:8080/` * Ping URL: `http://hostname:8080/ping` -However, for security reasons, you may want to be able to expose the `/ping` health-check URL to outside health-checkers, e.g. an Internet service or cloud load-balancer, _without_ exposing your admin panel's port. +However, for security reasons, you may want to be able to expose the `/ping` health-check URL to outside health-checkers, e.g. an Internet service or cloud load-balancer, _without_ exposing your administration panel's port. In many environments, the security staff may not _allow_ you to expose it. You have two options: -* Enable `/ping` on a regular entrypoint +* Enable `/ping` on a regular entry point * Enable `/ping` on a dedicated port -### Enable ping health check on a regular entrypoint +### Enable ping health check on a regular entry point -To proxy `/ping` from a regular entrypoint to the admin one without exposing the panel, do the following: +To proxy `/ping` from a regular entry point to the administration one without exposing the panel, do the following: ```toml -[backends] - [backends.traefik] - [backends.traefik.servers.server1] - url = "http://localhost:8080" - weight = 10 +defaultEntryPoints = ["http"] + +[entryPoints] + [entryPoints.http] + address = ":80" + +[ping] +entryPoint = "http" -[frontends] - [frontends.traefikadmin] - backend = "traefik" - [frontends.traefikadmin.routes.ping] - rule = "Path:/ping" ``` -The above creates a new backend called `traefik`, listening on `http://localhost:8080`, i.e. the local admin port. -We only expose the admin panel via the `frontend` named `traefikadmin`, and only expose the `/ping` Path. -Be careful with the `traefikadmin` frontend. If you do _not_ specify a `Path:` rule, you would expose the entire dashboard. +The above link `ping` on the `http` entry point and then expose it on port `80` ### Enable ping health check on dedicated port -If you do not want to or cannot expose the health-check on a regular entrypoint - e.g. your security rules do not allow it, or you have a conflicting path - then you can enable health-check on its own entrypoint. -Use the following config: +If you do not want to or cannot expose the health-check on a regular entry point - e.g. your security rules do not allow it, or you have a conflicting path - then you can enable health-check on its own entry point. +Use the following configuration: ```toml defaultEntryPoints = ["http"] @@ -390,32 +385,18 @@ defaultEntryPoints = ["http"] [entryPoints.ping] address = ":8082" -[backends] - [backends.traefik] - [backends.traefik.servers.server1] - url = "http://localhost:8080" - weight = 10 - -[frontends] - [frontends.traefikadmin] - backend = "traefik" - entrypoints = ["ping"] - [frontends.traefikadmin.routes.ping] - rule = "Path:/ping" +[ping] +entryPoint = "ping" ``` -The above is similar to the previous example, but instead of enabling `/ping` on the _default_ entrypoint, we enable it on a _dedicated_ entrypoint. +The above is similar to the previous example, but instead of enabling `/ping` on the _default_ entry point, we enable it on a _dedicated_ entry point. -In the above example, you would access a regular path, admin panel and health-check as follows: +In the above example, you would access a regular path and health-check as follows: * Regular path: `http://hostname:80/foo` -* Admin panel: `http://hostname:8080/` * Ping URL: `http://hostname:8082/ping` Note the dedicated port `:8082` for `/ping`. -In the above example, it is _very_ important to create a named dedicated entrypoint, and do **not** include it in `defaultEntryPoints`. -Otherwise, you are likely to expose _all_ services via that entrypoint. - -In the above example, we have two entrypoints, `http` and `ping`, but we only included `http` in `defaultEntryPoints`, while explicitly tying `frontend.traefikadmin` to the `ping` entrypoint. -This ensures that all the "normal" frontends will be exposed via entrypoint `http` and _not_ via entrypoint `ping`. +In the above example, it is _very_ important to create a named dedicated entry point, and do **not** include it in `defaultEntryPoints`. +Otherwise, you are likely to expose _all_ services via this entry point. From 45fe218ee25630da1908ae4f1b0d542618afbb24 Mon Sep 17 00:00:00 2001 From: SALLEYRON Julien Date: Fri, 16 Feb 2018 11:04:04 +0100 Subject: [PATCH 3/9] Isolate backend with same name on different provider --- integration/basic_test.go | 28 +++++++++++++++++++++ integration/fixtures/multiple_provider.toml | 25 ++++++++++++++++++ integration/resources/compose/base.yml | 6 +++++ server/server.go | 8 +++--- 4 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 integration/fixtures/multiple_provider.toml diff --git a/integration/basic_test.go b/integration/basic_test.go index 7684d5507..7b1cab07b 100644 --- a/integration/basic_test.go +++ b/integration/basic_test.go @@ -358,3 +358,31 @@ func (s *SimpleSuite) TestMetricsPrometheusDefaultEntrypoint(c *check.C) { err = try.GetRequest("http://127.0.0.1:8080/metrics", 1*time.Second, try.StatusCodeIs(http.StatusOK)) c.Assert(err, checker.IsNil) } + +func (s *SimpleSuite) TestMultipleProviderSameBackendName(c *check.C) { + + s.createComposeProject(c, "base") + s.composeProject.Start(c) + ipWhoami01 := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ipWhoami02 := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress + file := s.adaptFile(c, "fixtures/multiple_provider.toml", struct{ IP string }{ + IP: ipWhoami02, + }) + defer os.Remove(file) + cmd, output := s.traefikCmd(withConfigFile(file)) + defer output(c) + + err := cmd.Start() + c.Assert(err, checker.IsNil) + defer cmd.Process.Kill() + + err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("PathPrefix")) + c.Assert(err, checker.IsNil) + + err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.BodyContains(ipWhoami01)) + c.Assert(err, checker.IsNil) + + err = try.GetRequest("http://127.0.0.1:8000/file", 1*time.Second, try.BodyContains(ipWhoami02)) + c.Assert(err, checker.IsNil) + +} diff --git a/integration/fixtures/multiple_provider.toml b/integration/fixtures/multiple_provider.toml new file mode 100644 index 000000000..8b197261d --- /dev/null +++ b/integration/fixtures/multiple_provider.toml @@ -0,0 +1,25 @@ +defaultEntryPoints = ["http"] + +debug=true + +[entryPoints] + [entryPoints.http] + address = ":8000" + +[api] + +[docker] +endpoint = "unix:///var/run/docker.sock" +watch = true +exposedbydefault = false + +[file] + [frontends] + [frontends.frontend-1] + backend = "backend-test" + [frontends.frontend-1.routes.test_1] + rule = "PathPrefix:/file" + [backends] + [backends.backend-test] + [backends.backend-test.servers.website] + url = "http://{{ .IP }}" diff --git a/integration/resources/compose/base.yml b/integration/resources/compose/base.yml index 8af2e9a99..f51d51750 100644 --- a/integration/resources/compose/base.yml +++ b/integration/resources/compose/base.yml @@ -3,3 +3,9 @@ whoami1: labels: - traefik.enable=true - traefik.frontend.rule=PathPrefix:/whoami + - traefik.backend="test" + +whoami2: + image: emilevauge/whoami + labels: + - traefik.enable=false \ No newline at end of file diff --git a/server/server.go b/server/server.go index e5857d167..5b8b2a297 100644 --- a/server/server.go +++ b/server/server.go @@ -913,7 +913,7 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura backendsHealthCheck := map[string]*healthcheck.BackendHealthCheck{} errorHandler := NewRecordingErrorHandler(middlewares.DefaultNetErrorRecorder{}) - for _, config := range configurations { + for providerName, config := range configurations { frontendNames := sortedFrontendNamesForConfig(config) frontend: for _, frontendName := range frontendNames { @@ -970,7 +970,7 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura } } } - if backends[entryPointName+frontend.Backend] == nil { + if backends[entryPointName+providerName+frontend.Backend] == nil { log.Debugf("Creating backend %s", frontend.Backend) roundTripper, err := s.getRoundTripper(entryPointName, globalConfiguration, frontend.PassTLSCert, entryPoint.TLS) @@ -1191,14 +1191,14 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura } else { n.UseHandler(lb) } - backends[entryPointName+frontend.Backend] = n + backends[entryPointName+providerName+frontend.Backend] = n } else { log.Debugf("Reusing backend %s", frontend.Backend) } if frontend.Priority > 0 { newServerRoute.route.Priority(frontend.Priority) } - s.wireFrontendBackend(newServerRoute, backends[entryPointName+frontend.Backend]) + s.wireFrontendBackend(newServerRoute, backends[entryPointName+providerName+frontend.Backend]) err := newServerRoute.route.GetError() if err != nil { From 083bde64eed23a2d9293419e7b2d37f79dc748be Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Fri, 16 Feb 2018 13:22:02 +0100 Subject: [PATCH 4/9] Fix traffic pronounce dead link --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8e2b7809a..2ff4947ed 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ [![Twitter](https://img.shields.io/twitter/follow/traefikproxy.svg?style=social)](https://twitter.com/intent/follow?screen_name=traefikproxy) -Træfik (pronounced like [traffic](https://speak-ipa.bearbin.net/speak.cgi?speak=%CB%88tr%C3%A6f%C9%AAk)) is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease. +Træfik (pronounced like _traffic_) is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease. It supports several backends ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), and a lot more) to manage its configuration automatically and dynamically. --- diff --git a/docs/index.md b/docs/index.md index 53791bccd..1f1968753 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,7 +10,7 @@ [![Twitter](https://img.shields.io/twitter/follow/traefikproxy.svg?style=social)](https://twitter.com/intent/follow?screen_name=traefikproxy) -Træfik (pronounced like [traffic](https://speak-ipa.bearbin.net/speak.cgi?speak=%CB%88tr%C3%A6f%C9%AAk)) is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease. +Træfik (pronounced like _traffic_) is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease. It supports several backends ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), and a lot more) to manage its configuration automatically and dynamically. ## Overview From f98c537ec2f534a12083d46809c4e6fbb06b67aa Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Fri, 16 Feb 2018 16:02:03 +0100 Subject: [PATCH 5/9] Smooth dashboard refresh. --- webui/package.json | 1 + webui/src/app/sections/providers/providers.controller.js | 9 ++++++++- webui/yarn.lock | 6 +++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/webui/package.json b/webui/package.json index daa04ed2d..7cf319d9d 100644 --- a/webui/package.json +++ b/webui/package.json @@ -21,6 +21,7 @@ "angular-ui-router": "^0.3.1", "animate.css": "^3.4.0", "bootstrap": "^3.3.6", + "lodash": "^4.17.5", "moment": "^2.14.1", "nvd3": "^1.8.4" }, diff --git a/webui/src/app/sections/providers/providers.controller.js b/webui/src/app/sections/providers/providers.controller.js index 2ea187590..f7814b9d8 100644 --- a/webui/src/app/sections/providers/providers.controller.js +++ b/webui/src/app/sections/providers/providers.controller.js @@ -1,5 +1,7 @@ 'use strict'; +var _ = require('lodash'); + /** @ngInject */ function ProvidersController($scope, $interval, $log, Providers) { const vm = this; @@ -7,7 +9,12 @@ function ProvidersController($scope, $interval, $log, Providers) { function loadProviders() { Providers .get() - .then(providers => vm.providers = providers) + .then(providers => { + if (!_.isEqual(vm.previousProviders, providers)) { + vm.providers = providers; + vm.previousProviders = _.cloneDeep(providers); + } + }) .catch(error => { vm.providers = {}; $log.error(error); diff --git a/webui/yarn.lock b/webui/yarn.lock index 2c429591d..c62c5e850 100644 --- a/webui/yarn.lock +++ b/webui/yarn.lock @@ -1105,7 +1105,7 @@ camelcase@^1.0.2, camelcase@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" -camelcase@^2.0.0, camelcase@^2.0.1: +camelcase@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" @@ -3925,6 +3925,10 @@ lodash@^4.17.2: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" +lodash@^4.17.5: + version "4.17.5" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" + lodash@~4.16.4: version "4.16.6" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777" From 7ea76929d43b6a5e95eae0a5a4ba4ba78d0f3a88 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 20 Feb 2018 08:12:02 +0100 Subject: [PATCH 6/9] Empty ip address when endpoint mode dnsrr --- provider/docker/builder_test.go | 27 +++++++++++++++++ provider/docker/docker.go | 4 ++- provider/docker/swarm_test.go | 54 ++++++++++++++++++++++++++------- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/provider/docker/builder_test.go b/provider/docker/builder_test.go index 7e8a4ba5d..b8679d7d3 100644 --- a/provider/docker/builder_test.go +++ b/provider/docker/builder_test.go @@ -95,6 +95,25 @@ func taskSlot(slot int) func(*swarm.Task) { } } +func taskNetworkAttachment(id string, name string, driver string, addresses []string) func(*swarm.Task) { + return func(task *swarm.Task) { + task.NetworksAttachments = append(task.NetworksAttachments, swarm.NetworkAttachment{ + Network: swarm.Network{ + ID: id, + Spec: swarm.NetworkSpec{ + Annotations: swarm.Annotations{ + Name: name, + }, + DriverConfiguration: &swarm.Driver{ + Name: driver, + }, + }, + }, + Addresses: addresses, + }) + } +} + func taskStatus(ops ...func(*swarm.TaskStatus)) func(*swarm.Task) { return func(task *swarm.Task) { status := &swarm.TaskStatus{} @@ -113,6 +132,14 @@ func taskState(state swarm.TaskState) func(*swarm.TaskStatus) { } } +func taskContainerStatus(id string) func(*swarm.TaskStatus) { + return func(status *swarm.TaskStatus) { + status.ContainerStatus = swarm.ContainerStatus{ + ContainerID: id, + } + } +} + func swarmService(ops ...func(*swarm.Service)) swarm.Service { service := &swarm.Service{ ID: "serviceID", diff --git a/provider/docker/docker.go b/provider/docker/docker.go index a56823065..e949e9547 100644 --- a/provider/docker/docker.go +++ b/provider/docker/docker.go @@ -849,7 +849,9 @@ func listTasks(ctx context.Context, dockerClient client.APIClient, serviceID str continue } dockerData := parseTasks(task, serviceDockerData, networkMap, isGlobalSvc) - dockerDataList = append(dockerDataList, dockerData) + if len(dockerData.NetworkSettings.Networks) > 0 { + dockerDataList = append(dockerDataList, dockerData) + } } return dockerDataList, err } diff --git a/provider/docker/swarm_test.go b/provider/docker/swarm_test.go index e0fe058e5..55e31658e 100644 --- a/provider/docker/swarm_test.go +++ b/provider/docker/swarm_test.go @@ -709,14 +709,19 @@ func TestSwarmTaskParsing(t *testing.T) { type fakeTasksClient struct { dockerclient.APIClient - tasks []swarm.Task - err error + tasks []swarm.Task + container dockertypes.ContainerJSON + err error } func (c *fakeTasksClient) TaskList(ctx context.Context, options dockertypes.TaskListOptions) ([]swarm.Task, error) { return c.tasks, c.err } +func (c *fakeTasksClient) ContainerInspect(ctx context.Context, container string) (dockertypes.ContainerJSON, error) { + return c.container, c.err +} + func TestListTasks(t *testing.T) { testCases := []struct { service swarm.Service @@ -728,11 +733,30 @@ func TestListTasks(t *testing.T) { { service: swarmService(serviceName("container")), tasks: []swarm.Task{ - swarmTask("id1", taskSlot(1), taskStatus(taskState(swarm.TaskStateRunning))), - swarmTask("id2", taskSlot(2), taskStatus(taskState(swarm.TaskStatePending))), - swarmTask("id3", taskSlot(3)), - swarmTask("id4", taskSlot(4), taskStatus(taskState(swarm.TaskStateRunning))), - swarmTask("id5", taskSlot(5), taskStatus(taskState(swarm.TaskStateFailed))), + swarmTask("id1", + taskSlot(1), + taskNetworkAttachment("1", "network1", "overlay", []string{"127.0.0.1"}), + taskStatus(taskState(swarm.TaskStateRunning)), + ), + swarmTask("id2", + taskSlot(2), + taskNetworkAttachment("1", "network1", "overlay", []string{"127.0.0.2"}), + taskStatus(taskState(swarm.TaskStatePending)), + ), + swarmTask("id3", + taskSlot(3), + taskNetworkAttachment("1", "network1", "overlay", []string{"127.0.0.3"}), + ), + swarmTask("id4", + taskSlot(4), + taskNetworkAttachment("1", "network1", "overlay", []string{"127.0.0.4"}), + taskStatus(taskState(swarm.TaskStateRunning)), + ), + swarmTask("id5", + taskSlot(5), + taskNetworkAttachment("1", "network1", "overlay", []string{"127.0.0.5"}), + taskStatus(taskState(swarm.TaskStateFailed)), + ), }, isGlobalSVC: false, expectedTasks: []string{ @@ -753,7 +777,7 @@ func TestListTasks(t *testing.T) { t.Parallel() dockerData := parseService(test.service, test.networks) dockerClient := &fakeTasksClient{tasks: test.tasks} - taskDockerData, _ := listTasks(context.Background(), dockerClient, test.service.ID, dockerData, map[string]*docker.NetworkResource{}, test.isGlobalSVC) + taskDockerData, _ := listTasks(context.Background(), dockerClient, test.service.ID, dockerData, test.networks, test.isGlobalSVC) if len(test.expectedTasks) != len(taskDockerData) { t.Errorf("expected tasks %v, got %v", spew.Sdump(test.expectedTasks), spew.Sdump(taskDockerData)) @@ -896,8 +920,14 @@ func TestListServices(t *testing.T) { withEndpointSpec(modeDNSSR)), }, tasks: []swarm.Task{ - swarmTask("id1", taskStatus(taskState(swarm.TaskStateRunning))), - swarmTask("id2", taskStatus(taskState(swarm.TaskStateRunning))), + swarmTask("id1", + taskNetworkAttachment("yk6l57rfwizjzxxzftn4amaot", "network_name", "overlay", []string{"127.0.0.1"}), + taskStatus(taskState(swarm.TaskStateRunning)), + ), + swarmTask("id2", + taskNetworkAttachment("yk6l57rfwizjzxxzftn4amaot", "network_name", "overlay", []string{"127.0.0.1"}), + taskStatus(taskState(swarm.TaskStateRunning)), + ), }, dockerVersion: "1.30", networks: []dockertypes.NetworkResource{ @@ -934,7 +964,9 @@ func TestListServices(t *testing.T) { t.Run(strconv.Itoa(caseID), func(t *testing.T) { t.Parallel() dockerClient := &fakeServicesClient{services: test.services, tasks: test.tasks, dockerVersion: test.dockerVersion, networks: test.networks} - serviceDockerData, _ := listServices(context.Background(), dockerClient) + + serviceDockerData, err := listServices(context.Background(), dockerClient) + assert.NoError(t, err) assert.Equal(t, len(test.expectedServices), len(serviceDockerData)) for i, serviceName := range test.expectedServices { From d675d4693076d1d85ffea7dc9ba33d696a2beca9 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Tue, 20 Feb 2018 10:44:03 +0100 Subject: [PATCH 7/9] Multiple issue and pull request templates. --- .github/ISSUE_TEMPLATE.md | 2 +- .github/ISSUE_TEMPLATE/bugs.md | 68 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/features.md | 32 ++++++++++ .github/PULL_REQUEST_TEMPLATE/mergeback.md | 7 +++ .github/PULL_REQUEST_TEMPLATE/release.md | 7 +++ 5 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/bugs.md create mode 100644 .github/ISSUE_TEMPLATE/features.md create mode 100644 .github/PULL_REQUEST_TEMPLATE/mergeback.md create mode 100644 .github/PULL_REQUEST_TEMPLATE/release.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 782643358..48aa39567 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -22,7 +22,7 @@ If you intend to ask a support question: DO NOT FILE AN ISSUE. HOW TO WRITE A GOOD ISSUE? -- Respect the issue template as more as possible. +- Respect the issue template as much as possible. - If it's possible use the command `traefik bug`. See https://www.youtube.com/watch?v=Lyz62L8m93I. - The title must be short and descriptive. - Explain the conditions which led you to write this issue: the context. diff --git a/.github/ISSUE_TEMPLATE/bugs.md b/.github/ISSUE_TEMPLATE/bugs.md new file mode 100644 index 000000000..4cee4a159 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bugs.md @@ -0,0 +1,68 @@ + + + +### Do you want to request a *feature* or report a *bug*? + +Bug + +### What did you do? + + + +### What did you expect to see? + + + +### What did you see instead? + + + +### Output of `traefik version`: (_What version of Traefik are you using?_) + + + +``` +(paste your output here) +``` + +### What is your environment & configuration (arguments, toml, provider, platform, ...)? + +```toml +# (paste your configuration here) +``` + + + + +### If applicable, please paste the log output in debug mode (`--debug` switch) + +``` +(paste your output here) +``` diff --git a/.github/ISSUE_TEMPLATE/features.md b/.github/ISSUE_TEMPLATE/features.md new file mode 100644 index 000000000..a7d9ab9bb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/features.md @@ -0,0 +1,32 @@ + + + +### Do you want to request a *feature* or report a *bug*? + +Feature + +### What did you expect to see? + + + diff --git a/.github/PULL_REQUEST_TEMPLATE/mergeback.md b/.github/PULL_REQUEST_TEMPLATE/mergeback.md new file mode 100644 index 000000000..dfc856011 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/mergeback.md @@ -0,0 +1,7 @@ +### What does this PR do? + +Merge v{{.Version}} into master + +### Motivation + +Be sync. diff --git a/.github/PULL_REQUEST_TEMPLATE/release.md b/.github/PULL_REQUEST_TEMPLATE/release.md new file mode 100644 index 000000000..226a85a73 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/release.md @@ -0,0 +1,7 @@ +### What does this PR do? + +Prepare release v{{.Version}}. + +### Motivation + +Create a new release. From ba046b4d3a03553d25ad2a8b0e382921bd75852e Mon Sep 17 00:00:00 2001 From: Emile Vauge Date: Wed, 21 Feb 2018 08:00:03 +0100 Subject: [PATCH 8/9] Fix doc cipher suites --- docs/configuration/entrypoints.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/configuration/entrypoints.md b/docs/configuration/entrypoints.md index 9ec90931b..08b2dff30 100644 --- a/docs/configuration/entrypoints.md +++ b/docs/configuration/entrypoints.md @@ -13,7 +13,10 @@ [entryPoints.http.tls] minVersion = "VersionTLS12" - cipherSuites = ["TLS_RSA_WITH_AES_256_GCM_SHA384"] + cipherSuites = [ + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384" + ] [[entryPoints.http.tls.certificates]] certFile = "path/to/my.cert" keyFile = "path/to/my.key" @@ -308,7 +311,10 @@ To specify an https entry point with a minimum TLS version, and specifying an ar address = ":443" [entryPoints.https.tls] minVersion = "VersionTLS12" - cipherSuites = ["TLS_RSA_WITH_AES_256_GCM_SHA384"] + cipherSuites = [ + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384" + ] [[entryPoints.https.tls.certificates]] certFile = "integration/fixtures/https/snitest.com.cert" keyFile = "integration/fixtures/https/snitest.com.key" From 31550fd2c9796043e08a346cb2982d8815bbacd6 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 21 Feb 2018 16:28:03 +0100 Subject: [PATCH 9/9] Replace nginx by whoami in integration tests --- integration/constraint_test.go | 36 +++--- integration/consul_catalog_test.go | 118 +++++++++--------- integration/docker_test.go | 6 +- integration/ratelimit_test.go | 2 +- integration/resources/compose/constraints.yml | 4 +- .../resources/compose/consul_catalog.yml | 12 +- integration/resources/compose/error_pages.yml | 4 +- integration/resources/compose/file.yml | 20 +-- integration/resources/compose/ratelimit.yml | 4 +- 9 files changed, 103 insertions(+), 103 deletions(-) diff --git a/integration/constraint_test.go b/integration/constraint_test.go index dd2968584..cf148f8ef 100644 --- a/integration/constraint_test.go +++ b/integration/constraint_test.go @@ -91,11 +91,11 @@ func (s *ConstraintSuite) TestMatchConstraintGlobal(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx") + whoami := s.composeProject.Container(c, "whoami") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api"}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) c.Assert(err, checker.IsNil) @@ -117,11 +117,11 @@ func (s *ConstraintSuite) TestDoesNotMatchConstraintGlobal(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx") + whoami := s.composeProject.Container(c, "whoami") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) c.Assert(err, checker.IsNil) @@ -143,11 +143,11 @@ func (s *ConstraintSuite) TestMatchConstraintProvider(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx") + whoami := s.composeProject.Container(c, "whoami") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api"}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) c.Assert(err, checker.IsNil) @@ -169,11 +169,11 @@ func (s *ConstraintSuite) TestDoesNotMatchConstraintProvider(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx") + whoami := s.composeProject.Container(c, "whoami") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) c.Assert(err, checker.IsNil) @@ -196,11 +196,11 @@ func (s *ConstraintSuite) TestMatchMultipleConstraint(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx") + whoami := s.composeProject.Container(c, "whoami") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api", "traefik.tags=eu-1"}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api", "traefik.tags=eu-1"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) c.Assert(err, checker.IsNil) @@ -223,11 +223,11 @@ func (s *ConstraintSuite) TestDoesNotMatchMultipleConstraint(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx") + whoami := s.composeProject.Container(c, "whoami") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api", "traefik.tags=us-1"}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"traefik.tags=api", "traefik.tags=us-1"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) c.Assert(err, checker.IsNil) diff --git a/integration/consul_catalog_test.go b/integration/consul_catalog_test.go index 40765059c..7a17c7aac 100644 --- a/integration/consul_catalog_test.go +++ b/integration/consul_catalog_test.go @@ -145,9 +145,9 @@ func (s *ConsulCatalogSuite) TestSingleService(c *check.C) { err = try.GetRequest("http://127.0.0.1:8000/", 2*time.Second, try.StatusCodeIs(http.StatusNotFound)) c.Assert(err, checker.IsNil) - nginx := s.composeProject.Container(c, "nginx1") + whoami := s.composeProject.Container(c, "whoami1") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) @@ -157,7 +157,7 @@ func (s *ConsulCatalogSuite) TestSingleService(c *check.C) { err = try.Request(req, 10*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody()) c.Assert(err, checker.IsNil) - s.deregisterService("test", nginx.NetworkSettings.IPAddress) + s.deregisterService("test", whoami.NetworkSettings.IPAddress) err = try.Request(req, 10*time.Second, try.StatusCodeIs(http.StatusNotFound), try.HasBody()) c.Assert(err, checker.IsNil) @@ -175,11 +175,11 @@ func (s *ConsulCatalogSuite) TestExposedByDefaultFalseSingleService(c *check.C) c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx1") + whoami := s.composeProject.Container(c, "whoami1") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) c.Assert(err, checker.IsNil) @@ -201,16 +201,16 @@ func (s *ConsulCatalogSuite) TestExposedByDefaultFalseSimpleServiceMultipleNode( c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx1") - nginx2 := s.composeProject.Container(c, "nginx2") + whoami := s.composeProject.Container(c, "whoami1") + whoami2 := s.composeProject.Container(c, "whoami2") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) - err = s.registerService("test", nginx2.NetworkSettings.IPAddress, 80, []string{"traefik.enable=true"}) + err = s.registerService("test", whoami2.NetworkSettings.IPAddress, 80, []string{"traefik.enable=true"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx2.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami2.NetworkSettings.IPAddress) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) c.Assert(err, checker.IsNil) @@ -232,16 +232,16 @@ func (s *ConsulCatalogSuite) TestExposedByDefaultTrueSimpleServiceMultipleNode(c c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx1") - nginx2 := s.composeProject.Container(c, "nginx2") + whoami := s.composeProject.Container(c, "whoami1") + whoami2 := s.composeProject.Container(c, "whoami2") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1"}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) - err = s.registerService("test", nginx2.NetworkSettings.IPAddress, 80, []string{"name=nginx2"}) + err = s.registerService("test", whoami2.NetworkSettings.IPAddress, 80, []string{"name=whoami2"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx2.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami2.NetworkSettings.IPAddress) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) c.Assert(err, checker.IsNil) @@ -250,7 +250,7 @@ func (s *ConsulCatalogSuite) TestExposedByDefaultTrueSimpleServiceMultipleNode(c err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody()) c.Assert(err, checker.IsNil) - err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1", "nginx2")) + err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1", "whoami2")) c.Assert(err, checker.IsNil) } @@ -267,16 +267,16 @@ func (s *ConsulCatalogSuite) TestRefreshConfigWithMultipleNodeWithoutHealthCheck c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx1") - nginx2 := s.composeProject.Container(c, "nginx2") + whoami := s.composeProject.Container(c, "whoami1") + whoami2 := s.composeProject.Container(c, "whoami2") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1"}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) - err = s.registerAgentService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1"}) + err = s.registerAgentService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering agent service")) - defer s.deregisterAgentService(nginx.NetworkSettings.IPAddress) + defer s.deregisterAgentService(whoami.NetworkSettings.IPAddress) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) c.Assert(err, checker.IsNil) @@ -285,25 +285,25 @@ func (s *ConsulCatalogSuite) TestRefreshConfigWithMultipleNodeWithoutHealthCheck err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody()) c.Assert(err, checker.IsNil) - err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1")) + err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1")) c.Assert(err, checker.IsNil) - err = s.registerService("test", nginx2.NetworkSettings.IPAddress, 80, []string{"name=nginx2"}) + err = s.registerService("test", whoami2.NetworkSettings.IPAddress, 80, []string{"name=whoami2"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1", "nginx2")) + err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1", "whoami2")) c.Assert(err, checker.IsNil) - s.deregisterService("test", nginx2.NetworkSettings.IPAddress) + s.deregisterService("test", whoami2.NetworkSettings.IPAddress) - err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1")) + err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1")) c.Assert(err, checker.IsNil) - err = s.registerService("test", nginx2.NetworkSettings.IPAddress, 80, []string{"name=nginx2"}) + err = s.registerService("test", whoami2.NetworkSettings.IPAddress, 80, []string{"name=whoami2"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx2.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami2.NetworkSettings.IPAddress) - err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1", "nginx2")) + err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1", "whoami2")) c.Assert(err, checker.IsNil) } @@ -320,13 +320,13 @@ func (s *ConsulCatalogSuite) TestBasicAuthSimpleService(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx1") + whoami := s.composeProject.Container(c, "whoami1") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{ + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{ "traefik.frontend.auth.basic=test:$2a$06$O5NksJPAcgrC9MuANkSoE.Xe9DSg7KcLLFYNr1Lj6hPcMmvgwxhme,test2:$2y$10$xP1SZ70QbZ4K2bTGKJOhpujkpcLxQcB3kEPF6XAV19IdcqsZTyDEe", }) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) c.Assert(err, checker.IsNil) @@ -357,16 +357,16 @@ func (s *ConsulCatalogSuite) TestRefreshConfigTagChange(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx1") + whoami := s.composeProject.Container(c, "whoami1") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1", "traefik.enable=false", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1", "traefik.enable=false", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) - err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 5*time.Second, try.BodyContains("nginx1")) + err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 5*time.Second, try.BodyContains("whoami1")) c.Assert(err, checker.NotNil) - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1", "traefik.enable=true", "traefik.backend.circuitbreaker=ResponseCodeRatio(500, 600, 0, 600) > 0.5"}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1", "traefik.enable=true", "traefik.backend.circuitbreaker=ResponseCodeRatio(500, 600, 0, 600) > 0.5"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) @@ -376,7 +376,7 @@ func (s *ConsulCatalogSuite) TestRefreshConfigTagChange(c *check.C) { err = try.Request(req, 20*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody()) c.Assert(err, checker.IsNil) - err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1")) + err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1")) c.Assert(err, checker.IsNil) } @@ -397,19 +397,19 @@ func (s *ConsulCatalogSuite) TestCircuitBreaker(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx1") - nginx2 := s.composeProject.Container(c, "nginx2") - nginx3 := s.composeProject.Container(c, "nginx3") + whoami := s.composeProject.Container(c, "whoami1") + whoami2 := s.composeProject.Container(c, "whoami2") + whoami3 := s.composeProject.Container(c, "whoami3") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1", "traefik.enable=true", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1", "traefik.enable=true", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) - err = s.registerService("test", nginx2.NetworkSettings.IPAddress, 42, []string{"name=nginx2", "traefik.enable=true", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"}) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) + err = s.registerService("test", whoami2.NetworkSettings.IPAddress, 42, []string{"name=whoami2", "traefik.enable=true", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx2.NetworkSettings.IPAddress) - err = s.registerService("test", nginx3.NetworkSettings.IPAddress, 42, []string{"name=nginx3", "traefik.enable=true", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"}) + defer s.deregisterService("test", whoami2.NetworkSettings.IPAddress) + err = s.registerService("test", whoami3.NetworkSettings.IPAddress, 42, []string{"name=whoami3", "traefik.enable=true", "traefik.backend.circuitbreaker=NetworkErrorRatio() > 0.5"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx3.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami3.NetworkSettings.IPAddress) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) c.Assert(err, checker.IsNil) @@ -432,9 +432,9 @@ func (s *ConsulCatalogSuite) TestRefreshConfigPortChange(c *check.C) { c.Assert(err, checker.IsNil) defer cmd.Process.Kill() - nginx := s.composeProject.Container(c, "nginx1") + whoami := s.composeProject.Container(c, "whoami1") - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 81, []string{"name=nginx1", "traefik.enable=true"}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 81, []string{"name=whoami1", "traefik.enable=true"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil) @@ -444,15 +444,15 @@ func (s *ConsulCatalogSuite) TestRefreshConfigPortChange(c *check.C) { err = try.Request(req, 20*time.Second, try.StatusCodeIs(http.StatusBadGateway)) c.Assert(err, checker.IsNil) - err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 5*time.Second, try.BodyContains("nginx1")) + err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 5*time.Second, try.BodyContains("whoami1")) c.Assert(err, checker.IsNil) - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{"name=nginx1", "traefik.enable=true"}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{"name=whoami1", "traefik.enable=true"}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) - defer s.deregisterService("test", nginx.NetworkSettings.IPAddress) + defer s.deregisterService("test", whoami.NetworkSettings.IPAddress) - err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("nginx1")) + err = try.GetRequest("http://127.0.0.1:8080/api/providers/consul_catalog/backends", 60*time.Second, try.BodyContains("whoami1")) c.Assert(err, checker.IsNil) err = try.Request(req, 20*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody()) @@ -491,9 +491,9 @@ func (s *ConsulCatalogSuite) TestRetryWithConsulServer(c *check.C) { s.composeProject.Scale(c, "consul", 1) s.waitToElectConsulLeader() - nginx := s.composeProject.Container(c, "nginx1") + whoami := s.composeProject.Container(c, "whoami1") // Register service - err = s.registerService("test", nginx.NetworkSettings.IPAddress, 80, []string{}) + err = s.registerService("test", whoami.NetworkSettings.IPAddress, 80, []string{}) c.Assert(err, checker.IsNil, check.Commentf("Error registering service")) // Provider consul catalog should be present diff --git a/integration/docker_test.go b/integration/docker_test.go index 4920ceb32..db8e5912b 100644 --- a/integration/docker_test.go +++ b/integration/docker_test.go @@ -14,7 +14,7 @@ import ( "github.com/docker/docker/pkg/namesgenerator" "github.com/go-check/check" d "github.com/libkermit/docker" - docker "github.com/libkermit/docker-check" + "github.com/libkermit/docker-check" checker "github.com/vdemeester/shakers" ) @@ -25,8 +25,8 @@ var ( // Images to have or pull before the build in order to make it work // FIXME handle this offline but loading them before build RequiredImages = map[string]string{ - "swarm": "1.0.0", - "nginx": "1", + "swarm": "1.0.0", + "emilevauge/whoami": "latest", } ) diff --git a/integration/ratelimit_test.go b/integration/ratelimit_test.go index c307d6748..163744313 100644 --- a/integration/ratelimit_test.go +++ b/integration/ratelimit_test.go @@ -19,7 +19,7 @@ func (s *RateLimitSuite) SetUpSuite(c *check.C) { s.createComposeProject(c, "ratelimit") s.composeProject.Start(c) - s.ServerIP = s.composeProject.Container(c, "nginx1").NetworkSettings.IPAddress + s.ServerIP = s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress } func (s *RateLimitSuite) TestSimpleConfiguration(c *check.C) { diff --git a/integration/resources/compose/constraints.yml b/integration/resources/compose/constraints.yml index 1d5395281..92648815c 100644 --- a/integration/resources/compose/constraints.yml +++ b/integration/resources/compose/constraints.yml @@ -11,7 +11,7 @@ consul: - "8301/udp" - "8302" - "8302/udp" -nginx: - image: nginx:alpine +whoami: + image: emilevauge/whoami ports: - "8881:80" diff --git a/integration/resources/compose/consul_catalog.yml b/integration/resources/compose/consul_catalog.yml index 9569a32c4..cb1380eda 100644 --- a/integration/resources/compose/consul_catalog.yml +++ b/integration/resources/compose/consul_catalog.yml @@ -11,9 +11,9 @@ consul: - "8301/udp" - "8302" - "8302/udp" -nginx1: - image: nginx:alpine -nginx2: - image: nginx:alpine -nginx3: - image: nginx:alpine +whoami1: + image: emilevauge/whoami +whoami2: + image: emilevauge/whoami +whoami3: + image: emilevauge/whoami diff --git a/integration/resources/compose/error_pages.yml b/integration/resources/compose/error_pages.yml index 964b87b7f..3d36b0709 100644 --- a/integration/resources/compose/error_pages.yml +++ b/integration/resources/compose/error_pages.yml @@ -1,4 +1,4 @@ nginx1: - image: nginx:alpine + image: nginx:1.13.8-alpine nginx2: - image: nginx:alpine + image: nginx:1.13.8-alpine diff --git a/integration/resources/compose/file.yml b/integration/resources/compose/file.yml index 1d3dddd1d..07276d3be 100644 --- a/integration/resources/compose/file.yml +++ b/integration/resources/compose/file.yml @@ -1,20 +1,20 @@ -nginx1: - image: nginx:alpine +whoami1: + image: emilevauge/whoami ports: - "8881:80" -nginx2: - image: nginx:alpine +whoami2: + image: emilevauge/whoami ports: - "8882:80" -nginx3: - image: nginx:alpine +whoami3: + image: emilevauge/whoami ports: - "8883:80" -nginx4: - image: nginx:alpine +whoami4: + image: emilevauge/whoami ports: - "8884:80" -nginx5: - image: nginx:alpine +whoami5: + image: emilevauge/whoami ports: - "8885:80" diff --git a/integration/resources/compose/ratelimit.yml b/integration/resources/compose/ratelimit.yml index d4699ed71..87a055a5c 100644 --- a/integration/resources/compose/ratelimit.yml +++ b/integration/resources/compose/ratelimit.yml @@ -1,2 +1,2 @@ -nginx1: - image: nginx:alpine +whoami1: + image: emilevauge/whoami