容器化技術與微服務結合---Pod詳解(三)

系列

容器化技術與微服務結合—docker(一)
容器化技術與微服務結合—Kubernetes基本介紹(二)
容器化技術與微服務結合—Pod詳解(三)
容器化技術與微服務結合—實操service並部署一個簡單對外開放的springboot HelloWord服務(四)
容器化技術與微服務結合—結合springcloud微服務框架進行部署(含切換成阿里雲docker倉庫)(五)
容器化技術與微服務結合—SpringCloud框架與阿里雲serverless k8s的結合(六)

設想

如果按照現有操作系統、微服務集羣、軟件來做比喻

  • 容器便是某個應用進程
  • Kubernetes則是操作系統
  • 那麼,容器鏡像看來應該就是各種軟件安裝包
  • Pod便是微服務集羣,統一管理裏面的微服務(其實就是一個group組的概念,進程組)

那麼爲什麼需要Pod,我們按照互聯網業務方面想想,爲什麼在數據結構上往往有更多的父子關係,一父多子?是不是更加方便管理和運維。

Pod這種組的概念,讓具體某些進程(應用或者服務)更加親密,更加方便管理。

例子

  • 我們現在想搭建內網業務集羣,開始劃分網段VPC(相當於Namespace),然後定義一些網段名稱,比如:1. A網段有三個ip子集,用於管理業務(Pod-A); 2. B網段用於存儲管理,有2個高可用ip子集(Pod-B)
  • 訂單場景:我們想給所有的子訂單定義範圍和類型。我們設定父子關係,父訂單上打標籤:1. A類父訂單表示線上支付,擁有幾萬個子訂單(Pod-A); 2. B類父訂單標識線下交易,擁有幾十萬的子訂單(Pod-B)
  • 等等等等

在這裏插入圖片描述
Pod可以讓進程間變得更加親密,方便管理。

微服務層面

當容器(微服務應用)應該是捆綁耦合提供服務的時候,可以將他們完全綁定在一個pod,利用localhost機制通信,對外提供相應的服務
在這裏插入圖片描述

微服務業務場景下,針對k8s內部部署,最重要的就是通信問題,而Pod通信又分爲三種:

pod內部容器之間通信

這種情況很簡單,微服務都部署在一起,localhost通信即可,但是一旦跨地域跨節點就比較麻煩了,你的機器得有多大才可以部署一個pod下所有微服務

pod 與 pod 容器之間

  1. 兩個pod在一臺主機上面

  2. 兩個pod分佈在不同主機之上

針對第一種情況,就比較簡單了,就是docker默認的docker網橋互連容器。

第二種情況需要更爲複雜的網絡模型了,k8s官方推薦的是使用flannel組建一個大二層扁平網絡,pod的ip分配由flannel統一分配,通訊過程也是走flannel的網橋。

docker --daemon --bip=172.17.18.1/24

注意其中的“–bip=172.17.18.1/24”這個參數,它限制了所在節點容器獲得的IP範圍。

每個node上面都會創建一個flannel0虛擬網卡,用於跨node之間通訊。所以容器直接可以直接使用pod id進行通訊。

也就是說,你要自己維護ip池,設計ip規劃。 頭疼啊,相當於造一個vpc出來

pod 訪問service服務

這個就和外面調用的沒啥區別了。。。。。參考上一張service的概念

實例

在這裏插入圖片描述
如圖,我們有兩個微服務,分別部署在不同的pod中,在Customer Service中,我們打算從Account Service調用API方法。 這是聲明式REST客戶端@FeignClient聲明。 所有具有Account Service的Pod在服務名稱和默認服務端口2222下均可用。此類設置是Kubernetes上服務配置的結果。

@FeignClient(name = "account-service", url = "http://account-service:2222")
public interface AccountClient {
@RequestMapping(method = RequestMethod.GET, value = "/accounts/customer/{customerId}")
List<Account> getAccounts(@PathVariable("customerId") String customerId);

}

Pod的實現機制

共享網絡

在這裏插入圖片描述

共享存儲

在這裏插入圖片描述

部署舉例

我現在要發佈一個應用,這個應用是 JAVA 寫的,有一個 WAR 包需要把它放到 Tomcat 的 web APP 目錄下面,這樣就可以把它啓動起來了。可是像這樣一個 WAR 包或 Tomcat 這樣一個容器的話,怎麼去做,怎麼去發佈?這裏面有幾種做法。

  • 第一種方式:可以把 WAR 包和 Tomcat,打包放進一個鏡像裏面。但是這樣帶來一個問題,就是現在這個鏡像實際上揉進了兩個東西。那麼接下來,無論是我要更新 WAR 包還是說我要更新Tomcat,都要重新做一個新的鏡像,這是比較麻煩的;
  • 第二種方式:就是鏡像裏面只打包 Tomcat。它就是一個 Tomcat,但是需要使用數據卷的方式,比如說 hostPath,從宿主機上把WAR 包掛載進我們 Tomcat 容器中,掛到我的 web APP 目錄下面,這樣把這個容器啓用起來之後,裏面就能用了。

但是這時會發現一個問題:這種做法一定需要維護一套分佈式存儲系統。因爲這個容器可能第一次啓動是在宿主機 A 上面,第二次重新啓動就可能跑到 B 上去了,容器它是一個可遷移的東西,它的狀態是不保持的。所以必須維護一套分佈式存儲系統,使容器不管是在 A 還是在 B 上,都可以找到這個 WAR 包,找到這個數據。

參考Pod,我們可以將他們利用共享存儲的方式進行部署,如下
在這裏插入圖片描述

Pod的輔助小祕-Sidecar

通過定義一些特殊的容器,來執行一些業務的輔助性工作,如日誌手機、腳本執行、應用監控等,從而和主業務進行解耦。方便重用,並具有獨立性

這裏從研發角度來看,更傾向於非業務性組件,輔助業務進行快速調用和迭代。

舉個例子,sidecar可以作爲代理來去分發。比如某些集羣需要訪問外面的一些集羣信息,但是不想去修改代碼,存儲外部集羣的ip池子。這個時候我們可以創建一個小的sidecar,所有服務訪問統一的sidecar即可(類似於lb)

Pod的yaml配置

我們可以看一下詳細的yaml配置:

# yaml格式的pod定義文件完整內容:
apiVersion: v1        #必選,版本號,例如v1
kind: Pod       #必選,Pod
metadata:       #必選,元數據
  name: string        #必選,Pod名稱
  namespace: string     #必選,Pod所屬的命名空間
  labels:       #自定義標籤
    - name: string      #自定義標籤名字
  annotations:        #自定義註釋列表
    - name: string
spec:         #必選,Pod中容器的詳細定義
  containers:       #必選,Pod中容器列表
  - name: string      #必選,容器名稱
    image: string     #必選,容器的鏡像名稱
    imagePullPolicy: [Always | Never | IfNotPresent]  #獲取鏡像的策略 Alawys表示下載鏡像 IfnotPresent表示優先使用本地鏡像,否則下載鏡像,Nerver表示僅使用本地鏡像
    command: [string]     #容器的啓動命令列表,如不指定,使用打包時使用的啓動命令
    args: [string]      #容器的啓動命令參數列表
    workingDir: string      #容器的工作目錄
    volumeMounts:     #掛載到容器內部的存儲卷配置
    - name: string      #引用pod定義的共享存儲卷的名稱,需用volumes[]部分定義的的卷名
      mountPath: string     #存儲卷在容器內mount的絕對路徑,應少於512字符
      readOnly: boolean     #是否爲只讀模式
    ports:        #需要暴露的端口庫號列表
    - name: string      #端口號名稱
      containerPort: int    #容器需要監聽的端口號
      hostPort: int     #容器所在主機需要監聽的端口號,默認與Container相同
      protocol: string      #端口協議,支持TCP和UDP,默認TCP
    env:        #容器運行前需設置的環境變量列表
    - name: string      #環境變量名稱
      value: string     #環境變量的值
    resources:        #資源限制和請求的設置
      limits:       #資源限制的設置
        cpu: string     #Cpu的限制,單位爲core數,將用於docker run --cpu-shares參數
        memory: string      #內存限制,單位可以爲Mib/Gib,將用於docker run --memory參數
      requests:       #資源請求的設置
        cpu: string     #Cpu請求,容器啓動的初始可用數量
        memory: string      #內存清楚,容器啓動的初始可用數量
    livenessProbe:      #對Pod內個容器健康檢查的設置,當探測無響應幾次後將自動重啓該容器,檢查方法有exec、httpGet和tcpSocket,對一個容器只需設置其中一種方法即可
      exec:       #對Pod容器內檢查方式設置爲exec方式
        command: [string]   #exec方式需要制定的命令或腳本
      httpGet:        #對Pod內個容器健康檢查方法設置爲HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:      #對Pod內個容器健康檢查方式設置爲tcpSocket方式
         port: number
       initialDelaySeconds: 0   #容器啓動完成後首次探測的時間,單位爲秒
       timeoutSeconds: 0    #對容器健康檢查探測等待響應的超時時間,單位秒,默認1秒
       periodSeconds: 0     #對容器監控檢查的定期探測時間設置,單位秒,默認10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged: false
    restartPolicy: [Always | Never | OnFailure] #Pod的重啓策略,Always表示一旦不管以何種方式終止運行,kubelet都將重啓,OnFailure表示只有Pod以非0退出碼退出才重啓,Nerver表示不再重啓該Pod
    nodeSelector: obeject   #設置NodeSelector表示將該Pod調度到包含這個label的node上,以key:value的格式指定
    imagePullSecrets:     #Pull鏡像時使用的secret名稱,以key:secretkey格式指定
    - name: string
    hostNetwork: false      #是否使用主機網絡模式,默認爲false,如果設置爲true,表示使用宿主機網絡
    volumes:        #在該pod上定義共享存儲卷列表
    - name: string      #共享存儲卷名稱 (volumes類型有很多種)
      emptyDir: {}      #類型爲emtyDir的存儲卷,與Pod同生命週期的一個臨時目錄。爲空值
      hostPath: string      #類型爲hostPath的存儲卷,表示掛載Pod所在宿主機的目錄
        path: string      #Pod所在宿主機的目錄,將被用於同期中mount的目錄
      secret:       #類型爲secret的存儲卷,掛載集羣與定義的secre對象到容器內部
        scretname: string  
        items:     
        - key: string
          path: string
      configMap:      #類型爲configMap的存儲卷,掛載預定義的configMap對象到容器內部
        name: string
        items:
        - key: string
          path: string  

參考

基於Kubernetes和Springboot構建微服務
基於Kubernetes和Docker構建微服務之路

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章