Nginx

在 Nginx Ingress 控制器內部配置外部 IP 重定向

  • October 28, 2020

問題

我想知道如何配置 Nginx Ingress 控制器以在呼叫外部 IP 地址時重定向到 URL。

入口控制器 yaml

apiVersion: v1
kind: Service
metadata:
labels:
 helm.sh/chart: ingress-nginx-3.4.1
 app.kubernetes.io/name: ingress-nginx
 app.kubernetes.io/instance: ingress-nginx
 app.kubernetes.io/version: 0.40.2
 app.kubernetes.io/managed-by: Helm
 app.kubernetes.io/component: controller
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
type: NodePort
ports:
 - name: http
   port: 80
   protocol: TCP
   targetPort: http
 - name: https
   port: 443
   protocol: TCP
   targetPort: https
externalIPs: 
- ip1
- ip2
- ip3
selector:
 app.kubernetes.io/name: ingress-nginx
 app.kubernetes.io/instance: ingress-nginx
 app.kubernetes.io/component: controller

如果我在瀏覽器中輸入我的外部 IP,我當然會進入 Nginx 404 頁面。在這種特殊情況下,我想設置一個重定向到它的特定域,例如 google.com。我想提高公共 K8s 集群的安全性。我還沒有配置這種特殊情況,想知道是否可以設置這樣的轉發過程。所有配置的 Ingress 資源都將其服務發佈到 Internet。

裸機環境缺乏傳統雲環境提供的網路負載均衡器可用的商品,並且單個 K8s 清單足以提供與 NGINX 入口控制器的單點聯繫。當然,我們必須記住,內部重定向遵循入口資源,然後相應地配置入口控制器。

使用外部 IP方法不會保留 HTTP 的源 IP,因此儘管它看起來很簡單,但不建議使用它。因此,您將失去與您的請求有關的資訊(除非您將監控入口控制器)

要回答如何在 Nginx 入口控制器中配置外部 IP 重定向的問題,我們必須從了解入口實際是什麼開始:

Ingress 將來自集群外部的 HTTP 和 HTTPS 路由暴露給集群內的服務。流量路由由 Ingress 資源上定義的規則控制。必須有一個 Ingress 控制器來滿足一個 Ingress。僅創建 Ingress 資源沒有任何效果。

為了達到預期的結果,您應該創建兩個單獨的入口對象(而不是控制器)。第一個沒有指定主機,因此該規則適用於通過指定 IP 地址的所有入站 HTTP 流量,如Ingress 規則中所述:

apiVersion: extensions/v1beta1
kind: Ingress
metadata: 
 annotations: 
   nginx.ingress.kubernetes.io/permanent-redirect: "https://www.google.com"
 name: ingress-redirect
spec: 
 rules: 
 - http: 
     paths: 
     - path: / 
       pathType: Prefix 
       backend: 
         serviceName: example
         servicePort: 12 

第二個入口對象與提供的主機(例如,hello-world.info,以便規則適用於該主機。如下例所示:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
 name: ingress-host
spec: 
 rules: 
 - host: hello-world.info
   http: 
    paths: 
    - path: / 
      pathType: Prefix  
      backend: 
       serviceName: web
       servicePort: 80

如下所示,上述配置在 nginx-ingress-controller 的 nginx.conf 中創建了以下部分。一個負責為帶有特定 Host: 標頭的請求提供服務,另一個負責為沒有 Host: 標頭的請求提供服務,例如,如果請求直接發送到 IP 地址:

enter http { 

# works when no Host header is provided

   ## start server _
   server {
           server_name _ ;

           listen 80 default_server reuseport backlog=511 ;
           listen 443 default_server reuseport backlog=511 ssl http2 ;

           location / {


                   set $namespace      "default";
                   set $ingress_name   "ingress-redirect";
                   set $service_name   "";
                   set $service_port   "";
                   set $location_path  "/";

                   return 301 https://www.google.com;


# works when specific Host header is provided

   ## start server hello-world.info
   server {
           server_name hello-world.info ;

           listen 80  ;
           listen 443  ssl http2 ;


           location / {

                   set $namespace      "default";
                   set $ingress_name   "ingress-host";
                   set $service_name   "web";
                   set $service_port   "80";
                   set $location_path  "/";

           }

   }
   ## end server hello-world.info

出於測試目的,我已經快速部署了這兩個入口對象和 nginx pod:

➜ kubectl run --image nginx web   

並將其公開以在第二個入口對像後面提供服務:

➜ kubectl expose pod web --port 80 

正如您所看到的,當捲曲重定向按預期工作時:

➜  ~ curl $(minikube ip)  -I                            
HTTP/1.1 301 Moved Permanently
Server: nginx/1.19.0
Date: Tue, 27 Oct 2020 13:22:06 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://www.google.com

如果你 curl 與主機名相同的地址,它會重定向到 nginx pod:

➜  ~ curl $(minikube ip) -H "Host: hello-world.info"    
---
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
---

另外值得一提的是 Kubernetes 文件,它也提供了基於名稱的虛擬主機的良好範例。它支持將 HTTP 流量路由到同一 IP 地址的多個主機名。文件中的範例告訴備份負載均衡器根據Host 標頭路由請求。

例如,上面文件頁面中提到的 Ingress 將請求的流量路由first.bar.comservice1second.foo.comservice2以及任何沒有hostname在請求中定義的 IP 地址(即沒有顯示請求標頭)的流量到service3

引用自:https://serverfault.com/questions/1040038