<form id="tznrh"><form id="tznrh"><th id="tznrh"></th></form></form>

            云原生架構|K8S服務暴露: HAProxy在RDS場景下的妙用

            發布時間:2020-10-10 | 信息來源: | 發布作者:


            01

            前  言


            隨著云原生架構kubernetes的飛速發展,越來越多的公司,團隊將服務以容器化的形式部署在云原生架構k8s集群上。在集群內成百上千的服務里,總會有一些作為交互入口需要對用戶提供服務,但集群本身是一個封閉的網絡環境,如何將集群內部的服務暴露出來供人使用便成了一個值得討論的話題。


            02

            概  念


            POD

            用戶在集群內運行的服務可以被抽象為pod。Pod是 云原生架構Kubernetes 應用程序的基本執行單元,它是 云原生架構Kubernetes 對象模型中創建或部署的最小和最簡單的單元。Pod 表示在集群上運行的進程。

            Services

            每個 Pod 都有自己的 IP 地址,這導致了一個問題:如果一組 Pod(稱為“后端”)為群集內的其他 Pod(稱為“前端”)提供功能,那么前端如何找出并跟蹤要連接的 IP 地址,以便前端確??梢栽L問到正確的后端?

            云原生架構Kubernetes Service定義了這樣一種抽象:邏輯上的一組Pod,一種可以訪問它們的策略 —— 通常稱為微服務。這一組Pod能夠被云原生架構Service訪問到。

            舉個例子,考慮一個圖片處理 backend,它運行了3個副本。這些副本是可互換的 —— frontend 不需要關心它們調用了哪個 backend 副本。然而組成這一組 backend 程序的Pod實際上可能會發生變化,frontend 客戶端不應該也沒必要知道,而且也不需要跟蹤這一組 backend 的狀態。云原生架構Service定義的抽象能夠解耦這種關聯。

            云原生架構|簡言之,通過對POD和Services關系的闡述,我們將云原生架構k8s服務暴露的問題簡化為:如何讓外部用戶可以訪問到集群內的云原生架構Service?

            官方提供了NodePort,LoadBalancer形式讓Service對外暴露,兩種方式配置起來相對簡便,但各有短板。

            NodePort存在端口上限的瓶頸,雖然可以更改配置擴容,但由于實現方式的問題,NodePort的存在不可忽視的性能損耗。

            而LoadBalancer需要云提供商支持,在私有云環境下無法實現(況且云提供商的lb服務并不免費?。?。

            除此之外,官方還提供了第三種方式,也是相對DIY的一種實現Ingress,接下來將對ingress進行詳細展開。



            03

            Ingress


            什么是ingress?

            官方對此這樣描述:

            Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster. Traffic routing is controlled by rules defined on the Ingress resource.

            internet

            |

            [ Ingress ]

            --|-----|--

            [ Services ]

            An Ingress may be configured to give Services externally-reachable URLs, load balance traffic, terminate SSL / TLS, and offer name based virtual hosting. An Ingress controller is responsible for fulfilling the Ingress, usually with a load balancer, though it may also configure your edge router or additional frontends to help handle the traffic.

            An Ingress does not expose arbitrary ports or protocols. Exposing services other than HTTP and HTTPS to the internet typically uses a service of type Service.Type=NodePort or Service.Type=LoadBalancer.

            簡而言之,通過ingress的形式暴露服務只需兩個條件:

            1、創建云原生架構Ingress資源,該資源聲明了轉發規則,即流量到達ingress后將會轉發到哪個(哪些)云原生架構service。

            2、搭建一個Ingress Controller監聽ingress資源,并實現ingress聲明的轉發規則。

            相比于NodePort和LoadBalancer,ingress的配置可能相對復雜,但帶來的強大功能會完全掩蓋開發部署的繁瑣。

            有哪些Ingress Controller可供選擇?

            Nginx Ingress Controller

            作為反代巨頭,nginx提供的Ingress Controller被官方作為默認的L7 Ingress Controller實現。

            Traefik Ingress Controller

            Traefik作為邊緣路由新貴,憑借他和容器平臺的良好適性(go編寫)以及創新的配置讀取功能(其他代理僅支持純文本配置)在容器領域獲取了大量的簇擁,我自己也是Traefik粉絲之一。

            上述兩種云原生架構Ingress Controller在L7代理方面非常穩定高效且功能齊全,完全可以在生產環境使用。但在RDS場景下,或說在TCP長連接需求的場景下卻顯得不盡人意:

            Nginx在熱加載配置時將會斷開所有已經建立的連接,這在RDS場景下肯定是不允許的,試想一個客戶創建了一個新的RDS集群,結果其他客戶創建的幾百個集群全部連接中斷。即使是瞬時的中斷也會對業務造成不良影響。

            Traefik在2019年末更新的大版本v2.0上推出了對tcp的支持,功能方面非常穩定高效。但由于traefik的架構限制,用戶無法在運行時新增或刪除一個服務器端口。這意味著需要在一開始就根據集群的規模來確定需要監聽n個端口,并且在運行時無法變更端口。這其實違背了云原生架構k8s作為容器編排工具動態擴縮容的初衷。


            04

            HAProxy Ingress Controller


            上述內容為我們引出了本文的主角haproxy

            什么是HAProxy?

            The world"s fastest and most widely used software load balancer. -- haproxy.com

            為什么選用HAProxy?

            1、HAProxy支持動態配置加載. 用戶只需將變更后的配置文件提交給HAProxy, 就可以實現無縫的規則變更.

            2、HAProxy支持Hitless Reload.。顧名思義,在HAProxy熱加載過程中,單一配置的變更不會影響其他無關的配置。HAProxy通過reusesocket的形式,將old process持有的已經建立的連接fd傳遞給new process,對于使用者來說整個熱加載的過程是無感知的。

            3、按需監聽端口。只有在配置中顯示bind端口時,HAProxy才會去監聽宿主機上的端口。且相較于NodePort,haproxy只在任意指定的機器上暴露了端口。

            上述三點滿足了RDS進行服務暴露的需求。

            如何實現HAProxy Ingress Controller?

            HAProxy Ingress Controller由兩部分組成,HAProxy和Ingress Controller。

            Ingress Controller是一個由go編寫的程序,通過監聽云原生架構service資源來發現用戶需要暴露的服務,例如:

            # mysql-svc.yaml

            apiVersion: v1

            kind: Service

            metadata:

            annotations:

            haproxy-ingress/3306: "26735" # 為service3306端口分配了宿主機26735端口, 由Ingress Controller寫入

            ingress: haproxy-ingress # 指定ingress類型為haproxy, Ingress Controller將發現此標記并為service分配端口

            labels:

            app: mysqlcluster

            name: mysqlcluster

            namespace: default

            spec:

            ports:

            - name: mysql

            port: 3306

            protocol: TCP

            targetPort: 3306

            selector:

            Name: mysqlcluster

            type: ClusterIP


            云原生架構|在上面的mysql-svc.yaml中聲明了一個service,,并在annotation中打了ingress=haproxy-ingress標記。Ingress Controller監聽了service資源的變更,當發現帶有指定標記的service配置出現,就在預先指定的端口池中找到一個(多個)空閑的端口并分配給云原生架構service。

            如圖所示, 整個流程可以整理如下:

            1、用戶創建service資源,并打上ingress=haproxy-ingress標記。

            2、Ingress Controller監聽到service資源的變更,并根據標記得知該service需要haproxy進行服務暴露。

            3、Ingress Controller遍歷service spec中聲明的ports,并從端口池中取出等量空閑宿主機port分配。

            4、Ingress Controller將處理后的service配置通過jinja2模板轉換為haproxy配置文件。

            5、發送信號通知haproxy進行熱加載,此過程中haproxy監聽了新的宿主機端口并將流量導向service中指定的服務。

            流程結束后, 用戶即可通過haproxy所在的機器(負載機器)的ip+分配的端口訪問到自己的服務。

            更進一步

            通過將HAProxy Ingress Controller部署在多臺宿主機上,在前端通過keepalived/f5等手段進行機器級別的負載來達到高可用。



            05

            總  結


            由于RDS需求的特殊網絡環境,云原生架構k8s提供的常規服務暴露手段很難完全契合業務需求。HAProxy作為一個20年老品牌負載均衡器為我們提供了必要的網絡技術支持,結合依賴k8s標準包開發的Ingress Controller,讓我們用更超然的手段實現了RDS的服務暴露。

            references


            k8s official:https://kubernetes.io

            ingress-controller: https://github.com/jcmoraisjr/haproxy-ingress


            | 作者簡介

            謝鋼鵬·沃趣科技高級開發工程師


            沃趣QFusion項目組研發,云原生架構技術求道者,致力于容器和云原生架構技術的推廣。多年golang及python編程經驗,主要司職服務端開發,目前著眼于RDS相關技術研究,kubernetes crd控制器編寫。




            沃趣科技,讓客戶用上更好的數據庫技術!
            三分快3