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