1. 程式人生 > >kubernetes 簡介:kube-proxy 和 service

kubernetes 簡介:kube-proxy 和 service

簡介

在 kubernetes 叢集中,網路是非常基礎也非常重要的一部分。對於大規模的節點和容器來說,要保證網路的連通性、網路轉發的高效,同時能做的 ip 和 port 自動化分配和管理,並讓使用者用直觀簡單的方式來訪問需要的應用,這是需要複雜且細緻設計的。

kubernetes 在這方面下了很大的功夫,它通過 service 、 dns 、 ingress 等概念,解決了服務發現、負載均衡的問題,也大大簡化了使用者的使用和配置。

這篇文章就講解如何配置 kubernetes 的網路,最終從叢集內部和叢集外部都能訪問應用。

跨主機網路配置:flannel

一直以來,kubernetes 並沒有專門的網路模組負責網路配置,它需要使用者在主機上已經配置好網路。kubernetes 對網路的要求是:容器之間(包括同一臺主機上的容器,和不同主機的容器)可以互相通訊,容器和叢集中所有的節點也能直接通訊。

至於具體的網路方案,使用者可以自己選擇,目前使用比較多的是 flannel,因為它比較簡單,而且剛好滿足 kubernetes 對網路的要求。我們會使用 flannel vxlan 模式,具體的配置我在部落格之前有文章介紹過,這裡不再贅述。

以後 kubernetes 網路的發展方向是希望通過外掛的方式來整合不同的網路方案, CNI 就是這一努力的結果,flannel 也能夠通過 CNI 外掛的形式使用。

kube-proxy 和 service

配置好網路之後,叢集是什麼情況呢?我們可以建立 pod,也能通過 ReplicationController 來建立特定副本的 pod(這是更推薦也是生產上要使用的方法,即使某個 rc 中只有一個 pod 例項)。可以從叢集中獲取每個 pod ip 地址,然後也能在叢集內部直接通過 podIP:Port

 來獲取對應的服務。

但是還有一個問題: pod 是經常變化的,每次更新 ip 地址都可能會發生變化 ,如果直接訪問容器 ip 的話,會有很大的問題。而且進行擴充套件的時候,rc 中會有新的 pod 創建出來,出現新的 ip 地址,我們需要一種更靈活的方式來訪問 pod 的服務。

Service 和 cluster IP

針對這個問題,kubernetes 的解決方案是“服務”(service),每個服務都一個固定的虛擬 ip(這個 ip 也被稱為 cluster IP),自動並且動態地繫結後面的 pod,所有的網路請求直接訪問服務 ip,服務會自動向後端做轉發。Service 除了提供穩定的對外訪問方式之外,還能起到負載均衡(Load Balance)的功能,自動把請求流量分佈到後端所有的服務上,服務可以做到對客戶透明地進行水平擴充套件(scale)。

而實現 service 這一功能的關鍵,就是 kube-proxy。kube-proxy 執行在每個節點上,監聽 API Server 中服務物件的變化,通過管理 iptables 來實現網路的轉發。

NOTE: kube-proxy 要求 NODE 節點作業系統中要具備 /sys/module/br_netfilter 檔案,而且還要設定 bridge-nf-call-iptables=1,如果不滿足要求,那麼 kube-proxy 只是將檢查資訊記錄到日誌中,kube-proxy 仍然會正常執行,但是這樣通過 Kube-proxy 設定的某些 iptables 規則就不會工作。

kube-proxy 有兩種實現 service 的方案:userspace 和 iptables

  • userspace 是在使用者空間監聽一個埠,所有的 service 都轉發到這個埠,然後 kube-proxy 在內部應用層對其進行轉發。因為是在使用者空間進行轉發,所以效率也不高
  • iptables 完全實現 iptables 來實現 service,是目前預設的方式,也是推薦的方式,效率很高(只有核心中 netfilter 一些損耗)。

這篇文章通過 iptables 模式執行 kube-proxy,後面的分析也是針對這個模式的,userspace 只是舊版本支援的模式,以後可能會放棄維護和支援。

kube-proxy 引數介紹

kube-proxy 的功能相對簡單一些,也比較獨立,需要的配置並不是很多,比較常用的啟動引數包括:

引數 含義 預設值
–alsologtostderr 列印日誌到標準輸出 false
–bind-address HTTP 監聽地址 0.0.0.0
–cleanup-iptables 如果設定為 true,會清理 proxy 設定的 iptables 選項並退出 false
–healthz-bind-address 健康檢查 HTTP API 監聽埠 127.0.0.1
–healthz-port 健康檢查埠 10249
–iptables-masquerade-bit 使用 iptables 進行 SNAT 的掩碼長度 14
–iptables-sync-period iptables 更新頻率 30s
–kubeconfig kubeconfig 配置檔案地址
–log-dir 日誌檔案目錄/路徑
–masquerade-all 如果使用 iptables 模式,對所有流量進行 SNAT 處理 false
–master kubernetes master API Server 地址
–proxy-mode 代理模式, userspace 或者 iptables , 目前預設是 iptables ,如果系統或者 iptables 版本不夠新,會 fallback 到 userspace 模式 iptables
–proxy-port-range 代理使用的埠範圍, 格式為 beginPort-endPort ,如果沒有指定,會隨機選擇 0-0
–udp-timeout UDP 空連線 timeout 時間,只對 userspace 模式有用 250ms
–v 日誌級別 0

kube-proxy 的工作模式可以通過 --proxy-mode 進行配置,可以選擇 userspace 或者 iptables 。

例項啟動和測試

我們可以在終端上啟動 kube-proxy ,也可以使用諸如 systemd 這樣的工具來管理它,比如下面就是一個簡單的 kube-proxy.service 配置檔案

[[email protected]]# cat /usr/lib/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Proxy Service
Documentation=http://kubernetes.com
After=network.target
Wants=network.target

[Service]
Type=simple
EnvironmentFile=-/etc/sysconfig/kube-proxy
ExecStart=/usr/bin/kube-proxy 
    --master=http://172.17.8.100:8080 
    --v=4 
    --proxy-mode=iptables
TimeoutStartSec=0
Restart=on-abnormal

[Install]
WantedBy=multi-user.target

為了方便測試,我們建立一個 rc,裡面有三個 pod。這個 pod 執行的是 cizixs/whoami 容器 ,它是一個簡單的 HTTP 伺服器,監聽在 3000 埠,訪問它會返回容器的 hostname。

[[email protected] ~]# cat whoami-rc.yml
apiVersion: v1
kind: ReplicationController
metadata:
  name: whoami
spec:
  replicas: 3
  selector:
    app: whoami
  template:
    metadata:
      name: whoami
      labels:
        app: whoami
        env: dev
    spec:
      containers:
      - name: whoami
        image: cizixs/whoami:v0.5
        ports:
        - containerPort: 3000
        env:
          - name: MESSAGE
            value: viola

我們為每個 pod 設定了兩個 label: app=whoami 和 env=dev ,這兩個標籤很重要,也是後面服務進行繫結 pod 的關鍵。

為了使用 service,我們還要定義另外一個檔案,並通過 kubectl create -f ./whoami-svc.yml 來創建出來物件:

apiVersion: v1
kind: Service
metadata:
  labels:
    name: whoami
  name: whoami
spec:
  ports:
    - port: 3000
      targetPort: 3000
      protocol: TCP
  selector:
    app: whoami
    env: dev

其中 selector 告訴 kubernetes 這個 service 和後端哪些 pod 繫結在一起,這裡包含的鍵值對會對所有 pod 的 labels 進行匹配,只要完全匹配,service 就會把 pod 作為後端。也就是說,service 和 rc 並不是對應的關係,一個 service 可能會使用多個 rc 管理的 pod 作為後端應用。

ports 欄位指定服務的埠資訊:

  • port :虛擬 ip 要繫結的 port,每個 service 會創建出來一個虛擬 ip,通過訪問 vip:port 就能獲取服務的內容。這個 port 可以使用者隨機選取,因為每個服務都有自己的 vip,也不用擔心衝突的情況
  • targetPort :pod 中暴露出來的 port,這是執行的容器中具體暴露出來的埠,一定不能寫錯
  • protocol :提供服務的協議型別,可以是 TCP 或者 UDP

建立之後可以列出 service ,發現我們建立的 service 已經分配了一個虛擬 ip (10.10.10.28),這個虛擬 ip 地址是不會變化的(除非 service 被刪除)。檢視 service 的詳情可以看到它的 endpoints 列出,對應了具體提供服務的 pod 地址和埠。

[[email protected] ~]# kubectl get svc
NAME         CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
kubernetes   10.10.10.1            443/TCP    19d
whoami       10.10.10.28           3000/TCP   1d

[[email protected] ~]# kubectl describe svc whoami
Name:                   whoami
Namespace:              default
Labels:                 name=whoami
Selector:               app=whoami
Type:                   ClusterIP
IP:                     10.10.10.28
Port:                    3000/TCP
Endpoints:              10.11.32.6:3000,10.13.192.4:3000,10.16.192.3:3000
Session Affinity:       None
No events.

預設的 service 型別是 ClusterIP ,這個也可以從上面輸出看出來。在這種情況下,只能從叢集內部訪問這個 IP,不能直接從叢集外部訪問服務。如果想對外提供服務,我們後面會講解決方案。

測試一下,訪問 service 服務的時候可以看到它會隨機地訪問後端的 pod,給出不同的返回:

[[email protected] ~]# curl http://10.10.10.28:3000
viola from whoami-8fpqp
[[email protected] ~]# curl http://10.10.10.28:3000
viola from whoami-c0x6h
[[email protected] ~]# curl http://10.10.10.28:3000
viola from whoami-8fpqp
[[email protected] ~]# curl http://10.10.10.28:3000
viola from whoami-dc9ds

預設情況下,服務會隨機轉發到可用的後端。如果希望保持會話(同一個 client 永遠都轉發到相同的 pod),可以把 service.spec.sessionAffinity 設定為 ClientIP 。

NOTE: 需要注意的是,服務分配的 cluster IP 是一個虛擬 ip,如果你嘗試 ping 這個 IP 會發現它沒有任何響應,這也是剛接觸 kubernetes service 的人經常會犯的錯誤。實際上,這個虛擬 IP 只有和它的 port 一起的時候才有作用,直接訪問它,或者想訪問該 IP 的其他埠都是徒勞。

外部能夠訪問的服務

上面建立的服務只能在叢集內部訪問,這在生產環境中還不能直接使用。如果希望有一個能直接對外使用的服務,可以使用 NodePort 或者 LoadBalancer 型別的 Service。我們先說說 NodePort ,它的意思是在所有 worker 節點上暴露一個埠,這樣外部可以直接通過訪問 nodeIP:Port 來訪問應用。

我們先把剛才建立的服務刪除:

[[email protected] ~]# kubectl delete rc whoami
replicationcontroller "whoami" deleted

[[email protected] ~]# kubectl delete svc whoami
service "whoami" deleted

[[email protected] ~]# kubectl get pods,svc,rc
NAME         CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   10.10.10.1           443/TCP   14h

對我們原來的 Service 配置檔案進行修改,把 spec.type 寫成 NodePort 型別:

[[email protected] ~]# cat whoami-svc.yml
apiVersion: v1
kind: Service
metadata:
  labels:
    name: whoami
  name: whoami
spec:
  ports:
    - port: 3000
      protocol: TCP
      # nodePort: 31000
  selector:
    app: whoami
  type: NodePort

因為我們的應用比較簡單,只有一個埠。如果 pod 有多個埠,也可以在 spec.ports 中繼續新增,只有保證多個 port 之間不衝突就行。

重新建立 rc 和 svc:

[[email protected] ~]# kubectl create -f ./whoami-svc.yml
service "whoami" created
[[email protected] ~]# kubectl get rc,pods,svc
NAME        DESIRED   CURRENT   READY     AGE
rc/whoami   3         3         3         10s

NAME              READY     STATUS    RESTARTS   AGE
po/whoami-8zc3d   1/1       Running   0          10s
po/whoami-mc2fg   1/1       Running   0          10s
po/whoami-z6skj   1/1       Running   0          10s

NAME             CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
svc/kubernetes   10.10.10.1             443/TCP          14h
svc/whoami       10.10.10.163          3000:31647/TCP   7s

需要注意的是,因為我們沒有指定 nodePort 的值,kubernetes 會自動給我們分配一個,比如這裡的 31647 (預設的取值範圍是 30000-32767)。當然我們也可以刪除配置中 # nodePort: 31000 的註釋,這樣會使用 31000 埠。

nodePort 型別的服務會在所有的 worker 節點(運行了 kube-proxy)上統一暴露出埠對外提供服務,也就是說外部可以任意選擇一個節點進行訪問。比如我本地叢集有三個節點: 172.17.8.100 、 172.17.8.101 和 172.17.8.102 :

[[email protected] ~]# curl http://172.17.8.100:31647
viola from whoami-mc2fg
[[email protected] ~]# curl http://172.17.8.101:31647
viola from whoami-8zc3d
[[email protected] ~]# curl http://172.17.8.102:31647
viola from whoami-z6skj

有了 nodePort ,使用者可以通過外部的 Load Balance 或者路由器把流量轉發到任意的節點,對外提供服務的同時,也可以做到負載均衡的效果。

nodePort 型別的服務並不影響原來虛擬 IP 的訪問方式,內部節點依然可以通過 vip:port 的方式進行訪問。

LoadBalancer 型別的服務需要公有云支援,如果你的叢集部署在公有云(GCE、AWS等)可以考慮這種方式。

service 原理解析

目前 kube-proxy 預設使用 iptables 模式,上述展現的 service 功能都是通過修改 iptables 實現的。

我們來看一下從主機上訪問 service:port 的時候發生了什麼(通過 iptables-save 命令打印出來當前機器上的 iptables 規則)。

所有傳送出去的報文會進入 KUBE-SERVICES 進行處理

*nat
-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES

KUBE-SERVICES 每條規則對應了一個 service,它告訴繼續進入到某個具體的 service chain 進行處理,比如這裡的 KUBE-SVC-OQCLJJ5GLLNFY3XB

-A KUBE-SERVICES -d 10.10.10.28/32 -p tcp -m comment --comment "default/whoami: cluster IP" -m tcp --dport 3000 -j KUBE-SVC-OQCLJJ5GLLNFY3XB

更具體的 chain 中定義了怎麼轉發到對應 endpoint 的規則,比如我們的 rc 有三個 pods,這裡也就會生成三個規則。這裡利用了 iptables 隨機和概率轉發的功能

-A KUBE-SVC-OQCLJJ5GLLNFY3XB -m comment --comment "default/whoami:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-VN72UHNM6XOXLRPW
-A KUBE-SVC-OQCLJJ5GLLNFY3XB -m comment --comment "default/whoami:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-YXCSPWPTUFI5WI5Y
-A KUBE-SVC-OQCLJJ5GLLNFY3XB -m comment --comment "default/whoami:" -j KUBE-SEP-FN74S3YUBFMWHBLF

我們來看第一個 chain,這個 chain 有兩個規則,第一個表示給報文打上 mark;第二個是進行 DNAT(修改報文的目的地址),轉發到某個 pod 地址和埠。

-A KUBE-SEP-VN72UHNM6XOXLRPW -s 10.11.32.6/32 -m comment --comment "default/whoami:" -j KUBE-MARK-MASQ
-A KUBE-SEP-VN72UHNM6XOXLRPW -p tcp -m comment --comment "default/whoami:" -m tcp -j DNAT --to-destination 10.11.32.6:3000

因為地址是傳送出去的,報文會根據路由規則進行處理,後續的報文就是通過 flannel 的網路路徑傳送出去的。

nodePort 型別的 service 原理也是類似的,在 KUBE-SERVICES chain 的最後,如果目標地址不是 VIP 則會通過 KUBE-NODEPORTS :

Chain KUBE-SERVICES (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 KUBE-NODEPORTS  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL

而 KUBE-NODEPORTS chain 和 KUBE-SERVICES chain 其他規則一樣,都是轉發到更具體的 servicechain,然後轉發到某個 pod 上面。

-A KUBE-NODEPORTS -p tcp -m comment --comment "default/whoami:" -m tcp --dport 31647 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/whoami:" -m tcp --dport 31647 -j KUBE-SVC-OQCLJJ5GLLNFY3XB

不足之處

看起來 service 是個完美的方案,可以解決服務訪問的所有問題,但是 service 這個方案(iptables 模式)也有自己的缺點。

首先,如果轉發的 pod 不能正常提供服務,它不會自動嘗試另一個 pod,當然這個可以通過 readiness probes 來解決。每個 pod 都有一個健康檢查的機制,當有 pod 健康狀況有問題時,kube-proxy 會刪除對應的轉發規則。

另外, nodePort 型別的服務也無法新增 TLS 或者更復雜的報文路由機制。

相關推薦

kubernetes 簡介kube-proxy service

簡介 在 kubernetes 叢集中,網路是非常基礎也非常重要的一部分。對於大規模的節點和容器來說,要保證網路的連通性、網路轉發的高效,同時能做的 ip 和 port 自動化分配和管理,並讓使用者用直觀簡單的方式來訪問需要的應用,這是需要複雜且細緻設計的。 kubern

『高級篇』docker之kubernetes基礎集群附加功能kube-proxykube-dns(

成了 附加 需要 應用 hub 文件 ron 鏈接地址 ima >原創文章,歡迎轉載。轉載請註明:轉載自IT人故事會,謝謝!>原文鏈接地址:『高級篇』docker之kubernetes基礎集群附在功能kube-proxy和kube-dns(36) 上次搭建了ku

14.深入k8skube-proxy ipvs及其原始碼分析

![82062770_p0](https://img.luozhiyun.com/20201008173220.png) > 轉載請宣告出處哦~,本篇文章釋出於luozhiyun的部落格:https://www.luozhiyun.com > > 原始碼版本是[1.19](https://github.co

達觀資料kubernetes簡介實戰

在本文中,我們從技術細節上對kubernetes進行簡單運用介紹,利用一些yaml指令碼層面上例項告訴大家kubernetes基本概念。Kubernetes以及它呈現出的程式設計正規化值得你去使用和整合到自己的技術棧中。 kubernetes簡單介紹 1 kubernet

kubernetes中port、target port、node port的對比分析,以及kube-proxy代理

ans toc contain exp red lec adb service 接口 轉:http://blog.csdn.net/xinghun_4/article/details/50492041 容器網絡實例 服務中的3個端口設置 這幾個port的概念很容易混淆,比

簡介操作系統集群開源技術研究

pla 設計 成本 期貨 jit cin 虛擬化技術 特性 基礎 作者:王步宙、陳晨 2008年似乎是個有魔力的一年,在這一年裏大西洋兩岸的德國和紐約兩大證券交易所集團幾乎不約而同的啟動了交易系統開源化項目。對於開源項目的動因,有人提出成本論,有人提出是低延遲論,我們認為可

編碼格式簡介ASCII碼、ANSI、GBK、GB2312、GB18030Unicode、UTF-8,BOM頭

family 用兩個 圖片 and 正是 全球化 asc 即使 little 編碼格式簡介:ASCII碼、ANSI、GBK、GB2312、GB18030和Unicode、UTF-8,BOM頭 二進制: 只有0和1。 十進制、十六進制、八進制: 計算機其實挺笨的,它只

[k8s]kube-router替代kube-proxy實現svc網絡pod網絡

config文件 開啟 ref ldp auth pam ext pro red 也是基於cni網絡, 1.替代了kube-proxy組件,無需在部署kube-router,解決了svc網絡 2.自帶cni,bgp,解決了pod網絡 3.基於ipvs轉發 4.路由傳

手動安裝K8s第七節node節點部署-kube-proxy

docker k8s kubernetes 容器 部署Kubernetes Proxy vim CentOS-Base.repo [base]name=CentOS-$releasever - Base#mirrorlist=http://mirrorlist.centos.org/?rele

計算機視覺簡介歷史、現狀發展趨勢

【導讀】本文由中國科學院自動化研究所模式識別國家重點實驗室胡佔義研究員撰寫,對計算機視覺40多年的發展歷程進行了簡要總結,包括:馬爾計算視覺理論,主動視覺與目的視覺,多視幾何與攝像機自標定,以及基於學習的視覺。在此基礎上,對計算機視覺的未來發展趨勢給出了一些展望。 原文連結 1.1

二進制安裝kubernetes v1.11.2 (第十四章 kube-proxy部署)

scheduler ntc ips kubecon .json done ecs rest sna 繼續前一章的部署。 部署 kube-proxy 組件 14.1 下載和分發二進制文件,參考 第三章 分發到各節點 source /opt/k8s/bin/environme

Hyperledger Indy 分散式賬本的兩個組成部分indy-node indy-plenum 簡介

從 Hyperledger wiki-indy 上,看到 Indy 的分散式賬本(Distributed Ledger)包括兩個主要部分:Indy-Node 和 Indy-Plenum。 Indy-No

Spring5@Autowired註解、@Resource註解@Service註解

什麼是註解 傳統的Spring做法是使用.xml檔案來對bean進行注入或者是配置aop、事物,這麼做有兩個缺點: 1、如果所有的內容都配置在.xml檔案中,那麼.xml檔案將會十分龐大;如果按需求分開.xml檔案,那麼.xml檔案又會非常多。總之這將導致配置檔案的可讀性

ES6語法知識點代理proxy

Proxy 可以理解成,在目標物件之前架設一層“攔截”,外界對該物件的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。 var obj = new Proxy({}, { get: function (target, key, recei

kube-proxy 原理分析技術演進

一、引言        談到 kube-proxy,就不得不提到 k8s 中的 Service,下面就對二者的關係作簡單介紹: kube-proxy 其實就是管理 Service 的訪問入口,包括叢集內 Pod 到 Service

Ajax_簡介 非同步的 JS XML

AJAX Asynchronous JavaScript And XML 通過 AJAX 可以在 瀏覽器中向 伺服器 傳送非同步請求 一種 使用現有標準的 新方法,而非新語言 XML  可擴充套件標記語言 被設計用來傳輸和儲存資料 被 JSON 替代,JSON 內容更少,解析

Kubernetes(k8s)中文文件 名詞解釋Security ContextPSP_Kubernetes中文社群

Security Context Security Context的目的是限制不可信容器的行為,保護系統和其他容器不受其影響。 Kubernetes提供了三種配置Security Context的方法: Container-level Security Context:僅應用到指定的容器 Pod-

CentOS7環境安裝Kubernetes四部曲之二配置模板安裝master

本文是《CentOS7環境安裝Kubernetes四部曲》系列的第二篇,前一篇《CentOS7環境安裝Kubernetes三部曲:標準化機器準備》我們把機器準備好了,並且做了必要的設定,現在我們用這些機器來接著安裝kubernetes; 安裝rancher

SeaJS簡介模組載入引用

       之前對模組有過介紹,一個模組對應一個js檔案,而載入模組時一般都是提供一個字串引數告訴載入函式需要的模組,所以就需要有一套從字串標識到實際模組所在檔案路徑的解析演算法。SeaJS支援如下幾

kubernetes/k8s原始碼分析】kube proxy原始碼分析

本文再次於2018年11月15日再次編輯,基於1.12版本,包括IPVS 序言 kube-proxy管理sevice的Endpoints,service對外暴露一個Virtual IP(Cluster IP), 叢集內Cluster IP:Port就能訪問到叢集內對應