docker(一):認識docker


一、docker由來

  Docker 最初是 dotCloud 公司創始人Solomon Hykes 在法國期間發起的一個公司內部項目,它是基於 dotCloud 公司多年雲服務技術的一次革新,並於 2013 年 3 月以 Apache 2.0 授權協議開源,主要項目代碼在 GitHub 上進行維護。由於 Docker 項目的火爆,在 2013 年底,dotCloud 公司決定改名為 Docker。Docker 最初是在 Ubuntu 12.04 上開發實現的;Red Hat則從 RHEL 6.5 開始對 Docker 進行支持;Docker 項目后來還加入了 Linux 基金會,並成立推動開放容器聯盟(OCI)。

  說到docker開源就插播一段故事,docker的火爆讓一家公司甚是惆悵,沒錯就是Google,據說Google悄悄研究容器已經十幾年了,本來准備作為殺手鐧的,沒想到半路殺出個docker,迅速占領容器大半江山,怎么辦?容器領域已經木得了,那只能換道了,容器一般是需要和編排工具配套使用的,此時Google自己的編排工具已經用了十幾年了,該踩的坑都踩的差不多了,當機立斷,k8s橫空出世,幾乎橫掃了編排工具領域的所有玩家,獨領風騷。另外雖說docker確實火爆,但是docker公司始終沒有辦法變現,所以就在后面發行的docker中附帶了兩個licence,社區版和企業版,docker把社區版改名為Moby,把原來開源的docker的流量全部引入到了企業版上,這樣使得docker社區直接炸鍋了,“步搖碧蓮”,“對不起社區”等等謾罵聲接踵而來,雖然后來docker的CEO出面解釋,但還是使得那段時間使用docker的人心存疑慮。相比而言,Google就非常聰明了,主導成立了CNCF(Cloud Native Computing Foundation,雲原生計算基金會),將k8s的源碼直接捐給CNCF,表明立場:我不會做那種“步搖碧蓮”的事,大伙放心用,k8s的主導是CNCF組織,不是我一家的東西。這也就是后來k8s社區茁壯成長的原因。之后,CNCF聯合google糾集除docker外的幾乎全部做容器的公司准備給docker制定標准(運行、管理、文件格式等等),不過這么做明擺着是針對docker,有點以大欺小的意思,所以他們就給docker放話了:“小子,給你個機會,這個標准由你來定,但是你得把docker開源出來”。結果么,就是現在的結果,大家伙一起happy,其樂融融。

  Docker 使用 Google 公司推出的 Go 語言進行開發實現(k8s也是Go語言),基於 Linux 內核的cgroup,namespace,以及 AUFS 類的 Union FS 等技術,對進程進行封裝隔離,屬於操作系統層面的虛擬化技術。由於隔離的進程獨立於宿主和其它的隔離的進程,因此也稱其為容器。最初實現是基於 LXC,從 0.7 版本以后開始去除 LXC,轉而使用自行開發的 libcontainer,從 1.11 開始,則進一步演進為使用 runC 和 containerd。

二、什么是docker

  docker應該是目前最流行的容器解決方案,它的思想來源於集裝箱,集裝箱的作用是什么?封存、隔離貨物。我們把海鮮和水果分別裝在不同的集裝箱里,由同一艘大船去運輸。這是不是要比分兩艘船來的方便、快捷、高效呢。舉例:公司的開發環境和生產環境不一致,開發出來的程序在開發人員本地能運行,上了生產卻運行不了。你懂得,這個時候就要開始甩鍋了。這中情況如果用docker就不一樣了,我們直接把開發環境build成一個鏡像,然后由運維去把這個docker鏡像部署上就OK了。環境一毛一樣。

  docker與虛擬化的區別如下圖。傳統虛擬化是虛擬出一套硬件后,在其上運行一個完整的操作系統,在系統之上再運行應用進程;而容器內的應用進程直接運行於宿主機的內核,容器內沒有自己的內核,也沒有進行硬件虛擬。因此容器要比傳統虛擬機更為輕便的。

圖1 - 傳統虛擬化
圖2 - Docker

三、為什么要用docker?

  1. 更高效的利用系統資源
      由於容器不需要進行硬件虛擬以及運行完整操作系統等額外開銷,Docker 對系統資源的利用率更高。無論是應用執行速度、內存損耗或者文件存儲速度,都要比傳統虛擬機技術更高效。因此,相比虛擬機技術,一個相同配置的主機,往往可以運行更多數量的應用。

  2. 更短的啟動時間
      傳統的虛擬機技術啟動應用服務往往需要數分鍾,而 Docker 容器應用是直接運行於宿主內核,無需啟動完整的操作系統,因此可以做到秒級、甚至毫秒級的啟動時間。大大的節約了開發、測試、部署的時間。

  3. 一致的運行環境
      開發過程中一個常見的問題是環境一致性問題。由於開發環境、測試環境、生產環境不一致,導致有些 bug 並未在開發過程中被發現。而 Docker 的鏡像提供了除內核外完整的運行時環境,確保了應用運行環境一致性,從而不會再出現 「這段代碼在我機器上沒問題啊」 這類問題。

  4. 持續交付和部署
      對開發和運維(DevOps)人員來說,最希望的就是一次創建或配置,可以在任意地方正常運行。使用 Docker 可以通過定制應用鏡像來實現持續集成、持續交付、部署。開發人員可以通過 Dockerfile 來進行鏡像構建,並結合持續集成(Continuous Integration) 系統進行集成測試,而運維人員則可以直接在生產環境中快速部署該鏡像,甚至結合持續部署(Continuous Delivery/Deployment) 系統進行自動部署。而且使用 Dockerfile 使鏡像構建透明化,不僅僅開發團隊可以理解應用運行環境,也方便運維團隊理解應用運行所需條件,幫助更好的生產環境中部署該鏡像。

  5. 更輕松的遷移
      由於 Docker 確保了執行環境的一致性,使得應用的遷移更加容易。Docker 可以在很多平台上運行,無論是物理機、虛擬機、公有雲、私有雲,甚至是筆記本,其運行結果是一致的。因此用戶可以很輕易的將在一個平台上運行的應用,遷移到另一個平台上,而不用擔心運行環境的變化導致應用無法正常運行的情況。

  6. 更輕松的維護和擴展
      Docker 使用的分層存儲以及鏡像的技術,使得應用重復部分的復用更為容易,也使得應用的維護更新更加簡單,基於基礎鏡像進一步擴展鏡像也變得非常簡單。此外,Docker 團隊同各個開源項目團隊一起維護了一大批高質量的官方鏡像,既可以直接在生產環境使用,又可以作為基礎進一步定制,大大的降低了應用服務的鏡像制作成本。

  7. 對比傳統虛擬機總結

特性 容器 虛擬機
啟動 秒級 分鍾級
硬盤使用 一般為MB 一般為GB
性能 接近原生 弱於
系統支持量 單機支持上千個容器 一般幾十個

四、docker組件

鏡像(image)

  操作系統分為內核空間和用戶空間。對於 Linux 而言,內核啟動后,會掛載 root 文件系統為其提供用戶空間支持。而 Docker 鏡像(Image),就相當於是一個 root 文件系統。比如官方鏡像ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系統的 root 文件系統。docker充分利用Union FS的技術獎docker鏡像設計成分層存儲的架構,也就是說docker鏡像並非是由ISO那樣的打包文件,而是由一組文件系統組成。鏡像構建時也是分層構建,前一層是后一層的基礎。每一層構建完就不會再發生改變,后一層上的任何改變只發生在自己這一層。比如,刪除前一層文件的操作,實際不是真的刪除前一層的文件,而是僅在當前層標記為該文件已刪除。在最終容器運行的時候,雖然不會看到這個文件,但是實際上該文件會一直跟隨鏡像。另外每一層都是只讀的,只有容器啟動后,才會在最上層生成一個可寫層。關於鏡像構建,將會在后續博客中進一步講解。

容器(container)

  容器啟動必須要依賴鏡像,它是鏡像運行時的實體。容器可以被創建、啟動、停止、刪除、暫停等。容器的實質是進程,但與直接在宿主執行的進程不同,容器進程運行於屬於自己的獨立的 命名空間。因此容器可以擁有自己的 root 文件系統、自己的網絡配置、自己的進程空間,甚至自己的用戶 ID 空間。容器內的進程是運行在一個隔離的環境里,使用起來,就好像是在一個獨立於宿主的系統下操作一樣。這種特性使得容器封裝的應用比直接在宿主運行更加安全。也因為這種隔離的特性,很多人初學Docker 時常常會混淆容器和虛擬機。

  容器運行時,在其最上層會創建一個當前容器的可寫層,也稱為容器存儲層。容器存儲層的生存周期和容器一樣,容器消亡時,容器存儲層也隨之消亡。因此,任何保存於容器存儲層的信息都會隨容器刪除而丟失。so,容器不應該向其存儲層內寫入任何數據,容器存儲層要保持無狀態化。所有的文件寫入操作,都應該使用數據卷(Volume)或者綁定宿主目錄,這種情況讀寫操作就會跳過容器存儲層,直接對宿主機(或網絡存儲)發生讀寫,其性能和穩定性更高,容器刪除或者重新運行之后,數據也不會丟失。

倉庫(repository)

  鏡像構建完成后,可以很容易的在當前宿主機上運行,但是,如果需要在其它服務器上使用這個鏡像,我們就需要一個集中的存儲、分發鏡像的服務,Docker Registry 就是這樣的服務。一個 Docker Registry 中可以包含多個倉庫( Repository );每個倉庫可以包含多個標簽( Tag );每個標簽對應一個鏡像。通常,一個倉庫會包含同一個軟件不同版本的鏡像,而標簽就用於區分軟件的不同版本。我們可以通過 <倉庫名>:<標簽> 的格式來指定具體是這個軟件哪個版本的鏡像。如果不給出標簽,將以 latest 作為默認標簽。以nginx為例,docker pull nginx:1.14就是指定下載nginx的1.14版本,docker pull nginx就是直接下載最新的版本。

  Docker Registry 公開服務是開放給用戶使用、允許用戶管理鏡像的 Registry 服務。一般這類公開服務允許用戶免費上傳、下載公開的鏡像,並可能提供收費服務供用戶管理私有鏡像。最常使用的 Registry 公開服務是官方的 Docker Hub,這也是默認的 Registry,並擁有大量的高質量的官方鏡像。除此以外,還有 CoreOS 的 Quay.io,CoreOS 相關的鏡像存儲在這里;Google 的 Google Container Registry,Kubernetes 的鏡像使用的就是這個服務。由於某些原因,在國內訪問這些服務可能會比較慢。國內的一些雲服務商提供了針對 Docker Hub 的鏡像服務( Registry Mirror ),這些鏡像服務被稱為加速器。常見的有阿里雲加速器、DaoCloud 加速器等。后面的docker安裝博客中會提到加速器的使用。

  除了使用公開服務外,用戶還可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 鏡像,可以直接使用做為私有 Registry 服務。開源的 Docker Registry 鏡像只提供了 Docker Registry API 的服務端實現,足以支持 docker 命令,不影響使用。但不包含圖形界面,以及鏡像維護、用戶管理、訪問控制等高級功能。在官方的商業化版本 Docker Trusted Registry 中,提供了這
些高級功能。除了官方的 Docker Registry 外,還有第三方軟件實現了 Docker Registry API,甚至提供了用戶界面以及一些高級功能。比如,Harbor 和 Sonatype Nexus。一般企業都會選擇自己搭建 Docker Registry,相比會更加安全些。具體后面也會講。

五、docker運行流程

  如下圖所示,運行一個容器的過程:

  1. 去registry中拉取鏡像,如果本地已經存在,則直接使用本地鏡像
  2. 根據鏡像創建容器
  3. 給容器分配文件系統,並在最上層掛載一個可讀寫層。
  4. 分配網絡接口,創建一個允許容器和宿主機訪問得網絡接口
  5. 運行指定的程序
  6. 收集容器的運行狀態

六、docker底層技術

Namespaces

  1. PID Namespace:不同容器的進程就是通過PID Namespace隔離的,每個容器中都會有PID為1的進程,每個容器中的進程都是docker daemon的子進程。

  2. Mnt Namespace:隔離文件系統掛載點。每個容器能看到不同的文件系統層次結構。

  3. User Namespace:隔離用戶ID和組ID。每個容器都有自己的 user 和 group ID,可以跟宿主機的不同,宿主機中的非特權用戶可以成為容器內的特權用戶。

  4. Net Namespace:每個容器用有其獨立的網絡設備,IP 地址,IP 路由表,/proc/net 目錄等等。docker默認采用 veth 的方式將容器中的虛擬網卡同host上的一個docker bridge: docker0連接在一起。

  5. UTS Namespace:UTS Namespace允許每個容器擁有獨立的hostname和domain name,使其在網絡上可以被視作一個獨立的節點而非宿主機上的一個進程。

  6. IPC Nampspace:每個容器有其自己的 System V IPC 和 POSIX 消息隊列,因此,只有在同一個 IPC namespace 的進程之間才能互相通信。

Control groups

  把系統級的資源分成多個組,然后把組內的資源分配到用戶空間的進程上去。cgroups可以限制以下九大資源:

  • blkio:設置限制每個塊設備的輸入輸出控制。例如:磁盤,光盤以及usb等等。
  • cpu:使用調度程序為cgroup任務提供cpu的訪問。
  • cpuacct:產生cgroup任務的cpu資源報告。
  • cpuset:CPU核心的分派 。CPU有兩種分配方式,按比例和按核數。
  • devices:允許或拒絕cgroup任務對設備的訪問。
  • freezer:暫停和恢復cgroup任務。
  • memory:設置每個cgroup的內存限制以及產生內存資源報告。
  • perf_event:對cgroup中的任務進行統一性能測試。
  • net_cls:標記每個網絡包以供cgroup方便使用。

Union file systems

  Docker Engine 使用Union FS為容器提供構建模塊(使用此技術實現聯合掛載),Docker Engine 可以使用多種不同的Union FS技術,包括AUFS、btrfs、vfs和DeviceMapper。鏡像從registry中拉下之后會存儲在本地一個專門存儲鏡像的空間中,這個存儲空間需要是特殊而且專用的文件系統,Ubuntu系統下默認使用的是AUFS (advanced multi-layered unification filesystem) ;而在Centos7上新版docker使用的是overlayFS(自從OverlayFS加入kernel主線后,它在kernel模塊中的名稱就被從overlayfs改為overlay了。但是為了在本文中區別,我們仍使用OverlayFS代表整個文件系統)。overlayFS是一種二層抽象的文件系統,早期的overlay和現在的overlay2就是overlayFS的存儲驅動,它需要建構在宿主機的文件系統之上,如下:

[root@docker1 ~]# cat /etc/redhat-release 
CentOS Linux release 7.4.1708 (Core) 
[root@docker1 ~]# uname -r
3.10.0-693.el7.x86_64
[root@docker1 ~]# docker info
Server Version: 18.09.6
Storage Driver: overlay2
 Backing Filesystem: xfs


參考資料


寫作不易,轉載請注明出處,謝謝~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM