Kubernetes 入門與安裝部署

月圓吖發表於2020-11-22

一、簡介

參考:Kubernetes 官方文件Kubernetes中文社群 | 中文文件
Kubernetes 是一個可移植的、可擴充套件的開源平臺,用於管理容器化的工作負載和服務,可促進宣告式配置和自動化,擁有一個龐大且快速增長的生態系統。

為什麼Kubernetes如此有用?

container_evolution

傳統部署時代: 早期,組織在物理伺服器上執行應用程式。無法為物理伺服器中的應用程式定義資源邊界,這會導致資源分配問題。例如,如果在物理伺服器上執行多個應用程式,則可能會出現一個應用程式佔用大部分資源的情況,結果可能導致其他應用程式的效能下降。一種解決方案是在不同的物理伺服器上執行每個應用程式,但是由於資源利用不足而無法擴充套件,並且組織維護許多物理伺服器的成本很高。

虛擬化部署時代: 作為解決方案,引入了虛擬化功能,它允許您在單個物理伺服器的 CPU 上執行多個虛擬機器(VM)。虛擬化功能允許應用程式在 VM 之間隔離,並提供安全級別,因為一個應用程式的資訊不能被另一應用程式自由地訪問。
因為虛擬化可以輕鬆地新增或更新應用程式、降低硬體成本等等,所以虛擬化可以更好地利用物理伺服器中的資源,並可以實現更好的可伸縮性。
每個 VM 是一臺完整的計算機,在虛擬化硬體之上執行所有元件,包括其自己的作業系統。

容器部署時代: 容器類似於 VM,但是它們具有輕量級的隔離屬性,可以在應用程式之間共享作業系統(OS)。因此,容器被認為是輕量級的。容器與 VM 類似,具有自己的檔案系統、CPU、記憶體、程式空間等。由於它們與基礎架構分離,因此可以跨雲和 OS 分發進行移植。
容器因具有許多優勢而變得流行起來,下面列出了容器的一些好處:

  • 敏捷應用程式的建立和部署:與使用 VM 映象相比,提高了容器映象建立的簡便性和效率。

  • 持續開發、整合和部署:通過快速簡單的回滾(由於映象不可變性),提供可靠且頻繁的容器映象構建和部署。

  • 關注開發與運維的分離:在構建/釋出時而不是在部署時建立應用程式容器映象,從而將應用程式與基礎架構分離。

  • 可觀察性不僅可以顯示作業系統級別的資訊和指標,還可以顯示應用程式的執行狀況和其他指標訊號。

  • 跨開發、測試和生產的環境一致性:在行動式計算機上與在雲中相同地執行。

  • 雲和作業系統分發的可移植性:可在 Ubuntu、RHEL、CoreOS、本地、Google Kubernetes Engine 和其他任何地方執行。

  • 以應用程式為中心的管理:提高抽象級別,從在虛擬硬體上執行 OS 到使用邏輯資源在 OS 上執行應用程式。

  • 鬆散耦合、分散式、彈性、解放的微服務:應用程式被分解成較小的獨立部分,並且可以動態部署和管理 - 而不是在一臺大型單機上整體執行。

  • 資源隔離:可預測的應用程式效能。

  • 資源利用:高效率和高密度。

Kubernetes能做什麼?

容器是打包和執行應用程式的好方式。在生產環境中,您需要管理執行應用程式的容器,並確保不會停機。例如,如果一個容器發生故障,則需要啟動另一個容器。如果系統處理此行為,會不會更容易?

這就是 Kubernetes 的救援方法!Kubernetes 為您提供了一個可彈性執行分散式系統的框架。Kubernetes 會滿足您的擴充套件要求、故障轉移、部署模式等。例如,Kubernetes 可以輕鬆管理系統的 Canary 部署。

Kubernetes 為您提供:

  • 服務發現和負載均衡
    Kubernetes 可以使用 DNS 名稱或自己的 IP 地址公開容器,如果到容器的流量很大,Kubernetes 可以負載均衡並分配網路流量,從而使部署穩定。

  • 儲存編排
    Kubernetes 允許您自動掛載您選擇的儲存系統,例如本地儲存、公共雲提供商等。

  • 自動部署和回滾
    您可以使用 Kubernetes 描述已部署容器的所需狀態,它可以以受控的速率將實際狀態更改為所需狀態。例如,您可以自動化 Kubernetes 來為您的部署建立新容器,刪除現有容器並將它們的所有資源用於新容器。

  • 自動二進位制打包
    Kubernetes 允許您指定每個容器所需 CPU 和記憶體(RAM)。當容器指定了資源請求時,Kubernetes 可以做出更好的決策來管理容器的資源。

  • 自我修復
    Kubernetes 重新啟動失敗的容器、替換容器、殺死不響應使用者定義的執行狀況檢查的容器,並且在準備好服務之前不將其通告給客戶端。

  • 金鑰與配置管理
    Kubernetes 允許您儲存和管理敏感資訊,例如密碼、OAuth 令牌和 ssh 金鑰。您可以在不重建容器映象的情況下部署和更新金鑰和應用程式配置,也無需在堆疊配置中暴露金鑰。

二、搭建Kubernetes叢集

如何搭建?

參考:睿雲智合 圖形化Kubernetes叢集部署工具和我一步步部署 kubernetes 叢集

我這裡是根據睿雲智合一步一步搭建的,它提供了圖形化介面,適合初學者搭建一個環境

搭建一個Kubernetes叢集(整個元件的基礎設施包含k8s叢集等各種監控運維元件)需要如下節點資訊:

序號 主機名 角色 CPU 記憶體 OS 部署元件
1 breeze-deploy 部署節點 4核 8G CentOS-7.6-x64 docker/docker-compose/breeze
2 k8s-master01 k8s主節點 4核 16G CentOS-7.6-x64 docker/master元件/etcd/haproxy/keepalive/prometheus
3 k8s-master02 k8s主節點 4核 16G CentOS-7.6-x64 docker/master元件/etcd/haproxy/keepalive/prometheus
4 k8s-master03 k8s主節點 4核 16G CentOS-7.6-x64 docker/master元件/etcd/haproxy/keepalive/prometheus
5 k8s-worker01 k8s工作節點 8核 32G CentOS-7.6-x64 docker/worker元件/prometheus/grafana/altermanager
6 k8s-worker02 k8s工作節點 8核 32G CentOS-7.6-x64 docker/worker元件/prometheus/grafana/altermanager
7 k8s-worker03 k8s工作節點 8核 32G CentOS-7.6-x64 docker/worker元件/prometheus/grafana/altermanager
8 k8s-worker04 k8s工作節點 8核 32G CentOS-7.6-x64 docker/worker元件/prometheus/grafana/altermanager
9 k8s-worker05 k8s工作節點 8核 32G CentOS-7.6-x64 docker/worker元件/prometheus/grafana/altermanager
10 k8s-worker06 k8s工作節點 8核 32G CentOS-7.6-x64 docker/worker元件/prometheus/grafana/altermanager
11 harbor 映象倉庫節點 4核 16G CentOS-7.6-x64 harbor
12 VIP 3臺k8s master節點的高可用虛擬浮動IP地址

master元件:kube-apiserver、kube-controller-manager、kube-scheduler
worker元件:kubelet、kube-proxy
備註:

  • 適合的作業系統:RHEL/CentOS: 7.4/7.5/7.6/7.7/7.8、Ubuntu 16/18
  • 部署節點請儘量保證其為裸機,配置最低為2核4G
  • 磁碟每個節點都儘量大一點60G+
  • 為了保證K8S的高可用性,需要為所有的master節點繫結一個VIP

本人在本地採用虛擬機器部署方式如下(不推薦):

主機名 角色 IP OS CPU 記憶體 磁碟 部署元件
breeze-deploy 部署節點 192.168.47.130 CentOS-7.8-x64 2核 2G 20G docker/docker-compose/breeze
k8s-master01 k8s主節點 192.168.47.131 CentOS-7.8-x64 2核 4G 20G k8s master元件/etcd
k8s-worker01 k8s工作節點 192.168.47.132 CentOS-7.8-x64 2核 4G 20G k8s worker元件/prometheus
harbor 映象倉庫節點 192.168.47.133 CentOS-7.8-x64 2核 2G 20G harbor

遇到的問題

  1. Kubernetes建立Pod時從Harbor倉庫拉取映象出現‘沒有許可權’

    生成的登入的資訊

    $ docker login --username=admin 192.168.47.133    # 登入映象倉庫
    $ cat ~/.docker/config.json    # 登入後生成的登入資訊存放於該檔案
    $ cat ~/.docker/config.json | base64 -w 0    # 使用base64加密生成金鑰
    

    建立harbor-secret.yaml檔案,內容如下:

    apiVersion: v1
    kind: Secret
    metadata:
      name: adminsecret    # 金鑰名稱
    data:
      .dockerconfigjson: ***    # 輸入上面生產的金鑰
    type: kubernetes.io/dockerconfigjson
    

    生成Secret物件

    $ kubectl create -f harbor-secret.yam    # 建立Secret物件
    

    然後在Pod的模板檔案中新增

    spec:
      imagePullSecrets:
      - name: adminsecret    # 拉取映象時使用 adminsecret Secret 物件
    
  2. 如果Harbor映象倉庫所在節點的磁碟滿了,會導致Harbor頁面無法登入

    先對該節點進行擴容,參考centos虛擬機器擴充套件磁碟空間(經歷無數坑,血一樣總結,史上最全)並結合評論區對該節點進行擴容

    因為上面需要先關閉虛擬機器,所以需要再重新啟動Harbor

    $ find / -name docker-compose.yml    # 找到 Harbor 的配置檔案後進入該目錄
    $ docker-compose down    # 關閉 Harbor
    $ ./prepare    # 進行準備工作,建立相應的配置檔案
    $ docker-compose up -d # 以後臺方式啟動 Harbor
    

三、Pod

Pod是Kubernetes建立或部署的最小/最簡單的基本單位,一個Pod代表叢集上正在執行的一個程式。
一個Pod封裝一個應用容器(也可以有多個容器),儲存資源、一個獨立的網路IP以及管理控制容器執行方式的策略選項。Pod代表部署的一個單位:Kubernetes中單個應用的例項,它可能由單個容器或多個容器共享組成的資源。

3.1 配置示例

apiVersion: v1                  # 1.9.0 之前的版本使用 apps/v1beta2,可通過命令 kubectl api-versions 檢視
kind: Pod                       # 指定建立資源的角色/型別
metadata:                       # 資源的後設資料/屬性
  name: nginx                   # 資源的名字,在同一個namespace中必須唯一
  labels:
    app: nginx1.19.1            # 標籤
spec:                           # 模板的規範
  containers:
  - name: nginx                 # 容器的名字
    image: 192.168.47.133/dwzq-info/nginx:v1.19.1   # 容器的映象地址
    imagePullPolicy: IfNotPresent
    # IfNotPresent:預設值,本地有則使用本地映象,不拉取,如果不存在則拉取
    # Always:總是拉取
    # Never:只使用本地映象,從不拉取
    ports:
    - name: http
      containerPort: 8085       # 對service暴露埠
    resources:                  # 資源限制標籤
       requests:                # 建立pod時向k8s請求的資源大小
         memory: "64Mi"
         cpu: "250m"
       limits:                  # 執行中pod的最大資源空間
         memory: "64Mi"
         cpu: "250m"
  restartPolicy: OnFailure      
  # Always:當容器停止,總是重建容器(預設)
  # OnFailure:當容器異常退出(退出狀態碼非0)時才重啟容器
  # Never:從不重啟容器
  imagePullSecrets:             # 因為我需要從harbor私庫拉取映象,需要配置金鑰,'adminsecret'是我已經建立好的
  - name: adminsecret

3.2 建立pod的流程

pod-create-process 描述:
  1. 客戶端通過kubectl命令,或者通過API Server的Restful API(支援json和yaml格式)發起建立一個Pod請求;
  2. API Server處理使用者請求,儲存Pod資訊資料到etcd叢集中;
  3. Scheduler排程器通過API Server檢視未繫結的Pod,嘗試為Pod進行分配主機,通過排程演算法選擇主機後,繫結到這臺機器上並且把排程資訊寫入etcd叢集;
  4. Kubelet根據排程結果執行Pod建立操作,成功後將資訊通過API Server更新到etcd叢集中;
  5. 整個Pod建立過程完成,每個元件都在於API Server進行互動,API Server就是k8s叢集的中間者,元件之間的協同者,是一個叢集訪問入口

3.3 控制器

  • ReplicaSet
    代使用者建立指定數量的pod副本數量,確保pod副本數量符合預期狀態,並且支援滾動式自動擴容和縮容功能。
    ReplicaSet主要三個元件組成:

    • 使用者期望的pod副本數量
    • 標籤選擇器,判斷哪個pod歸自己管理
    • 當現存的pod數量不足,會根據pod資源模板進行新建幫助使用者管理無狀態的pod資源,精確反應使用者定義的目標數量,但是RelicaSet不是直接使用的控制器,而是使用Deployment。
  • Deployment
    工作在ReplicaSet之上,用於管理無狀態應用,目前來說最好的控制器。支援滾動更新和回滾功能,還提供宣告式配置。

  • DaemonSet
    用於確保叢集中的每一個節點只執行特定的pod副本,通常用於實現系統級後臺任務,比如ingress,elk.服務是無狀態的,服務必須是守護程式。參考文章:https://www.cnblogs.com/xzkzzz/p/9553321.html

  • Job
    只要任務或程式執行完成就立即退出,不需要重啟或重建。 參考文章:https://blog.csdn.net/bbwangj/article/details/82011610

  • Cronjob
    週期性任務控制,執行後就退出, 不需要持續後臺執行, 參考文章:https://blog.csdn.net/bbwangj/article/details/82867830

  • StatefulSet
    管理有狀態應用,比如redis,mysql

3.4 常用命令

$ kubectl create -f pod.yaml 	   # 建立Pod資源
$ kubectl get pods nginx-pod 	   # 檢視pods
$ kubectl describe pod/nginx       # 檢視pod描述
$ kubectl apply -f pod.yaml        # 更新資源
$ kubectl delete -f pod.yaml       # 刪除資源
$ kubectl delete pods nginx-pod    # 刪除資源
$ kubectl logs -f pod/nginx        # 檢視日誌
$ kubectl exec -it pod/nginx /bin/bash    # 進入容器

四、Deployment

  • 使用Deployment來建立ReplicaSet(升級版的ReplicationController),ReplicaSet在後臺建立pod。檢查啟動狀態,看它是成功還是失敗。
  • 通過更新Deployment的PodTemplateSpec欄位來宣告Pod的新狀態。這會建立一個新的ReplicaSet,Deployment會按照控制的速率將pod從舊的ReplicaSet移動到新的ReplicaSet中。
  • 如果當前狀態不穩定,回滾到之前的Deployment revision。每次回滾都會更新Deployment的revision。
  • 擴容Deployment以滿足更高的負載。
  • 暫停Deployment來應用PodTemplateSpec的多個修復,然後恢復上線。
  • 根據Deployment 的狀態判斷上線是否hang住了。
  • 清除舊的不必要的ReplicaSet

4.1 配置示例

apiVersion: apps/v1        # 1.9.0之前的版本使用 apps/v1beta2,可通過命令 kubectl api-versions 檢視
kind: Deployment           # 指定建立資源的角色/型別
metadata:                  # 資源的後設資料/屬性
  name: nginx-deployment   # 資源的名字,在同一個namespace中必須唯一
  namespace:  default      # 名稱空間,預設為default
  labels: 
    app: nginx1.19.0       # 標籤
spec:
  replicas: 3              # 副本數量3
  strategy:
    rollingUpdate:   	   # 由於replicas為3,則整個升級,pod個數在2-4個之間
      maxSurge: 1          # 滾動升級時會先啟動1個pod
      maxUnavailable: 1    # 滾動升級時允許的最大Unavailable的pod個數
  selector:                # 定義標籤選擇器,部署需要管理的pod(帶有該標籤的的會被管理)需在pod 模板中定義
    matchLabels:
      app: nginx1.19.0
  template:                # 從這裡開始是Pod的定義
    metadata:
      labels:              # Pod的label
        app: nginx1.19.0
    spec:        		  # 模板的規範  
      containers:  
      - name: nginx        # 容器的名字  
        image: 192.168.47.133/dwzq-info/nginx:v1.19.0  	# 容器的映象地址 
        # command: [ "/bin/sh","-c","cat /etc/config/path/to/special-key" ]    # 啟動命令   
        args:                                                                # 啟動引數
            - '-storage.local.retention=$(STORAGE_RETENTION)'
            - '-storage.local.memory-chunks=$(STORAGE_MEMORY_CHUNKS)'
            - '-config.file=/etc/prometheus/prometheus.yml'
            - '-alertmanager.url=http://alertmanager:9093/alertmanager'
            - '-web.external-url=$(EXTERNAL_URL)'
        # 如果command和args均沒有寫,那麼用Docker預設的配置。
        # 如果command寫了,但args沒有寫,那麼Docker預設的配置會被忽略而且僅僅執行.yaml檔案的command(不帶任何引數的)。
        # 如果command沒寫,但args寫了,那麼Docker預設配置的ENTRYPOINT的命令列會被執行,但是呼叫的引數是.yaml中的args。
        # 如果如果command和args都寫了,那麼Docker預設的配置被忽略,使用.yaml的配置。
        imagePullPolicy: IfNotPresent  
        # IfNotPresent:預設值,本地有則使用本地映象,不拉取,如果不存在則拉取
        # Always:總是拉取
        # Never:只使用本地映象,從不拉取
        livenessProbe:       
	    # 表示container是否處於live狀態。如果LivenessProbe失敗,將會通知kubelet對應的container不健康了,
	    # 隨後kubelet將kill掉container,並根據RestarPolicy進行進一步的操作。
	    # 預設情況下LivenessProbe在第一次檢測之前初始化值為Success,
	    # 如果container沒有提供LivenessProbe,則也認為是Success;
	    # readinessProbe:如果檢查失敗,Kubeneres會把Pod從service endpoints中剔除。
          httpGet:
            path: / 			# 如果沒有心跳檢測介面就為/
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60 	 # 啟動後延時多久開始執行檢測
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        ports:
        - name: http
          containerPort: 8085 		# 對service暴露埠
        resources:              	# CPU記憶體限制
          requests:
            cpu: 2
            memory: 2048Mi
          limits:
            cpu: 2
            memory: 2048Mi
        env:                    	# 通過環境變數的方式,直接傳遞pod=自定義Linux OS環境變數
        - name: LOCAL_KEY     		# 本地Key
          value: value
        - name: CONFIG_MAP_KEY  	# 局策略可使用configMap的配置Key,
          valueFrom:
            configMapKeyRef:
              name: special-config   # configmap中找到name為special-config
              key: special.type      # 找到name為special-config裡data下的key
        volumeMounts:     		    # 掛載volumes中定義的磁碟
        - name: log-cache
          mount: /tmp/log
        - name: sdb       		    # 普通用法,該卷跟隨容器銷燬,掛載一個目錄
          mountPath: /data/media    
        - name: nfs-client-root    	# 直接掛載硬碟方法,如掛載下面的nfs目錄到/mnt/nfs
          mountPath: /mnt/nfs
        - name: rbd-pvc             # 高階用法第2中,掛載PVC(PresistentVolumeClaim)
      volumes:					  # 定義磁碟給上面volumeMounts掛載
      - name: log-cache
        emptyDir: {}
      - name: sdb				  # 掛載宿主機上面的目錄
        hostPath:
          path: /any/path/it/will/be/replaced
      - name: nfs-client-root	   # 供掛載NFS儲存型別
        nfs:
          server: hostaddr	       # NFS伺服器地址
          path: /opt/public        # showmount -e 看一下路徑
      - name: rbd-pvc              # 掛載PVC磁碟
        persistentVolumeClaim:
          claimName: rbd-pvc1      # 掛載已經申請的PVC磁碟

4.2 相關使用

建立

$ kubectl create -f  deployment.yaml --record   # --record 為True,在annotation中記錄當前命令建立或者升級了該資源,如檢視在每個Deployment revision中執行了哪些命令
$ kubectl get deployments -n default -o wide    # 獲取Deployments資訊
$ kubectl get rs -n default -o wide    		 # 獲取Replica Set資訊,名字總是<Deployment的名字>-<pod template的hash值>
$ kubectl get pods -n default -o wide --show-labels    # 獲取Pod資訊

更新

注意: Deployment的rollout當且僅當Deployment的pod template(例如.spec.template)中的label更新或者映象更改時被觸發。其他更新,例如擴容Deployment不會觸發rollout。
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1   # 更新映象
$ kubectl edit deployment/nginx-deployment    # 或使用edit命令來編輯Deployment模板,儲存後即更新
$ kubectl rollout status deployment/nginx-deployment    # 檢視rollout狀態

回退

$ kubectl describe deployment    # 檢視狀態
$ kubectl rollout history deployment/nginx-deployment    # 檢查Deployment升級的歷史記錄
$ kubectl rollout history deployment/nginx-deployment --revision=1   #  檢視某個revision的詳細資訊
$ kubectl rollout undo deployment/nginx-deployment    # 回退當前的rollout到之前的版本
$ kubectl rollout undo deployment/nginx-deployment --to-revision=1    # 回退當前的rollout到某個歷史版本

擴容

$ kubectl scale deployment nginx-deployment --replicas 3    # 擴容,指定執行的副本
# 基於當前Pod的CPU利用率選擇最少和最多的Pod數(需啟用horizontal pod autoscaling)
$ kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80    

暫停和恢復

$ kubectl get deployment    # 檢視deployment列表(default namespace)
$ kubectl rollout pause deployment/nginx-deployment    # 暫停deployment
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.19.1    # 更新映象
# 恢復之前可以多次進行更新操作,在恢復之前更新過程不會產生任何影響(前提是已暫停)
$ kubectl rollout resume deployment/nginx-deployment    # 恢復deployment

五、StatefulSet

StatefulSet 是Kubernetes中的一種控制器,在很多的分散式應用場景中,他們各個例項之間往往會有對應的關係,例如:主從、主備。還有資料儲存類應用,它的多個例項,往往會在本地磁碟存一份資料,而這些例項一旦被殺掉,即使重建起來,例項與資料之間關係也會丟失,而這些例項有不對等的關係,例項與外部儲存有依賴的關係的應用,被稱作“有狀態應用”。StatefulSet與Deployment相比,相同於他們管理相同容器規範的Pod,不同的是,StatefulSet為Pod建立一個持久的識別符號,他可以在任何編排的時候得到相同的識別符號。

說明:進行下述操作前請先準備好2個1G的PersistentVolumes儲存卷

參考:Kubernetes之StatefulSet

5.1 配置示例

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  type: "ClusterIP"    # 預設服務型別
  ports:
  - port: 80
    name: web
  selector:
    app: nginx
  clusterIP: "None"    # 建立 Headless Service
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:    # 生成PVC
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

六、Service

Kubernetes Pod 是有生命週期的。 它們可以被建立,而且銷燬之後不會再啟動。 如果您使用 Deployment 來執行您的應用程式,則它可以動態建立和銷燬 Pod。
每個 Pod 都有自己的 IP 地址,但是在 Deployment 中,在同一時刻執行的 Pod 集合可能與稍後執行該應用程式的 Pod 集合不同。
這導致了一個問題: 如果一組 Pod(稱為“後端”)為群集內的其他 Pod(稱為“前端”)提供功能, 那麼前端如何找出並跟蹤要連線的 IP 地址,以便前端可以使用工作量的後端部分?


Kubernetes Service,一個 Pod 的邏輯分組(Endpoint),一種可以訪問它們的策略(負載均衡),通常稱為微服務,這一組 Pod 能夠被 Service 訪問(服務發現,支援環境變數和DNS模式),通常是通過 Label Selector。

6.1 配置示例

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: default
spec:
  selector: # 指定標籤 app:nginx1.19.0 來進行對Pod進行關聯(也就是上面Deployment配置裡labels定義的標籤 )
    app: nginx1.19.0
  ports:
  - protocol: TCP
    port: 8085 # 需要暴露的叢集埠(service暴露的)
    targetPort: 8085 # 容器的埠(後端容器提供服務的埠)
    nodePort: 30000 # 對映到物理機的埠(30000-32767),不填則隨機對映
  type: NodePort

對映到物理機的埠範圍為:30000-32767
暴露的埠在Node節點上由kube-proxy來啟動並監聽的,可通過:的方式直接進行訪問,因為kube-proxy進行了代理。
kube-proxy是如何代理訪問到容器的呢?
因為kube-proxy在啟動的時候通過--proxy-mode=ipvs可以指定底層核心代理模式,預設是iptables進行代理轉發,kube-proxy通過這兩種模式來進行代理轉發,kube-proxy通過這兩種模式來代理直接對外提供服務。

6.2 服務型別

Service型別:ClusterIP(預設)、NodePort、LoadBalancer、ExternalName

  • ClusterIP
    通過叢集的內部 IP 暴露服務,選擇該值,服務只能夠在叢集內部(同namespace內的pod)可以訪問,不對外提供訪問服務,這也是預設的服務型別。

  • NodePort
    通過每個 Node 上的 IP 和靜態埠(NodePort)暴露服務。 NodePort 服務會路由到 ClusterIP 服務,這個 ClusterIP 服務會自動建立。 通過請求 :,可以從叢集的外部訪問一個 NodePort 服務。

  • LoadBalancer
    使用雲提供商的負載局衡器,可以向外部暴露服務。 外部的負載均衡器可以路由到 NodePort 服務和 ClusterIP 服務,適用於雲平臺,AWS預設支援。

6.3 常用命令

kubectl get service -o wide # service可以使用縮寫svc,-n指定名稱空間,預設default
kubectl describe service nginx-service

6.4 代理模式

userspace模式

這種模式,kube-proxy 會監視 Kubernetes master 對 Service 物件和 Endpoints 物件的新增和移除。 對每個 Service,它會在本地 Node 上開啟一個埠(隨機選擇)。 任何連線到“代理埠”的請求,都會被代理到 Service 的 Backend Pods 中的某個上面(如 Endpoints 所報告的一樣)。 使用哪個 Backend Pod,是基於 Service 的 SessionAffinity 來確定的。 最後,它安裝 iptables 規則,捕獲到達該 Service 的 ClusterIP(虛擬 IP)和 Port 的請求,並重定向到代理埠,代理埠再代理請求到 Backend Pod。

網路返回的結果是,任何到達 Service 的 IP:Port 的請求,都會被代理到一個合適的 backend,不需要客戶端知道關於 Kubernetes、Service、或 Pod 的任何資訊。

預設的策略是,通過 round-robin 演算法來選擇 backend Pod。 實現基於客戶端 IP 的會話親和性,可以通過設定 service.spec.sessionAffinity 的值為 "ClientIP" (預設值為 "None")。
service-userspace

iptables模式

這種模式,kube-proxy 會監視 Kubernetes master 對 Service 物件和 Endpoints 物件的新增和移除。 對每個 Service,它會安裝 iptables 規則,從而捕獲到達該 Service 的 ClusterIP(虛擬 IP)和埠的請求,進而將請求重定向到 Service 的一組 Backend Pod 中的某個上面。 對於每個 Endpoints 物件,它也會安裝 iptables 規則,這個規則會選擇一個 Backend Pod。

預設的策略是,隨機選擇一個 backend。 實現基於客戶端 IP 的會話親和性,可以將 service.spec.sessionAffinity 的值設定為 "ClientIP" (預設值為 "None")。

和 userspace 代理類似,網路返回的結果是,任何到達 Service 的 IP:Port 的請求,都會被代理到一個合適的 backend,不需要客戶端知道關於 Kubernetes、Service、或 Pod 的任何資訊。 這應該比 userspace 代理更快、更可靠。然而,不像 userspace 代理,如果初始選擇的 Pod 沒有響應,iptables 代理能夠自動地重試另一個 Pod,所以它需要依賴 readiness probes

service-iptables

IPVS模式

在 ipvs 模式下,kube-proxy監視Kubernetes服務和端點,呼叫 netlink 介面相應地建立 IPVS 規則, 並定期將 IPVS 規則與 Kubernetes 服務和端點同步。 該控制迴圈可確保IPVS 狀態與所需狀態匹配。訪問服務時,IPVS 將流量定向到一組 Backend Pod 中的某個上面。

IPVS代理模式基於類似於 iptables 模式的 netfilter 掛鉤函式, 但是使用雜湊表作為基礎資料結構,並且在核心空間中工作。 這意味著,與 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通訊的延遲要短,並且在同步代理規則時具有更好的效能。 與其他代理模式相比,IPVS 模式還支援更高的網路流量吞吐量。

IPVS提供了更多選項來平衡後端Pod的流量。 提供如下排程演算法:

  • rr: round-robin
  • lc: least connection (smallest number of open connections)
  • dh: destination hashing
  • sh: source hashing
  • sed: shortest expected delay
  • nq: never queue

說明:
要在 IPVS 模式下執行 kube-proxy,必須在啟動 kube-proxy 之前使 IPVS Linux 在節點上可用。
當 kube-proxy 以 IPVS 代理模式啟動時,它將驗證 IPVS 核心模組是否可用。 如果未檢測到 IPVS 核心模組,則 kube-proxy 將退回到以 iptables 代理模式執行。

service-ipvs

在這些代理模型中,繫結到服務IP的流量: 在客戶端不瞭解Kubernetes或服務或Pod的任何資訊的情況下,將Port代理到適當的後端。 如果要確保每次都將來自特定客戶端的連線傳遞到同一 Pod, 則可以通過將 service.spec.sessionAffinity 設定為 "ClientIP" (預設值是 "None"),來基於客戶端的 IP 地址選擇會話關聯。
您還可以通過適當設定 service.spec.sessionAffinityConfig.clientIP.timeoutSeconds 來設定最大會話停留時間。 (預設值為 10800 秒,即 3 小時)。

七、Ingress

Ingress公開了從叢集外部到叢集內服務(Service)的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 資源上定義的規則控制。

    internet
        |
   [ Ingress ]
   --|-----|--
   [ Services ]

可以將 Ingress 配置為服務提供外部可訪問的 URL、負載均衡流量、終止 SSL/TLS,以及提供基於名稱的虛擬主機等能力。 Ingress 控制器 通常負責通過負載均衡器來實現 Ingress,儘管它也可以配置邊緣路由器或其他前端來幫助處理流量。

你必須具有 Ingress 控制器才能滿足 Ingress 的要求。 僅建立 Ingress 資源本身沒有任何效果。
你可能需要部署 Ingress 控制器,例如 ingress-nginx。 你可以從許多 Ingress 控制器 中進行選擇。
理想情況下,所有 Ingress 控制器都應符合參考規範。但實際上,不同的 Ingress 控制器操作略有不同。

示例

foo.bar.com -> 192.168.47.131 -> / foo    service1:4200
                                 / bar    service2:8080
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress-example
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        backend:
          serviceName: service1
          servicePort: 4200
      - path: /bar
        backend:
          serviceName: service2
          servicePort: 8080

八、日誌收集

進行中

相關文章