Add app-root annotation support for kubernetes ingress
This commit is contained in:
parent
d47c1a7975
commit
5ef55dd8b4
4 changed files with 96 additions and 6 deletions
|
@ -127,6 +127,7 @@ The following general annotations are applicable on the Ingress object:
|
||||||
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. |
|
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. |
|
||||||
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Default: `PathPrefix`. |
|
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Default: `PathPrefix`. |
|
||||||
| `traefik.ingress.kubernetes.io/whitelist-source-range: "1.2.3.0/24, fe80::/16"` | A comma-separated list of IP ranges permitted for access. all source IPs are permitted if the list is empty or a single range is ill-formatted. |
|
| `traefik.ingress.kubernetes.io/whitelist-source-range: "1.2.3.0/24, fe80::/16"` | A comma-separated list of IP ranges permitted for access. all source IPs are permitted if the list is empty or a single range is ill-formatted. |
|
||||||
|
| `traefik.ingress.kubernetes.io/app-root: "/index.html"` | Redirects all requests for `/` to the defined path. Non-root paths will not be affected by this annotation and handled normally. This annotation may not be combined with the `ReplacePath` rule type or any other annotation leveraging that rule type. Trying to do so leads to an error and the corresponding Ingress object being ignored. |
|
||||||
|
|
||||||
<1> `traefik.ingress.kubernetes.io/error-pages` example:
|
<1> `traefik.ingress.kubernetes.io/error-pages` example:
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ const (
|
||||||
annotationKubernetesRateLimit = "ingress.kubernetes.io/rate-limit"
|
annotationKubernetesRateLimit = "ingress.kubernetes.io/rate-limit"
|
||||||
annotationKubernetesErrorPages = "ingress.kubernetes.io/error-pages"
|
annotationKubernetesErrorPages = "ingress.kubernetes.io/error-pages"
|
||||||
annotationKubernetesBuffering = "ingress.kubernetes.io/buffering"
|
annotationKubernetesBuffering = "ingress.kubernetes.io/buffering"
|
||||||
|
annotationKubernetesAppRoot = "ingress.kubernetes.io/app-root"
|
||||||
|
|
||||||
annotationKubernetesSSLRedirect = "ingress.kubernetes.io/ssl-redirect"
|
annotationKubernetesSSLRedirect = "ingress.kubernetes.io/ssl-redirect"
|
||||||
annotationKubernetesHSTSMaxAge = "ingress.kubernetes.io/hsts-max-age"
|
annotationKubernetesHSTSMaxAge = "ingress.kubernetes.io/hsts-max-age"
|
||||||
|
|
|
@ -226,7 +226,13 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rule := getRuleForPath(pa, i); rule != "" {
|
rule, err := getRuleForPath(pa, i)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get rule for ingress %s/%s: %s", i.Namespace, i.Name, err)
|
||||||
|
delete(templateObjects.Frontends, baseName)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if rule != "" {
|
||||||
templateObjects.Frontends[baseName].Routes[pa.Path] = types.Route{
|
templateObjects.Frontends[baseName].Routes[pa.Path] = types.Route{
|
||||||
Rule: rule,
|
Rule: rule,
|
||||||
}
|
}
|
||||||
|
@ -313,19 +319,34 @@ func (p *Provider) loadConfig(templateObjects types.Configuration) *types.Config
|
||||||
return configuration
|
return configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRuleForPath(pa extensionsv1beta1.HTTPIngressPath, i *extensionsv1beta1.Ingress) string {
|
func getRuleForPath(pa extensionsv1beta1.HTTPIngressPath, i *extensionsv1beta1.Ingress) (string, error) {
|
||||||
if len(pa.Path) == 0 {
|
if len(pa.Path) == 0 {
|
||||||
return ""
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleType := getStringValue(i.Annotations, annotationKubernetesRuleType, ruleTypePathPrefix)
|
ruleType := getStringValue(i.Annotations, annotationKubernetesRuleType, ruleTypePathPrefix)
|
||||||
rules := []string{ruleType + ":" + pa.Path}
|
rules := []string{ruleType + ":" + pa.Path}
|
||||||
|
|
||||||
if rewriteTarget := getStringValue(i.Annotations, annotationKubernetesRewriteTarget, ""); rewriteTarget != "" {
|
var pathReplaceAnnotation string
|
||||||
rules = append(rules, ruleTypeReplacePath+":"+rewriteTarget)
|
if ruleType == ruleTypeReplacePath {
|
||||||
|
pathReplaceAnnotation = annotationKubernetesRuleType
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(rules, ";")
|
if rewriteTarget := getStringValue(i.Annotations, annotationKubernetesRewriteTarget, ""); rewriteTarget != "" {
|
||||||
|
if pathReplaceAnnotation != "" {
|
||||||
|
return "", fmt.Errorf("rewrite-target must not be used together with annotation %q", pathReplaceAnnotation)
|
||||||
|
}
|
||||||
|
rules = append(rules, ruleTypeReplacePath+":"+rewriteTarget)
|
||||||
|
pathReplaceAnnotation = annotationKubernetesRewriteTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
if rootPath := label.GetStringValue(i.Annotations, annotationKubernetesAppRoot, ""); rootPath != "" && pa.Path == "/" {
|
||||||
|
if pathReplaceAnnotation != "" {
|
||||||
|
return "", fmt.Errorf("app-root must not be used together with annotation %q", pathReplaceAnnotation)
|
||||||
|
}
|
||||||
|
rules = append(rules, ruleTypeReplacePath+":"+rootPath)
|
||||||
|
}
|
||||||
|
return strings.Join(rules, ";"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRuleForHost(host string) string {
|
func getRuleForHost(host string) string {
|
||||||
|
|
|
@ -737,6 +737,45 @@ rateset:
|
||||||
iPaths(onePath(iPath("/ratelimit"), iBackend("service1", intstr.FromInt(80))))),
|
iPaths(onePath(iPath("/ratelimit"), iBackend("service1", intstr.FromInt(80))))),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
buildIngress(
|
||||||
|
iNamespace("testing"),
|
||||||
|
iAnnotation(annotationKubernetesAppRoot, "/root"),
|
||||||
|
iRules(
|
||||||
|
iRule(
|
||||||
|
iHost("root"),
|
||||||
|
iPaths(
|
||||||
|
onePath(iPath("/"), iBackend("service1", intstr.FromInt(80))),
|
||||||
|
onePath(iPath("/root1"), iBackend("service1", intstr.FromInt(80))),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
buildIngress(
|
||||||
|
iNamespace("testing"),
|
||||||
|
iAnnotation(annotationKubernetesAppRoot, "/root2"),
|
||||||
|
iAnnotation(annotationKubernetesRewriteTarget, "/abc"),
|
||||||
|
iRules(
|
||||||
|
iRule(
|
||||||
|
iHost("root2"),
|
||||||
|
iPaths(
|
||||||
|
onePath(iPath("/"), iBackend("service2", intstr.FromInt(80))),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
buildIngress(
|
||||||
|
iNamespace("testing"),
|
||||||
|
iAnnotation(annotationKubernetesRuleType, ruleTypeReplacePath),
|
||||||
|
iAnnotation(annotationKubernetesRewriteTarget, "/abc"),
|
||||||
|
iRules(
|
||||||
|
iRule(
|
||||||
|
iHost("root2"),
|
||||||
|
iPaths(
|
||||||
|
onePath(iPath("/"), iBackend("service2", intstr.FromInt(80))),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
buildIngress(
|
buildIngress(
|
||||||
iNamespace("testing"),
|
iNamespace("testing"),
|
||||||
iAnnotation(annotationKubernetesIngressClass, "traefik"),
|
iAnnotation(annotationKubernetesIngressClass, "traefik"),
|
||||||
|
@ -880,6 +919,20 @@ rateset:
|
||||||
server("http://example.com", weight(1))),
|
server("http://example.com", weight(1))),
|
||||||
lbMethod("wrr"),
|
lbMethod("wrr"),
|
||||||
),
|
),
|
||||||
|
backend("root/",
|
||||||
|
servers(
|
||||||
|
server("http://example.com", weight(1))),
|
||||||
|
lbMethod("wrr"),
|
||||||
|
),
|
||||||
|
backend("root/root1",
|
||||||
|
servers(
|
||||||
|
server("http://example.com", weight(1))),
|
||||||
|
lbMethod("wrr"),
|
||||||
|
),
|
||||||
|
backend("root2/",
|
||||||
|
servers(),
|
||||||
|
lbMethod("wrr"),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
frontends(
|
frontends(
|
||||||
frontend("foo/bar",
|
frontend("foo/bar",
|
||||||
|
@ -994,6 +1047,20 @@ rateset:
|
||||||
route("/customheaders", "PathPrefix:/customheaders"),
|
route("/customheaders", "PathPrefix:/customheaders"),
|
||||||
route("custom-headers", "Host:custom-headers")),
|
route("custom-headers", "Host:custom-headers")),
|
||||||
),
|
),
|
||||||
|
frontend("root/",
|
||||||
|
passHostHeader(),
|
||||||
|
routes(
|
||||||
|
route("/", "PathPrefix:/;ReplacePath:/root"),
|
||||||
|
route("root", "Host:root"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
frontend("root/root1",
|
||||||
|
passHostHeader(),
|
||||||
|
routes(
|
||||||
|
route("/root1", "PathPrefix:/root1"),
|
||||||
|
route("root", "Host:root"),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue