kubernetes-sigs / aws-load-balancer-controller

A Kubernetes controller for Elastic Load Balancers
https://kubernetes-sigs.github.io/aws-load-balancer-controller/
Apache License 2.0
3.93k stars 1.46k forks source link

Multiple separate rules with the same target group #1150

Closed maxtacu closed 4 years ago

maxtacu commented 4 years ago

How to create multiple separate rules with the same target group which is defined as a service. For example something like:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig":
      { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
    alb.ingress.kubernetes.io/certificate-arn: <certificate_arn>
    alb.ingress.kubernetes.io/conditions.k8s-service: |
      [{"Field":"http-header","HttpHeaderConfig":{"HttpHeaderName": "AnyHeaderName", "Values":["AnyHeaderValue"]}}]
    alb.ingress.kubernetes.io/conditions.k8s-service: |
      [{"Field":"source-ip","SourceIpConfig":{"Values":["1.1.1.1/1"]}}]
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
    alb.ingress.kubernetes.io/scheme: internet-facing
    kubernetes.io/ingress.class: alb
  labels:
    app.kubernetes.io/name:application-name
  name: some-web-ingress
spec:
  rules:
  - host: example.com
  - http:
      paths:
      - backend:
          serviceName: ssl-redirect
          servicePort: use-annotation
        path: /*
      - backend:
          serviceName: k8s-service
          servicePort: 443
        path: /*

I want to specify a few conditions alb.ingress.kubernetes.io/conditions.k8s-service for the same service name which will create different separate rules to the same target group, but the above solution doesn't work. A workaround which I found here is to create a second service with different name, but pointing to the same resource and then use it in alb.ingress.kubernetes.io/conditions.k8s-service2. Workaround example I will post in comments bellow.

P.S. Just to be more clear, in my case I dont want to create something like:

alb.ingress.kubernetes.io/conditions.k8s-service: >
  [{"Field":"http-header","HttpHeaderConfig":{"HttpHeaderName": "AnyHeaderName", "Values":["AnyHeaderValue"]}},{"Field":"source-ip","SourceIpConfig":{"Values":["1.1.1.1/1"]}}]

because this creates multiple conditions in the same rule.

maxtacu commented 4 years ago

workaround example Create two services pointing to the same resource:

apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: aplication-name
  name: k8s-service
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  - name: https
    port: 443
    protocol: TCP
    targetPort: 8080
  selector:
    app.kubernetes.io/name: aplication-name

---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: aplication-name
  name: k8s-service2
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  - name: https
    port: 443
    protocol: TCP
    targetPort: 8080
  selector:
    app.kubernetes.io/name: aplication-name

Create the ingress-controller

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig":
      { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
    alb.ingress.kubernetes.io/certificate-arn: <certificate_arn>
    alb.ingress.kubernetes.io/conditions.k8s-service: |
      [{"Field":"http-header","HttpHeaderConfig":{"HttpHeaderName": "AnyHeaderName", "Values":["AnyHeaderValue"]}}]
    alb.ingress.kubernetes.io/conditions.k8s-service2: |
      [{"Field":"source-ip","SourceIpConfig":{"Values":["1.1.1.1/1"]}}]
    alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
    alb.ingress.kubernetes.io/scheme: internet-facing
    kubernetes.io/ingress.class: alb
  labels:
    app.kubernetes.io/name: k8s-service
  name: some-web-ingress
spec:
  rules:
  - host: example.com
  - http:
      paths:
      - backend:
          serviceName: ssl-redirect
          servicePort: use-annotation
        path: /*
      - backend:
          serviceName: k8s-service
          servicePort: 443
        path: /*
      - backend:
          serviceName: k8s-service2
          servicePort: 443
        path: /*

This creates two different rules on ALB with two different target groups which are pointing to the same resource. These rules are working as OR - If condition is met in one rule OR another, all other requests are dropped.

daparthi001 commented 4 years ago

@tmxak what did you install for internal pod communication ?For me target type instance is not working on cluster ip ?

maxtacu commented 4 years ago

@daparthi001 I'm using basic EKS cluster configurations with coredns. NodePort is needed to create an application load balancer. Share your config here

M00nF1sh commented 4 years ago

@tmxak 🤦‍♂️ 🤦‍♂️ 🤦‍♂️u just found a bug....it's not the intended usage of conditions annotation.. The original intended usage requires there are servicePort: use-annotation to able to use conditions. It's missing a check for servicePort here. But after all, I think it's good usage, and help user that don't want extra actions annotation. So I'll keep this behavior and update the docs instead(to "The conditions-name in the annotation must match the serviceName in the ingress rules,and servicePort must be use-annotation").

Back to your original question. You can solve it by using our actions annotation like:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    alb.ingress.kubernetes.io/conditions.fake-k8s-service1: |
      [{"Field":"http-header","HttpHeaderConfig":{"HttpHeaderName": "AnyHeaderName", "Values":["AnyHeaderValue"]}}]
    alb.ingress.kubernetes.io/conditions.fake-k8s-service2: |
      [{"Field":"source-ip","SourceIpConfig":{"Values":["1.1.1.1/1"]}}]
    alb.ingress.kubernetes.io/actions.fake-k8s-service1: |
        {"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"k8s-service","ServicePort":"443"}]}}
    alb.ingress.kubernetes.io/actions.fake-k8s-service2: |
        {"Type":"forward","ForwardConfig":{"TargetGroups":[{"ServiceName":"k8s-service","ServicePort":"443"}]}}
    alb.ingress.kubernetes.io/scheme: internet-facing
    kubernetes.io/ingress.class: alb
  labels:
    app.kubernetes.io/name: k8s-service
  name: some-web-ingress
spec:
  rules:
  - host: example.com
  - http:
      paths:
      - backend:
          serviceName: fake-k8s-service1
          servicePort: use-annotation
        path: /*
      - backend:
          serviceName: fake-k8s-service2
          servicePort: use-annotation
        path: /*

not a bug

M00nF1sh commented 4 years ago

/kind documentation should update the docs to "The conditions-name in the annotation must match the serviceName in the ingress rules, and servicePort must be use-annotation"

k8s-ci-robot commented 4 years ago

@M00nF1sh: The label(s) kind/ cannot be applied, because the repository doesn't have them

In response to [this](https://github.com/kubernetes-sigs/aws-alb-ingress-controller/issues/1150#issuecomment-585018447): >/kind documentation >should update the docs to "The conditions-name in the annotation must match the serviceName in the ingress rules, ~~and servicePort must be use-annotation~~" Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md). If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
maxtacu commented 4 years ago

thanks, @M00nF1sh for the explanation! Glad that we found a feature :smile: and not a bug

myroslavmail commented 2 years ago

@M00nF1sh in your example you are using action naming fake-k8s-service1 and fake-k8s-service2 as service names, and further mentioning real service name under the block {"ServiceName":"k8s-service","ServicePort":"443"} I have absolutely same case, want to use few rules for one service (one target group), but in my case all rules are binded, for a reason that I can use only ONE REAL service name. Fake service names are not working for me at all ... Below are my annotations and specs:

metadata:
  annotations:
    alb.ingress.kubernetes.io/actions.review1: >
      {"type":"forward","forwardConfig":{"targetGroups":[{"ServiceName":"review-auto-deploy"}]}}
    alb.ingress.kubernetes.io/conditions.review1: >
      [{"field":"path-pattern", "pathPatternConfig":{"values":["/"]}}]
    alb.ingress.kubernetes.io/actions.review2: >
      {"type":"forward","forwardConfig":{"TargetGroups":[{"ServiceName":"review-auto-deploy"}]}}
    alb.ingress.kubernetes.io/conditions.review2: >
      [{"field":"path-pattern", "pathPatternConfig":{"values":["/admin"]}},{"field":"source-ip","sourceIpConfig":{"values": ["1.111.111.111/32"]}}]
    alb.ingress.kubernetes.io/certificate-arn: arn-of-certificate
    alb.ingress.kubernetes.io/group.name: new-development
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/target-type: instance
    kubernetes.io/ingress.class: alb
    kubernetes.io/tls-acme: "true"
    meta.helm.sh/release-name: review-dev-4jxwt5
    meta.helm.sh/release-namespace: cloud-review-dev-4jxwt5

spec:
  rules:
    - host: myhost.com
      http:
        paths:
          - path: /
            backend:
              serviceName: review1
              servicePort: use-annotation
          - path: /admin
            backend:
              serviceName: review2
              servicePort: use-annotation

so in fact it works when condition and action are named "review-auto-deploy"

khosro-copper commented 1 year ago

For those of you that are using kubernetes 1.22+, these are the changes:

Ingress and IngressClass resources have graduated to networking.k8s.io/v1. Ingress and IngressClass types in the extensions/v1beta1 and networking.k8s.io/v1beta1 API versions are deprecated and will no longer be served in 1.22+. Persisted objects can be accessed via the networking.k8s.io/v1 API. Notable changes in v1 Ingress objects (v1beta1 field names are unchanged):