(一)容器從入門到深入-容器和鏡像

一、容器與鏡像

什么是容器?

在介紹容器的具體概念之前,先簡單回顧一下操作系統是如何管理進程的。

首先,當我們登錄到操作系統之后,可以通過 ps 等操作看到各式各樣的進程,這些進程包括系統自帶的服務和用戶的應用進程。那么,這些進程都有什么樣的特點?

  • 第一,這些進程可以相互看到、相互通信;
  • 第二,它們使用的是同一個文件系統,可以對同一個文件進行讀寫操作;
  • 第三,這些進程會使用相同的系統資源。

這樣的三個特點會帶來什么問題呢?

  • 因為這些進程能夠相互看到并且進行通信,高級權限的進程可以攻擊其他進程;
  • 因為它們使用的是同一個文件系統,因此會帶來兩個問題:這些進程可以對于已有的數據進行增刪改查,具有高級權限的進程可能會將其他進程的數據刪除掉,破壞掉其他進程的正常運行;此外,進程與進程之間的依賴可能會存在沖突,如此一來就會給運維帶來很大的壓力;
  • 因為這些進程使用的是同一個宿主機的資源,應用之間可能會存在資源搶占的問題,當一個應用需要消耗大量 CPU 和內存資源的時候,就可能會破壞其他應用的運行,導致其他應用無法正常地提供服務。

針對上述的三個問題,如何為進程提供一個獨立的運行環境呢?

  • 針對不同進程使用同一個文件系統所造成的問題而言,Linux 和 Unix 操作系統可以通過 chroot 系統調用將子目錄變成根目錄,達到視圖級別的隔離;進程在 chroot 的幫助下可以具有獨立的文件系統,對于這樣的文件系統進行增刪改查不會影響到其他進程;
  • 因為進程之間相互可見并且可以相互通信,使用 Namespace 技術來實現進程在資源的視圖上進行隔離。在 chroot 和 Namespace 的幫助下,進程就能夠運行在一個獨立的環境下了;
  • 但在獨立的環境下,進程所使用的還是同一個操作系統的資源,一些進程可能會侵蝕掉整個系統的資源。為了減少進程彼此之間的影響,可以通過 Cgroup 來限制其資源使用率,設置其能夠使用的 CPU 以及內存量。

那么,應該如何定義這樣的進程集合呢?

其實,容器就是一個視圖隔離、資源可限制、獨立文件系統的進程集合。所謂“視圖隔離”就是能夠看到部分進程以及具有獨立的主機名等;控制資源使用率則是可以對于內存大小以及 CPU 使用個數等進行限制。容器就是一個進程集合,它將系統的其他資源隔離開來,具有自己獨立的資源視圖。

容器具有一個獨立的文件系統,因為使用的是系統的資源,所以在獨立的文件系統內不需要具備內核相關的代碼或者工具,我們只需要提供容器所需的二進制文件、配置文件以及依賴即可。只要容器運行時所需的文件集合都能夠具備,那么這個容器就能夠運行起來。

什么是鏡像?

綜上所述,我們將這些容器運行時所需要的所有的文件集合稱之為容器鏡像。

那么,一般都是通過什么樣的方式來構建鏡像的呢?通常情況下,我們會采用 Dockerfile 來構建鏡像,這是因為 Dockerfile 提供了非常便利的語法糖,能夠幫助我們很好地描述構建的每個步驟。當然,每個構建步驟都會對已有的文件系統進行操作,這樣就會帶來文件系統內容的變化,我們將這些變化稱之為 changeset。當我們把構建步驟所產生的變化依次作用到一個空文件夾上,就能夠得到一個完整的鏡像。 changeset 的分層以及復用特點能夠帶來幾點優勢:

  • 第一,能夠提高分發效率,簡單試想一下,對于大的鏡像而言,如果將其拆分成各個小塊就能夠提高鏡像的分發效率,這是因為鏡像拆分之后就可以并行下載這些數據;
  • 第二,因為這些數據是相互共享的,也就意味著當本地存儲上包含了一些數據的時候,只需要下載本地沒有的數據即可,舉個簡單的例子就是 golang 鏡像是基于 alpine 鏡像進行構建的,當本地已經具有了 alpine 鏡像之后,在下載 golang 鏡像的時候只需要下載本地 alpine 鏡像中沒有的部分即可;
  • 第三,因為鏡像數據是共享的,因此可以節約大量的磁盤空間,簡單設想一下,當本地存儲具有了 alpine 鏡像和 golang 鏡像,在沒有復用的能力之前,alpine 鏡像具有 5M 大小,golang 鏡像有 300M 大小,因此就會占用 305M 空間;而當具有了復用能力之后,只需要 300M 空間即可。

如何構建鏡像?

如下圖所示的 Dockerfile 適用于描述如何構建 golang 應用的。

8 分鐘入門 K8s | 詳解容器基本概念
如圖所示:

  1. FROM 行表示以下的構建步驟基于什么鏡像進行構建,正如前面所提到的,鏡像是可以復用的;
  2. WORKDIR 行表示會把接下來的構建步驟都在哪一個相應的具體目錄下進行,其起到的作用類似于 Shell 里面的 cd;
  3. COPY 行表示的是可以將宿主機上的文件拷貝到容器鏡像內;
  4. RUN 行表示在具體的文件系統內執行相應的動作。當我們運行完畢之后就可以得到一個應用了;
  5. CMD 行表示使用鏡像時的默認程序名字。

當有了 Dockerfile 之后,就可以通過 docker build 命令構建出所需要的應用。構建出的結果存儲在本地,一般情況下,鏡像構建會在打包機或者其他的隔離環境下完成。

那么,這些鏡像如何運行在生產環境或者測試環境上呢?這時候就需要一個中轉站或者中心存儲,我們稱之為 docker registry,也就是鏡像倉庫,其負責存儲所有產生的鏡像數據。我們只需要通過 docker push 就能夠將本地鏡像推動到鏡像倉庫中,這樣一來,就能夠在生產環境上或者測試環境上將相應的數據下載下來并運行了。

如何運行容器?

運行一個容器一般情況下分為三步:

  • 第一步:從鏡像倉庫中將相應的鏡像下載下來;
  • 第二步:當鏡像下載完成之后就可以通過 docker images 來查看本地鏡像,這里會給出一個完整的列表,我們可以在列表中選中想要的鏡像;
  • 第三步:當選中鏡像之后,就可以通過 docker run 來運行這個鏡像得到想要的容器,當然可以通過多次運行得到多個容器。一個鏡像就相當于是一個模板,一個容器就像是一個具體的運行實例,因此鏡像就具有了一次構建、到處運行的特點。

小結

簡單回顧一下,容器就是和系統其它部分隔離開來的進程集合,這里的其他部分包括進程、網絡資源以及文件系統等。而鏡像就是容器所需要的所有文件集合,其具備一次構建、到處運行的特點。

二、容器的生命周期

容器運行時的生命周期

容器是一組具有隔離特性的進程集合,在使用 docker run 的時候會選擇一個鏡像來提供獨立的文件系統并指定相應的運行程序。這里指定的運行程序稱之為 initial 進程,這個 initial 進程啟動的時候,容器也會隨之啟動,當 initial 進程退出的時候,容器也會隨之退出。

因此,可以認為容器的生命周期和 initial 進程的生命周期是一致的。當然,因為容器內不只有這樣的一個 initial 進程,initial 進程本身也可以產生其他的子進程或者通過 docker exec 產生出來的運維操作,也屬于 initial 進程管理的范圍內。當 initial 進程退出的時候,所有的子進程也會隨之退出,這樣也是為了防止資源的泄漏。 但是這樣的做法也會存在一些問題,首先應用里面的程序往往是有狀態的,其可能會產生一些重要的數據,當一個容器退出被刪除之后,數據也就會丟失了,這對于應用方而言是不能接受的,所以需要將容器所產生出來的重要數據持久化下來。容器能夠直接將數據持久化到指定的目錄上,這個目錄就稱之為數據卷。

數據卷有一些特點,其中非常明顯的就是數據卷的生命周期是獨立于容器的生命周期的,也就是說容器的創建、運行、停止、刪除等操作都和數據卷沒有任何關系,因為它是一個特殊的目錄,是用于幫助容器進行持久化的。簡單而言,我們會將數據卷掛載到容器內,這樣一來容器就能夠將數據寫入到相應的目錄里面了,而且容器的退出并不會導致數據的丟失。

通常情況下,數據卷管理主要有兩種方式:

  • 第一種是通過 bind 的方式,直接將宿主機的目錄直接掛載到容器內;這種方式比較簡單,但是會帶來運維成本,因為其依賴于宿主機的目錄,需要對于所有的宿主機進行統一管理。
  • 第二種是將目錄管理交給運行引擎。

三、容器項目架構

moby 容器引擎架構

moby 是目前最流行的容器管理引擎,mobydaemon 會對上提供有關于容器、鏡像、網絡以及 Volume的管理。moby daemon 所依賴的最重要的組件就是 containerd,containerd 是一個容器運行時管理引擎,其獨立于 moby daemon ,可以對上提供容器、鏡像的相關管理。

containerd 底層有 containerd shim 模塊,其類似于一個守護進程,這樣設計的原因有幾點:

  • 首先,containerd 需要管理容器生命周期,而容器可能是由不同的容器運行時所創建出來的,因此需要提供一個靈活的插件化管理。而 shim 就是針對于不同的容器運行時所開發的,這樣就能夠從 containerd 中脫離出來,通過插件的形式進行管理。
  • 其次,因為 shim 插件化的實現,使其能夠被 containerd 動態接管。如果不具備這樣的能力,當 moby daemon 或者 containerd daemon 意外退出的時候,容器就沒人管理了,那么它也會隨之消失、退出,這樣就會影響到應用的運行。
  • 最后,因為隨時可能會對 moby 或者 containerd 進行升級,如果不提供 shim 機制,那么就無法做到原地升級,也無法做到不影響業務的升級,因此 containerd shim 非常重要,它實現了動態接管的能力。

本節課程只是針對于 moby 進行一個大致的介紹,在后續的課程也會詳細介紹。

四、容器 VS VM

容器和 VM 之間的差異

VM 利用 Hypervisor 虛擬化技術來模擬 CPU、內存等硬件資源,這樣就可以在宿主機上建立一個 Guest OS,這是常說的安裝一個虛擬機。

每一個 Guest OS 都有一個獨立的內核,比如 Ubuntu、CentOS 甚至是 Windows 等,在這樣的 Guest OS 之下,每個應用都是相互獨立的,VM 可以提供一個更好的隔離效果。但這樣的隔離效果需要付出一定的代價,因為需要把一部分的計算資源交給虛擬化,這樣就很難充分利用現有的計算資源,并且每個 Guest OS 都需要占用大量的磁盤空間,比如 Windows 操作系統的安裝需要 10~30G 的磁盤空間,Ubuntu 也需要 5~6G,同時這樣的方式啟動很慢。正是因為虛擬機技術的缺點,催生出了容器技術。 容器是針對于進程而言的,因此無需 Guest OS,只需要一個獨立的文件系統提供其所需要文件集合即可。所有的文件隔離都是進程級別的,因此啟動時間快于 VM,并且所需的磁盤空間也小于 VM。當然了,進程級別的隔離并沒有想象中的那么好,隔離效果相比 VM 要差很多。

總體而言,容器和 VM 相比,各有優劣,因此容器技術也在向著強隔離方向發展。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444562.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444562.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444562.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

leetcode461. 漢明距離

兩個整數之間的漢明距離指的是這兩個數字對應二進制位不同的位置的數目。 給出兩個整數 x 和 y&#xff0c;計算它們之間的漢明距離。 注意&#xff1a; 0 ≤ x, y < 231. 示例: 輸入: x 1, y 4 輸出: 2 解釋: 1 (0 0 0 1) 4 (0 1 0 0) ↑ ↑ 上面的箭…

(二)容器從入門到深入-初識Kubernetes

Kubernetes 是什么 Kubernetes 脫胎于 Google 的 Borg 系統&#xff0c;是一個功能強大的容器編排系統。Kubernetes 及其整個生態系統&#xff08;工具、模塊、插件等&#xff09;均使用 Go 語言編寫&#xff0c;從而構成一套面向 API、可高速運行的程序集合&#xff0c;這些程…

記一次海外大型SLG游戲服務器進程被OOM的修復經歷

事情經過 最近剛接手一個多次獲得海外GooglePlay推薦的SLG的游戲項目,服務器是java的netty框架寫的,客戶端是cocos lua。 好吧既然服務器進程運行在jvm之上,吃內存倒是挺厲害的,我一個16G內存的服務器被吃的滿滿的,這個時候為了解決內存不足,我開啟了4G的虛擬內存,方法…

leetcode50. Pow(x, n)

實現 pow(x, n) &#xff0c;即計算 x 的 n 次冪函數。 示例 1: 輸入: 2.00000, 10 輸出: 1024.00000 示例 2: 輸入: 2.10000, 3 輸出: 9.26100 示例 3: 輸入: 2.00000, -2 輸出: 0.25000 解釋: 2-2 1/22 1/4 0.25 說明: -100.0 < x < 100.0 n 是 32 位有符號整數…

GCC在C語言中內嵌匯編 asm __volatile__

在內嵌匯編中,可以將C語言表達式指定為匯編指令的操作數,而且不用去管如何將C語言表達式的值讀入哪個寄存器,以及如何將計算結果寫回C 變量,你只要告訴程序中C語言表達式與匯編指令操作數之間的對應關系即可, GCC會自動插入代碼完成必要的操作。 1、簡單的內嵌匯編 例: …

MYSQL增量備份和全量備份腳本

首先配置下mysql增量備份: server-id = 1 log_bin = /var/log/mysql/mysql-bin.log binlog-ignore-db = sys, mysql, information_schema, performance_schema #設置日志格式 binlog_format = mixed #設置日志路徑,注意路經需要mysql用戶…

MYSQL增量備份和全量備份腳本分享

mysql的全量備份與增量備份全量備份&#xff1a;可以使用mysqldump直接備份整個庫或者是備份其中某一個庫或者一個庫中的某個表。增量備份&#xff1a;增量備份是針對于數據庫的bin-log日志進行備份的&#xff0c;需要開始數據庫的bin-log日志。增量備份是在全量的基礎上進行操…

leetcode48. 旋轉圖像

給定一個 n n 的二維矩陣表示一個圖像。 將圖像順時針旋轉 90 度。 說明&#xff1a; 你必須在原地旋轉圖像&#xff0c;這意味著你需要直接修改輸入的二維矩陣。請不要使用另一個矩陣來旋轉圖像。 示例 1: 給定 matrix [ [1,2,3], [4,5,6], [7,8,9] ], 原地旋轉…

(一)nodejs循序漸進-nodejs環境安裝(基礎篇)

目錄 Node Node的優點 Node.js 安裝配置 使用nvm管理不同版本的 node 與 npm nvm 與 n 的區別 卸載全局安裝的 node/npm Windows 安裝 Linux 安裝 安裝多版本 node/npm 在不同版本間切換 列出已安裝實例 在多環境中&#xff0c;npm該如何使用呢&#xff1f; 其他命…

leetcode49. 字母異位詞分組

給定一個字符串數組&#xff0c;將字母異位詞組合在一起。字母異位詞指字母相同&#xff0c;但排列不同的字符串。 示例: 輸入: ["eat", "tea", "tan", "ate", "nat", "bat"], 輸出: [ ["ate",&quo…

(二)nodejs循序漸進-nodejs基本類型和循環條件語法篇(基礎篇)

目錄 入門之helloworld 進階之helloworld http服務器 步驟一、引入 required 模塊 步驟二、創建服務器 基本語法篇 變量聲明 基礎類型 if else 循環語句 for for ... in while do和do while 運算符 加減乘除 , , !, ! typeof null&#xff0c;undefine…

(三)nodejs循序漸進-值傳遞和引用傳遞,深拷貝和淺拷貝(基礎篇)

值傳遞和引用傳遞 值類型變量&#xff1a; 存在內存的堆中&#xff0c;比如:a1引用類型變量 &#xff1a; 1.指針存在于棧中&#xff0c;2.引用類型的具體內容存在于堆中 ex:let a{b:1} a的指針指向 堆中的地址0xffac0ec 正如我在 第二章 說的&#xff0c; numberstringbo…

(四)nodejs循序漸進-函數,類和對象(基礎篇)

上一篇文章講到了基本數據類型和運算符&#xff0c;相信大家都能做簡單的運算&#xff0c;本篇文章將講述函數&#xff0c;類&#xff0c;對象。 函數 在nodejs中&#xff0c;一個函數可以作為另一個函數的參數。我們可以先定義一個函數&#xff0c;然后傳遞&#xff0c;也可…

leetcode38. 外觀數列

「外觀數列」是一個整數序列&#xff0c;從數字 1 開始&#xff0c;序列中的每一項都是對前一項的描述。前五項如下&#xff1a; 1. 1 2. 11 3. 21 4. 1211 5. 111221 1 被讀作 "one 1" ("一個一") , 即 11。 11 被讀作 "two …

(五)nodejs循序漸進-回調函數和異常處理(基礎篇)

上篇文章我們講完了類和對象&#xff0c;接下來我們將要說回調函數. 我在第一篇說到nodejs的一個優勢是異步IO&#xff0c;實際上異步IO直接體現就是使用回調函數&#xff0c;當然不是用了回調函數&#xff0c;他就一定是異步IO的&#xff0c;因為inodejs是一個單線程函數&…

(六)nodejs循序漸進-數據流和文件操作(基礎篇)

Buffer JS 語言自身只有字符串數據類型&#xff0c;沒有二進制數據類型&#xff0c;因此 NodeJS 提供了一個與 String 對等的全局構造函數 Buffer 來提供對二進制數據的操作。除了可以讀取文件得到 Buffer 的實例外&#xff0c;還能夠直接構造&#xff0c;Buffer 與字符串類似…

leetcode171. Excel表列序號

給定一個Excel表格中的列名稱&#xff0c;返回其相應的列序號。 例如&#xff0c; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ... 示例 1: 輸入: "A" 輸出: 1 示例 2: 輸入: "AB" 輸出: 28 …

(七)nodejs循序漸進-模塊系統(進階篇)

模塊系統 為了讓Node.js的文件可以相互調用&#xff0c;Node.js提供了一個簡單的模塊系統。 模塊是Node.js 應用程序的基本組成部分&#xff0c;文件和模塊是一一對應的。換言之&#xff0c;一個 Node.js 文件就是一個模塊&#xff0c;這個文件可能是JavaScript 代碼、JSON 或…

(八)nodejs循序漸進-事件驅動(進階篇)

事件驅動程序 Node.js 使用事件驅動模型&#xff0c;當web server接收到請求&#xff0c;就把它關閉然后進行處理&#xff0c;然后去服務下一個web請求。 當這個請求完成&#xff0c;它被放回處理隊列&#xff0c;當到達隊列開頭&#xff0c;這個結果被返回給用戶。 這個模型…

leetcode304. 二維區域和檢索 - 矩陣不可變

給定一個二維矩陣&#xff0c;計算其子矩形范圍內元素的總和&#xff0c;該子矩陣的左上角為 (row1, col1) &#xff0c;右下角為 (row2, col2)。 上圖子矩陣左上角 (row1, col1) (2, 1) &#xff0c;右下角(row2, col2) (4, 3)&#xff0c;該子矩形內元素的總和為 8。 示例…