天天看點

ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料

本篇已加入《 .NET Core on K8S學習實踐系列文章索引 》,可以點選檢視更多容器化技術相關系列文章。

一、關于Ingress

Kubernetes對外暴露Service主要有三種方式:NodePort、LoadBalancer 以及 Ingress。前兩種我們在第四篇《

你必須知道的Service

》一文中已經加以介紹,這裡我們主要來看看Ingress是個什麼鬼。

官網對 Ingress 的定義為 管理對外服務到叢集内服務之間規則的集合,通俗點講就是它定義規則來允許進入叢集的請求被轉發到叢集中對應服務上,從來實作服務暴漏。Ingress 能把叢集内 Service 配置成外網能夠通路的 URL,流量負載均衡,終止SSL,提供基于域名通路的虛拟主機等等。

我們可以再次回顧一下我們通常通路一個業務的流程:

  • User在浏覽中輸入一個域名
  • DNS至業務入口,這裡一般指外部負載均衡器(Load Balancer),比如阿裡雲的SLB服務
  • 外部負載均衡器反向代理到K8S的入口,比如Ingress
  • Ingress将請求轉交給對應的Service
  • Service将請求對應到某一個具體的Pod  
ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料

了解了整個流程,我們再結合官網的定義來看Ingress,可以知道Ingress就是一個K8S叢集業務的入口,一個統一通路入口。我們可以使用Traefik、Istio、Nginx、HAProxy來作為Ingress使用,這裡我們主要介紹Nginx Ingress,因為我們比較熟悉Nginx一些。

二、Nginx Ingress的安裝與配置

這裡我們在k8s-master上執行以下的yaml檔案來通過DaemonSet的方式部署Nginx Ingress,這個yaml檔案可以從ingress-nginx的github上擷取,這裡我選擇的是0.30.0版本。

擷取方式:

https://github.com/kubernetes/ingress-nginx/tree/nginx-0.30.0/deploy
ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料
ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料

在static目錄下,将mandatory.yaml檔案擷取下來如下代碼所示,這裡我做了一點修改(注意我标紅的配置):

(1)将原本為Deployment的類型換為了DaemonSet

(2)為Ingress-Controller增加hostNetwork: true的配置,即直接占用主控端80/443端口

(3)将Ingress-Controller部署到有ingressHost: yes這個label的Node節點上,即我的k8s-node1伺服器上

(4)将Ingress-Controller的鏡像源改為阿裡雲鏡像倉庫:registry.cn-hangzhou.aliyuncs.com

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/os: linux
            **ingressHost: ****"yes"****
          hostNetwork: true**
          containers:
            - name: nginx-ingress-controller
              image: **registry.cn-hangzhou.aliyuncs.com/google_containers/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
                  protocol: TCP
                - name: https
                  containerPort: 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           

這裡順便說下Ingress的兩種部署方式:

(1)基于NodePort方式

ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料

基于NodePort的部署思路就是通過在每個節點上開辟NodePort的端口,将流量引入進來,而後通過iptables首先轉發到ingress-controller容器中(圖中的nginx容器),而後由nginx根據ingress的規則進行判斷,将其轉發到對應的應用web容器中。

(2)基于HostNetwork方式

ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料

相比較起來,HostNetwork模式不再需要建立一個nodePort的svc,而是直接在每個節點都建立一個ingress-controller的容器,而且将該容器的網絡模式設為HostNetwork。也就是說每個節點實體機的80和443端口将會被ingress-controller中的nginx容器占用。當流量通過80/443端口進入時,将直接進入到nginx中。而後nginx根據ingress規則再将流量轉發到對應的web應用容器中。

OK,兩種模式我們就了解到這裡,本文采用的是基于hostNetwork的方式占用主控端80/443端口來作為流量入口。

然後,我們就可以運作建立指令來建立Ingress-Controller了:

kubectl apply -f mandatory.yaml           

執行後的顯示如下圖所示,它會執行一系列的建立工作如namespace、configmap、serviceaccount、rbac以及daemonset等:

ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料

Ingress-Controller建立好之後,我們再來建立一個指導Ingress進行路由轉發的規則集ingress-nginx.yaml,其配置如下:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress
  namespace: xdp-poc
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /api/$2
spec:
  rules:
  - host: portal.k8s.xi-life.cn
    http:
      paths:
      - path: /apple(/|$)(.*)
        backend:
          serviceName: apple-api-svc
          servicePort: 80
      - path: /banana(/|$)(.*)
        backend:
          serviceName: banana-api-svc
          servicePort: 80           

它的作用其實是幫助Nginx生成正确的Nginx.conf,幫助Nginx将請求轉發不同的K8s叢集中的Service入口進行處理。這裡,我定義了兩個後端Service服務,稍後我會介紹這兩個Service,現在我們現将其建立一下:

kubectl apply -f ingress-nginx.yaml           

現在可以通過kubectl看看是否已經Running:

ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料

好了,搭建和配置部分到此為止,下面我們可以準備剛剛提到的兩個Service來進行一個簡單的驗證了。

三、Nginx Ingress的快速驗證

3.1 後端API項目準備

這裡我準備兩個ASP.NET Core WebAPI項目,他們的代碼很簡單,就隻有一個HomeController,負責請求到api/home路由時傳回一個json即可。

其中,AppleApi項目傳回:

// GET api/home
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
    return new string[] { "AppleApi-Home", "v1.0", "Welcome to use AppleApi!" };
}           

BananApi項目傳回:

// GET api/home
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
    return new string[] { "BananaApi-Home", "v1.0", "Welcome to use BananaApi!" };
}           

這部分的代碼檔案可以在我的github上擷取:

點此擷取

ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料

然後,我們将這兩個項目分别打一個docker鏡像并上傳到docker hub上,你可以直接使用我的鏡像進行這個實驗,具體的打包鏡像和上傳鏡像的過程我就不示範了。

ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料

直接拉取鏡像:docker pull xilife/apple-api-demo:1.0 / docker pull xilife/banana-api-demo:1.0 

3.2 部署yaml檔案準備

接下來,我們就分别為兩個API項目準備部署yaml檔案,并應用該yaml檔案建立pod和service:

(1)deploy-appleapi-svc.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: apple-api-demo
  namespace: xdp-poc
  labels:
    name: apple-api-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      name: apple-api-demo
  template:
    metadata:
      labels:
        name: apple-api-demo
    spec:
      containers:
      - name: apple-api-demo
        image: edisonsaonian/apple-api-demo:1.0
        ports:
        - containerPort: 80
        imagePullPolicy: IfNotPresent

---

kind: Service
apiVersion: v1
metadata:
  name: apple-api-svc
  namespace: xdp-poc
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
  selector:
    name: apple-api-demo           

需要注意的就是:確定這裡Service中定義的namespace(這裡是xdp-poc)、服務名(這裡是apple-api-svc)以及端口(這裡是80)跟之前我們在ingress-nginx.yaml中設定的後端服務名和端口保持一緻,否則無法實作請求轉發。下面的BananaApi也是需要保持一緻,就不再贅述。

(2)deploy-bananaapi-svc.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: banana-api-demo
  namespace: xdp-poc
  labels:
    name: banana-api-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      name: banana-api-demo
  template:
    metadata:
      labels:
        name: banana-api-demo
    spec:
      containers:
      - name: banana-api-demo
        image: edisonsaonian/banana-api-demo:1.0
        ports:
        - containerPort: 80
        imagePullPolicy: IfNotPresent

---

kind: Service
apiVersion: v1
metadata:
  name: banana-api-svc
  namespace: xdp-poc
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
  selector:
    name: banana-api-demo           

最後,我們将其部署到K8s叢集:

kubectl apply -f deploy-appleapi-svc
kubectl apply -f deploy-bananaapi-svc           
ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料

3.3 快速驗證Ingress

由于我們設定的host是portal.k8s.xi-life.cn,是以我們現在自己的客戶機上修改一下hosts檔案(Windows的話在system32/etc/drivers/hosts)增加一條記錄,然後就可以通過浏覽器輸入域名來進行通路測試了:

(1)apple-api

ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料

(2)banana-api

ASP.NET Core on K8S深入學習(12)Ingress一、關于Ingress二、Nginx Ingress的安裝與配置三、Nginx Ingress的快速驗證四、小結參考資料

四、小結

本文介紹了Ingress的基本概念與Nginx Ingress的安裝與配置,然後通過部署兩個ASP.NET Core WebAPI服務到K8s叢集進行Ingress的快速驗證。當然,我們也可以使用自己的網關來代替Ingress作為外部統一流量入口,也可以使用雲産品的LoadBalancer或API網關來替代Ingress也都是可以的(不缺錢的情況下)。

參考資料

(1)梁寬,《

再也不踩坑的Kubernetes實戰指南

(2)李振良,《

一天入門Kubernets教程

(3)馬哥(馬永亮),《

Kubernetes快速入門

(4)花田犯的錯,《

K8S Nginx Ingress介紹

(5)Lucie_xxm,《

Ingress 統一通路入口

繼續閱讀