ingress和ingressController


ingress是一個API,是一個規則,是個虛擬的東西

kubernetes提供service我們常用兩種方式ClusterIP和NodePort,另外還有LoadBalance類型和ExternalName類型(目前這兩種沒用過,不做闡述)。ClusterIP是在集群內部用service的IP加端口來訪問服務;而NodePort可以跨主機訪問,只要能ping通k8s節點就能訪問而不必局限在本集群環境,使用集群內部的節點IP加端口來訪問,這種方式非常方便,但當有幾十上百的服務在集群中運行時,NodePort的端口管理就比較困難。k8s還提供了一種集群維度暴露服務的方式,也就是ingress。Ingress 不是一種服務類型,ingress可以簡單理解為service的service,它充當集群的入口點。 它可以將路由規則整合到一個資源中,因為它可以在同一IP地址下公開多個服務。

需要知道的是,ingress只是個規則,你必須具有 IngressController 才能滿足 Ingress 的要求。僅創建 Ingress資源本身沒有任何效果。下面是一個官網上的ingress示例的修改版,我把其中host可選項去掉了,如果沒有host的話就適用於通過指定 IP 地址的所有入站 HTTP 通信。 如果提供了 host(例如 foo.bar.com),則 rules 適用於該 host.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-fanout-example
spec:
  rules:
  - http:
      paths:
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 4200
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              number: 8080

這個表示訪問curl http://foo訪問的是服務service1:4200端口,curl http://bar訪問的是服務service2:8080端口。

Ingress Controller是需要用戶自己實現的

Ingress是一個非常“極客”並需要DIY的產物,kubernetes只負責提供一個API定義,具體的IngressController需要用戶自己實現!官方提供了Nginx Ingress Controller等其他幾種Controller示例共開發者參考。實現一個IngressController大致框架是:List/Watch Kubernetes 的Service、Endpoints、Ingress對象,並根據這些信息刷新外部Load Balancer(例如nginx)的規則和配置。值得注意的是,如果想要通過域名訪問Ingress,則需要用戶自己配置域名和IngressIP的配置關系,例如host文件、自己的DNS(不是kube-dns). 下圖是nginx官網給出的nginx-ingress-controller架構圖

ingress和ingressController創建實例

Talk is cheap,show me the code.下面說一下我創建ingress和ingressController創建的過程,以及在這個過程中看到的一些思考和問題。

創建ingress

我使用如下YAML文件創建了一個ingress, 創建完之后除了可以kubectl get ingress有輸出之外,不會有任何服務或者容器啟動。只是創建了一個規則而已。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress 
spec:
  ingressClassName: nginx-ingress-controller 
  rules:
  - host: test-ko-mix-master-1 
    http:
      paths:
      - path: /index.html
        pathType: Prefix
        backend:
          service:
            name: nginx
            port:
              number: 80
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: nginx2
            port:
              number: 80

注意,這里的http前面沒有橫杠,這里沒有namespace,ingressClassName我暫且理解為指明你想用哪個ingressController,如果你沒有定義一個class,那么你的雲provider會使用缺省的ic.用這個創建之后查看ingress,得到如下結果:

[root@test-ko-mix-master-1 20211109]# kubectl get ingress -A -o wide
NAMESPACE   NAME            CLASS                      HOSTS                  ADDRESS   PORTS   AGE
default     nginx-ingress   nginx-ingress-controller   test-ko-mix-master-1             80      2s

這里,ADDRESS一欄是空的(后面設定了service后會更新為service的IP),如果沒有設定ingressClassName那么CLASS這一欄是none.

創建nginx-ingress-controller

這個nginx-ingress-controller是官方寫的一個ic示例,如果你需要controller其他的資源需要自己去開發,這個資源可以是daemonset,也可以是deployment.啟動的容器會自動拉起一個nginx進程並且會根據ingress的規則配置容器內nginx的配置。我
用如下的mandatory.yaml 文件來創建nginx-ingress-controller:

點擊查看代碼
[root@test-ko-mix-master-1 20211109]# cat mandatory.yaml 
apiVersion: v1
kind: Namespace
metadata:
  name: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
kind: ConfigMap
apiVersion: v1
metadata:
  name: tcp-services
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
kind: ConfigMap
apiVersion: v1
metadata:
  name: udp-services
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nginx-ingress-serviceaccount
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: nginx-ingress-clusterrole
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - endpoints
      - nodes
      - pods
      - secrets
    verbs:
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - events
    verbs:
      - create
      - patch
  - apiGroups:
      - "extensions"
      - "networking.k8s.io"
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - "extensions"
      - "networking.k8s.io"
    resources:
      - ingresses/status
    verbs:
      - update

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
  name: nginx-ingress-role
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - pods
      - secrets
      - namespaces
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - configmaps
    resourceNames:
      # Defaults to "<election-id>-<ingress-class>"
      # Here: "<ingress-controller-leader>-<nginx>"
      # This has to be adapted if you change either parameter
      # when launching the nginx-ingress-controller.
      - "ingress-controller-leader-nginx"
    verbs:
      - get
      - update
  - apiGroups:
      - ""
    resources:
      - configmaps
    verbs:
      - create
  - apiGroups:
      - ""
    resources:
      - endpoints
    verbs:
      - get

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
  name: nginx-ingress-role-nisa-binding
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: nginx-ingress-role
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: nginx-ingress-clusterrole-nisa-binding
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: nginx-ingress-clusterrole
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx

---

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
#  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/part-of: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
    spec:
      # wait up to five minutes for the drain of connections
      terminationGracePeriodSeconds: 300
      serviceAccountName: nginx-ingress-serviceaccount
      nodeSelector:
        kubernetes.io/hostname: test-ko-mix-master-1
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
        - name: nginx-ingress-controller
          image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
          args:
            - /nginx-ingress-controller
            - --configmap=$(POD_NAMESPACE)/nginx-configuration
            - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
            - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
            - --publish-service=$(POD_NAMESPACE)/ingress-nginx
            - --annotations-prefix=nginx.ingress.kubernetes.io
          securityContext:
            allowPrivilegeEscalation: true
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE
            # www-data -> 101
            runAsUser: 101
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          ports:
            - name: http
              containerPort: 80
              hostPort: 80
              protocol: TCP
            - name: https
              containerPort: 443
              hostPort: 443
              protocol: TCP
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10
          lifecycle:
            preStop:
              exec:
                command:
                  - /wait-shutdown

---

apiVersion: v1
kind: LimitRange
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  limits:
  - min:
      memory: 90Mi
      cpu: 100m
    type: Container

找到創建出來的nginx-ingress-controller容器,kubectl exec -ti -n ingress-nginx pod/nginx-ingress-controller-vt5lq cat /etc/nginx/nginx.conf ,可以看到ingress設定的一些規則:

        ## start server test-ko-mix-master-1
        server {
                server_name test-ko-mix-master-1 ;
                
                listen 80  ;
                listen 443  ssl http2 ;
                
                set $proxy_upstream_name "-";
        ...
                location /foo {
                        
                        set $namespace      "default";
                        set $ingress_name   "nginx-ingress";
                        set $service_name   "";
                        set $service_port   "";
                        set $location_path  "/foo";
  

這個時候你外集群外節點去curl ngin-ingress-controller所在主機的80 端口可以得到404網頁返回。另外,我們查看nginx-ingress-controller的log,發現它一直在報錯:err services "ingress-nginx" not found.這個是說我們創建nginx-ingress-controller中啟動參數制定了publish-service為ingress-nginx:

- /nginx-ingress-controller
            - --configmap=$(POD_NAMESPACE)/nginx-configuration
            - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
            - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
            - --publish-service=$(POD_NAMESPACE)/ingress-nginx
            - --annotations-prefix=nginx.ingress.kubernetes.io

因此我們要創建一個nodeport類型的service,name是ingress-nginx,創建該service的YAML文件如下:

點擊查看代碼
[root@test-ko-mix-master-1 20211109]# cat service-nodeport.yaml 
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
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

創建完ingress-nginx service之后再次查看ingress,ADDRESS欄位有了值,也就是service IP Address:

[root@test-ko-mix-master-1 20211109]# kubectl get ingress -A -o wide 
NAMESPACE   NAME            CLASS                      HOSTS                  ADDRESS           PORTS   AGE
default     nginx-ingress   nginx-ingress-controller   test-ko-mix-master-1   192.168.255.207   80      48m
[root@test-ko-mix-master-1 20211109]# kubectl describe ingress -n default     nginx-ingress 
Name:             nginx-ingress
Namespace:        default
Address:          192.168.255.207
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host                  Path  Backends
  ----                  ----  --------
  test-ko-mix-master-1  
                        /index.html   nginx:80 (10.8.188.31:80)
                        /bar          nginx2:80 (10.8.188.36:80)
Annotations:            <none>
Events:                 <none>

正是有了這個nodeport類型的service我們才能在集群外的節點curl test-ko-mix-master-1: /index.html(這里test-ko-mix-master-1可以在/etc/hosts中配成集群的任何一個節點的IP)才能得到復雜的nginx容器的頁面。否則只能把test-ko-mix-master-1在/etc/hosts中配成controller所在節點的IP才能訪問(這是加nodePort或者80端口都可以訪問,why?)。
因為我們ingress制定的url foo后端的service是nginx,所以我們要創建這個service及其后面的endpoints.否則nginx-ingress-controller會報錯說找不到nginx這個service. 創建完成之后我的理解就是在集群群外的節點輸入curl test-ko-mix-master-1 /foo 就訪問到那邊呢?nginx service對應的endpoint pod上嗎?還是負載到nginx-ingress-controller里面的nginx進程上呢?根據官網的架構圖理解應該是先到nginx-ingress-controller的容器,由它負載到后面的service,也就是nginx service對應的endpoints我看到過有的文檔說流量不經過service由nginx-ingress-controller直接負載到service后面的endpoint也就是pod上,但是我沒有找到controller所在主機的80監聽端口也沒有找到ipvs轉發主機80端口的規則。那么我不敢妄評說controller的流量到底是怎么轉發的。有知道的大神可以在評論區指教!
另外,我在集群主機上看到這樣一條IPVS轉發規則:

TCP  172.18.8.203:32629 rr
  -> 10.8.188.30:80               Masq    1      0          0      

意思就是訪問本機(172.18.8.203)32629 端口的轉發到10.8.188.30:80,其中10.8.188.30是nginx-ingress-controller 容器的IP Address.

ingressClass

當集群中存在多於一個的 Ingress Controller 時,就需要為 Ingress 指定對應的 Controller 是哪個,在 Kubernetes 1.18 之前,通常是在 Ingress 資源上通過 kubernetes.io/ingress.class 注解來指定使用的 Ingress Controller。雖然這個注解從未被正式定義過,但確是被各個 Ingress Controller 所廣泛支持的。Kubernetes 1.18 起,正式提供了一個 IngressClass 資源,作用與 kubernetes.io/ingress.class 注解類似,例如:

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb
spec:
  controller: nginx-ingress-internal-controller
  parameters:
    apiGroup: k8s.example.com
    kind: IngressParameters
    name: external-lb

其中重要的屬性是 metadata.name 和 spec.controller,前者是這個 IngressClass 的名稱,需要設定在 Ingress 中,后者是 Ingress Controller 的名稱。Ingress 中的 spec.ingressClassName 屬性,可以用來指定對應的 IngressClass,並進而由 IngressClass 關聯到對應的 Ingress Controller,如:

kind: Ingress
metadata:
  name: spring-k8s
spec:
  ingressClassName: external-lb
  defaultBackend:
    service:
      name: spring-k8s
      port:
        number: 80

注意,spec.ingressClassName 與 metadata.annotations.kubernetes.io/ingress.class 的作用並不完全相同,因為 ingressClassName 字段引用的是 IngressClass 資源的名稱,IngressClass 資源中,除了指定了 Ingress Controller 的名稱之外,還可能會通過 spec.parameters 屬性定義一些額外的配置。

題外話,正向代理和反向代理

  • 正向代理類似一個跳板機,代理訪問外部資源。比如我們國內訪問谷歌,直接訪問訪問不到,我們可以通過一個正向代理服務器,請求發到代理服,代理服務器能夠訪問谷歌,這樣由代理去谷歌取到返回數據,再返回給我們,這樣我們就能訪問谷歌了。正向代理即是客戶端代理, 代理客戶端, 服務端不知道實際發起請求的客戶端.
    正向代理的用途:
    (1)訪問原來無法訪問的資源,如google
    (2)可以做緩存,加速訪問資源
    (3)對客戶端訪問授權,上網進行認證
    (4)代理可以記錄用戶訪問記錄(上網行為管理),對外隱藏用戶信息
  • 反向代理(Reverse Proxy)實際運行方式是指以代理服務器來接受internet上的連接請求,然后將請求轉發給內部網絡上的服務器,並將從服務器上得到的結果返回給internet上請求連接的客戶端,此時代理服務器對外就表現為一個服務器。反向代理即是服務端代理, 代理服務端, 客戶端不知道實際提供服務的服務端。
    反向代理的作用:
    (1)保證內網的安全,阻止web攻擊,大型網站,通常將反向代理作為公網訪問地址,Web服務器是內網
    (2)負載均衡,通過反向代理服務器來優化網站的負載

參考


免責聲明!

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



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