Calico 用於 Kubernetes 中的網路:介紹和一點經驗

Calico 用於 Kubernetes 中的網路:介紹和一點經驗

本文的目的是向讀者介紹 Kubernetes 中的網路和管理網路策略的基礎知識,以及擴展標準功能的第三方 Calico 外掛程式。 在此過程中,我們將使用我們操作經驗中的真實範例來演示配置的簡單性和一些功能。

Kubernetes 網路設備快速介紹

無法想像沒有網路的 Kubernetes 叢集。 我們已經發布了有關其基礎知識的資料:“Kubernetes 網路圖解指南“和”面向安全專業人員的 Kubernetes 網絡策略簡介“。

在本文中,需要注意的是,K8s 本身不負責容器和節點之間的網路連接:為此,各種 CNI 插件 (容器網路介面)。 關於這個概念的更多信息,我們 他們還告訴我.

例如,這些插件中最常見的是 絨布 — 透過在每個節點上架設網橋並為其指派子網,在所有叢集節點之間提供完整的網路連線。 然而,完全且不受監管的可訪問性並不總是有益的。 為了在集群中提供某種最小程度的隔離,有必要幹預防火牆的配置。 在一般情況下,它被置於同一個 CNI 的控制之下,這就是為什麼 iptables 中的任何第三方乾預都可能被錯誤解釋或完全忽略的原因。

並提供「開箱即用」的方式在 Kubernetes 叢集中組織網路策略管理 網路策略API。 這項資源分佈在選定的名稱空間上,可以包含區分從一個應用程式到另一個應用程式的存取的規則。 它還允許您配置特定 Pod、環境(命名空間)或 IP 位址區塊之間的可存取性:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

這不是最原始的例子 官方文檔 可能一勞永逸地阻礙人們了解網路政策如何運作的邏輯的願望。 然而,我們仍然會嘗試了解使用網路策略處理流量的基本原理和方法...

從邏輯上講,有兩種類型的流量:進入 Pod 的流量(Ingress)和從 Pod 流出的流量(Egress)。

Calico 用於 Kubernetes 中的網路:介紹和一點經驗

實際上,政治根據運動方向分為這兩類。

下一個必需的屬性是選擇器; 規則適用的人。 這可以是一個 Pod(或一組 Pod)或一個環境(即命名空間)。 一個重要的細節:這兩種類型的物件都必須包含一個標籤(標籤 在 Kubernetes 術語中)—這些是政客所使用的。

除了有限數量的選擇器(由某種標籤聯合起來)之外,還可以以不同的變體編寫“允許/拒絕一切/所有人”之類的規則。 為此,使用以下形式的結構:

  podSelector: {}
  ingress: []
  policyTypes:
  - Ingress

— 在此範例中,環境中的所有 Pod 都會被阻止接收傳入流量。 透過以下結構可以實現相反的行為:

  podSelector: {}
  ingress:
  - {}
  policyTypes:
  - Ingress

同樣對於傳出:

  podSelector: {}
  policyTypes:
  - Egress

- 將其關閉。 以下是要包含的內容:

  podSelector: {}
  egress:
  - {}
  policyTypes:
  - Egress

回到叢集的 CNI 插件的選擇,值得注意的是 並非每個網頁外掛程式都支援 NetworkPolicy。 例如已經提到的Flannel不知道如何設定網路策略,這 是直接說的 在官方儲存庫中。 那裡也提到了另一個選擇——開源項目 印花布,它在網路策略方面顯著擴展了 Kubernetes API 標準集。

Calico 用於 Kubernetes 中的網路:介紹和一點經驗

了解 Calico:理論

Calico 插件可以與 Flannel 整合使用(子項目 運河)或獨立,涵蓋網路連線和可用性管理功能。

使用 K8s「盒裝」解決方案和 Calico 的 API 集提供了哪些機會?

以下是 NetworkPolicy 的內建內容:

  • 政治家受到環境的限制;
  • 策略應用於標有標籤的 Pod;
  • 規則可以應用於 Pod、環境或子網路;
  • 規則可以包含協定、命名或符號連接埠規格。

以下是 Calico 如何擴展這些功能:

  • 策略可以應用於任何物件:pod、容器、虛擬機器或介面;
  • 規則可以包含特定的操作(禁止、許可、記錄);
  • 規則的目標或來源可以是連接埠、一系列連接埠、協定、HTTP 或 ICMP 屬性、IP 或子網路(第四代或第六代)、任何選擇器(節點、主機、環境);
  • 此外,您可以使用 DNAT 設定和流量轉送策略來調節流量的通過。

Calico 儲存庫中 GitHub 上的首次提交可以追溯到 2016 年 XNUMX 月,一年後該專案在組織 Kubernetes 網路連接方面佔據了領先地位 - 例如,調查結果就證明了這一點: 由 New Stack 進行:

Calico 用於 Kubernetes 中的網路:介紹和一點經驗

許多使用 K8s 的大型託管解決方案,例如 亞馬遜EKS, Azure AKS, GoogleGKE 其他人開始推薦使用它。

至於性能,這裡一切都很棒。 在測試他們的產品時,Calico 開發團隊展示了天文學數位般的效能,在 50000 個實體節點上運行了 500 多個容器,每秒創建 20 個容器。 沒有發現縮放問題。 這樣的結果 被宣布 已經在第一個版本的公告中。 針對吞吐量和資源消耗的獨立研究也證實 Calico 的表現幾乎與 Flannel 一樣好。 例如:

Calico 用於 Kubernetes 中的網路:介紹和一點經驗

該專案發展非常迅速,它支援在流行的解決方案管理的K8s、OpenShift、OpenStack中工作,在部署叢集時可以使用Calico ,有參考Service Mesh網路的建置(這是一個例子 與 Istio 結合使用)。

與 Calico 一起練習

在使用普通 Kubernetes 的一般情況下,安裝 CNI 歸結為使用該文件 calico.yaml, 從官方網站下載, 透過使用 kubectl apply -f.

通常,目前版本的外掛程式與 Kubernetes 的最新 2-3 個版本相容:舊版中的操作未經測試且無法保證。 據開發人員稱,Calico 運行在 3.10 以上的 Linux 核心上,運行 CentOS 7、Ubuntu 16 或 Debian 8,基於 iptables 或 IPVS。

環境內隔離

為了進行一般性理解,讓我們來看一個簡單的案例,以了解 Calico 表示法中的網路策略與標準策略有何不同,以及創建規則的方法如何簡化其可讀性和配置靈活性:

Calico 用於 Kubernetes 中的網路:介紹和一點經驗

叢集中部署了 2 個 Web 應用程式:Node.js 和 PHP,其中之一使用 Redis。 要阻止從 PHP 存取 Redis,同時保持與 Node.js 的連接,只需套用以下策略:

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-redis-nodejs
spec:
  podSelector:
    matchLabels:
      service: redis
  ingress:
  - from:
    - podSelector:
        matchLabels:
          service: nodejs
    ports:
    - protocol: TCP
      port: 6379

本質上,我們允許從 Node.js 傳入 Redis 埠的流量。 他們顯然沒有禁止任何其他事情。 NetworkPolicy一出現,其中提到的所有選擇器就開始被隔離,除非另有說明。 但是,隔離規則不適用於選擇器未覆寫的其他物件。

此範例使用 apiVersion Kubernetes 開箱即用,但沒有什麼可以阻止您使用它 來自 Calico 交付的同名資源。 那裡的語法更詳細,因此您需要以以下形式重寫上述情況的規則:

apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
  name: allow-redis-nodejs
spec:
  selector: service == 'redis'
  ingress:
  - action: Allow
    protocol: TCP
    source:
      selector: service == 'nodejs'
    destination:
      ports:
      - 6379

上述用於允許或拒絕通過常規 NetworkPolicy API 的所有流量的結構包含帶有括號的結構,這些結構難以理解和記憶。 對於 Calico,要將防火牆規則的邏輯變更為相反的邏輯,只需更改 action: Allowaction: Deny.

環境隔離

現在想像這樣一種情況:應用程式產生業務指標,以便在 Prometheus 中收集並使用 Grafana 進行進一步分析。 上傳的內容可能包含敏感數據,預設情況下這些數據也是公開可見的。 讓我們隱藏這些數據以免被窺探:

Calico 用於 Kubernetes 中的網路:介紹和一點經驗

通常,Prometheus 放置在單獨的服務環境中 - 在範例中它將是這樣的命名空間:

apiVersion: v1
kind: Namespace
metadata:
  labels:
    module: prometheus
  name: kube-prometheus

領域 metadata.labels 事實證明這並非偶然。 正如剛才所提到的, namespaceSelector (也 podSelector)與標籤一起操作。 因此,要允許從特定連接埠上的所有 Pod 取得指標,您必須新增某種標籤(或從現有標籤中取得),然後套用如下配置:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-metrics-prom
spec:
  podSelector: {}
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          module: prometheus
    ports:
    - protocol: TCP
      port: 9100

如果您使用 Calico 策略,語法將如下所示:

apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
  name: allow-metrics-prom
spec:
  ingress:
  - action: Allow
    protocol: TCP
    source:
      namespaceSelector: module == 'prometheus'
    destination:
      ports:
      - 9100

一般來說,透過針對特定需求添加此類策略,可以防止叢集中應用程式的運行受到惡意或意外幹擾。

根據 Calico 的創建者的說法,最佳實踐是「阻止所有內容並明確打開您需要的內容」方法,記錄在 官方文檔 (其他人也遵循類似的方法 - 特別是在 已經提過的文章).

使用額外的 Calico 對象

讓我提醒您,透過 Calico API 的擴充集,您可以調節節點的可用性,而不僅限於 pod。 在下面的範例中使用 GlobalNetworkPolicy 在叢集中傳遞 ICMP 請求的功能已關閉(例如,從 pod 到節點、pod 之間或從節點到 IP pod 的 ping):

apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
  name: block-icmp
spec:
  order: 200
  selector: all()
  types:
  - Ingress
  - Egress
  ingress:
  - action: Deny
    protocol: ICMP
  egress:
  - action: Deny
    protocol: ICMP

在上述情況下,叢集節點仍可透過 ICMP 相互「聯繫」。 這個問題是透過以下方式解決的 GlobalNetworkPolicy,應用於實體 HostEndpoint:

apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
  name: deny-icmp-kube-02
spec:
  selector: "role == 'k8s-node'"
  order: 0
  ingress:
  - action: Allow
    protocol: ICMP
  egress:
  - action: Allow
    protocol: ICMP
---
apiVersion: crd.projectcalico.org/v1
kind: HostEndpoint
metadata:
  name: kube-02-eth0
  labels:
    role: k8s-node
spec:
  interfaceName: eth0
  node: kube-02
  expectedIPs: ["192.168.2.2"]

VPN 案例

最後,我將給出一個非常真實的範例,當一組標準策略不夠時,使用 Calico 函數來處理近集群互動的情況。 要存取 Web 應用程序,用戶端使用 VPN 隧道,且此存取受到嚴格控制並僅限於允許使用的特定服務清單:

Calico 用於 Kubernetes 中的網路:介紹和一點經驗

用戶端透過標準 UDP 連接埠 1194 連接到 VPN,並在連接後接收 Pod 和服務的叢集子網路的路由。 推送整個子網,以免在重新啟動和位址變更期間遺失服務。

配置中的連接埠是標準的,這給配置應用程式並將其傳輸到 Kubernetes 叢集的過程帶來了一些細微差別。 例如,去年年底,AWS LoadBalancer for UDP 確實出現在有限的區域清單中,而 NodePort 由於在所有叢集節點上轉送而無法使用,並且無法擴展伺服器執行個體的數量容錯的目的。 另外,您必須更改連接埠的預設範圍...

經過搜尋可能的解決方案,選擇以下方案:

  1. 具有 VPN 的 Pod 按節點調度 hostNetwork,即為實際IP。
  2. 該服務透過外部發布 ClusterIP。 連接埠實體安裝在節點上,可以從外部訪問,但需要進行少量保留(有條件地存在真實 IP 位址)。
  3. 確定豆莢升起的節點超出了我們故事的範圍。 我只想說,你可以將服務緊緊地「釘」在一個節點上,或者編寫一個小型sidecar 服務來監視VPN 服務的當前IP 位址並編輯向客戶端註冊的DNS 記錄- 無論誰有足夠的想像力。

從路由的角度來看,我們可以透過VPN伺服器發佈的IP位址來唯一標識VPN客戶端。 以下是限制此類客戶端存取服務的原始範例,在上述 Redis 上進行了說明:

apiVersion: crd.projectcalico.org/v1
kind: HostEndpoint
metadata:
  name: vpnclient-eth0
  labels:
    role: vpnclient
    environment: production
spec:
  interfaceName: "*"
  node: kube-02
  expectedIPs: ["172.176.176.2"]
---
apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
  name: vpn-rules
spec:
  selector: "role == 'vpnclient'"
  order: 0
  applyOnForward: true
  preDNAT: true
  ingress:
  - action: Deny
    protocol: TCP
    destination:
      ports: [6379]
  - action: Allow
    protocol: UDP
    destination:
      ports: [53, 67]

在這裡,嚴格禁止連接到連接埠 6379,但同時保留 DNS 服務的操作,在製定規則時,該服務的功能經常受到影響。 因為,如前所述,當選擇器出現時,除非另有指定,否則預設拒絕策略將會套用到它。

結果

因此,使用 Calico 的高級 API,您可以靈活配置和動態更改叢集內部和周圍的路由。 一般來說,它的使用看起來就像用大砲射麻雀,並且在平坦網路上的簡單Kubernetes 安裝中實現具有BGP 和IP-IP 隧道的L3 網路看起來很可怕......但是,除此之外,該工具看起來非常可行且有用。

隔離群集來滿足安全要求可能並不總是可行,這就是 Calico(或類似的解決方案)可以解決的問題。 本文中給出的範例(稍作修改)已用於我們在 AWS 中的多個客戶端安裝。

聚苯乙烯

另請閱讀我們的博客:

來源: www.habr.com

添加評論