Kubernetes上使用Ingress Nginx將服務發布到外部IP


Kubernetes的網絡結構

K8s的網絡相對比較復雜, 包含了如下幾類IP地址:

Host Network

運行K8s集群的宿主服務器的內網IP, 其網段在配置宿主機時設置. 這些服務器可能是物理機, 也可能是ESXi或KVM虛機. 可以根據這個IP在K8s初始化時設置--apiserver-advertise-address, 配置外網訪問時, 前端的負載均衡要通過這些IP訪問服務.

Docker Bridge Network

運行Docker服務時啟動的虛擬網卡docker0的IP, 通常為 172.17.0.1/16, 對應docker內部默認的bridge網段. 這個網絡在K8s中不會用到.

Pod Network

K8s中Pod單元的IP, 其網段在K8s初始化時使用--pod-network-cidr設置, 此處使用172.16.0.0/16, 在每個宿主(node節點)上, 都會有一個對應的二級網段, 例如 172.16.1.0/24, 如果使用的是flannel, 那么在宿主機上會對應成對出現的兩個虛擬網卡 cni0 和 flannel.1 (如果宿主機上還沒部署pod, cni0可能不會出現)

Pod網絡在集群內可以跨節點相互ping通, 在master和node主機上也可以直接訪問Pod的IP

Service Network

K8s中Service單元的IP, 其網段在K8s初始化時使用--service-cidr設置, 在master和node主機上不能直接訪問. 這里使用10.1.0.0/16.

Ingress的機制

要解決的問題

因為K8s中Pod是易變的, Pod IP在更新中會自動修改, 使用Service能使訪問入口相對固定, 但是Service IP在集群外不能訪問, 要對外提供訪問, 只能把Service以NodePort, LoadBalancer這些方式Expose出去, 但是NodePort會與每一個Node主機綁定, 而LoadBalancer需要雲服務商提供相應的服務(或自己安裝).

原理

Ingress 啟動一個獨立的Pod來運行七層代理, 可以是 Nginx, Traefik 或者是 Envoy. Ingress Pod會直接代理后端提供服務的Pod, 為了能監聽后端Pod的變化, 需要一個 Headless Service 通過Selector選擇指定的Pod, 並收集到Pod對應的IP. 一旦后端Pod產生變化, Headless Service 會自動根據變化更改配置文件並重載.

如果使用的是 Nginx 類型的 Ingress Pod, 則每次變化后通過reload修改過的配置文件實現規則更新.

Ingress Controller

在kubernetes集群內節點上運行web七層代理所對應的Pod, 由此Pod代理集群內部的Service, Service再把流量轉發給集群內部對應的Pod, 這就叫做 Ingress Controller, Ingress Controller 基於 DaemonSet 控制器實現, DaemonSet用於保證集群內部每個節點上都運行一個指定的Pod.

部署Ingress Nginx

軟件版本

這里使用的環境是 K8s 1.17, Docker 18.06.3, Ingress Nginx 0.26.2

Ingress Nginx項目地址: https://github.com/kubernetes/ingress-nginx/

Ingress Nginx的安裝文檔: https://kubernetes.github.io/ingress-nginx/deploy/ 使用 https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/ 

安裝前提

已經配置好K8s集群

 

部署公共部分

現在最新的標簽是0.26.2, 使用部署模板

https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.26.2/deploy/static/mandatory.yaml

下載后在master主機上執行

kubectl apply -f mandatory.yaml

可以使用下面的命令查看部署的結果

kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx --watch
kubectl get services

 

部署Nodeport部分

因為不使用雲服務商的服務, 所以要使用Nodeport的方式, 對應的部署模板在

https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.26.2/deploy/static/provider/baremetal/service-nodeport.yaml

這一步實際上是創建一個Nodeport將ingress-nginx服務發布到Node節點的Host Network上, 原模板中未指定端口, 創建后會隨機設置端口, 可以修改一下, 只能使用端口范圍 3000 ~ 32767. 修改后的service-nodeport.yaml, 將80端口映射到了30080, 443映射到了30443

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  type: NodePort
  ports:
    - name: http
      port: 80
      targetPort: 80
      protocol: TCP
      nodePort: 30080
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
      nodePort: 30443
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

可以使用下面的命令查看發布的結果, 以及映射出去的實際端口

kubectl get services -n ingress-nginx

 

創建服務並測試

以下都是使用defalut的namespace. 都使用kubectl apply -f 模板名 命令進行發布

Deployment, 創建兩個nginx的pod

# nginx-deployment.yml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: registry.cn-shanghai.aliyuncs.com/jovi/nginx:alpine
        ports:
        - containerPort: 80

Service, 將上面創建的兩個Pod發布為Servce, 將Pod的80端口映射到Service的8080端口

# nginx-service.yml 
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 80

查看service詳情

$ kubectl describe service my-service
Name:              my-service
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                     {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"my-service","namespace":"default"},"spec":{"ports":[{"port":8080,...
Selector:          app=nginx
Type:              ClusterIP
IP:                10.1.116.99
Port:              <unset>  8080/TCP
TargetPort:        80/TCP
Endpoints:         172.16.1.6:80,172.16.1.7:80
Session Affinity:  None
Events:            <none>

  

Ingress, 將上面的Service的8080端口映射到Ingress的http

# ingress-test.yaml 
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    # use the shared ingress-nginx
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: my-service
          servicePort: 8080

查看Ingress詳情

$ kubectl get services -n ingress-nginx
NAME            TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   10.1.60.152   <none>        80:30080/TCP,443:30443/TCP   69m
milton@k8s00:~/backup$ kubectl describe ingress test-ingress
Name:             test-ingress
Namespace:        default
Address:          10.1.60.152
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host  Path  Backends
  ----  ----  --------
  *     
           my-service:8080 (172.16.1.6:80,172.16.1.7:80)
Annotations:
  kubectl.kubernetes.io/last-applied-configuration:  {"apiVersion":"networking.k8s.io/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx"},"name":"test-ingress","namespace":"default"},"spec":{"rules":[{"http":{"paths":[{"backend":{"serviceName":"my-service","servicePort":8080}}]}}]}}

  kubernetes.io/ingress.class:  nginx
Events:                         <none>

這時候, 就可以通過 http://宿主機IP:30080 訪問到這兩個Pod的Nginx默認頁.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM