這周分享的內(nèi)容是關(guān)于 Docker 的基礎(chǔ),大概的內(nèi)容分為下面的兩個部分,另外還做了個視頻,其實這個視頻僅僅用來娛樂娛樂而已。
前言
第一趴---Docker容器圈簡介
Docker容器圈簡介
第二趴---Docker基本操作
Docker基本操作
容器圈
容器這個新生事物,現(xiàn)在還可以說是新生事物嗎?對于我們學(xué)生而言,我覺得沒毛病,你說呢?
容器技術(shù)可說重塑了整個云計算市場的形態(tài),帶動了一批年輕有為的容器技術(shù)兒,不過「容器」這個概念是Docker公司發(fā)明的么,不是,它只是眾多Paas項目中的最底層,沒人關(guān)注的那一部分而已。
什么是Pass項目?
Paas項目之所會被很多公司所接受,自然是因為解放了部分開發(fā)人員的勞動力,盡快干玩活兒早點下班。其依賴的就是「應(yīng)用托管」的能力,在電腦上斗過地主的應(yīng)該知道,托管了以后就會自動出牌,同樣的道理,為了盡量的彌補本地和云上的環(huán)境差異,就出現(xiàn)了Paas開源項目。
舉個例子來說,運維人員小仙云上部署一個Cloud Foundry項目,開發(fā)人員只需要簡單的一行代碼就可以實現(xiàn)將本地的應(yīng)用部署到云上
就這樣一行代碼就實現(xiàn)了將本地應(yīng)用上傳到云上,屬實很輕松。
那么這個命令執(zhí)行的基本原理是怎樣的?
實際上,我們可以將其最核心的組件理解為一套應(yīng)用的打包和分發(fā)機(jī)制。云上部署的Cloud Foundry會為大部分編程語言定義一種打包的格式,當(dāng)開發(fā)人員執(zhí)行命令的時候,實際上是將可執(zhí)行文件和啟動腳本打包上傳到云上的Coulud Foudry中,然后Cloud Foundry通過相應(yīng)的調(diào)度器選擇一個虛擬機(jī)的Agent將壓縮包下載后啟動
那如何區(qū)分虛擬機(jī)中的不同應(yīng)用呢?
虛擬機(jī)一般不可能只跑一個應(yīng)用,因為這樣確實也太浪費資源了,我們可以想想,現(xiàn)在手上的電腦,可以用Vmvare導(dǎo)入幾個虛擬機(jī),所以諸如Cloud Foundry通過引入操作系統(tǒng)的Cgroups和Namespace等機(jī)制,從而來為每個應(yīng)用單獨創(chuàng)建一個叫做「沙盒」的隔離環(huán)境,然后在這些「沙盒」中啟動應(yīng)用,通過這樣的方法就讓虛擬機(jī)中應(yīng)用各自互不干擾,讓其自由翱翔,至于Cgroups和 Namespace 的實現(xiàn)原理,后續(xù)我們再共同的探討
這里所謂的隔離環(huán)境就是「容器」。
那 Docker 和這 Pass 項目的 Cloud Foundry 的容器有啥不一樣?
自然不一樣,不然現(xiàn)在我們一旦提到容器,想到的不會是Docker,而是Cloud Foundry了吧。Cloud Foundry的首席產(chǎn)品經(jīng)理就覺得沒什么,畢竟自己放的屁都是香的!
不一樣,而且當(dāng)時還發(fā)了一份報告,報告中還寫到:“Docker不就是使用了 Cgroups和 Namespace實現(xiàn)的「沙盒」而已,不用過于關(guān)注”。
沒想到的是,隨后短短的幾個月,Docker項目迅速起飛以至于其他所有 Paas社區(qū)都還沒來及反應(yīng)過來,就已經(jīng)宣告出局
什么魔力讓 Docker 一發(fā)不可收拾?
就是提出了鏡像的概念。上面我們說過,Paas提供的一套應(yīng)用打包的功能,看起很輕松省事,但是一旦使用了Paas,你就要終身服務(wù)于它,畢竟他是提供商,是「爸爸」,用戶需要為每個版本,每種語言去維護(hù)一個包,這個打包的過程是需要多次的嘗試,多次試錯后,才能摸清本地應(yīng)用和遠(yuǎn)端Paas的脾氣,從而順利部署。
而Docker 鏡像恰恰就是解決了打包這一根本問題。
什么是Docker鏡像?
Docker鏡像也是一個壓縮包,只是這個壓縮包不只是可執(zhí)行文件,環(huán)境部署腳本,它還包含了完整的操作系統(tǒng)。因為大部分的鏡像都是基于某個操作系統(tǒng)來構(gòu)建,所以很輕松的就可以構(gòu)建本地和遠(yuǎn)端一樣的環(huán)境。
這就很牛皮了,如果我們的應(yīng)用是在Centos7上部署,我們只需要將項目環(huán)境部署在基于Centos7的環(huán)境中,然后無論在哪里去解壓這個壓縮包,都可以保證環(huán)境的一致性。在整個過程中,我們根本不需要進(jìn)行任何的配置,因為這個壓縮包可以保證:本地的環(huán)境和云端是一致的,這也是Docker鏡像的精髓
開發(fā)者體驗到了Docker的便利,從而很快宣布Paas時代的結(jié)束,不過對于大規(guī)模應(yīng)用的部署,Docker能否實現(xiàn)在當(dāng)時還是個問號
就在 2014 年的DockerCon上,緊接著發(fā)布了自研的「Docker swarm」,Docker就這樣 一度奔向高潮,即將就到達(dá)了自己夢想之巔。
為什么會推出Docker Swarm?
雖然Docker通過「容器」完成了對Paas的「降維打擊」,但是Docker的目的是:如何讓更多的開發(fā)者將項目部署在自己的項目上,從技術(shù),商業(yè),市場多方位的爭取開發(fā)者的群體,為此形成自家的 Paas平臺做鋪墊
Docker項目雖然很受歡迎,就目前看來只是一個創(chuàng)建和啟動容器的小工具。需要應(yīng)該清楚的一點是,用戶最終部署的還是他們的網(wǎng)站,服務(wù)甚至云計算業(yè)務(wù)。所以推出一個完整的整體對外提供集群管理功能的Swarm勢在必行,這個項目中的最大亮點即直接使用了Docker原生的API來完成對集群的管理。
對于單機(jī)項目,只需要執(zhí)行下面一條語句即可實現(xiàn)容器
對于多機(jī)的項目,只需要執(zhí)行
你看,從單機(jī)切換到多機(jī),使用的方法也就參數(shù)不同而已,所以這樣一個原生的「Docker容器集群管理」一發(fā)布就受到大家的青睞。隨著自身生態(tài)的逐漸完善,借助這一波浪潮并通過各種并購來強大自己的平層能力
要說最成功的案例,非Fig項目莫屬。之所以這么屌,是因為作者提出了「容器編排」的概念。
什么是容器編排?
其實這也不是什么新鮮內(nèi)容,比如在Linux中的Makefile和常見的SHELL腳本,它是一種通過工具或者配置來完成一組虛擬機(jī)或者關(guān)聯(lián)資源的定義、配置、創(chuàng)建等工具。
容器的編排是怎么樣的呢
我們先以 Fig 為例,假設(shè)開發(fā)人員小黑,現(xiàn)在要部署一個項目,其中包含了應(yīng)用容器A,數(shù)據(jù)庫容器B,負(fù)載容器C,這個時候Fig只需要將三個容器定義在一個配置文件,然后指定他們的關(guān)聯(lián)關(guān)系,執(zhí)行下面的命令即可
當(dāng)然也可以在Fig的配置文件中配置各種容器的副本,然后加上Swarm的集群管理功能,這樣不就是Paas了么。只是這個項目被收購以后,修改名字為compose了,后續(xù)也會的compose進(jìn)行詳細(xì)的闡述
就這樣一個以「鯨魚」為商標(biāo)的Docker,火遍全球,因為它秉持將「開發(fā)者」群體放在食物鏈的頂端。一分鐘實現(xiàn)網(wǎng)站的部署,三分鐘搭建集群,這么多年以來,很多后端開發(fā)者很少將眼光放在Linux技術(shù)上,開發(fā)者們?yōu)榱松钊氲牧私釪ocker的技術(shù)原理,終于將眼光放入諸如Cgroups和Namespace技術(shù)中。
就在這一時之間,后端及云計算領(lǐng)域的大佬都匯聚于這個「小鯨魚」的身邊。隨后到了考慮集群的方案,論集群的管理調(diào)度能力,還不得不提Berkeley的Mesos,專注于大數(shù)據(jù)領(lǐng)域,更加關(guān)注的是計算密集型的業(yè)務(wù)。憑借著它天生的兩層調(diào)度機(jī)制,讓它很快發(fā)布了一個叫做Marathon的項目,這個項目隨即成為了Swarm的有力競爭對手。
這還沒完,說了這么久,還沒有提到在基礎(chǔ)設(shè)施領(lǐng)域翹楚的Google公司,是的,同在這一年,宣告了一個叫做Kubernetes項目的誕生。
隨著 Docker生態(tài)的建立,Docker swarm,Docker compose,Machine形成了三件套,此時大量圍繞Docker項目的網(wǎng)絡(luò),存儲,監(jiān)控都涌現(xiàn)。在令人興奮的背后,是對它更多的擔(dān)憂,這主要來源于對Docker商業(yè)化戰(zhàn)略的顧慮,Docker公司對于Docker著絕對的權(quán)威并在多個場合直接和谷歌,微軟對干
其實在Docker興起的時候,谷歌也開源了一個Linux容器:Imctfy,在當(dāng)時這個項目在Docker面前真是弟弟,所以向Docker公司表示想合作的意愿,Docker顯然不同意,且在之后的不久自己發(fā)布了一個容器運行時的庫Libcontainer,可能由于太急躁,其代碼可讀性極差,不穩(wěn)定和頻繁的變更,讓社區(qū)叫苦不迭
為了切割Docker項目的話語權(quán),決定成立一個中立的基金會。所以于 2015 年將這個Libcontainer捐出,并修改名稱為Runc,然后依據(jù)RunC項目,制定了一套容器和鏡像的標(biāo)準(zhǔn)和規(guī)范----OCI
什么是OCI
為了讓Docker不能太囂張,其他玩家構(gòu)建自身平臺的時候不依賴于Docker項目,提出一個標(biāo)準(zhǔn)和規(guī)范----OCI。這一標(biāo)準(zhǔn)并沒有改變 Docker 在容器領(lǐng)域一家獨大的現(xiàn)狀。Google 坐不住了,必須得搞點大招
**Google **給RedHat等伙伴打了電話,說咱們共同牽頭發(fā)起一個基金會-----CNCF。目的很簡單,以kubernetes為基礎(chǔ),建立一個以由開源基礎(chǔ)設(shè)置主導(dǎo),按照獨立基金會方式運營的平臺級社區(qū),來對抗Docker公司為核心的容器商業(yè)生態(tài)
為了做好這個事兒,CNCF 必須完成兩件事兒
必須在編排領(lǐng)取足夠的優(yōu)勢
CNCF 必須以 kubernetes 為核心,覆蓋更多的場景
CNCF 如何解決第一個問題----編排能力
Swarm的無縫集成以及Mesos的大規(guī)模集群的調(diào)度管理能力,很明顯,如果繼續(xù)往這兩個方向發(fā)展,后面的路不一定好走。所以,kubernetes選擇的方式是Borg,其基礎(chǔ)特性是 Google 在容器化基礎(chǔ)設(shè)施多年來實踐的經(jīng)驗,這也正是項目從一開始就避免了和Swarm,mesos 社區(qū)同質(zhì)化的重要手段
看似很有技巧,怎么落地?
RedHat正好擅長這玩意呀,它能真正的理解開源社區(qū)運作和項目研發(fā)真諦的合作伙伴。作為Docker一方,主要不管的強調(diào)「Docker native」,但是由于kubernetes沒有跟Swarm展開同質(zhì)化的競爭,所以這個「Docker Native」的說法并沒有什么殺傷力。反而其獨特的設(shè)計理念和號召力,讓其構(gòu)建了一個完全與眾不同的容器編排管理生態(tài)。
就這樣很快就把Swarm甩在了身后。隨機(jī)開始探討第二個問題,CNCF 添加了一系列容器工具和項目,面對這樣的壓迫,Docker在2016年決定放棄現(xiàn)有的Swarm項目,而是將容器編排等全部內(nèi)置到Docker項目中。
而kubunetes的應(yīng)對方案也蠻有意思,開啟「民主化架構(gòu)」,kubernetes為開發(fā)者暴露可以擴(kuò)展的插件機(jī)制,讓用戶可以隨意的通過植入代碼的方式介入到kubernetes的每一個階段,很快,整個容器圈出現(xiàn)了優(yōu)秀的作品:火熱的微服務(wù)治理項目lstio等
面對kubernetes的 強力攻擊,Docker公司不得不面對失敗的事實,只好放棄開源社區(qū)專注于商業(yè)化轉(zhuǎn)型,所以于2017年將容器運行時部分containerd捐贈給了CNCF,從而將Docker項目改名為Moby,然后交給社區(qū)維護(hù),于 2017 年,**Docker **公司宣布將在企業(yè)版內(nèi)置kubernetes項目,這也標(biāo)志了kubernetes「編排之爭」的結(jié)束
Docker能做什么
Docker是一個用于開發(fā),發(fā)布,運行應(yīng)用的程序于一體的開放平臺。如果我們需要將貨物整齊的擺放在船上且互不影響,那么一種可行的方案即通過集裝箱進(jìn)行標(biāo)準(zhǔn)化,我們將各種貨品通過集裝箱打包,然后統(tǒng)一的放在船上進(jìn)行運輸,Docker其實就是這樣一個將各種軟件進(jìn)行打包成集裝箱,然后分發(fā)。
Docker的安裝
Docker是一個跨平臺的解決方案,支持各大平臺比如Centos,Ubuntu等Linux發(fā)行版。下面講述的是在Centos中的使用,安裝
卸載當(dāng)前已經(jīng)存在的舊版Docker,執(zhí)行下面的命令
添加Docker安裝源
安裝最新版本
如果需要安裝指定版本,可以通過下面命令查看版本并選擇需要的版本
安裝完成,啟動Docker
按照國際案例,先跑一個 helloworld
運行上述命令,Docker首先會檢查本地是否有hello-world這個鏡像,如果發(fā)現(xiàn)本地沒有這個鏡像,Docker就會去Docker Hub官方倉庫下載此鏡像,然后運行它。最后我們看到該鏡像輸出 "Hello from Docker!" 并退出。
Docker核心概念
Docker的操作主要圍繞鏡像,容器,倉庫三大核心概念
什么是鏡像?
一句話說即鏡像是Docker容器啟動的先決條件,因為鏡像會提供容器運行的一些基礎(chǔ)文件和配置文件,是容器啟動的基礎(chǔ)。說白了,要啟動容器,需要鏡像來提供一些基礎(chǔ)環(huán)境。
使用的鏡像的方式有哪些?
自定義創(chuàng)建鏡像。首先找一個基礎(chǔ)鏡像,比如此鏡像是Centos,然后在此鏡像基礎(chǔ)上自定義需要的內(nèi)容。舉個例子,基礎(chǔ)鏡像為Centos,先安裝Nginx服務(wù),然后部署咱們的應(yīng)用程序,最后做一些自定義的配置,這樣一個鏡像就完成了,此鏡像的操作系統(tǒng)是Centos,其中包含了Nginx服務(wù)
從倉庫尋找別人已經(jīng)做好的鏡像。直接去 **Docker hub **或者其他公開倉庫 下載即可
什么是容器?
容器是鏡像的運行實體。鏡像是靜態(tài)的只讀文件,可是容器是要運行的,需要可寫文件層。所以容器運行著真正的應(yīng)用進(jìn)程,所以自然會有創(chuàng)建,運行,停止,暫停和刪除五種狀態(tài)
既然容器是直接運行的運行程序,那它是有自己的命名空間嘛?
容器有自己獨立的命名空間和資源限制,意味著在容器內(nèi)部,你無法看到主機(jī)上面的進(jìn)程,環(huán)境變量等信息,這就是容器和物理機(jī)上的進(jìn)程本質(zhì)區(qū)別
什么是倉庫?
鏡像倉庫類似于代碼倉庫,用來分發(fā)和存儲鏡像,分為公共鏡像和私有鏡像。Docker hub是Docker的官方公開鏡像倉庫,很多的官方鏡像都可以在上面找到,但是訪問很慢,所以可以找國內(nèi)的鏡像源,當(dāng)然后面我們也會自己搭建一個私有鏡像倉庫
三者的關(guān)系是怎么樣的?
上圖清晰的展現(xiàn)了鏡像是容器的基石,容器是在鏡像的基礎(chǔ)上創(chuàng)建的。一個鏡像可以創(chuàng)建多個容器,倉庫用來存放和分發(fā)鏡像
Docker架構(gòu)
容器技術(shù)的發(fā)展可說突飛猛進(jìn)了,市面上除了Docker容器還有coreos的 rkt,lxc 等,這么多種容器,是不是需要一個標(biāo)準(zhǔn)呢,不然就太容易亂套了
你可能會說直接把Docker作為標(biāo)準(zhǔn)不就好了,但是有這么多相關(guān)的容器技術(shù),誰不想吃個好瓜,除此之外,當(dāng)時的編排的技術(shù)也競爭火爆,當(dāng)時的三主力分別是Docker Swarm,kubernetes以及mesos。作為原生的Docker Swarm自然優(yōu)勢明顯,但是kubernetes不同意啊,它們覺得調(diào)度形式太單一了
因此爆發(fā)了容器大戰(zhàn),OCI也就在此出現(xiàn)。
OCI是開放的容器標(biāo)準(zhǔn),輕量級開放的治理結(jié)構(gòu),目前主要有兩個標(biāo)準(zhǔn),分別是容器運行時標(biāo)準(zhǔn)和容器鏡像標(biāo)準(zhǔn)
在如此競爭激烈下面,Docker的架構(gòu)成為了下面這個樣子
Docker的整體架構(gòu)為CS架構(gòu),客戶端和服務(wù)端兩部分組成,客戶端發(fā)送命令,服務(wù)端接受處理指令,其通信的方式有多種,即可以通過Unix套接字通信,也可以網(wǎng)絡(luò)鏈接遠(yuǎn)程通信
Docker客戶端
我們平時通常使用Docker命令行的方式和服務(wù)端打交道,其實還可以通過 **REST API **的方式和Docker服務(wù)端交互,甚至使用各種預(yù)言的sdk和Docker的服務(wù)端交互,美滋滋
Docker服務(wù)端
Docker服務(wù)端是 Docker 后臺服務(wù)的總稱。其中Dockerd是一個非常重要的后臺進(jìn)程,它負(fù)責(zé)響應(yīng)并處理Docker客戶端的請求,然后轉(zhuǎn)化為Docker的具體操作
Docker 重要的組件
我們?nèi)?Docker 默認(rèn)安裝路徑先看看有哪些組件
這里主要說明下runc和contained組件
runc:是一個用來運行容器的輕量級工具
contained:是容器標(biāo)準(zhǔn)化后的產(chǎn)物,從Dockerd剝離出來,contained通過contained-shim啟動并管理runc,可以說contained是真正管理容器的生命周期
通過上圖,可以看到,dockerd通過gRPC與containerd通信,由于dockerd與真正的容器運行時,runC中間有了containerd這一 OCI標(biāo)準(zhǔn)層,使得dockerd可以確保接口向下兼容。
gRPC是一種遠(yuǎn)程服務(wù)調(diào)用。containerd-shim的意思是墊片,類似于擰螺絲時夾在螺絲和螺母之間的墊片。containerd-shim的主要作用是將containerd和真正的容器進(jìn)程解耦,使用containerd-shim作為容器進(jìn)程的父進(jìn)程,從而實現(xiàn)重啟dockerd不影響已經(jīng)啟動的容器進(jìn)程。
docker 各個組件之間的關(guān)系
啟動一個容器
啟動完成,通過下面命令查看 docker 的 pid
此時發(fā)現(xiàn)其 pid 為 4428,隨后我們查看進(jìn)程之間的關(guān)系
通過 pstree 查看進(jìn)程之間的關(guān)系
注意,docker19 就看不到兩者是父子關(guān)系了
可以先使用 ps aux | grep contained ,然后使用pstree查看 contained 的 pid ,實際上,Docker 啟動的時候,contained 就啟動了,dockerd 和 contained 一直就存在。當(dāng)執(zhí)行了docker run以后,contained 就會創(chuàng)建 contained-shim 充當(dāng)墊片進(jìn)程,然后啟動容器的真正進(jìn)程 sleep 3600,這和架構(gòu)圖一致
075528566666
Docker相關(guān)組件
docker
對于我們最直觀的即Docker命令,作為Docker客戶端的完整實現(xiàn),通過Docker命令來實現(xiàn)所有的Docker客戶與服務(wù)端的通信
Docker 客戶端于服務(wù)端的交互過程是怎么樣的呢
Docker組件向服務(wù)端發(fā)送請求后,服務(wù)端根據(jù)請求執(zhí)行具體的動作并將結(jié)果返回給Docker,Docker解析服務(wù)端的返回結(jié)果,并將結(jié)果通過命令行標(biāo)準(zhǔn)輸出展示給用戶。這樣一次完整的客戶端服務(wù)端請求就完成了
dockerd
dockerd 為Docker服務(wù)端后臺的常駐進(jìn)程,負(fù)責(zé)接收客戶端的請求,處理具體的任務(wù)并將結(jié)果返回客戶端
那么 Docke r客戶端采用哪幾種方式發(fā)送請求
第一種方式:通過unix套接字與服務(wù)端通信,配置的格式為:unix://socket_path。默認(rèn)的dockerd生成的 socket文件存放在 /var/run/docker.sock,此文件只能是root用戶才能訪問,這也是為什么剛安裝完Docker后只能root 來進(jìn)行訪問操作
第二種方式:采用TCP的方式與服務(wù)端通信,配置格式為:tcp://host:por,為了保證安全,通常還需要使用TLS認(rèn)證
第三種方式:通過fd文件描述符的方式,配置格式為:fd://這種格式一般用于systemd管理的系統(tǒng)中。
docker-init
在Linux中,有一個叫做init的進(jìn)程,是所有進(jìn)程的父進(jìn)程,用來回收那些沒有回收的進(jìn)程,同樣的道理,在容器內(nèi)部,可以通過加上參數(shù) --init 的方式,讓 1 號進(jìn)程管理所有的子進(jìn)程,例如回收僵尸進(jìn)程
舉個例子示范,以鏡像 busybox 為例
此時的 1 號進(jìn)程為為 sh 進(jìn)程,如果加上 --init
你會發(fā)現(xiàn),此時的 1 號進(jìn)程為docker-init,而不是sh了
docker-proxy
docker-proxy 用來將容器啟動的端口映射到主機(jī),方便主機(jī)的訪問。
假設(shè)目前啟動一個nginx容器并將容器的80端口映射到主機(jī)的8080端口
查看容器 IP
此時使用 ps 查看主機(jī)是否有 docker-proxy 進(jìn)程
可以發(fā)現(xiàn)當(dāng)進(jìn)行端口映射的時候,docker為我們創(chuàng)建了一個docker-proxy進(jìn)程,并且通過參數(shù)將容器的IP和端口傳遞給docker-proxy,然后proxy通過iptables完成nat的轉(zhuǎn)發(fā)
從最后一句可以看出,當(dāng)我們主機(jī)訪問 8080 端口的時候,iptable將流量會轉(zhuǎn)發(fā)給 172.17.0.2 的 80 ,從而實現(xiàn)主機(jī)上直接訪問容器的業(yè)務(wù)
使用curl訪問一下nginx容器
contained組件
containerd
contained主要負(fù)責(zé)容器的生命周期管理,同時還會負(fù)責(zé)一些其他的功能
主要負(fù)責(zé)那些功能?
鏡像的管理
接收dockerd的請求
管理存儲相關(guān)資源
管理網(wǎng)絡(luò)資源
containerd-shim
containerd-shim 的意思是墊片,類似于擰螺絲時夾在螺絲和螺母之間的墊片。containerd-shim 的主要作用是將 containerd 和真正的容器進(jìn)程解耦,使用 containerd-shim 作為容器進(jìn)程的父進(jìn)程,從而實現(xiàn)重啟 containerd 不影響已經(jīng)啟動的容器進(jìn)程。
ctr
ctr 實際上是 containerd-ctr,它是 containerd 的客戶端,主要用來開發(fā)和調(diào)試,在沒有 dockerd 的環(huán)境中,ctr 可以充當(dāng) docker 客戶端的部分角色,直接向 containerd 守護(hù)進(jìn)程發(fā)送操作容器的請求。
Docker鏡像使用
來,繼續(xù),我們看看鏡像是什么。鏡像是一個只讀的鏡像模版且包含了啟動容器所需要的文件結(jié)構(gòu)內(nèi)容。鏡像不包含動態(tài)數(shù)據(jù),構(gòu)建完成將不會改變
對于鏡像都有哪些操作?
對于鏡像的操作分為:
拉取鏡像:通過docker pull拉取遠(yuǎn)程倉庫的鏡像
重命名鏡像:通過docker tag重命名鏡像
查看鏡像:通過docker image ls查看本地已經(jīng)存在的鏡像
刪除鏡像:通過docekr rmi刪除沒有用的鏡像
構(gòu)建鏡像
第一種是通過docker build命令基于dockerfile構(gòu)建鏡像,推薦
第二種是通過docker commit基于運行的容器提交為鏡像
拉取鏡像
拉取鏡像直接使用 docker pull 命令即可,命令的格式如下
registry為注冊的服務(wù)器,docker 默認(rèn)會從官網(wǎng)docker.io上拉取鏡像,當(dāng)然可以將registry注冊為自己的服務(wù)器
repository為鏡像倉庫,library為默認(rèn)的鏡像倉庫
image為鏡像的名稱
tag為給鏡像打的標(biāo)簽
現(xiàn)在舉個例子,這里有個鏡像叫做busybox,這個鏡像集成了上百個常用的Linux命令,可以通過這個鏡像方便快捷的查找生產(chǎn)環(huán)境中的問題,下面我們一起操作一波
docker pull busybox
首先會在本地鏡像庫查找,如果不存在本地庫則直接去官網(wǎng)拉取鏡像。拉取完鏡像后隨即查看鏡像
查看鏡像---docker images
如果要查看指定的鏡像,則使用docker image ls命令進(jìn)一步查詢
重命名鏡像采用打標(biāo)簽的方式重命名,格式如下
我們仔細(xì)觀察這兩個鏡像,就會發(fā)現(xiàn)這兩個鏡像的 IMAGE ID其實是一樣的,這是什么原因呢
實際上他們都是指向的同一個鏡像文件,只不過其別名不一樣而已,如果此時不想要mybox鏡像,想刪除這個鏡像
使用 docker rmi 刪除鏡像
此時再次使用 docker images 查看確實刪除了
如何自己構(gòu)建自己鏡像呢
之前說過,有兩種方式,一種是通過docker commit的方式,一種是docker build的方式。首先看看使用容器提交鏡像的方式
此時啟動了一個busybox容器并進(jìn)入到容器,并在容器中創(chuàng)建一個文件,并寫入內(nèi)容
此時就在當(dāng)前目錄下創(chuàng)建了一個hello.txt文件并寫入了內(nèi)容?,F(xiàn)在新建另外一個窗口,然后提交為一個鏡像
然后使用 docker image ls 查看發(fā)現(xiàn)確實生成了鏡像
然后我們再看看使用 dockerfile 的方式
dockerfile的每一行的命令都會生成獨立的鏡像層并擁有唯一的id
dockerfile命令是完全透明的,通過查看dockerfile的內(nèi)容,就可以知道鏡像是怎么一步步構(gòu)建的
dockerfile為純文本,方便做版本控制
先看看都有哪些命令
這么多,不存在的,我們先看一個dockerfile就知道如何用了
首先第一行表示基于什么鏡像構(gòu)建
第二行是拷貝文件nginx。repo 到容器內(nèi)的 /etc/yum.repos.d
第三行為容器中運行 yum install 命令,安裝 nginx 命令到容器
第四行為生命容器使用 80 端口對外開放
第五行定義容器啟動時的環(huán)境變量HOST=mynginx,容器啟動后可以獲取到環(huán)境變量 HOST 的值為 mynginx。
第六行定義容器的啟動命令,命令格式為json 數(shù)組。這里設(shè)置了容器的啟動命令為 nginx ,并且添加了 nginx 的啟動參數(shù) -g 'daemon off;' ,使得 nginx 以前臺的方式啟動。
基本操作已經(jīng)會了,現(xiàn)在我們看看鏡像的實現(xiàn)原理
第一行:創(chuàng)建一個 busybox 鏡像層
第二行:拷貝本機(jī) test 文件到鏡像內(nèi)
第三行 在tmp 文件夾創(chuàng)建一個目錄 testdir
為了清楚的看見鏡像的存儲結(jié)構(gòu),通過 docker build 構(gòu)建鏡像
因為我的 docker 使用的是 overlay2 文件驅(qū)動,所以進(jìn)入到/var/lib/docker/overlay2 ,使用 tree 查看
可以清楚的看到,dockerfile 的每一行命令都會生成一個鏡像層
Docker容器操作
我們通過一個鏡像可以輕松的創(chuàng)建一個容器,一個鏡像可以有多個容器,在運行容器的時候,實際上是在容器內(nèi)部創(chuàng)建了這個文件系統(tǒng)的讀寫副本,如下圖所示
容器的生命周期是怎么樣的?
容器的生命周期一共有五個狀態(tài)分別為
created 初建狀態(tài)
running 運行狀態(tài)
stopped 停止?fàn)顟B(tài)
opaused 暫停狀態(tài)
deleted 刪除狀態(tài)
通過docker cretate進(jìn)入容器的初建狀態(tài),然后通過docker start進(jìn)入運行狀態(tài),通過docker stop進(jìn)入停止?fàn)顟B(tài),運行狀態(tài)的容器可以通過docker pause讓其變?yōu)闀和顟B(tài),為了詳細(xì)的查看這些過程,我們實操一下
創(chuàng)建并啟動容器
通過docker create創(chuàng)建的容器處于停止的狀態(tài),使用docker start busybox進(jìn)入啟動狀態(tài)
當(dāng)使用docker run創(chuàng)建并啟動容器的時候,docker后臺的執(zhí)行邏輯為
首先檢查本地是否有busybox鏡像,不存在則取dockerhub中拉取
使用busybox鏡像啟動一個容器
分配文件系統(tǒng),并在鏡像的只讀層外創(chuàng)建一個讀寫層
從docker ip池分配個ip給容器
運行鏡像
可以進(jìn)入交互模式么
同時使用-it 參數(shù)可以讓我們進(jìn)入交互模式,容器內(nèi)部和主機(jī)是完全隔離的。另外由于此時的 sh 為 1 號進(jìn)程,所以如果通過 exit 退出 sh,那么容器也就退出,所以對于容器而言,殺死容器中的主進(jìn)程,那么容器也就會被殺死
通過docker stop停止容器,其原理是給運行中的容器給 sigterm 信號,如果容器為 1 號進(jìn)程接受并處理sigterm,則等待 1 號進(jìn)程處理完畢后就退出,如果等待一段時間后還是沒有處理,則會通過發(fā)送sigkill命令強制終止容器
如何進(jìn)入容器?
想要進(jìn)入容器,有三種方案,分別是 docker attach,docker exec,nsenter 等
使用 docker attach 方式進(jìn)入容器
通過 docker ps -a 查看當(dāng)前的進(jìn)程信息
可是當(dāng)我們在進(jìn)行窗口進(jìn)行docker attach的時候,這個命令就不好用了,所以使用docker exec的方式
使用 docker exec進(jìn)入容器
奇怪的發(fā)現(xiàn)居然是兩個sh 進(jìn)程,主要是因為,當(dāng)我們使用 docker exec方式進(jìn)入容器的時候,會單獨啟動一個 sh 進(jìn)程,此時的多個窗口都是獨立且不受干擾,也是非常常用的方式
刪除容器
現(xiàn)在基本上知道了如何創(chuàng)建,啟動容器,那么怎么刪除容器呢
使用docker rm的方式刪除容器
如果此時,容器正在運行,那么需要添加-f的方式停止正在運行的容器
如果想要導(dǎo)出容器怎么操作呢
這簡單,不過在導(dǎo)出之前先進(jìn)入容器創(chuàng)建一個文件
然后導(dǎo)出為文件
此時會在當(dāng)前目錄生成一個 busybox.tar 文件,此時就可以將其拷貝到其他的機(jī)器上使用
那如何導(dǎo)入容器呢
通過 docker import的方式導(dǎo)入,然后使用docker run啟動就完成了容器的遷移
此時容器名稱為 busybox:test,然后我們使用 docker run 啟動并進(jìn)入容器
此時發(fā)現(xiàn)之前在/tmp創(chuàng)建的目錄也被遷移了過來
倉庫
容器的基本操作應(yīng)該都會了,那么我們應(yīng)該如何去存儲和分發(fā)這些鏡像,這就需要介紹下倉庫;
我們可以使用共有鏡像倉庫分發(fā),也可以搭建私有的倉庫
倉庫是啥玩意
錢錢倉庫放錢,這個倉庫放鏡像。Github 放代碼,我們理解鏡像的倉庫可以聯(lián)想 Github 倉庫。
在學(xué)習(xí)的過程中,不太能區(qū)分注冊服務(wù)器和倉庫的關(guān)系。注冊服務(wù)器其實是用來存放倉庫的實際機(jī)器,而倉庫我們可以將其理解為具體的項目或者目錄。一個注冊服務(wù)器可以存放多個倉庫,每個倉庫可以存放多個鏡像
公有倉庫
Docker hub 是當(dāng)前全球最大的鏡像市場,差不多超過 10w 個容器鏡像,大部分操作系統(tǒng)鏡像都來自于此。
如何使用公共鏡像倉庫和存儲鏡像
注冊 Docker hub
創(chuàng)建倉庫
實戰(zhàn)鏡像推送到倉庫
此時假設(shè)我的賬戶是 xiaolantest,創(chuàng)建一個 busybox 的倉庫,隨后將鏡像推送到倉庫中。
第一步:拉取 busybox 鏡像
第二步:推送鏡像之前先登錄鏡像服務(wù)器(注意用戶名密碼哦),出現(xiàn) login Succeeded表示登錄成功
第三步:推送之前還要做一件事,重新對鏡像命名,這樣測能正確的推動到自己創(chuàng)建的倉庫中
第四步:docker push 到倉庫中
私有倉庫
Docker 官方提供了開源的鏡像倉庫 Distribution,鏡像存放于 Docker hub 的 Registry中
啟動本地鏡像倉庫
使用 docker ps查看啟動的容器
重命名鏡像
此時 Docker 為busybox鏡像創(chuàng)建了一個別名localhost:5000/busybox,localhost:5000為主機(jī)名和端口,Docker 將會把鏡像推送到這個地址。
推送鏡像到本地倉庫
刪除之前存在的鏡像
此時,我們驗證一下從本地鏡像倉庫拉取鏡像。首先,我們刪除本地的busybox和localhost:5000/busybox鏡像。
查看當(dāng)前本地鏡像
可以看到此時本地已經(jīng)沒有busybox這個鏡像了。下面,我們從本地鏡像倉庫拉取busybox鏡像:
隨后再使用 docker image ls busybox 命令,這時可以看到我們已經(jīng)成功從私有鏡像倉庫拉取 busybox 鏡像到本地了
總結(jié)
本篇文章從 Docker 容器圈到基本使用,寫的應(yīng)該蠻清楚了。另外說明一下,由于直接使用代碼很可能導(dǎo)致格式排版混亂,所以全部采用截圖的方式,更加直觀和清晰,當(dāng)然如有不妥之處也望大家指正。
責(zé)任編輯:lq
-
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
6859瀏覽量
123502 -
編程語言
+關(guān)注
關(guān)注
10文章
1948瀏覽量
34849 -
Docker
+關(guān)注
關(guān)注
0文章
489瀏覽量
11890
發(fā)布評論請先 登錄
相關(guān)推薦
評論