Вход Nginx — перенаправление WWW на не-WWW на Minikube против GKE

#redirect #kubernetes #kubernetes-ingress #minikube #nginx-ingress

#перенаправление #kubernetes #kubernetes-вход #minikube #nginx-вход

Вопрос:

Я знаю, что эта тема возникает время от времени. Я прочитал многие существующие сообщения и ответы, бит не смог разобраться.

Что мне нужно, так это nginx-вход для перенаправления с www.foo.bar just на just foo.bar . Я настроил тестовую среду на Minikube, установив вход nginx способом minikube: minikube addons enable ingress и поместил на место следующий входной манифест:

 apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.allow-http: "false"
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($host = 'www.foo.bar') {
        return 301 https://foo.bar;
      }
    nginx.ingress.kubernetes.io/proxy-body-size: 600m
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.org/client-max-body-size: 600m
  name: foo-ingress
spec:
  rules:
  - host: api.foo.bar
    http:
      paths:
      - backend:
          service:
            name: identity
            port:
              number: 80
        path: /identity
        pathType: ImplementationSpecific
      - backend:
          service:
            name: catalog
            port:
              number: 80
        path: /catalog
        pathType: ImplementationSpecific
      - backend:
          service:
            name: marketing
            port:
              number: 80
        path: /marketing
        pathType: ImplementationSpecific
      - backend:
          service:
            name: marketplace
            port:
              number: 80
        path: /marketplace
        pathType: ImplementationSpecific
      - backend:
          service:
            name: notification
            port:
              number: 80
        path: /notification
        pathType: ImplementationSpecific
      - backend:
          service:
            name: provider
            port:
              number: 80
        path: /provider
        pathType: ImplementationSpecific
  - host: www.foo.bar
    http:
      paths:
      - backend:
          service:
            name: frontend
            port:
              number: 80
        path: /
        pathType: ImplementationSpecific
  - host: foo.bar
    http:
      paths:
      - backend:
          service:
            name: frontend
            port:
              number: 80
        path: /
        pathType: ImplementationSpecific
  - host: blog.foo.bar
    http:
      paths:
      - backend:
          service:
            name: wordpress
            port:
              number: 80
        path: /
        pathType: ImplementationSpecific
  tls:
  - hosts:
    - foo.bar
    - api.foo.bar
    - blog.foo.bar
    secretName: foo-cert
 

И это работает:

   ~ curl -k -v -o /dev/null https://www.foo.bar
  ...
> GET / HTTP/2
> Host: www.foo.bar
> user-agent: curl/7.68.0
> accept: */*
> 
< HTTP/2 301 
< date: Sat, 27 Mar 2021 16:37:50 GMT
< content-type: text/html
< content-length: 162
< location: https://foo.bar
 

Теперь позвольте мне перейти к проблеме: у меня есть производственный кластер на GCP (GKE), на который я установил nginx-вход через Helm:

 helm -n nginx-ingress ls
NAME            NAMESPACE       REVISION    UPDATED                                 STATUS      CHART               APP VERSION
nginx-ingress   nginx-ingress   2           2021-03-27 15:05:41.229254628  0000 UTC deployed    nginx-ingress-0.8.1 1.10.1  
 

У меня есть входной манифест (я не вижу существенной разницы с приведенным выше):

 apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.allow-http: "false"
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($host = 'www.foo.bar') {
        return 301 https://foo.bar;
      }
    nginx.ingress.kubernetes.io/proxy-body-size: 600m
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.org/client-max-body-size: 600m
  name: foo-ingress
spec:
  rules:
  - host: api.foo.bar
    http:
      paths:
      - backend:
          service:
            name: identity
            port:
              number: 80
        path: /identity
        pathType: ImplementationSpecific
      - backend:
          service:
            name: catalog
            port:
              number: 80
        path: /catalog
        pathType: ImplementationSpecific
      - backend:
          service:
            name: marketing
            port:
              number: 80
        path: /marketing
        pathType: ImplementationSpecific
      - backend:
          service:
            name: marketplace
            port:
              number: 80
        path: /marketplace
        pathType: ImplementationSpecific
      - backend:
          service:
            name: notification
            port:
              number: 80
        path: /notification
        pathType: ImplementationSpecific
      - backend:
          service:
            name: provider
            port:
              number: 80
        path: /provider
        pathType: ImplementationSpecific
  - host: foo.bar
    http:
      paths:
      - backend:
          service:
            name: frontend
            port:
              number: 80
        path: /
        pathType: ImplementationSpecific
  - host: www.foo.bar
    http:
      paths:
      - backend:
          service:
            name: frontend
            port:
              number: 80
        path: /
        pathType: ImplementationSpecific
  - host: blog.foo.bar
    http:
      paths:
      - backend:
          service:
            name: wordpress
            port:
              number: 80
        path: /
        pathType: ImplementationSpecific
  tls:
  - hosts:
    - foo.bar
    - api.foo.bar
    - www.foo.bar
    - blog.foo.bar
    secretName: foo-cert
 

Вы можете видеть, перенаправление не работает:

   ~ curl -v -o /dev/null https://www.foo.bar
> GET / HTTP/1.1
> Host: www.foo.bar
> User-Agent: curl/7.68.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: nginx/1.19.8
< Date: Sat, 27 Mar 2021 16:42:18 GMT
< Content-Type: text/html
< Content-Length: 671097
< Connection: keep-alive
< Last-Modified: Tue, 09 Mar 2021 11:51:47 GMT
< ETag: "60476153-a3d79"
< Expires: Thu, 01 Jan 1970 00:00:01 GMT
< Cache-Control: no-cache
< Accept-Ranges: bytes
 

Я заметил, что prod и Minikube развертывают разные образы, но на самом деле не знаю, в чем разница, если она есть.

Prod:

   ~ kubectl -n nginx-ingress get pod nginx-ingress-nginx-ingress-68f5bc7654-kffnm -o json | jq ".spec.containers[0].image"
"nginx/nginx-ingress:1.10.1"
 

Minikube:

   ~ kubectl -n kube-system get pod ingress-nginx-controller-65cf89dc4f-xkdtn -o json | jq ".spec.containers[0].image"
"us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.40.2@sha256:46ba23c3fbaafd9e5bd01ea85b2f921d9f2217be082580edc22e6c704a83f02f"
 

Есть идеи, что происходит?

Ответ №1:

Причина, по которой это происходит, заключается в том, что вы развернули другую версию входного контроллера nginx, вызываемого nginxinc в вашем кластере GKE. Это очень распространенная ошибка, особенно если вы используете helm, который вы на самом деле не проверяете, который вы развертываете.

Таким образом, kubernetes / ingress-nginx, который вы использовали в minikube, поддерживается сообществом Kubernetes с открытым исходным кодом, а nginxinc / kubernetes-ingress поддерживается NGINX, Inc. Вы заметите много случаев, когда тот, который поддерживается Kubernetes, будет обычно называться контроллером входа в сообщество, а второй — контроллером NGINX.

Вы можете найти различия здесь, но основное, что вызывает у вас проблемы, заключается в том, что они оба используют различную формулу аннотации с разным префиксом. Например:

  • Контроллер входа в сообщество использует: nginx.ingress.kubernetes.io/server-snippet
  • Использование NGINX: nginx.org/server-snippets