目錄
系列
容器化技術與微服務結合—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 容器之間
-
兩個pod在一臺主機上面
-
兩個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