容器系列: 1 docker的底層技術(shù)和快速實(shí)踐

故事

file

程序員小張: 剛畢業(yè),參加工作1年左右,日常工作是CRUD

file

架構(gòu)師老李: 多個(gè)大型項(xiàng)目經(jīng)驗(yàn),精通各種屠龍寶術(shù);

有一天,小張碰到了老李,他想向老李請(qǐng)教有關(guān)Docker的知識(shí)。于是,小張走向老李并問道:“老李,我聽說你懂得很多關(guān)于Docker的知識(shí),請(qǐng)問你能否給我講講Docker的基本結(jié)構(gòu)和組件?”

老李微笑著點(diǎn)了點(diǎn)頭,開始向小張介紹Docker的基本結(jié)構(gòu)和組件。他告訴小張,Docker由三個(gè)主要概念構(gòu)成:鏡像、容器和倉庫。其中,鏡像是一個(gè)只讀的模板,容器則是基于這個(gè)模板創(chuàng)建的可運(yùn)行實(shí)例,而倉庫則是用于存儲(chǔ)鏡像的地方。

隨后,老李詳細(xì)地介紹了Docker的各個(gè)組件,包括Docker客戶端、Docker守護(hù)進(jìn)程、Docker鏡像以及Docker容器。他為小張講解了每個(gè)組件的作用以及它們之間如何相互配合來實(shí)現(xiàn)Docker的功能。

在老李的深入講解下,小張逐漸理解了Docker的基本結(jié)構(gòu)和組件,并感到非常興奮。他決定在未來的工作中深入研究Docker,并將其應(yīng)用于項(xiàng)目中,以提高團(tuán)隊(duì)的效率和質(zhì)量。

Docker是一個(gè)開源平臺(tái),用于快速開發(fā)、部署和運(yùn)行應(yīng)用程序。它由多個(gè)組件組成,以下是Docker的主要組件:

  1. Docker Daemon:它是Docker的核心組件,負(fù)責(zé)管理鏡像、容器、網(wǎng)絡(luò)和卷等資源,并將Docker API暴露給客戶端。
  1. Docker Client:它是與Docker Daemon通信的主要接口,可以通過命令行或API向Daemon發(fā)送請(qǐng)求。
  1. Docker鏡像(Docker Image):它是一個(gè)只讀的模板,它包含了所有用于運(yùn)行應(yīng)用程序所需要的代碼、庫文件、環(huán)境變量和配置文件等內(nèi)容。
  1. Docker容器(Docker Container):它是基于Docker鏡像創(chuàng)建的可運(yùn)行實(shí)例。每個(gè)容器都是一個(gè)獨(dú)立的、輕量級(jí)的操作系統(tǒng),它們之間相互隔離并且可以共享主機(jī)的內(nèi)核。
  1. Docker Registry:它是用于存儲(chǔ)和分發(fā)Docker鏡像的公共或私有倉庫。Docker Hub是最流行的公共Registry,而Docker Trusted Registry則是一種常見的私有Registry解決方案。
  1. Docker Compose:它是一個(gè)工具,用于定義和運(yùn)行多個(gè)容器的應(yīng)用程序。使用Docker Compose,可以通過一個(gè)簡(jiǎn)單的配置文件來描述應(yīng)用程序的各個(gè)組件,從而使它們可以在一個(gè)統(tǒng)一的環(huán)境中運(yùn)行。
  1. Docker Swarm:它是Docker的原生集群管理工具,用于協(xié)調(diào)和管理多個(gè)Docker節(jié)點(diǎn)。使用Docker Swarm,可以將多個(gè)Docker節(jié)點(diǎn)組成一個(gè)大型的虛擬集群,并在其中部署、管理和擴(kuò)展Docker容器。

這些組件共同構(gòu)成了Docker的核心功能,使得開發(fā)人員和系統(tǒng)管理員能夠更加便捷地開發(fā)、部署和管理應(yīng)用程序。

接下來,我們深入到docker內(nèi)部,分析和學(xué)習(xí)一下它的底層實(shí)現(xiàn)核心技術(shù),并對(duì)常見的操作進(jìn)行實(shí)踐操作。

容器vs虛擬機(jī)

容器是一種沙盒技術(shù),可以看成集裝箱,這樣應(yīng)用之間就有了邊界而不至于互相干擾,方便搬動(dòng);

程序運(yùn)行起來的計(jì)算機(jī)執(zhí)行環(huán)境的總和 就是進(jìn)程;

容器的核心功能: 通過約束和修改進(jìn)程的動(dòng)態(tài)表現(xiàn),創(chuàng)造出一個(gè)邊界;

制造約束: Cgroups技術(shù)
修改進(jìn)程視圖: Namespace技術(shù)

容器的本質(zhì):

int pid = clone(main_function, stack_size,CLONE_NEWPID|SIGCHLD,NULL);

多次調(diào)用clone方法可以創(chuàng)建多個(gè)pid的進(jìn)程N(yùn)ameSpace ,每個(gè)namespace中都會(huì)人為自己是第一號(hào)進(jìn)程,看不到宿主機(jī)的進(jìn)程空間也看不到其它的pid的進(jìn)程空間;

除了PID Namespace ,linux還提供了Mount (掛載點(diǎn)信息), UTS , IPC , Network (網(wǎng)絡(luò)設(shè)備和配置), User這些namespace,來對(duì)各種不同的進(jìn)程上下文進(jìn)行障眼法操作;

只能看到namespace所限定的資源,文件,設(shè)備,狀態(tài),配置 ;對(duì)宿主機(jī)和其它的不相關(guān)程序完全看不到;

所以,容器是一種限定了namespace的進(jìn)程而已;

file

旁路式的輔助和管理工作;

對(duì)比項(xiàng)目 虛擬機(jī) docker容器
真實(shí)存在 真實(shí)存在,并運(yùn)行一個(gè)完整的GuestOs 不真實(shí)存在,只是輔助作用
會(huì)帶來額外的資源消耗和占用 100-200M內(nèi)存,通過虛擬化軟件的攔截和處理 無消耗
內(nèi)核 多個(gè)虛擬機(jī)可以使用不同的內(nèi)核 共享操作系統(tǒng)內(nèi)核

敏捷和高性能 是容器相比于虛擬機(jī)最大的優(yōu)勢(shì);

缺點(diǎn): 容器隔離的不徹底

  1. 多個(gè)容器之間使用的還是同一個(gè)宿主機(jī)的操作系統(tǒng)內(nèi)核;

  2. linux內(nèi)核中很多資源和對(duì)象不能被namespace化,比如時(shí)間;(基于虛擬化和獨(dú)立內(nèi)核技術(shù)的容器實(shí)現(xiàn)隔離)

容器的底層實(shí)現(xiàn)基礎(chǔ)

cgroups

容器對(duì)宿主機(jī)操作系統(tǒng)來說是一個(gè)普通進(jìn)程,普通進(jìn)程的資源限制如果設(shè)置,會(huì)擠占別的進(jìn)程的資源。

Linux Control Groups : 限制一個(gè)進(jìn)程組使用的資源上限,包括: CPU, 內(nèi)存,磁盤,網(wǎng)絡(luò)帶寬。對(duì)進(jìn)程進(jìn)行優(yōu)先級(jí)設(shè)置,審計(jì),對(duì)進(jìn)程掛起和恢復(fù)操作。

/sys/fs/cgoup

可以對(duì)資源進(jìn)行獨(dú)特的限制:

blkio 塊設(shè)備設(shè)定io限制
cpuset 進(jìn)程分配單獨(dú)的cpu和對(duì)應(yīng)的內(nèi)存節(jié)點(diǎn)
memory 設(shè)定內(nèi)存使用限制

在docker run啟動(dòng)的時(shí)候可以傳遞這些資源限制參數(shù):

--cpu-period=100000 --cpu-quota=20000 

缺點(diǎn): 容器中 linux的 /proc top 顯示的是宿主機(jī)的信息 lxcfs

namespace

進(jìn)程看到的經(jīng)過特殊處理的視圖。

nt 設(shè)備掛載點(diǎn)

network 網(wǎng)絡(luò)

user 用戶目錄

UTS host

IPC 進(jìn)程通信

rootfs

進(jìn)入容器之后,看到的文件系統(tǒng),即容器鏡像,它保持了應(yīng)用在不同環(huán)境下的一致性。

主要使用了下面兩種技術(shù)來實(shí)現(xiàn)。

技術(shù) 操作效果
mount Namespace 對(duì)容器進(jìn)程視圖的改變,伴隨著掛載操作才能生效;
容器中看到的是一個(gè)獨(dú)立的隔離環(huán)境,而不是繼承宿主機(jī)的文件系統(tǒng);
chroot/pivot_root 改變進(jìn)程的根目錄

rootfs只包含了操作系統(tǒng)的文件,但是不包含操作系統(tǒng)的內(nèi)核。

這個(gè)就是容器鏡像: 掛載在容器的根目錄上,用來為容器進(jìn)程提供隔離后的執(zhí)行環(huán)境的文件系統(tǒng),就是所謂的容器鏡像。

一致性:
應(yīng)用+操作系統(tǒng)的文件和目錄;
鏡像是打包操作系統(tǒng)的能力;打通了應(yīng)用在本地開發(fā)和遠(yuǎn)端執(zhí)行環(huán)境之間難以逾越的鴻溝;

容器鏡像將會(huì)成為未來軟件的主流發(fā)布方式。

分層+聯(lián)合文件系統(tǒng) union file system ; AUFS ;

目錄:

/var/lib/docker/aufs/diff/layerid
/var/lib/docker/aufs/mnt

file

層分成三個(gè)部分:

  1. 可讀寫層;(修改層)
  2. init層;(配置層) /etc/hosts /etc/resolv.conf等配置信息 只針對(duì)當(dāng)前容器有效,不能提交
  3. 只讀層;(操作系統(tǒng)本身)

docker基本操作

1 購買一個(gè)cvm

為了學(xué)習(xí)和實(shí)驗(yàn)的目的,先購買一個(gè)遠(yuǎn)程的linux機(jī)器。

條目 選擇
1.進(jìn)入購買頁面 騰訊云的輕量級(jí)別cvm https://console.cloud.tencent.com/cvm/overview
2.新建實(shí)例, 選擇 競(jìng)價(jià)實(shí)例 最便宜
3.選擇區(qū)域 選擇離你最近的區(qū)域
4.選擇最低的配置 S6.MEDIUM2 2C4G 哪個(gè)最便宜買哪個(gè)
5.鏡像選擇 TencentOS,最新版本
6.帶寬 選擇按照使用流量計(jì)費(fèi) , 帶寬可以選擇10Mbps
7.安全組 默認(rèn)放行所有的請(qǐng)求和響應(yīng) 這里是測(cè)試目的
8.設(shè)置root賬號(hào)和密碼 自己設(shè)置
9.其他的免費(fèi)的開通即可 總價(jià)格大概是0.1元/小時(shí) 流量 0.8元/GB 流量基本用不上

購買成功頁面如下:

file

然后使用一個(gè)ssh工具,比如xshell或者finalshell 登錄上去;

file

登錄進(jìn)去之后,先確認(rèn)一下cpu和內(nèi)存是否對(duì)得上。

top 
然后按 1
file

2 安裝最新版本docker

指令:

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io

#啟動(dòng)docker
sudo systemctl start docker.service


#確認(rèn)docker可以使用
docker search redis

file

3 docker helloworld

一個(gè)簡(jiǎn)單的python程序。

from flask import Flask
import socket
import os

app = Flask(__name__)

@app.route('/')
def hello():
    html = "<h3>Hello {name}!</h3>" \
           "<b>Hostname:</b> {hostname}<br/>"
    return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname())

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)
Flask
# 使用官方提供的Python開發(fā)鏡像作為基礎(chǔ)鏡像
FROM python:2.7-slim

# 將工作目錄切換為/app
WORKDIR /app

# 將當(dāng)前目錄下的所有內(nèi)容復(fù)制到/app下
ADD . /app

# 使用pip命令安裝這個(gè)應(yīng)用所需要的依賴
RUN pip install --trusted-host pypi.python.org -r requirements.txt

# 允許外界訪問容器的80端口
EXPOSE 80

# 設(shè)置環(huán)境變量
ENV NAME World

# 設(shè)置容器進(jìn)程為:python app.py,即:這個(gè)Python應(yīng)用的啟動(dòng)命令
CMD ["python", "app.py"]

代碼放在我的gitlhub上。

制作鏡像:

# cd 到Dcokerfile所在的目錄
docker build -t p1:v1 .

# 運(yùn)行
docker run --name p1 -p 80:80 -it p1:v1

運(yùn)行效果:

file

Dockerfile的每個(gè)語句執(zhí)行后,都會(huì)生成一個(gè)對(duì)應(yīng)的鏡像層。

查看本地鏡像指令:

docker images

4 保存鏡像到倉庫

file
 docker tag p:v1 carter880522hn/app:pythondemo

docker login
#輸入你的docker hub的賬號(hào)密碼,即可推送到你的私有倉庫  當(dāng)然你也可以使用其他公有云廠商的鏡像倉庫
 
 docker push carter880522hn/app:pythondemo
file

5 docker commit 原理

也可以進(jìn)到正在運(yùn)行的鏡像,做一些修改,然后提交之后,推送到基礎(chǔ)鏡像。

docker ps 
# 可以找到運(yùn)行的容器id 
docker commit ContainerId  遠(yuǎn)程tag

按照分層邏輯。

鏡像分為三層:

  1. 只讀層,操作系統(tǒng);
  2. init層, hosts, sysctl.conf文件;
  3. 讀寫層,程序相關(guān)的層;

docker commit實(shí)際上是在容器運(yùn)行之后,把最上層的可讀寫層,加上原來容器的只讀層,打包成了一個(gè)新的鏡像,只讀層是宿主機(jī)共享,不占用額外空間。

6 docker exec 原理

這個(gè)命令是如何進(jìn)入到容器內(nèi)部的呢?

容器本質(zhì)上是宿主機(jī)創(chuàng)建的進(jìn)程,進(jìn)程的namespace在機(jī)器上是實(shí)實(shí)在在文件。

查看容器在宿主機(jī)上的進(jìn)程編號(hào):

docker inspect --format '{{.State.Pid}}' bc917451cee1

查看宿主機(jī)上的namespace文件。

ls -lh /proc/容器PID/ns
file

容器內(nèi)部的namespace實(shí)際上在宿主機(jī)上有對(duì)應(yīng)的文件進(jìn)行對(duì)應(yīng)。 所以,我們可以使用 exec 去控制容器的文件。

linux中一個(gè)進(jìn)程是可以選擇加入到某個(gè)進(jìn)程已有的namespace,從而達(dá)到進(jìn)入進(jìn)程所在容器的目的。

下面的參數(shù),啟動(dòng)容器的時(shí)候,可以進(jìn)入另外一個(gè)容器的network namesapce;

--net container:4ddf4638572d

7 volume原理

容器內(nèi)部的新建的文件,如何讓宿主機(jī)獲取到?
宿主機(jī)上的文件,容器內(nèi)部如何訪問?

答案就是Volume,即數(shù)據(jù)卷。

語法如下:

docker run -v /local:/container ...

rootfs的掛載過程:

  1. 容器被創(chuàng)建,開啟Mount Namespace ;
  2. 執(zhí)行chroot或者 pivot_root ;

volume,是在 1,2之間的時(shí)機(jī),把volune指定的宿主機(jī)和容器目錄對(duì)應(yīng)關(guān)系進(jìn)行綁定,從而完成掛載;
做這個(gè)掛載的時(shí)候,容器進(jìn)程已經(jīng)創(chuàng)建了,Mount Namespace已經(jīng)開啟了,這個(gè)掛載信息只在容器可見,在宿主機(jī)是看不見這個(gè)掛載點(diǎn)的,保證了容器的隔離性不被Volume打破。

利用的是linux的 bind mount機(jī)制。linux的文件系統(tǒng)節(jié)點(diǎn)叫做inode, 文件指針叫做dentry , bind mount實(shí)際修改的是dentry , 這樣容器內(nèi)部和宿主機(jī)對(duì)應(yīng)的目錄修改,就指向了同一個(gè)inode .

file

volume中的文件,不會(huì)寫到鏡像,但是如果你這個(gè)時(shí)候進(jìn)行docker commit 操作, 這個(gè)volume對(duì)應(yīng)的容器目錄會(huì)被提交。

docker 鏡像結(jié)構(gòu)圖:

file

容器運(yùn)行環(huán)境

在宿主機(jī)上,

應(yīng)用的靜態(tài)表現(xiàn)即

應(yīng)用的動(dòng)態(tài)表現(xiàn)即容器,是一個(gè)使用cgroups和namesace 限制隔離的進(jìn)程組。

維度 說明
應(yīng)用靜態(tài)表現(xiàn) 各種鏡像,鏡像即位于 /var/lib/docker/aufs/mnt上的 rootfs ;
應(yīng)用的動(dòng)態(tài)表現(xiàn) 容器,是一個(gè)使用cgroups和namesace 限制隔離的進(jìn)程組。
容器編排 把用戶提交的鏡像運(yùn)行起來
擴(kuò)展生態(tài) CI/CD、監(jiān)控、安全、網(wǎng)絡(luò)、存儲(chǔ)

k8s

k8s: google和redhat公司聯(lián)合推出的開源項(xiàng)目

價(jià)值: 基于容器構(gòu)建分布式系統(tǒng)的基礎(chǔ)依賴;

k8s的架構(gòu):

file

解決的問題: 編排,管理,調(diào)度用戶提交的作業(yè)。 大規(guī)模集群中的各種任務(wù),實(shí)際上存在各種關(guān)系,對(duì)這些關(guān)系的處理才是作業(yè)編排和管理系統(tǒng)最困難的地方。

docker只是CRI的一種實(shí)現(xiàn)方式。

物理部署/虛機(jī)部署 k8s部署
應(yīng)用 pod
訪問關(guān)系 直接維護(hù)配置文件 service
配置信息管理 通過文件 configmap/secret
daemon 做日志收集,災(zāi)難恢復(fù),數(shù)據(jù)備份 每臺(tái)主機(jī)只運(yùn)行一個(gè) daemonset
定時(shí)任務(wù) cronjob
一次性任務(wù) job
兩臺(tái)nginx做負(fù)載均衡

keepalive做一個(gè)vip
部署兩個(gè)nginx | 一個(gè)deployment,一個(gè)service |

處理思路:
1.通過pod,job來描述你管理的應(yīng)用;
2.定義一些平臺(tái)級(jí)的服務(wù)對(duì)象來編排: service,secret,autoscaler ;

file

小結(jié)

本文從一個(gè)了解docker的故事出發(fā),詳細(xì)分析了docker的三大底層核心技術(shù),cgroups,namesapce,rootfs ; 并從實(shí)踐出發(fā),購買一個(gè)遠(yuǎn)程的linux機(jī)器,安裝docker, 運(yùn)行一個(gè)簡(jiǎn)單的python應(yīng)用,并結(jié)合底層核心技術(shù),講述了docker exec , docker commit ,volume的實(shí)現(xiàn)原理,然后簡(jiǎn)單介紹了k8s的架構(gòu)和解決的問題,一些核心概念的引出;

file

原創(chuàng)不易,關(guān)注誠可貴,轉(zhuǎn)發(fā)價(jià)更高!轉(zhuǎn)載請(qǐng)注明出處,讓我們互通有無,共同進(jìn)步,歡迎溝通交流。
我會(huì)持續(xù)分享Java軟件編程知識(shí)和程序員發(fā)展職業(yè)之路,歡迎關(guān)注!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容