一. 什么是Docker
????????在docker的官方之什么是docker中提到了一句話:“當(dāng)今各大組織或者團(tuán)體的創(chuàng)新都源于軟件(例如OA永淌、ERP等),其實(shí)很多公司都是軟件公司"。用戶量的激增導(dǎo)致了并發(fā)帕棉、指數(shù)級(jí)增加的數(shù)據(jù)针肥、應(yīng)用的可靠性等問題,單體應(yīng)用已經(jīng)應(yīng)對(duì)不了這些問題香伴,于是誕生了分布式慰枕、集群、微服務(wù)即纲、邊緣計(jì)算等各種名詞具帮、架構(gòu)風(fēng)格和滿足這種架構(gòu)風(fēng)格的各種框架,那我們接下來跟大家談?wù)勥@些技術(shù)名詞低斋。
? ? ???? 分布式:將一個(gè)復(fù)雜的應(yīng)用按照模塊進(jìn)行拆分蜂厅,每個(gè)拆分的模塊做成一個(gè)應(yīng)用,分開部署膊畴,分開運(yùn)行掘猿,各個(gè)模塊之間通過webservice、http rest唇跨、rpc的方式進(jìn)行調(diào)用稠通。但是分布式系統(tǒng)中面臨著很多棘手的問題:1. 如果某一個(gè)應(yīng)用crash掉了,會(huì)導(dǎo)致調(diào)用該模塊的其他模塊也無法正常工作买猖;2. 因?yàn)榫W(wǎng)絡(luò)抖動(dòng)或者硬件的問題導(dǎo)致數(shù)據(jù)的一致性問題(即分布式事務(wù)問題)改橘;3. 運(yùn)維和硬件成本的急劇上升。
? ? ????集群:集群是指將某一個(gè)應(yīng)用或者某個(gè)模塊部署在多臺(tái)機(jī)器上(這些機(jī)器上跑的代碼是相同的)玉控,然后通過負(fù)載均衡的方式讓每個(gè)應(yīng)用都能處理請(qǐng)求飞主,即使某一個(gè)應(yīng)用宕掉了,其他的應(yīng)用一樣可以處理請(qǐng)求高诺,集群是為了解決我們上面提到的分布式應(yīng)用中的第一個(gè)問題碌识,但是集群也面臨著諸多的問題:1. 運(yùn)維和硬件成本的急劇增加;2. 實(shí)現(xiàn)集群勢(shì)必會(huì)引入第三方的插件虱而,那么第三方插件如何去保障其穩(wěn)定運(yùn)行丸冕;
? ? ? ? ? 微服務(wù):微服務(wù)只是一種架構(gòu)風(fēng)格,最早是由Martin Fowler(博客點(diǎn)擊這里)提出薛窥,他對(duì)微服務(wù)的解釋是:In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies(簡(jiǎn)而言之,微服務(wù)是一種架構(gòu)的風(fēng)格眼姐,將每一個(gè)單獨(dú)的應(yīng)用來作為一個(gè)服務(wù)套件诅迷,每一個(gè)服務(wù)套件運(yùn)行在其獨(dú)立的進(jìn)程當(dāng)中,使用輕量級(jí)的方式相互調(diào)用众旗,通常采用HTTP的方式罢杉。這些個(gè)服務(wù)是要建立在業(yè)務(wù)能力和自動(dòng)化獨(dú)立部署的基礎(chǔ)上的。這些服務(wù)間應(yīng)該以一種去中心化的方式運(yùn)行贡歧,而且這些服務(wù)可以使用不同的語言滩租、不同的存儲(chǔ)機(jī)制來實(shí)現(xiàn))赋秀。我用自己的話來表達(dá)一下,所謂的微服務(wù)就是將一個(gè)可以獨(dú)立部署律想、業(yè)務(wù)能力獨(dú)立的應(yīng)用猎莲,應(yīng)用之間耦合度盡量降低(只能盡量降低,不可能實(shí)現(xiàn)絕對(duì)的解耦)技即,盡可能的去中心化著洼。微服務(wù)也同樣的面臨著諸多的問題:1. 分布式事務(wù)問題;2. 運(yùn)維和硬件成本急劇上升而叼。
? ? ? ? 邊緣計(jì)算:首先跟大家說一下身笤,為什么要在這里提到邊緣計(jì)算呢?因?yàn)楸疚闹v的是docker, docker中提到了邊緣計(jì)算葵陵。所謂的邊緣計(jì)算是指在接近數(shù)據(jù)源的地方進(jìn)行數(shù)據(jù)的處理液荸,而不是將數(shù)據(jù)集中到一起進(jìn)行處理,邊緣計(jì)算可以實(shí)現(xiàn)數(shù)據(jù)的實(shí)時(shí)分析脱篙,將有價(jià)值的數(shù)據(jù)過濾后丟給云端娇钱。下面給一張圖方便大家的理解:
我們?cè)诨氐奖竟?jié)標(biāo)題“什么是docker”,我們?cè)诮榻B完上面這些名詞后涡尘,會(huì)發(fā)現(xiàn)無論當(dāng)今所流行的不論是分布式忍弛、集群還是微服務(wù)都面臨著一個(gè)問題:運(yùn)維和硬件成本的急劇上升。那么docker的出現(xiàn)就是為了解決這個(gè)問題:解決運(yùn)維和硬件成本的問題考抄。
提到這里結(jié)合自己的工作經(jīng)歷跟大家講解一下我以前在某家公司是如何解決這個(gè)問題的细疚,我們公司購買一臺(tái)服務(wù)器,然后在服務(wù)器上虛擬出多個(gè)計(jì)算機(jī)川梅,然后在虛擬的機(jī)器上部署我們的應(yīng)用疯兼,所謂虛擬機(jī)是借助于一些軟件虛擬出一臺(tái)和我們的物理機(jī)一樣的機(jī)器,也有CPU贫途、內(nèi)存吧彪、硬盤、光驅(qū)等丢早。雖然我們可以在一臺(tái)真實(shí)的物理機(jī)上虛擬出多臺(tái)機(jī)器姨裸,但是每個(gè)機(jī)器上其實(shí)都是有一套完整的操作系統(tǒng),那么多臺(tái)虛擬機(jī)上就有多套操作系統(tǒng)怨酝,這些操作系統(tǒng)也是要消耗物理機(jī)的資源的傀缩,那么如何解決這個(gè)問題呢?這同樣回到我們?cè)摴?jié)的主題“什么是docker”农猬。
二. Docker的優(yōu)點(diǎn)
其實(shí)這個(gè)問題赡艰,我們?cè)诘谝还?jié)“什么是docker”這個(gè)章節(jié)已經(jīng)給出了答案。在本節(jié)我們會(huì)給出系統(tǒng)的總結(jié):
2.1 資源的復(fù)用
? ? ? 上節(jié)筆者說到我們公司在解決運(yùn)維和機(jī)器成本問題的時(shí)候說到斤葱,通過傳統(tǒng)的虛擬機(jī)的方式每一臺(tái)虛擬機(jī)都有一套完整的操作系統(tǒng)慷垮,那么我們能不能就使用一個(gè)操作系統(tǒng)揖闸,每個(gè)隔離的進(jìn)程只運(yùn)行我們的應(yīng)用和所依賴的第三方軟件,docker恰恰可以解決這個(gè)問題料身。
2.2 一致的環(huán)境
? ? ? 我相信做過開發(fā)的朋友都有這樣的經(jīng)歷汤纸,我們?cè)诒镜亻_發(fā)一個(gè)應(yīng)用,尤其是分布式應(yīng)用惯驼,我們需要在本地安裝多臺(tái)虛擬機(jī)蹲嚣,在本地測(cè)試各種功能完好。接著修改各種參數(shù)后辛辛苦苦部署到測(cè)試機(jī)上后祟牲,測(cè)試的同事經(jīng)過緊張隙畜、嚴(yán)謹(jǐn)?shù)臏y(cè)試,一切都那么的prefect说贝。當(dāng)我們高高興興的修改完各種參數(shù)后部署到生產(chǎn)環(huán)境议惰,我嘞個(gè)擦,各種問題都出現(xiàn)乡恕。開發(fā)人員經(jīng)常掛在嘴邊的幾句話“昨天我跑著還是好好的呀”言询,“測(cè)試的時(shí)候還是好好的呀”,導(dǎo)致開發(fā)人員說這些話的原因是因?yàn)殚_發(fā)傲宜、測(cè)試运杭、生產(chǎn)環(huán)境的不一致所導(dǎo)致的。docker也可以解決這個(gè)問題函卒,docker的鏡像提供了除內(nèi)核以外完整運(yùn)行環(huán)境辆憔,確保的環(huán)境的一致性。
2.3 啟動(dòng)速度更快
? ? ? 以往的虛擬機(jī)的方式啟動(dòng)的時(shí)候需要的時(shí)間會(huì)很長(zhǎng)报嵌,因?yàn)橐獑?dòng)操作系統(tǒng)虱咧,可能需要幾分鐘甚至更長(zhǎng)。但是docker啟動(dòng)只需要幾秒锚国、幾毫秒腕巡。
2.4 應(yīng)用的遷移
? ? ? 給朋友舉個(gè)例子,以前你的應(yīng)用部署在阿里云上血筑,那么那天你的領(lǐng)導(dǎo)需要將應(yīng)用簽署到騰訊云上绘沉,使用docker的話,會(huì)變得非常的簡(jiǎn)單豺总。
三. Docker的安裝
Docker安裝步驟的官網(wǎng)地址:https://docs.docker.com/install/linux/docker-ce/ubuntu/
3.1配置倉庫
yum install -y yum-utils \
? device-mapper-persistent-data \
? lvm2
3.2 開始安裝
配置docker的下載源
yum-config-manager \
?? --add-repo \
?? http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
安裝docker
yum -y install docker-ce docker-ce-cli containerd.io
3.3? 驗(yàn)證docker是否安裝成功
docker -v ? ? ? #查看docker的版本信息
docker info ? ? #查看docker的基本信息梆砸,例如多少鏡像,多少個(gè)容器等
docker help ?? #查看docker命令
四. docker鏡像與容器
docker的鏡像與容器是docker中兩個(gè)至關(guān)重要的概念园欣,首先給各位讀者解釋一下這兩個(gè)概念。鏡像休蟹,我們從字面意思上看沸枯,鏡子里成像日矫,我們?nèi)苏驹阽R子面前,在鏡子中會(huì)呈現(xiàn)一個(gè)完整的我們(包括我們的著裝绑榴、表情哪轿、發(fā)型等等)。那么在軟件領(lǐng)域的鏡像是指對(duì)數(shù)據(jù)按照一定的格式的一個(gè)完整的拷貝翔怎;容器是鏡像運(yùn)行時(shí)的實(shí)體窃诉,比如說鏡像是個(gè)類,當(dāng)沒有被加載的時(shí)候赤套,它是存放在我們的硬盤上的飘痛,而容器是對(duì)象,對(duì)象只有在程序運(yùn)行的時(shí)候才會(huì)被創(chuàng)建容握,并且一個(gè)類可以創(chuàng)建N多個(gè)對(duì)象宣脉,對(duì)應(yīng)到我們的鏡像與容器,一個(gè)鏡像可以用于創(chuàng)建多個(gè)容器剔氏,每個(gè)容器運(yùn)行在各自的namespace中間塑猖。
鏡像是對(duì)文件的副本,能被特定的軟件或者硬件鎖識(shí)別谈跛。
在本節(jié)我們粗略的說一下鏡像羊苟,重點(diǎn)在于講解容器,因?yàn)槿萜饕欢ㄒ玫界R像感憾,所有我們又不得不提蜡励,會(huì)有專門的篇章來介紹鏡像。
4.1 鏡像倉庫的配置
所謂的鏡像倉庫就是鏡像集中存放的位置吹菱,docker默認(rèn)的鏡像倉庫地址是 https://hub.docker.com巍虫,由于該地址服務(wù)器不在內(nèi)地,訪問的速度可能會(huì)有一定的影響鳍刷。所以我們會(huì)經(jīng)常將docker默認(rèn)的鏡像倉庫換成阿里巴巴或者163的鏡像倉庫地址占遥,以便加快我們的訪問速度,本小節(jié)我們以阿里巴巴的鏡像倉庫為例為大家講解输瓜。
A. 注冊(cè)阿里云賬戶瓦胎,地址為:https://account.aliyun.com/login/login.htm
B.進(jìn)入到阿里云控制臺(tái),選擇“容器鏡像服務(wù)”
C.進(jìn)入到“鏡像加速器”尤揣,在右側(cè)會(huì)出現(xiàn)“加速器地址”以及如何配置加速器地址
D. 在 /etc/docker/目錄下是沒有 daemon.json文件的搔啊,所有你要進(jìn)入到 /etc/docker/ 目錄下執(zhí)行 touch? daemon.json? 命令創(chuàng)建 daemon.json文件,如下圖所示:
E.在新創(chuàng)建的daemon.json文件中加入如下內(nèi)容
{
? "registry-mirrors": ["https://zbhswmwr.mirror.aliyuncs.com"]
}
F.執(zhí)行如下命令
sudo systemctl daemon-reload ? ? ? ? ? ? ? ?? #重新加載守護(hù)進(jìn)程
sudo systemctl restart docker ? ? ? ? ? ? ? ? #重啟docker
4.2 docker鏡像的基本命令
A.查看docker本地有多少鏡像:docker images
B.拉取鏡像倉庫的某個(gè)鏡像:docker pull 鏡像名:tag北戏,例如:docker pull hello-world:linux
C.只查看鏡像的ID: docker images -aq
D.刪除一個(gè)鏡像: docker rmi 鏡像名[:tag]? 或者? docker rmi 鏡像ID? ?
五. 容器的基本命令
A. 容器的啟動(dòng):docker run 鏡像名:tag?
B.查看正在運(yùn)行的容器:docker container ls 或者 docker ps 或者 docker ps -n 2
注:docker ps -n 2表示查看最近運(yùn)行或者運(yùn)行過的兩個(gè)容器负芋。
C.查看所有的容器,包括已經(jīng)停止了的容器:docker container ls -a?或者?docker ps -a
D.以交互的方式啟動(dòng)容器嗜愈,例如我們啟動(dòng)一個(gè)centos容器:docker run -i -t centos
? 注意:-t的是宿主機(jī)分配一個(gè)終端旧蛾,并將該終端綁定到標(biāo)準(zhǔn)的輸入上莽龟;-i讓容器的標(biāo)準(zhǔn)輸入保持打開狀態(tài)。二者都是聯(lián)合在一起使用的锨天。
如果以上述的方式啟動(dòng)centos容器毯盈,那么我們?nèi)绾位氐轿覀兊乃拗鳈C(jī)呢?有兩種方式:
? ? ? ? ? 1). 執(zhí)行 exit 命令病袄,該命令會(huì)關(guān)閉容器搂赋,然后退出。
? ? ? ? ? ? ? ? ? 2).按住ctrl + p + q, 容器不關(guān)閉益缠,只是退出脑奠。
E.以后臺(tái)進(jìn)程的方式啟動(dòng)容器:docker run -d centos
細(xì)心的你一定會(huì)發(fā)現(xiàn),我們以守護(hù)進(jìn)程的方式啟動(dòng)容器后左刽,容器卻已經(jīng)退出了(status為Exited)捺信。原因是因?yàn)閐ocker容器啟動(dòng)后必須要有一個(gè)前臺(tái)進(jìn)程,說白了就是一直要有事情干欠痴,那么怎么能讓他有事干了迄靠,我們可以開啟一個(gè)一直掛起的命令,例如:top tail喇辽,否則就會(huì)自動(dòng)退出掌挚。那么有什么解決方法呢?其實(shí)這個(gè)問題解決的方法筆者搜集到三種(都是在網(wǎng)上查找的):
1).以交互的方式啟動(dòng)容器菩咨,然后通過ctrl + p + q 不關(guān)閉容器退出容器吠式,這種方式在上面已經(jīng)給大家提到過:
docker run -it centos
2).通過一個(gè)死循環(huán)間歇性的不停的輸出一個(gè)字符串 :
docker run -d centos /bin/bash -c "while true;do echo hello world;sleep 2;done"
? ? ? ? 3).通過我們上面提到過的top命令的方式開啟一個(gè)前臺(tái)進(jìn)程,讓容器有事情干:
docker run -d centos /usr/bin/top -b
F.容器的停止抽米,容器的停止有兩種方式:1.docker stop 容器ID特占;2.docker kill 容器ID。方式一是一種平滑云茸、優(yōu)雅的方式關(guān)閉容器是目;方式二是暴力的方式關(guān)閉容器。
G.刪除容器:docker rm [-f] 容器ID标捺。-f表示強(qiáng)制刪除剿另,正在運(yùn)行的容器用該命令赋铝。
H.查看容器的日志:docker logs -t -f 容器ID。-t是顯示日志的時(shí)間氧秘,-f是監(jiān)視日志的增長(zhǎng)括儒。
I.重新進(jìn)入已經(jīng)退出的容器:docker attach 容器ID
J.不進(jìn)入到容器谨朝,直接通過命令操作容器:docker exec 容器ID ls -l /?
啟動(dòng)mysql的命令:
docker run --name myMysql -e MYSQL_ROOT_PASSWORD=7890 -p 3307:3306 -d mysql:5.7.27
備注:?jiǎn)?dòng)mysql容器犀暑,指定容器名為myMysql帽揪,指定root的密碼是7890,將宿主機(jī)的3307端口映射到mysql容器中的3306端口。
Docker進(jìn)階
一. 數(shù)據(jù)卷(volume)
1.1 為什么需要數(shù)據(jù)卷
docker鏡像是由多個(gè)文件系統(tǒng)(只讀層)疊加而成阱佛,當(dāng)我們啟動(dòng)一個(gè)容器的時(shí)候帖汞,docker的服務(wù)端會(huì)加載鏡像的只讀層,并在最頂層創(chuàng)建一個(gè)可讀寫層凑术。當(dāng)運(yùn)行的容器修改現(xiàn)有的文件,該文件會(huì)從只讀層拷貝到讀寫層所意,其實(shí)并沒有影響到鏡像本身淮逊,依然存在于鏡像中。當(dāng)我們刪除掉容器扶踊,容器運(yùn)行時(shí)的數(shù)據(jù)都會(huì)丟失泄鹏,當(dāng)我們通過鏡像重新run一個(gè)容器,該容器還是會(huì)回到最初的狀態(tài)秧耗。那么問題來了备籽,我們?cè)撊绾伪4嫖覀冞\(yùn)行中的數(shù)據(jù)了?這個(gè)問題有兩種解決方法:a. 我們可以定期的將我們的容器通過commit的方式生成一個(gè)鏡像分井;b.通過數(shù)據(jù)卷來實(shí)現(xiàn)车猬。很明顯我們不可能不停的commit來生成鏡像,有些朋友可能會(huì)說你這么說的意思是通過數(shù)據(jù)卷來實(shí)現(xiàn)唄尺锚,可我都不知道什么是數(shù)據(jù)卷珠闰,怎么知道它好用了?那么接下來我們就開始來介紹數(shù)據(jù)卷瘫辩。
1.2 什么是數(shù)據(jù)卷
數(shù)據(jù)卷就是容器內(nèi)部的數(shù)據(jù)目錄直接映射到宿主機(jī)上的目錄上伏嗜,無論在宿主機(jī)還是容器內(nèi)對(duì)數(shù)據(jù)的修改在另外一方都是可見的。
1.3 數(shù)據(jù)卷的使用
1.3.1 命令的使用
我們還是通過前面篇章中使用的centos鏡像來講解伐厌,其實(shí)也就一個(gè)命令承绸,我們的工作也就是圍繞著該命令來講解:docker run -it -v /dataVolumn:/containerDataVolumn centos
?至于其他的命令在這里不作過多的解釋,只解釋一下 -v /dataVolumn:/containerDataVolumn 這個(gè)命令的意思挣轨,-v是綁定將容器中的目錄掛載到宿主機(jī)的目錄上军熏,/dataVolumn:/containerDataVolumn中冒號(hào)前的路徑是指自動(dòng)在宿主機(jī)上創(chuàng)建的目錄名(不用我們手動(dòng)去創(chuàng)建),冒號(hào)后的路徑是指在容器中自動(dòng)創(chuàng)建的目錄名刃唐。
1.3.2數(shù)據(jù)卷的創(chuàng)建與測(cè)試
我們前面提到過“論在宿主機(jī)還是容器內(nèi)對(duì)數(shù)據(jù)的修改在另外一方都是可見的”羞迷,那么本小節(jié)我們回來測(cè)試這個(gè)問題。
A.我們?cè)谌萜髦?/containerDataVolumn 目錄下創(chuàng)建一個(gè)container.txt文件画饥,并寫入內(nèi)容衔瓮,命令:echo "hello world" > container.txt
在宿主機(jī)的 /dataVolumn目錄下會(huì)查看到有container.txt文件,并查看內(nèi)容抖甘,如下圖所示:
B.在宿主機(jī)的 /dataVolumn目錄下新建 host.txt文件热鞍,并寫入內(nèi)容,命令為:echo "welcome" > host.txt
在容器的/containerDataVolumn目錄下會(huì)看到host.txt文件,并查看內(nèi)容薇宠,如下圖所示:
C.刪除掉容器偷办,查看宿主機(jī) /dataVolumn目錄,文件并沒有丟失
D.我們可以通過 docker inspect 容器ID 命令查看容器的信息澄港,其中hostConfig.binds可以查看到綁定信息椒涯,如下圖所示:
1.3.3 數(shù)據(jù)卷的其他創(chuàng)建方式
通過上面的方式創(chuàng)建數(shù)據(jù)卷的時(shí)候,我們每次在運(yùn)行鏡像的時(shí)候都需要去指定宿主機(jī)目錄和容器目錄回梧,不便于維護(hù)與遷移废岂,給大家舉個(gè)例子:例如我們的日志文件是存放在容器中的 /cloud-project/logs目錄下,而且在項(xiàng)目的配置文件中也是指定到該目錄下狱意,對(duì)應(yīng)到我們的宿主機(jī)是/mycloud-project/logs目錄湖苞,如果說由于項(xiàng)目發(fā)布啟動(dòng)的時(shí)候,運(yùn)維人員寫錯(cuò)了目錄名详囤,那將是很大的問題财骨。所以我們?cè)谏社R像文件的時(shí)候就指定數(shù)據(jù)卷的目錄豈不是更好。
具體操作是藏姐,我們根據(jù)Dockerfile目錄中通過VOLUMN指定數(shù)據(jù)卷的位置隆箩,至于什么是Dockerfile,在后面的篇章中會(huì)講解包各。
A. 新建一個(gè)空的目錄:mkdir my-dockerfile
B. 新建Dockerfile文件
C.在Dockerfile中添加如下內(nèi)容:
FROM centos
VOLUMN ["/containerDataVolumn"]
CMD /bin/bash
D.執(zhí)行命令 docker build -t mycentos:me .? 生成名為mycentos摘仅,tag為me的新的鏡像文件。注意:最后的一個(gè)點(diǎn)不能省略问畅,它不是結(jié)束的句號(hào)(我在這里栽了很大的跟頭)M奘簟!护姆!
E. 根據(jù)mycentos:me這個(gè)鏡像啟動(dòng)一個(gè)容器矾端,觀察根目錄下會(huì)生成 containerDataVolumn文件夾,如下圖所示:
F. 那么如何查看卵皂,容器中的數(shù)據(jù)卷目錄對(duì)應(yīng)的宿主機(jī)的目錄呢秩铆?上一小節(jié)我們講過,可以通過 docker inspect 容器ID 命令查看灯变,結(jié)果如下圖所示:?
補(bǔ)充:mysql的數(shù)據(jù)卷的啟動(dòng)方式殴玛,如下:
docker run --name myMysql -e MYSQL_ROOT_PASSWORD=7890 -v /mydatas/mysql/datas:/var/lib/mysql -p 3307:3306 -d mysql:5.7.27
二. 容器數(shù)據(jù)卷(了解)
我們?cè)谏弦还?jié)講到使用數(shù)據(jù)卷實(shí)現(xiàn)容器數(shù)據(jù)的持久化,那么如何實(shí)現(xiàn)容器間數(shù)據(jù)的共享了添祸?我們需要使用容器數(shù)據(jù)卷滚粟。其實(shí)就是利用數(shù)據(jù)卷的原理,將多個(gè)容器中的目錄映射到宿主機(jī)的同一個(gè)目錄刃泌,其實(shí)他們就是同一份文件凡壤。在一個(gè)容器中對(duì)數(shù)據(jù)的改變?cè)谄渌萜髦卸际强梢愿兄降氖鹩龋蛘f白了,每個(gè)容器中看到的其實(shí)就是同一份文件亚侠,我們可以通過:stat 文件名 查看文件的inode信息曹体,發(fā)現(xiàn)inode的編號(hào)都一樣。
A. 通過? docker run -it -v /host-datas:/container-datas --name u1 ubuntu:18.04? 命令啟動(dòng)一個(gè)容器硝烂。
B. 通過? docker run -it? --volumes-from u1 --name u2 ubuntu:18.04 命令啟動(dòng)另外一個(gè)容器
C. 在u1容器中的 /container-datas 目錄下創(chuàng)建abc.txt文件箕别,然后在u2容器中/container-datas目錄下可以看到該文件。同理在u2容器中創(chuàng)建一個(gè)文件滞谢,在u1容器中也能看到該文件究孕。
三. Dockerfile
2.1 Dockerfile是什么
Dockerfile是docker中鏡像文件的的描述文件,說的直白點(diǎn)就是鏡像文件到底是由什么東西一步步構(gòu)成的爹凹。例如我們?cè)谔詫毶腺I了一件商品,但是這個(gè)商品需要組裝才能使用镶殷,于是賣家就給了你一張圖紙禾酱,你就按照?qǐng)D紙一步一步的組裝起來,然后就成了你所需要的樣子绘趋。那么Dockerfile就是這張圖紙颤陶,鏡像文件就是你需要的商品。Dockerfile名字可以隨便命名陷遮,但是不建議你這做滓走,還是按照規(guī)范來使用,首字母要大寫帽馋。下面給出我們前幾個(gè)章節(jié)使用到的ubuntu為例搅方,來看看它的Dockerfile是怎么樣的,如下圖所示:
2.2 Dockerfile绽族、鏡像姨涡、容器
Dockerfile:是鏡像的構(gòu)建文件,描述的鏡像是一步步怎么來的吧慢。
鏡像:是通過Dockerfile做出來的涛漂,包含操作系統(tǒng)基礎(chǔ)文件和軟件運(yùn)行環(huán)境,它使用分層的存儲(chǔ)方式检诗。
容器:是運(yùn)行起來的鏡像匈仗,簡(jiǎn)單理解,Docker鏡像相當(dāng)于程序逢慌,容器相當(dāng)于進(jìn)程悠轩。
2.3 Dockerfile的基本語法及執(zhí)行流程
2.3.1 Dockerfile的基本語法
a.每個(gè)保留字必須放在每一行的開頭,可以大寫也可以小寫涕癣,但是建議大寫哗蜈;
b.指令按照順序前标,從上往下依次執(zhí)行;
c.#表示注釋距潘;
d.每條執(zhí)行指令都會(huì)創(chuàng)建一個(gè)新的鏡像炼列,并且執(zhí)行提交。
2.3.2 Dockerfile的執(zhí)行流程
a.docker從基礎(chǔ)鏡像中執(zhí)行一個(gè)容器音比;
b.執(zhí)行一條指令對(duì)容器進(jìn)行修改俭尖;
c.執(zhí)行docker commit命令,提交新的鏡像洞翩;
d.在基于剛剛提交的鏡像運(yùn)行一個(gè)新的容器稽犁;
e.執(zhí)行Dockerfile中的下一條指令,按照b骚亿、c已亥、d依次循環(huán)下去,直到所有的指令執(zhí)行完畢来屠。
2.3.3 演示講解
FROM centos ? ? ? ? ? ? ? ? ? ? ? ?? #指定要生成的鏡像的基礎(chǔ)鏡像虑椎,開頭第一句話必須也只能是FROM
MAINTAINER? qf@163.com ? ? ? ? ? ? ? #指定作者是誰
RUN apt-get install -y vim ? ? ? ? ? #執(zhí)行 yum install -y vim 命令,安裝vim
RUN apt-get install -y net-tools ? ? #執(zhí)行 yum install -y net-tools, 安裝net-tools工具
WORKDIR /dev/ ? ? ? ? ? ? ? ? ? ? ?? #啟動(dòng)容器后俱笛,如果啟動(dòng)交互模式捆姜,直接進(jìn)入到哪個(gè)目錄
CMD ["/bin/bash"] ? ? ? ? ? ? ? ? ?? #啟動(dòng)容器的時(shí)候,進(jìn)入到/bin/bash這種命令行
如上代碼所示迎膜,F(xiàn)ROM泥技、MAINTAINER、RUN磕仅、WORKDIR珊豹、CMD均為關(guān)鍵字,按照標(biāo)準(zhǔn)的規(guī)范需要大寫宽涌;FROM centos表示基礎(chǔ)鏡像是centos平夜,然后會(huì)啟動(dòng)centos這個(gè)容器,執(zhí)行第二行代碼又會(huì)生成新的鏡像文件卸亮,然后提交忽妒,周而復(fù)始。
2.4 Dockerfile關(guān)鍵字
關(guān)鍵字? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 作用
FROM????????????????????????????指定基礎(chǔ)鏡像
MAINTAINER????????????????????作者的信息
RUN????????????????????????????????執(zhí)行什么命令
EXPOSE????????????????????容器對(duì)外暴露的端口
WORKDIR????????????進(jìn)入到容器后進(jìn)入到哪個(gè)目錄
ENV????????????????????????????????配置環(huán)境變量
ADD????????????????????????????將文件拷貝到鏡像中并解壓
COPY????????????????????????????將文件拷貝到鏡像中
VOLUME????????????????????????????????配置數(shù)據(jù)卷
CMD????????????????????????????????容器啟動(dòng)時(shí)候執(zhí)行的命令
ENTRYPOINT????????????????容器啟動(dòng)時(shí)候執(zhí)行的命令
A.ADD指令兼贸,現(xiàn)在定義這樣一個(gè)Dockerfile段直,代碼如下所示:
FROM ubuntu:18.04
MAINTAINER? qf@163.com
RUN mkdir /datas
ADD jdk-8u60-linux-x64.tar.gz /datas/
WORKDIR /datas/
CMD ["/bin/bash"]
首先必須將jdk-8u60-linux-x64.tar.gz文件拷貝到Dockerfile同級(jí)目錄下,如下圖所示:
執(zhí)行命令:docker build -t myubuntu .? 構(gòu)建myubuntu鏡像溶诞,如下圖所示:
然后啟動(dòng)容器鸯檬,進(jìn)入到 /datas/目錄下,會(huì)發(fā)現(xiàn) jdk1.8.0_60 目錄螺垢,表示add命令還執(zhí)行了解壓命令喧务,如下圖所示:
B.COPY命令赖歌,先定義一個(gè)Dockerfile, 代碼如下:
FROM centos
MAINTAINER? qf@163.com
RUN mkdir /datas
COPY jdk-8u60-linux-x64.tar.gz /datas/
WORKDIR /datas/
CMD ["/bin/bash"]
執(zhí)行命令:docker build -t myubuntu .? 構(gòu)建myubuntu鏡像。
然后啟動(dòng)容器功茴,進(jìn)入到 /datas/目錄下庐冯,會(huì)看到j(luò)dk-8u60-linux-x64.tar.gz文件,并沒有解壓坎穿,如下圖所示:
C.ENV命令展父,配置環(huán)境變量,還是用上面提到的jdk為例玲昧,做過Java開發(fā)的朋友都知道栖茉,jdk需要配置環(huán)境變量,Dockerfile的內(nèi)容如下所示:
FROM ubuntu ? ? ? ? ? ? ? ? ? ? ?
MAINTAINER qf@163.com ?
RUN mkdir -p /datas/
ADD jdk-8u60-linux-x64.tar.gz /datas/
ENV JAVA_HOME=/datas/jdk1.8.0_60 ? ? ? ? ? ? ? ? ?? #配置JAVA_HOME
ENV PATH=$JAVA_HOME/bin:$PATH ? ? ? ? ? ? ? ? ? ? ? #配置PATH
CMD ["/bin/bash"]
容器啟動(dòng)后孵延,輸入:java? -version命令吕漂,就能看到我們熟悉的內(nèi)容了。
D.CMD關(guān)鍵字尘应,在鏡像構(gòu)建階段不執(zhí)行痰娱,在容器啟動(dòng)階段執(zhí)行(而的RUN關(guān)鍵字定義的指令在容器構(gòu)建階段就會(huì)執(zhí)行,請(qǐng)記住它與CMD的區(qū)別)菩收。如果一個(gè)Dockerfile中有多個(gè)CMD命令,后面的會(huì)覆蓋前面的鲸睛,說白了只有最后一個(gè)生效娜饵,如下代碼和注釋:
............省略............
CMD echo "<<<<<<<<<<<nice to meet you>>>>>>>>>>"
CMD /bin/bash
CMD echo "==========How are you?=============" ?? #當(dāng)容器啟動(dòng)的時(shí)候只有該行代碼會(huì)執(zhí)行,會(huì)將前兩行代碼覆蓋
CMD還有一個(gè)問題官辈,就是當(dāng)我們使用 docker run命令的時(shí)候箱舞,我們可以在整個(gè)docker命令的最后加上其他額外的命令,那么額外的命令會(huì)覆蓋Dockerfile中所有的CMD命令拳亿,例如我們執(zhí)行如下命令:docker run -it centos ls / -l晴股,最終的結(jié)果如下圖所示:?
E. ENTRYPOINT指令,和CMD命令差不多肺魁,如果一個(gè)Dockerfile中有多個(gè)ENTRYPOINT电湘,只有最后一個(gè)生效。但是他們還是有區(qū)別的鹅经,如果ENTRYPOINT后面有CMD寂呛,當(dāng)以exec的方式運(yùn)行的時(shí)候,CMD的值會(huì)作為參數(shù)給ENTRYPOINT瘾晃,可能很多人看到這句話不大理解贷痪,那么我們來兩個(gè)例子:
例一:
FROM centos ? ? ? ? ? ? ? ? ? ? ?
MAINTAINER? zhengjingmao@163.com ?
RUN mkdir -p /datas/
ENTRYPOINT ["echo", "hello"]
CMD ["world"] ? ? ? ? ? ?? #會(huì)將world作為echo hello的參數(shù),最后的命令其實(shí)為echo hello world
例二:
FROM centos? ? ? ? ? ? ? ? ? ? ?
MAINTAINER? zhengjingmao@163.com?
RUN mkdir -p /datas/
ENTRYPOINT ["echo", "hello"]
總結(jié):當(dāng)我們理解了CMD和ENTRYPOINT兩個(gè)命令的區(qū)別后蹦误,以后在使用的過程中就不會(huì)出現(xiàn)各種問題了劫拢。
四. docker-compose
在開發(fā)一個(gè)應(yīng)用的時(shí)候肉津,我們需要其他的很多東西,例如數(shù)據(jù)庫舱沧,nginx妹沙,網(wǎng)站應(yīng)用等很多的環(huán)境,而docker又推崇的是每一個(gè)容器只運(yùn)行一個(gè)進(jìn)程狗唉,那么我們勢(shì)必得很多的容器初烘,那么我們得通過docker build命令一個(gè)個(gè)的構(gòu)建鏡像,然后在通過docker run命令啟動(dòng)一個(gè)個(gè)容器分俯,那么當(dāng)我們修改了應(yīng)用后肾筐,我們又得去重復(fù)上面的操作。而且容器與容器之間存在著很多的依賴缸剪,我們?cè)诓僮鞯臅r(shí)候還得去考慮先啟動(dòng)哪個(gè)容器吗铐,在啟動(dòng)另外一個(gè)容器,這些操作和步驟都得花上大量的精力杏节。那么docker-compose的出現(xiàn)就是為了解決這個(gè)問題唬渗。
docker-compose是一種容器編排技術(shù),我們可以編寫一個(gè)docker-compose.yml文件奋渔,在文件中編排好我們的服務(wù)镊逝,只用通過一個(gè)命令即可搞定所有的工作。
3.1 安裝docker-compose
A. 運(yùn)行如下命令獲取最新版的docker-compose
curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
B. 給二進(jìn)制文件加上執(zhí)行權(quán)限
chmod +x /usr/local/bin/docker-compose
如果docker-compose命令無效嫉鲸,可以給這個(gè)文件創(chuàng)建一個(gè)在 /usr/bin 目錄下的一個(gè)軟連接撑蒜,如下所示:
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
C. 驗(yàn)證docker-compose是否安裝成功
docker-compose --version
3.2 docker-compose.yml的編寫
version: "3.7"
services:
? mysql:
? ? image: mysql:5.7.26
? ? ports:
? ? ? - "3306:3306"
? ? environment:
? ? ? - MYSQL_ROOT_PASSWORD=miller
? ? network_mode: "host"
? ? volumes:
? ? ? - "/datas/db:/var/lib/mysql"
? ? ? - "/docker-compose/mysql/my.cnf:/etc/my.cnf"
? eureka-server:
? ? build:
? ? ? context: ./eureka-server
? ? ? dockerfile: Dockerfile
? ? ports:
? ? ? - "8761:8761"
? ? network_mode: "host"
? provider:
? ? build:
? ? ? context: ./provider
? ? ? dockerfile: Dockerfile
? ? ports:
? ? ? - "6666:6666"
? ? network_mode: "host"
? ? depends_on:
? ? ? - "mysql"
? ? command: ["./wait-for-it.sh", "mysql:3306", "--", "java", "-jar", "provider.jar"]
? consumer:
? ? container_name: consumer
? ? build:
? ? ? context: ./consumer
? ? network_mode: "host"
? ? ports:
? ? ? - "8080:8080"
version
指定docker-compose文件的版本,對(duì)應(yīng)的版本信息如下:
services
定義服務(wù)玄渗。
image
指定基礎(chǔ)鏡像座菠。
ports
指定對(duì)外開放的端口。
environment
配置環(huán)境變量藤树。
network_mode
網(wǎng)絡(luò)模式浴滴,默認(rèn)為bridge(橋接)模式。
volumes
指定數(shù)據(jù)卷岁钓。
context
要構(gòu)建的鏡像的上下文升略,說白了就是相對(duì)于docker-compose.yml文件的位置。
dockerfile
指定Dockerfile文件的名字屡限,如果名字為Dockerfile的話降宅,不用指定。
depends_on
指定容器所依賴的另外一個(gè)容器的服務(wù)名囚霸,但是并不會(huì)等待所依賴的容器啟動(dòng)才去啟動(dòng)這個(gè)容器腰根。
3.3 啟動(dòng)
docker-compose up: 如果沒有構(gòu)建過鏡像,首先會(huì)構(gòu)建鏡像拓型,然后啟動(dòng)容器额嘿。
docker-compose up --build: 無論鏡像是否存在瘸恼,首先會(huì)構(gòu)建鏡像,然后啟動(dòng)容器册养。
docker-compose start [service...]: 啟動(dòng)已經(jīng)存在的容器东帅。
3.4 wait-for-it.sh使用
地址:https://github.com/vishnubob/wait-for-it
./wait-for-it.sh www.google.com:80 -- echo "google is up"
如果連接上谷歌的服務(wù)器,輸出“google is up”
五. Docker的工程化實(shí)踐
A. 創(chuàng)建spring-boot的工程球拦。
在主類上加上@SpringBootApplication, 來標(biāo)注該類為一個(gè)Spring-boot項(xiàng)目的啟動(dòng)類靠闭。
B.? 編寫代碼。
C. 將spring-boot項(xiàng)目打包后的jar包上傳到ubuntu的/spring-boot/目錄下坎炼。
D. 執(zhí)行:docker run -it -v /spring-boot:/jarDir -p 8088:8080 mcr.microsoft.com/java/jre:8u192-zulu-alpine? /bin/sh -c "java -jar /jarDir/spring-boot-1.0-SNAPSHOT.jar" 啟動(dòng)我們的docker的jre容器愧膀,然后運(yùn)行我們java程序。
E. docker run -it -e MYSQL_ROOT_PASSWORD=123456 -p 3305:3306 mysql:5.7.26谣光,啟動(dòng)mysql的容器檩淋。
F.? 將mysql容器的數(shù)據(jù)通過數(shù)據(jù)卷的方式映射到宿主的目錄下。
六. Idea與docker的整合
6.1 安裝docker插件
6.2 配置docker的端口
修改/lib/systemd/system/docker.service文件萄金,將14行代碼改為:
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
6.3 插件設(shè)置
6.4 Dockerfile
將Dockerfile文件放在項(xiàng)目的根目錄下蟀悦,文件內(nèi)容如下:
FROM store/oracle/serverjre:8
MAINTAINER decent_cat@126.com
ADD /target/boot-1.0-SNAPSHOT.jar boot.jar
EXPOSE 8080
CMD ["java", "-jar", "boot.jar"]
6.5 運(yùn)行配置
七. Docker私有倉庫的搭建
A. 拉取registry倉庫
docker pull registry:2
B. 啟動(dòng)容器
docker run -d -p 5000:5000 --restart always --name registry registry:2
C. 在瀏覽器訪問:http://192.168.223.141:5000/v2/,會(huì)出現(xiàn)如下內(nèi)容氧敢,表示registry啟動(dòng)成功
D.更改 /etc/hosts 文件日戈,在文件的末尾加入上下代碼,其中192.168.223.141 是本機(jī)IP
192.168.223.141? my-registry.com
E. 在 /etc/docker/daemon.json 文件中加入如下內(nèi)容:
"insecure-registries": ["my-registry.com:5000"]
代碼的完整內(nèi)容如下:
F. 重啟docker服務(wù)孙乖,命令如下:
systemctl daemon-reload
systemctl restart docker
G. 推送自己的鏡像到docker私有倉庫中:
# 將我們要推送到私有倉庫的centos鏡像打一個(gè)標(biāo)簽涎拉,名字叫my-centos, 這是my-centos就與本地的centos關(guān)聯(lián)#? 上了
docker tag centos my-registry.com:5000/my-centos
# 將之前已經(jīng)關(guān)聯(lián)的的鏡像推送到私有鏡像倉庫
docker push my-registry.com:5000/my-centos
H. 查看鏡像的命令
http://192.168.223.128:5000/v2/image_name/tags/list? ? #查看某個(gè)鏡像的所有的tag
附錄: