Kubernetes中Pod間共享記憶體方案
轉載本文需註明出處:微信公眾號EAWorld,違者必究。
摘要:
一些公共服務元件在追求效能過程中,與業務耦合太緊,造成在製作基礎映象時,都會把這些基礎元件都打包進去,因此當業務映象啟動後,容器裡面一大堆程式,這讓Kubernetes對Pod的管理存在很大隱患。為了讓業務容器瘦身,更是為了基礎元件自身的管理更獨立和方便,將基礎元件從業務映象中剝離並DaemonSet容器化部署。然而一些基礎元件Agent與業務Pod之間透過共享記憶體的方式進行通訊,同一Node中跨Pod的共享記憶體方案是首先要解決的問題。
目錄:
一、為什麼要將公共基礎元件Agent進行DaemonSet部署
二、Linux共享記憶體機制
三、同一Node上誇Pod的共享記憶體方案
四、灰度上線
自研的公共基礎元件,比如服務路由元件、安全元件等,通常以程式方式部署在Node上並同時為Node上所有的業務提供服務,微服務及容器化之後,服務數量成百上千的增長,如果以sidecar或者打包到業務Image中繼續Per Pod Per Agent的方式部署, 那麼基礎元件的Server端的壓力可能也會成百上千的增長,風險是很大的。因此,我們希望能以DaemonSet方式部署這些元件的Agents。
先說說Kubernetes大行其道的今天,如果不將這些基礎元件從業務Pod中剝離,存在哪些問題:
業務容器中存在一大堆程式,我們在為Pod申請資源(cpu/mem request and limit)時,不僅要考慮業務應用本身的資源消耗,還要考慮這些基礎元件的資源消耗。而且一旦某些Agent有Bug,比如記憶體洩漏,這將導致Pod牽連被重建,甚至Cgroup OOM在kill程式時,可能將業務程式kill了。
違背了Kubernetes&微服務的部署最佳實踐:Per Process Per Contaienr,並且業務程式在前臺執行,使其與容器共生死,不然這將導致Kubernetes無法根據業務程式狀態關聯到容器狀態,進而進行高可用管理。
一個Node上執行10個Pod,那麼就會有x10的基礎元件數量在Node上。沒有容器化之前,一個Node只要部署一個元件程式即可,容器化之後,叢集中元件Agents數量要幾十倍的增長,如果業務進行了微服務拆分,這個指數會更大,這些基礎元件服務端是否能承受比以往高几十倍上百倍的通訊請求,這是未知的。
如果你要全網升級某個基礎元件Agent,那你可能會瘋掉,你需要重新打所有業務映象,然後全網業務要進行灰度升級。因為一個Agent的升級,導致你不得不重建業務Pod。你可能會說,基礎元件Agents都會有自己的熱升級方案,我們透過它們的方案升級就好了呀,那你將引入很大麻煩:Agents的熱升級因為無法被Kubernetes感知,將引發Kubernetes中叢集中的資料不一致問題,那就真的要回到虛擬機器或者物理機部署的玩法了。當然,這樣的需求,我們也想過透過Operator也實現,但代價太大了,而且很不CloudNative!
將基礎元件Agents從業務Pod中剝離,以上的問題都能解決了,架構上的解耦帶來的好處無需多言。而且我們可以透過Kubernetes管理這些基礎元件Agents了,享受其自愈、滾動升級等好處。
然而,理想很美好,現實很殘酷。首先要解決的問題是,有些元件Agent與業務Pod之間是透過共享記憶體通訊的,這跟Kubernetes&微服務的最佳實踐背道而馳。
大家都知道,Kubernetes單個Pod內是共享IPC的,並且可以透過掛載Medium為Memory的EmptyDir Volume共享同一塊記憶體Volume。
首先我們來了解一下Linux共享記憶體的兩種機制:
POSIX共享記憶體(shm_open()、shm_unlink())
System V共享記憶體(shmget()、shmat()、shmdt())
其中,System V共享記憶體歷史悠久,一般的UNIX系統上都有這套機制;而POSIX共享記憶體機制介面更加方便易用,一般是結合記憶體對映mmap使用。
mmap和System V共享記憶體的主要區別在於:
sysv shm是持久化的,除非被一個程式明確的刪除,否則它始終存在於記憶體裡,直到系統關機
mmap對映的記憶體在不是持久化的,如果程式關閉,對映隨即失效,除非事先已經對映到了一個檔案上
/dev/shm 是Linux下sysv共享記憶體的預設掛載點
POSIX共享記憶體是基於tmpfs來實現的。實際上,更進一步,不僅PSM(POSIX shared memory),而且SSM(System V shared memory)在核心也是基於tmpfs實現的。
從這裡可以看到tmpfs主要有兩個作用:
用於SYSV共享記憶體,還有匿名記憶體對映;這部分由核心管理,使用者不可見
用於POSIX共享記憶體,由使用者負責mount,而且一般mount到/dev/shm ;依賴於CONFIG_TMPFS
雖然System V與POSIX共享記憶體都是透過tmpfs實現,但是受的限制卻不相同。也就是說 /proc/sys/kernel/shmmax只會影響SYS V共享記憶體,/dev/shm只會影響Posix共享記憶體 。實際上,System V與Posix共享記憶體本來就是使用的兩個不同的tmpfs例項(instance)。
SYS V共享記憶體能夠使用的記憶體空間只受/proc/sys/kernel/shmmax限制;而使用者透過掛載的/dev/shm,預設為實體記憶體的1/2。
概括一下:
POSIX共享記憶體與SYS V共享記憶體在核心都是透過tmpfs實現,但對應兩個不同的tmpfs例項,相互獨立。
透過/proc/sys/kernel/shmmax可以限制SYS V共享記憶體的最大值,透過/dev/shm可以限制POSIX共享記憶體的最大值(所有之和)。
基礎元件Agents DaemonSet部署後,Agents和業務Pod分別在同一個Node上不同的Pod,那麼Kubernetes該如何支援這兩種型別的共享記憶體機制呢?
當然,安全性上做出了犧牲,但在非容器化之前IPC的隔離也是沒有的,所以這一點是可以接受的。
對於叢集中的存量業務,之前都是將Agents與業務打包在同一個docker image,因此需要有灰度上線方案,以保證存量業務不受影響。
首先建立好對應的Kubernetes ClusterRole, SA, ClusterRoleBinding, PSP Object。關於PSP 的內容,請參考官方文件介紹pod-security-policy。
在叢集中任意選擇部分Node,給Node打上Label(AgentsDaemonSet:YES)和Taint(AgentsDaemonSet=YES:NoSchedule)。
$ kubectl label node $nodeName AgentsDaemonSet=YES
$ kubectl taint node $nodeName AgentsDaemonSet=YES:NoSchedule
(安卓系統可左右滑動檢視全部程式碼)
部署Agent對應的DaemonSet(注意DaemonSet需要加上對應的NodeSelector和Toleration, Critical Pod Annotations), Sample as follows:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: demo-agent
namespace: kube-system
labels:
k8s-app: demo-agent
spec:
selector:
matchLabels:
name: demo-agent
template:
metadata:
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ""
labels:
name: demo-agent
spec:
tolerations:
- key: "AgentsDaemonSet"
operator: "Equal"
value: "YES"
effect: "NoSchedule"
hostNetwork: true
hostIPC: true
nodeSelector:
AgentsDaemonSet: "YES"
containers:
- name: demo-agent
image: demo_agent:1.0
volumeMounts:
- mountPath: /dev/shm
name: shm
resources:
limits:
cpu: 200m
memory: 200Mi
requests:
cpu: 100m
memory: 100Mi
volumes:
- name: shm
hostPath:
path: /dev/shm
type: Directory
在該Node上部署不包含基礎元件Agent的業務Pod,檢查所有基礎元件和業務是否正常工作,如果正常,再分批次選擇剩餘Nodes,加上Label(AgentsDaemonSet:YES)和Taint(AgentsDaemonSet=YES:NoSchedule),DaemonSet Controller會自動在這些Nodes建立這些DaemonSet Agents Pod。如此逐批次完成叢集中基礎元件Agents的灰度上線。
總結:
在高併發業務下,尤其還是以C/C++程式碼實現的基礎元件,經常會使用共享記憶體通訊機制來追求高效能,本文給出了Kubernetes Pod間Posix/SystemV共享記憶體方式的折中方案,以犧牲一定的安全性為代價,請知悉。當然,如果微服務/容器化改造後,基礎服務的Server端確定不會有壓力,那麼建議以SideCar Container方式將基礎服務的Agents與業務Container部署在同一Pod中,利用Pod的共享IPC特性及Memory Medium EmptyDir Volume方式共享記憶體。
關於作者:王濤,騰訊雲高階工程師,西安電子科大碩士畢業,持續深耕雲端計算領域七年,目前在騰訊基於TKE(Tencent Kubernetes Engine)構建DevOps平臺,幫助集團自研業務上雲,曾在華為、唯品會、vivo從事企業私有云平臺的建設工作,2014年開始專注於Kubernetes/Docker等容器技術棧在DevOps、AI Platform方向的應用,積累了大量生產經驗。
關於EAWorld:微服務,DevOps,資料治理,移動架構原創技術分享。長按二維碼關注!
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31562043/viewspace-2637033/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 程式間通訊---共享記憶體記憶體
- 程式間通訊之共享記憶體記憶體
- 程序間通訊(3)-共享記憶體記憶體
- 共享記憶體記憶體
- Golang 共享記憶體Golang記憶體
- POSIX共享記憶體記憶體
- oracle 共享記憶體Oracle記憶體
- POSIX 共享記憶體記憶體
- Linux程式間通訊之共享記憶體Linux記憶體
- Linux程式間通訊——使用共享記憶體Linux記憶體
- linux程式間的通訊(C): 共享記憶體Linux記憶體
- nginx共享記憶體分析Nginx記憶體
- QT之共享記憶體QT記憶體
- 共享記憶體函式記憶體函式
- shmget() -- 建立共享記憶體記憶體
- SGA與共享記憶體記憶體
- linux共享記憶體Linux記憶體
- 【JVM故障問題排查心得】「記憶體診斷系列」JVM記憶體與Kubernetes中pod的記憶體、容器的記憶體不一致所引發的OOMKilled問題總結(上)JVM記憶體OOM
- 【JVM故障問題排查心得】「記憶體診斷系列」JVM記憶體與Kubernetes中pod的記憶體、容器的記憶體不一致所引發的OOMKilled問題總結(下)JVM記憶體OOM
- Akka系列(四):Akka中的共享記憶體模型記憶體模型
- Akka 系列(四):Akka 中的共享記憶體模型記憶體模型
- 自動共享記憶體管理 自動記憶體管理 手工記憶體管理記憶體
- Linux 程式間通訊之System V 共享記憶體Linux記憶體
- Qt共享記憶體QSharedMemoryQT記憶體
- Linux共享記憶體(二)Linux記憶體
- 修改/dev/shm共享記憶體dev記憶體
- 共享記憶體分段問題記憶體
- SGA與共享記憶體2記憶體
- fork函式中的記憶體複製和共享函式記憶體
- 在C++Builder中建立共享記憶體段 (轉)C++UI記憶體
- Kubernetes Pod OOM 排查日記OOM
- 【記憶體管理】Oracle如何使用ASMM自動共享記憶體管理記憶體OracleASM
- nginx中共享記憶體的使用Nginx記憶體
- Linux共享記憶體的管理Linux記憶體
- 共享記憶體相關(ipcs/ipcrm)記憶體
- aix 共享記憶體段大小限制AI記憶體
- linux共享記憶體段研究Linux記憶體
- aix 共享記憶體段問題AI記憶體