一、OCI
名為OCI,全稱 Open Container Initiative/開放容器倡議,其目的主要是為了制定容器技術的通用技術標準。目前主要有兩種標準:
?? ?1、容器運行時標準 (runtime spec)
?? ?2、容器鏡像標準(image spec)
?? ?
二、docker的架構? ??
1、組成
docker1.11版之后由單體分為了5大組成部分(解耦)
? ? 1、docker-client:客戶端命令
?? ?
?? ?2、dockerd守護進程:全稱docker daemon,主要提供客戶端命令接口,?? ?
?? ?3、containerd服務:
?? ??? ?containerd獨立負責容器運行時的生命周期(如創建、啟動、停止、暫停、信號處理、刪除),其他一些比如鏡像構建、存儲卷管理、日志操作都是dockerd(docker daemon)的一些模塊管理
?? ??? ?
?? ?4、containerd-shim:
?? ??? ?該進程由containerd服務創建
?? ??? ?每創建一個容器,都會啟動一個containerd-shim進程,然后由該進程調用runc來具體創建容器
?? ??? ?
?? ?5、runc:
?? ??? ?最早期docker只是把Runc單拿出來捐贈給了OCI來作為容器運行時的標準,? ? ? ??
?? ??? ?即runc造出來的容器自然就符合OCI標準,使用runc創造出來的就是一個符合oci規范的標準容器
?
2、為何需要有containerd-shim
- Runc創建出的容器需要依賴于某個進程或服務,如果容器直接依賴于containerd服務那意味著,一臺機器上啟動的多個容器都統一依附于containerd
- 一旦containernd退出,該主機上的所有容器都跟著一起退出了
?? ?
?? ?
?? ?于是引入了containerd-shim進程這種設計,由該進程調用runc來創建容器,容器創建出來之后就依賴于該進程
? ??并且該進程雖然是由containerd服務創建的,但是containerd-shim進程是1號進程的父進程
? ? 即containerd只負責創建containerd-shim這個進程,創建出來之后containerd-shim進程就與containerd服務無關了? ??
?? ?所以說,此時containerd服務掛掉了,根本影響不到containerd-shim進程
?? ?containerd-shim進程作為容器的依賴它不出問題就影響不到容器
?? ?
?? ?? ? ps:live-restore就是基于該設計而來。
3、containerd、containerd-shim及容器進程的關系
? ? 層級:
? ? ? ? dockerd服務
?? ??? ??? ?containerd服務
?? ??? ??? ??? ?containerd-shim進程---》runc(只是一個功能,造完容器就消失)--->容器的1號進程
?? ??? ??? ??? ?containerd-shim進程---》runc--->容器的1號進程
?? ??? ??? ??? ?containerd-shim進程---》runc--->容器的1號進程
?? ?依賴關系:
?? ??? ?dockerd服務沒有依賴,它爹是1號進程? ? ? ??
?? ??? ?containerd服務沒有依賴,它爹是1號進程?? ??? ?
?? ??? ?chontainerd-shim是由containerd創建的,但是containerd-shim它爹是1號進程,
?? ??? ??? ?強調:
?? ??? ??? ??? ?containerd創出出containerd-shim進程之后,這個shim進程與containerd就無關了
?? ??? ??? ??? ?所以containerd-shim也沒有依賴? ? ? ? ? ? ? ?
? ? ? ?
? ? ? ? 容器內的1號進程是有依賴,依賴于containerd-shim
?? ??? ??? ?1、容器內的1號進程的父進程是containerd-shim,容器一旦結束,進入僵尸進程狀? ? ? ? ? ? ? ? 態,會由containerd-shim來負責回收? ? ? ? ? ??
?? ??? ??? ?2、容器的一些如stdin、fd等都需要依賴于containerd-shim管理
?? ??? ??? ?所以containerd-shim一旦結束,容器就跟著一塊完蛋了
4、runtime
? ? runtime翻譯為容器運行時,指的就是用來管理鏡像或者容器的服務端軟件
? ? runtime分為兩大類
- high-level runtime:比如docker、containerd、podman等,支持更多高級功能(如鏡像管理和gRPC / Web API),對于高級別運行時來說,他們是通過調用低級別運行時來管理容器(可以簡單的理解為高級別是在低級別基礎上的上層封裝),一般可以是runc作為低級別運行時?
- low-level runtime: 比如lxc、runc、gvisor、kata等,只涉及到容器運行的一些基礎細節,比如namespace創建、cgroup設置
? ? ? ? ? ? ? ? 通常提到的都是低等級的runtime
containerd------是一個工業級標準的容器運行時,它強調簡單性、健壯性和可移植性,containerd 可以負責干下面這些事情:
- 管理容器的生命周期(從創建容器到銷毀容器)
- 拉取/推送容器鏡像
- 存儲管理(管理鏡像及容器數據的存儲)
- 調用 runc 運行容器(與 runc 等容器運行時交互)
- 管理容器網絡接口及網絡
三、k8s與docker
- 1.20版本之后k8s可以找直接和containerd通信,1.20開始放棄docker支持,containerd已經由docker的一部分演變為一個獨立的組件,可以對接多種服務
- 從 k8s 的角度看,選擇 containerd作為運行時的組件,它調用鏈更短,組件更少,更穩定,占用節點資源更少
- k8s不能直接與docker通信,只能與CRI運行時通信,要與 Docker 通信就必須使用橋接服務(dockershim)
- docker比k8s發布的早,Dockershim -直都是 Kubernetes 為了兼容 Docker 獲得市場采取的臨時產案(決定)
- k8s在過去因為 Docker 的熱門而選擇它,現在又因為高昂的維護成本而放棄它,對于已經統治市場的k8s來說,Docker的支持顯得非常雞肋,移除代碼也就順理成章
- 在集群中運行的容器運行時往往不需要docker這么復雜的功能,k8s需要的只是 CRI 中定義的那些接口
- 對于正式生產環境還是建議采用兼容CRI的containerd之類底層運行時。
四、docker中的cpu與gpu
定義
?? ?cpu:擅長邏輯控制,串行運算,cpu就好像一個老教授,老教授的特點是啥數學題都能算? ??
?? ?gpu:擅長大規模的并發計算機,gpu就好像是一群只會算簡單的加減法的小學生
?? ?
要想啟動一個容器使用gpu需要具備哪些條件:
? ? 1、宿主機上必須插一塊gpu卡
?? ?2、宿主機上需要為該gpu卡安裝驅動程序
?? ?3、安裝官方的容器引擎,例如docker容器引擎
?? ?4、配套安裝一個nvidia-container-runtime(對runc的擴展)
?? ?5、啟動容器采用參數--gpus指定啟動gpu,
?? ?或者修改配置文件把默認的runc替換為nvidia-container-runtime這樣就不用加--gpus參數啟動,容器默認都能訪問gpu
?? ?
?? ?強調:容器環境內必須有cuda環境才行(有cuda環境容器內的系統才能調用GPU)? ? ? ? ? ? ? ?cuda 編程模型
- 創建容器:docker -> dockerd-> containerd-> containerd-shim->runc-> container-process
- 創建GPU容器:docker-> dockerd-> containerd-> containerd-shim->nvidia-container-runtime -> nvidia-container-runtime.hook -> libnvidia-container-> runc-> container->process
實現
docker19.03之前還需要安裝nvidia-docker,之后只用安裝nvidia-container-runtime即可使用
#下載對應GPU驅動#安裝nvidia-container-runtime
#在https://nvidia.github.io/nvidia-container-runtime/查看并添加源并直接安裝
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-container-runtime/$distribution/nvidia-container-runtime.repo | \
sudo tee /etc/yum.repos.d/nvidia-container-runtime.repo
sudo yum install nvidia-container-runtime#檢查安裝
docker run --help | grep -i gpus--gpus gpu-request GPU devices to add to the container ('all' to pass all GPUs)#強調采用的鏡像里必須包含cuda
docker run -it --rm --gpus all nvidia/cuda:9.0-base nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.64.00 Driver Version: 440.64.00 CUDA Version: 10.2 |#操作
所有顯卡都對容器可見:
docker run --gpus all --name 容器名 -d -t 鏡像id
只有顯卡1對容器可見:
docker run --gpus="1" --name 容器名 -d -t 鏡像id如果不指定 --gpus ,運行nvidia-smi 會提示Command not found注意:
1. 顯卡驅動在所有方式中,都要先安裝好,容器是不會有顯卡驅動的,一臺物理機的顯卡只對應一個顯卡驅動,當顯卡驅動安裝好后(即使未安裝cuda),也可以使用命令nvidia-smi
2. nvidia-smi顯示的是顯卡驅動對應的cuda版本,nvcc -V 顯示的運行是cuda的版本
啟動容器時,容器如果想使用gpu,鏡像里必須有cuda環境,就是說,針對想使用gpu的容器,鏡像在制作時必須吧cuda環境打進去下面三個參數代表的都是是容器內可以使用物理機的所有gpu卡--gpus allNVIDIA_VISIBLE_DEVICES=all--runtime=nvidaNVIDIA_VISIBLE_DEVICES=2 只公開兩個gpu,容器內只能用兩個gpu舉例如下:
# 使用所有GPU
$ docker run --gpus all nvidia/cuda:9.0-base nvidia-smi# 使用兩個GPU
$ docker run --gpus 2 nvidia/cuda:9.0-base nvidia-smi# 指定GPU運行
$ docker run --gpus '"device=1,2"' nvidia/cuda:9.0-base nvidia-smi
$ docker run --gpus '"device=UUID-ABCDEF,1"' nvidia/cuda:9.0-base nvidia-smi