01 . Docker原理部署及經常使用操做命令

Docker的來源及構造:

容器是一種基礎工具:泛指任何用於容納其餘物品的工具,能夠部分或徹底封閉,被用於容納,儲存,運輸物品: 物品能夠被放置在容器中,而容器能夠保護內容物:前端

人類使用容器的歷史有十萬年,甚至可能有數百萬年的歷史:java

#   容器類型:
     #     瓶,罐,箱,籃,桶,袋

但咱們重點在LXC這裏;node

虛擬化和容器的關係:linux

主機級虛擬化:虛擬化的是整個完整的物理硬件平臺,好比VMware,KVM.裏面跑的是與宿主機不同的系統nginx

兩種類型:
類型一: 直接在硬件上裝一個虛擬機管理器,不裝宿主機,在虛擬機管理器上跑須要的操做系統:
類型二: Vmware,kvm
完整意義的操做系統: 咱們本身在上面裝一個內核,內核上面有一個用戶空間,用戶空間裏面跑進程。web

可是運行內核並非咱們主要目的,內核核心做用在於資源分配和管理。redis

就是說真正在應用空間跑的應用程序纔是能產生生產力的,就比如咱們跑一個web服務,內核其實不多提供服務。sql

而出於通用目的的而設計的資源管理平臺,操做系統管理內核。咱們並不太須要:docker

可是內核也不得不有,緣由在於要想在一組硬件平臺跑軟件程序,而如今的軟件都是針對於內核調用和系統調用,庫調用研發的,而不安裝這些無法運行程序,因此內核看上去沒多大用,可是也必不可少;shell

更況且,咱們一旦有了用戶空間後,裏面運行不少進程,這些進程爲了協調也須要內核。

但假設咱們建立一個虛擬機,只爲了運行一個nginx,tomcat,卻不得不去安裝內核,用戶空間,再去跑tomcat,代價就有點大了。

而在這裏若是咱們用二級虛擬化來分析的話:

若是爲了運行一個進程,就要實現兩級調度和資源分派。

第一,本身虛擬機有一個內核,已經實現了一次內存虛擬化,cpu調度以及IO調度和io 管理。

可是真正虛擬機也是被宿主機內核管理一次,這個中間浪費能夠想一下。

傳統的主機虛擬化技術,確實能讓咱們一組硬件平臺之上實現跨系統傳進的隔離和試驗,調試,資源高效利用。而帶來的資源開銷不容忽視的,而不少時候,咱們建立虛擬機只是爲了運行一個和幾個附有生產責任的進程而已,爲此;

減小中間層就是一個好的辦法,

好比在二級虛擬化咱們把虛擬機那一層給抽掉,只保留進程,可是咱們加虛擬機就是爲了環境隔離,好比說一臺機器跑兩個或者五個nginx,咱們一臺機器沒有那麼多套接字和80端口。

而咱們虛擬機就是爲了資源隔離,就算把裏面的nginx翻江倒海,壞的也是哪個虛擬機。

因此這裏的隔離纔是咱們的目標,咱們雖然想抽掉這一層內核,可是不能讓他回到在一個鍋裏吃飯那個環境,因此要讓每個組進程互相不可干擾的,只不過共享一個底層資源而已。

所以咱們想要的環境就是:

建立一個又一個隔離環境,咱們要運行隔離的程序就讓他跑在隔離環境中,內核提供的是內核空間,進程試運行在用戶空間,而這裏就能實現將用戶空間隔離成多個用戶空間,互不干擾,這裏通常都有一個空間是有特權的,通常第一個。而這裏衆多用戶空間運行的都是同一個內核,被同一個內核管理的。可是運行時候能看到的邊界只能是當前用戶空間的邊界,雖然沒有主機級虛擬化隔離那麼完全。

更重要是,這個用戶空間放進程,給進程提供運行環境,而且保護內部進程不被其餘進程所幹擾.叫作容器.

虛擬的隔離環境管理器

一層硬件平臺容器不是什麼新概念,最先出如今2000年,當年叫jail,監獄,監禁之意,裏面就像一個沙箱,就算裏面那個程序bug,有了故障,異常行爲,也沒法影響這個容器以外的程序運行,這也是jail初衷。

容器並不是起源於 Linux,但開源世界的最精彩之處就在於借鑑、修改和改進,容器也不例外.

但這個概念很是有吸引力。

2001 年,經過 Jacques Gélinas 的 [VServer 項目,]隔離環境的實施進入了 Linux 領域。正如 Gélinas 所說,這項工做的目的是「在高度獨立且安全的單一環境中運行多個通用 Linux 服務器 [sic]。」 在完成了這項針對 Linux 中多個受控制用戶空間的基礎性工做後,Linux 容器開始逐漸成形並最終發展成瞭如今的模樣。

通常來說,就算一個程序被遠程劫持在裏面搞起破壞,他的邊界也僅僅是哪一個容器的邊界,最初只是爲了應用的安全運行。

後來有人把這個技術山寨到Linux平臺上,叫Vserver(chroot),在一個子目錄定義一個根,讓裏面的程序覺得他就是根。

chroot他能實現的你看上去的那層空間,底層仍是同一個內核,進程運行是特權模式仍是普通模式,表面很簡單,真正實現起來涉及東西至少要有;

在一個單獨用戶空間當中,它主要目的是隔離使用,要讓裏面進程覺得他就運行在底層內核之上,有六點:

# 1. 主機名和域名: UTS
# 2. 根文件系統 :           MOUNT
# 3. 應該有本身的IPC,進程間的專用通道,若是能讓兩個用戶空間進程能互相通訊,也沒有意義了,共享內存,拒絕跨用戶空間。 IPC
# 4. 給每一個用戶空間作一個假的init,只能有一個,pid,1,每一個系統正常來講只有一個,爲了隔離,給每一個空間假裝一個。
# 5. 必須給每一個用戶假裝一個root,實現效果就是在真正系統只是普通用戶,在他所屬用戶空間裏面能夠隨心所欲,讓進程看起來是root.
# 6. IP地址,互相通訊,而在內核級別,tcp協議棧只有一個,

爲了容器機制的實現,Linux內核對着六種明成空間原生支持,namespaces。直接經過系統調用對外進行輸出,

直到今天,所謂的容器就是靠六個namespaces和chroot來實現的。

聽上去容易,這六種名成空間有一個是到內核3.8才實現的,因此要想完美使用容器,要內核版本3.8以上。centos6自然排除在外.

namespace 系統調用參數 隔離內容 內核版本
UTS clone_newuts 主機名和域名 2.6.19
IPC clone_newipc 信號量、消息隊列和共享內存 2.6.19
PID clone_newpid 進程編號 2.6.24
Network clon_newnet 網絡設備、網絡棧、端口等 2..29
Mount clone_newns 掛載點(文件系統) 2.4.19
User clone_newuser 用戶和用戶組 3.8

容器級虛擬化:

資源限制: 咱們能夠在總體資源作比例性分配,也能夠在單一用戶空間作核心綁定,你只能使用幾個核;否則的話一個進程內存泄露整個系統都蹦了;或者一個進程佔用了絕大部分CPU.

內存是壓縮不了的,多一點都不能,一給就收不回來了,由於內存是壓縮不了的;

實現這個Control Cgroups

blkio:  		# 塊設備IO
cpu: 			# CPU
cpuacct:  		# CPU資源使用報告
cpuset:   		# 多處理器平臺上的cpu集合
devices:  		# 設備訪問
freezer:   		# 掛起或恢復任務
memory:  		# 內存用量及報告
perf_event: 		# 對cgroup中的任務進行統一性能測試
net_cls:  		# cgroup中的任務建立的數據報文的類別;

劃分紅組後,在不一樣組內進行資源分配,組還能夠再分。

即便有了chroot,nameespaces, control cgroups,容器的隔離能力比起主機級別虛擬化依然差不少,由於容器畢竟屬於同一個內核,而主機級虛擬化那麼好,由於內核原本就是自然的隔離,所以爲了增強安全性,防止裏面的進程經過漏洞繞過邊界伸到別的用戶空間,經過selinux各類安全機制增強容器的邊界,爲了支撐容器作的更加完善。

容器實現就是靠chroot,nameespaces,cgroups核心技術實現,而這些在內核已經實現了。

容器原本是靠jail啓發有了vserver,後來爲了讓這種容器更加易用,

由於建立容器要本身寫代碼,系統調用,克隆等來實現的,但麻煩程度很大。

因此咱們最好把實現容器的這種功能作成一種工具,極大的簡化容器的使用,因而就有了LXC的解決方案,

LXCx container,最先一批真正把完整的容器技術用一組簡易使用的工具和摸板來極大的簡化了容器的使用方案。

lxc-create : 建立一個容器,template,摸板一組腳本,

建立一個明成空間後,這腳本自動執行後,自動實現安裝過程,指向了你所打算建立哪一類明成空間的系統發行版所屬的倉庫,從倉庫中鏡像下載過來,安裝,生成這個新的名成空間,就能夠像虛擬機同樣使用。

全部的明成空間都這樣實現,而lxc就靠這樣這一組工具包快速實現建立空間,利用模板完成內部所須要各類文件的安裝,同時還有些工具能夠經過chroot切換來切換去,因而咱們就能夠愉快的使用了,跟虛擬機沒多大區別;

lxc在容器技術推廣絕對功不可沒,但依然有很高門檻:

# 1. 學好lxc命令
# 2. 必要時候須要定製模板,
# 3. 若是在裏面運行Mysql,若是服務在裏面出現故障,如何遷移數據;
# 4. 批量建立也不容易

雖然極大的簡化了容器使用,可是在複雜程度沒有多大下降的,更況且他的隔離性沒有虛擬機那麼好,

好處是性能資源方面的節約,讓每個進程直接使用宿主機的性能。

因而後來出現了docker:

lxc加強版,也不是容器,容器的一個易用前端工具。

lxc批量建立挺難,docker就在這個上面找突破點,docker早期核心就是lxc,他是lxc的二次封裝發行版。

功能上利用lxc作容器管理引擎,建立容器時再也不使用模板安裝,而是使用一種鏡像技術,

咱們嘗試着把一個操做系統用戶空間所須要用到的所須要全部組件事先準備編排好,編排好後總體打包成一個文件,叫作鏡像文件,這個鏡像文件是放在一個集中統一的倉庫中的,我把你們都會用到的最小化centos,ubuntu分別放在倉庫內;

而在這裏咱們在這個最小化系統裏面先裝好源碼nginx,再打包成一個鏡像,也放入這個倉庫中,當啓動建立容器時候,需用鏡像,把鏡像拖到本地,基於鏡像啓動容器。因此docker極大的簡化了容器使用程度;

好比說你想跑一個tomcat,nginx直接docker run就完成了

爲了易於管理,docker還採用另一種方式,在一個用戶空間當中,咱們嘗試只運行一組進程或一個進程,咱們目的就是爲了運行一個有生產力的程序,好比咱們在主機上要跑tomcat,nginx,nginx運行在nginx容器中,tomcat運行在tomcat容器中,兩者用容器間通訊邏輯進行通訊,因此之後一個容器只運行一個進程,這也是docker的目的;

lxc就是當虛擬機使用,到時候管理極爲不便;

而docker這裏實現功能:

不用容器,一個內核之上運行各類進程 ,你們屬於同一個用戶空間,共享同一組主機名,用戶,ipc,pid,在同一個可視範圍內,若是一個黑客劫持一個進程以他作跳板能夠威脅到其餘進程

而docker,把他們給圈起來了,彼此間不可見,並且這個容器只爲了這一個進程,最小化定義的;
壞處,佔用更多空間,若是服務壞了,調試工具只針對一個容器有效,而若是加上調試工具違反了惟一進程目的,

因此帶來問題:原本調試一個進程極爲簡單,可能沒有工具:

而要想調試得突破他的邊界:

好處;刪除了不影響別人:

給運維帶來極大不便利,給開發帶來巨大好處,分發容易了,一次編寫處處運行。如今環境都是異構的,

centos5,6,7/Ubuntu/deepin/suse/kali/redhat/AIX

要開發一個軟件,要開發每一種平臺的軟件,各自組織一個團隊開發,只須要打包一個鏡像,無論你是windows,linux,unix跟內核不要緊,跟操做系統不要緊,他有本身的明成空間

跟java相似這種效果,可是java有不少版本,6,7,8

之前部署須要發佈,變動,故障處理

有了鏡像,直接one,就好了,可是還須要接路由器和調度器,若是有一個容器編排工具,之間run結束,甚至連run都不須要你手動執行;

像之前的java容器只能支持java一種語言;

而docker不會管你是什麼語言;

隨之帶來運維的問題,發佈操做用編排工具來實現,docker必需要使用編排工具來管理,不用的話手動管理比咱們直接管理應用程序更麻煩,增長咱們運維環境複雜度;但確實是下降開發壓力;

運維工做就是維穩,以往調試很容易,而容器可能沒有調試工具,這麼一來就意味着,我之後作鏡像須要爲每個鏡像自帶調試工具,這麼一來意味着作鏡像須要自帶一些工具,之前能共享的,如今不能,但他們倒是隔離的;

docker還有一個好處: 批量建立,他建立容器採用

分層構建,聯合掛載;使得咱們之後鏡像分發沒有那麼龐大,好比說我在一個系統上運行三個容器,都是基於底層centos構建,在這裏只用一個centos基礎鏡像,三個上層nginx,tomcat,mariadb,底層鏡像是共享的,底層鏡像是隻讀的,要想改,在每一層聯合掛載鏡像棧最頂層額外附加一個新層,這個層纔是能讀能寫的;

遷移很困難,若是要把容器遷移到其餘地方,但這裏是有狀態的,真正在使用容器時,不會在本地存儲有效數據,他會在文件系統上共享存儲,而用戶存儲數據,這個服務不當心宕掉了,再找一個主機從新數據加載就好了,再訪問數據還在,因此數據脫離宿主機,脫離容器而持久,容器能夠丟到任何主機上;

存儲須要一個外置持久性存儲,程序是由指令+數據組成,

把容器當進程使用,啓動一個容器,就是爲了運行一個進程,進程一終止,把容器刪了,不要了,下次從新建立,從新掛載

容器不須要持久,容器和進程同樣有生命週期,從建立而開始,從中止到結束,跟咱們主機都沒多大關係,能夠運行在任何主機上;

在docker之上建設一個層次,看那個主機更閒,來個調度法則,若是須要持久數據,給個web存儲空間,掛載上去存儲數據,一旦任務結束直接容器一刪,結束,這個組件能幫咱們把要啓動容器調度於整個底層集羣環境中某一個docker主機之上,當要構建lnmp,誰先啓動,docker就解決不來這種功能,咱們須要一個docker基礎之上,可以把這種應用程序依賴關係,從屬關係,隸屬關係反映在啓動關閉時的次序和管理邏輯中,這種功能叫容器編排工具;

# 在docker以後出現了各類編排工具,
machine+swarm+compose:    # compose只能單機編排,
mesos:    		  # 統一資源調度和分配的     + 實現編排鬚要加上  marathon
kubernetes  -- >  k8s

google使用容器有十幾年歷史了,聽說每一週銷燬和新建容器多達幾十億。

docker因緣巧合摸到了這個門道,而且作成開源軟件,谷歌就坐不住了,本身原本作爲獨門武器,那小子竟然找到一種辦法還公開全部人使用,原本我最有話語權,祕而不宣藏起來,這樣才能稱爲獨門武器,必要時候必殺技;

可是docker已然獨霸話語權了,好在docker也不是鐵板一塊,後來出來出來另外一個公司,谷歌就在後面大力扶植反對派,後來發現難以跟docker抗衡,上不來臺面;

容器編排工具在谷歌已經跑了十幾年了,該踩的坑都踩的差很少了;

docker三兩年作不到;

因而kubemetes橫空出世,佔據了百分八十的市場,成爲市場的標準,還成立了CNCF 容器標準組織,docker有一個問題,docker在編排上沒有經驗,義無建樹,技術沒走好,沒有吸引更多的土豪進來投資,上市作獨角獸,雖然互聯網上火的不要不要的,可是沒法變現,決定,把開源版拆分爲企業版和社區版,將社區更名,把docker流量引入企業版,後來更名叫moby,把全部docker引入企業版,

之因此這樣 docker是由於一家商業公司,谷歌在作k8s時候向你們代表我是沒有任何意圖的,因而把k8s源代碼捐給了cncf,cncf是由不少組織聯合成立的,主導權再也不屬於谷歌,屬於IMB,微軟等等,不會被人說想把k8s私有化,一年四個版本發佈,go研發的

後來docker研發了一個容器引擎,libcontainer,替換了lxc,docker已經被cncf挾持了,cncf本身玩,把docker排除在外,若是之後容器要走下去確定要開源,標準化,誰來負責標準化,cncf就能夠作,定義標準,但這樣太欺負docker了,因此給docker個機會,你來定標準化,同時作一款開源軟件。

如今新的docker引擎已是runC了,

雖然k8s支持不少種容器,但常見的仍是docker+k8s;

鏡像管理基礎

docker架構形式:只考慮單機之上,總體架構是這樣的:

總體是一個dockerhosts: docker server端

dockerhost 就是運行有docker進程(守護進程)的主機,被稱爲docerhost,dockerserver;

docker接收到建立和啓動容器命令後,將在本地建立容器,一個dockerhost上能夠啓動多個容器,此處咱們可能運行的分別不屬於各類不一樣程序的容器,而容器取決於鏡像來實現,若是本地沒有,dockerdaemon自動連接到registries上,然後從中得到鏡像後,先存儲到本地一個可以專門存儲所謂鏡像存儲空間中,要求得是特殊而且特殊的文件系統,overlay2,

1

這裏面可能有多個鏡像文件,鏡像自己是隻讀的,並且鏡像在registries放的時候倉庫名就是應用程序名,然後倉庫內能夠放多個鏡像,並且這些鏡像一般屬於同一個應用程序不一樣版本,咱們用標籤來識別;

docker鏡像:

含有啓動容器所須要的文件系統及其內容,所以,其用於建立並啓動docker容器:

採用分層構建機制,大致分爲兩層,最底層爲bootfs,其之爲rootfs

真正讓用戶拿來去構建用戶空間並運行進程容器的是rootfs;

bootfs: 用於系統引導的文件系統,包括bootloader和kernel ,容器啓動完成後會被卸載以節約內存資源

這裏的kernel僅僅用於引導並啓動一個用戶空間,啓動完以後就沒有了以節約內存資源,畢竟頗有可能咱們用戶空間跟底層內核仍是有一點不一樣之處的,向上就是rootfs了;

2

# rootfs: 位於bootfs之上,表現爲docker容器的根文件系統;
# rootfs:  位於bootfs之上,表現爲docker容器的根文件系統

傳統模式中,系統啓動時,內核掛載bootfs時會首先將其掛載爲只讀模式,完整性自檢完成後將其從新掛載爲讀寫模式;

docker中,rootfs由內核掛載爲「只讀」模式,然後經過「聯合掛載技術」額外掛載一個「可寫層」;

這裏的分層構建

咱們作一個apache鏡像,運行httpd鏡像,咱們頗有可能在一個底層的很是基礎系統鏡像之上一個純淨最小化centos版本,在他之上添加一個編輯器,至關於vim,除此以外添加一個httpd,每添加一個軟件都是一個獨立的層次,這裏是三層,底下bootfs那一層在容器啓動時,一旦被引導了完了rootfs時候再卸載並移除,不是刪除文件,而是從內存中移除;

而這時候底層只有三層,base image 用來構建一個系統基本組成,/bin;若是要用到額外一個工具,須要額外安裝;

可是對於咱們鏡像來說,底層鏡像是不會動的,額外安裝一個vim 他會在裏面額外生成一個vim 層,再裝個nginx,生成個nginx層;疊加在一塊兒掛載的,這三層都是隻讀的,所以,對於一個容器來說,僅能在writoble上能寫,並且若是刪除容器,writable也會被刪除;

含有啓動容器所須要的文件系統及其內容,所以,其用於建立並啓動docker容器:

採用分層構建機制,大致分爲兩層,最底層爲bootfs,其之爲rootfs

真正讓用戶拿來去構建用戶空間並運行進程容器的是rootfs;

bootfs: 用於系統引導的文件系統,包括bootloader和kernel ,容器啓動完成後會被卸載以節約內存資源

這裏的kernel僅僅用於引導並啓動一個用戶空間,啓動完以後就沒有了以節約內存資源,畢竟頗有可能咱們用戶空間跟底層內核仍是有一點不一樣之處的,向上就是rootfs了;

鏡像分層構建和聯合掛載依賴於文件系統的支撐

早起用到的是Aufs,高級多層統一文件系統:

最先被docker拿來用於實現聯合掛載的Linux文件系統,

aufs是以前的unionfs從新實現,重寫後依然很爛,三萬行代碼,一個ext4才四五千代碼,這是要被整合進內核的,所以被申請時,次次被拒絕,一直到不申請,aufs一直都不是內核中自有的文件系統,想用須要向內核打補丁,centos不會幹這種事情,由於他們以保守穩定爲初衷,ubuntu是很早一批把aufs打包進內核,早些時候想要使用docker需使用ubuntu.

aufs的競爭產品是overlayfs(),後者自從3.18版本纔開始被合併到linux內核;

docker的分層鏡像,除了aufs,docker還支持btrfs,devicemapper和vsf等;

docker默認是aufs; centos7用的是devicemapper;在試用聯合掛載不好,不穩定,由於它使用target driver;

比較成熟的支持的文件系統必需要可以是docker info當中的overlay2,xfs,overlay2是一種抽象的二級文件系統,他須要創建在本地文件系統之上;

構建鏡像時,鏡像作好以後,應該有一個統一存儲的位置,叫作doceker registry

啓動容器時,docker daemon會試圖從本地獲取相關的鏡像: 本地鏡像不存在時,將其從registry中下載該鏡像並保存到本地;

若是咱們沒有特別指定,那麼他就是registry,若是要指向別的registry咱們必須在鏡像的訪問路徑當中給明服務器地址;不然訪問默認的registry,除非咱們修改默認;
3

Docker Registry分類
# Registry用於保存docker鏡像,包括鏡像的層次結構和元數據
# 用戶可自建Registry,也可使用官方的docker  hub
分類:
# Sponsor Registry   第三方的registry,供客戶和docker社區使用           
# Mirror Registry        第三方的registry,只讓客戶使用            
# Vendor  Registry      由發佈docker 鏡像的供應商提供的registry提供給買了紅帽系統使用
# Private Registry      #  經過設有防火牆和額外的安全層的私有實體提供的registry 不消耗互聯網帶寬,尤爲是本地大規模容器自建本地registry;

OCI

由linux基金會於2015年6月創立
旨在圍繞容器格式和運行時制定一個開放的工業化標準
RunC: 不管是客戶端仍是服務端,都由docker一個程序提供,他有不少子程序,他能夠監聽在一個套件字之上;
docker有三種類型套接字,
docker啓動容器就是基於鏡像啓動,在鏡像基礎之上,爲一個容器建立一個專用可寫層;

containers:容器,

lmages: 鏡像  鏡像來自於Registry,註冊表,能夠稱爲docker的鏡像倉庫,默認就是docker hub,默認本地是沒有的,鏡像是分層構建的,因此下載到本地後,能夠共享多個上層鏡像使用,由於鏡像是隻讀的,因此啓動容器就是基於鏡像來啓動,在鏡像基礎上爲一個容器建立一個專用的可寫層,從而來啓動這個容器。

因此這裏鏡像也須要在docker本地存儲,所以這有專門的倉庫來放鏡像,而鏡像擁有幾十萬之多,因此放到一個公共的倉庫,須要時候拉取過來加載到本地,這裏的協議是http/https,默認是加密的,須要明肯定義成不安全才可使用;

docker的運行過程當中尤爲是建立容器時可能有一點慢,緣由是他要下載一次鏡像,取決於他的寬帶;

由於服務器在國外, 爲了能使加速訪問,docker在大陸這邊作了一個docker鏡像服務器,docker.cn,加速不太好,可使用阿里,科大,因此要想使用docker,必需要能接入到互聯網。

docker鏡像是分層構建的

倉庫:  一個docker擁有兩重功能,第一,他提供鏡像提供的倉庫,第二,他還提供用戶來獲取鏡像時的認證等功能,還提供了當前服務器全部可用鏡像的索引;

因此鏡像也會有應用到不一樣程序版本的鏡像,爲了讓鏡像跟應用程序版本有必定的關聯,給鏡像外面加了一個標籤,倉庫名+標籤才能惟一標識一個鏡像。若是隻給了倉庫名,那就是默認最新版;一個鏡像能夠有多個標籤,在倉庫名+標籤外面加上 stable最新版,穩定版什麼的;

鏡像是靜態的;

#       容器: 動態,生命週期,相似於程序;
#任何images,networks,volumes,plugins能夠支持增刪改查的,由於他們都是對象;
#       依賴的基礎環境:
#            64 bits CPU
#            Linux KERNEL  3.10+  CentOS6也支持docker,2.6.32,打了補丁;

若是咱們要是 就使用docker,若是咱們要使用在這的倉庫就下載docker,區別EE和CE;

Docker 從 1.13 版本以後採用時間線的方式做爲版本號,分爲社區版 CE 和企業版 EE,社區版是免費提供給我的開發者和小型團體使用的,企業版會提供額外的收費服務,好比通過官方測試認證過的基礎設施、容器、插件等。
社區版按照 stable 和 edge 兩種方式發佈,每一個季度更新 stable 版本,如 17.06,17.09;每月份更新 edge 版本,如17.09,17.10。

Docker的部署

初始化環境
init_security() {
systemctl stop firewalld
systemctl disable firewalld &>/dev/null
setenforce 0
sed -i '/^SELINUX=/ s/enforcing/disabled/'  /etc/selinux/config
sed -i '/^GSSAPIAu/ s/yes/no/' /etc/ssh/sshd_config
sed -i '/^#UseDNS/ {s/^#//;s/yes/no/}' /etc/ssh/sshd_config
systemctl enable sshd crond &> /dev/null
rpm -e postfix --nodeps
echo -e "\033[32m [安全配置] ==> OK \033[0m"
}
init_security

init_yumsource() {
if [ ! -d /etc/yum.repos.d/backup ];then
    mkdir /etc/yum.repos.d/backup
fi
mv /etc/yum.repos.d/* /etc/yum.repos.d/backup 2>/dev/null
if ! ping -c2 www.baidu.com &>/dev/null    
then
    echo "您沒法上外網,不能配置yum源"
    exit    
fi
    curl -o /etc/yum.repos.d/163.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo &>/dev/null
    curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo &>/dev/null
    yum clean all
    timedatectl set-timezone Asia/Shanghai
    echo "nameserver 114.114.114.114" > /etc/resolv.conf
    echo "nameserver 8.8.8.8" >> /etc/resolv.conf
    chattr +i /etc/resolv.conf
    echo -e "\033[32m [YUM Source] ==> OK \033[0m"
}
init_yumsource
安裝必要系統工具和軟件源
# 安裝一些必要的系統工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加軟件源信息
# docker 官方源
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 阿里雲源
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
安裝並啓動Docker-ce
# 安裝前能夠先更新 yum 緩存:
sudo yum makecache fast

# CentOS7安裝 Docker-ce
yum -y install docker-ce        # CentOS 中安裝
apt-get install docker-ce       # Ubuntu 中安裝
pacman -S docker                # Arch 中安裝
emerge --ask docker             # Gentoo 中安裝

# 若是想安裝特定版本的Docker-ce版本,先列出repo中可用版本,而後選擇安裝
yum list docker-ce --showduplicates |sort -r
Loading mirror speeds from cached hostfile
Loaded plugins: fastestmirror
Installed Packages
docker-ce.x86_64            3:19.03.4-3.el7                    docker-ce-stable
docker-ce.x86_64            3:19.03.4-3.el7                    @docker-ce-stable
docker-ce.x86_64            3:19.03.3-3.el7                    docker-ce-stable
docker-ce.x86_64            3:19.03.2-3.el7                    docker-ce-stable
docker-ce.x86_64            3:19.03.1-3.el7                    docker-ce-stable

yum install docker-ce-<VERSION STRING>
# 選擇安裝 docker-ce-18.06.1.ce
yum install docker-ce-18.06.1.ce

# Docker鏡像加速
# 沒有啓動/etc/docker目錄不存在,須要本身建立,docker啓動也會本身建立
# 爲了指望咱們的鏡像下載快一點,應該定義一個鏡像加速器,加速器在國內
mkdir /etc/docker
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}

# 啓動Docker後臺服務
systemctl start docker && systemctl enable docker
systemctl daemon-reload                 # 守護進程重啓

# 經過運行hello-world鏡像,驗證是否正確安裝了docker,或者經過查看版本
docker run hello-world
docker version
Client: Docker Engine - Community
Version:           19.03.4
API version:       1.40
Go version:        go1.12.10
Git commit:        9013bf583a
Built:            Fri Oct 18 15:52:22 2019
OS/Arch:           linux/amd64
Experimental:      false

CentOS/RHEL的用戶須要注意的事項

在 Ubuntu/Debian 上有 UnionFS 可使用,如 aufs 或者 overlay2 ,而 CentOS 和 RHEL 的內核中沒有相關驅動。所以對於這類系統,通常使用 devicemapper 驅動利用 LVM 的一些 機制來模擬分層存儲。這樣的作法除了性能比較差外,穩定性通常也很差,並且配置相對復 雜。Docker 安裝在 CentOS/RHEL 上後,會默認選擇 devicemapper ,可是爲了簡化配置, 其 devicemapper 是跑在一個稀疏文件模擬的塊設備上,也被稱爲 loop-lvm 。這樣的選擇是 由於不須要額外配置就能夠運行 Docker,這是自動配置惟一能作到的事情。可是 loop-lvm 的作法很是很差,其穩定性、性能更差,不管是日誌仍是 docker info 中都會看到警告信 息。官方文檔有明確的文章講解了如何配置塊設備給 devicemapper 驅動作存儲層的作法,這 類作法也被稱爲配置 direct-lvm 。

除了前面說到的問題外, devicemapper + loop-lvm 還有一個缺陷,由於它是稀疏文件,所 以它會不斷增加。用戶在使用過程當中會注意到 /var/lib/docker/devicemapper/devicemapper/data 不斷增加,並且沒法控制。不少人會但願刪 除鏡像或者能夠解決這個問題,結果發現效果並不明顯。緣由就是這個稀疏文件的空間釋放 後基本不進行垃圾回收的問題。所以每每會出現即便刪除了文件內容,空間卻沒法回收,隨 着使用這個稀疏文件一直在不斷增加。 因此對於 CentOS/RHEL 的用戶來講,在沒有辦法使用 UnionFS 的狀況下,必定要配置 direct-lvm 給 devicemapper ,不管是爲了性能、穩定性仍是空間利用率。 或許有人注意到了 CentOS 7 中存在被 backports 回來的 overlay 驅動,不過 CentOS 裏的 這個驅動達不到生產環境使用的穩定程度,因此不推薦使用。

標準化開發測試和生產環境

對於大部分企業來講,搭建PaaS既沒有那個精力,也沒那個必要,用Docker作我的的sandbox用處又小了點。能夠用Docker來標準化開發、測試、生產環境。

Docker佔用資源小,在一臺E5128G內存的服務器上部署100個容器都綽綽有餘,能夠單獨抽一個容器或者直接在宿主物理主機上部署samba,利用samba的home分享方案將每一個用戶的home目錄映射到開發中心和測試部門的Windows機器上。

針對某個項目組,由架構師搭建好一個標準的容器環境供項目組和測試部門使用,每一個開發工程師能夠擁有本身單獨的容器,經過 docker run -v 將用戶的home 目錄映射到容器中。須要提交測試時,只須要將代碼移交給測試部門,而後分配一個容器使用 -v加載測試部門的 home目錄啓動便可。這樣,在公司內部的開發、測試基本就統一了,不會出現開發部門提交的代碼,測試部門部署不了的問題。

測試部門發佈測試經過的報告後,架構師再次檢測容器環境,就能夠直接交由部署工程師將代碼和容器分別部署到生產環境中了。這種方式的部署橫向性能的擴展性也極好。

Docker鏡像使用

管理命令

Docker  --help
  container   管理容器
  image       管理鏡像
  network     管理網絡
命令:
  attach      介入到一個正在運行的容器
  build       根據 Dockerfile 構建一個鏡像
  commit      根據容器的更改建立一個新的鏡像
  cp          在本地文件系統與容器中複製 文件/文件夾
  create      建立一個新容器
  exec        在容器中執行一條命令
  images      列出鏡像
  kill        殺死一個或多個正在運行的容器    
  logs        取得容器的日誌
  pause       暫停一個或多個容器的全部進程
  ps          列出全部容器
  pull        拉取一個鏡像或倉庫到 registry
  push        推送一個鏡像或倉庫到 registry
  rename      重命名一個容器
  restart     從新啓動一個或多個容器
  rm          刪除一個或多個容器
  rmi         刪除一個或多個鏡像
  run         在一個新的容器中執行一條命令
  search      在 Docker Hub 中搜索鏡像
  start       啓動一個或多個已經中止運行的容器
  stats       顯示一個容器的實時資源佔用
  stop        中止一個或多個正在運行的容器
  tag         爲鏡像建立一個新的標籤
  top         顯示一個容器內的全部進程
  unpause     恢復一個或多個容器內全部被暫停的進程

Docker服務管理

service docker start       # 啓動 docker 服務,守護進程
service docker stop        # 中止 docker 服務
service docker status      # 查看 docker 服務狀態

chkconfig docker on        # 設置爲開機啓動
systemctl stop docker
systemctl start docker 
systemctl enable docker
systemctl daemon-reload    # 守護進程重啓

鏡像管理

獲取鏡像
# 鏡像能夠看作咱們平時裝系統的鏡像,裏面就是一個運行環境
# Docker Hub上有大量的高質量鏡像能夠用,這裏就說一下怎麼獲取這些鏡像,
# 從鏡像倉庫獲取鏡像的命令是docker pull,其命令格式爲:
docker pull [選項]  [Docker Registry 地址[:端口號]/]倉庫名[:標籤]

docker search centos                            # 搜索docker官方提供的centos鏡像
docker search centos --filter=stars=100         # 查找stars數至少爲100的鏡像
docker pull centos                              # 默認從官網拉取
docker pull centos:7.7.1908                     # 默認拉取centos8,須要指定版本才能下載7.
docker pull daocloud.io/library/centos          # 從daocloud拉取
docker dao pull centos                          # 從daocloud拉取,國內倉庫

注意

咱們使用docker image ls時候會發現,鏡像體積的所佔用空間在Docker Hub上看到的鏡像大小不一樣,好比nginx鏡像在docker hub官網上是50多兆,而把他pull下來就變成一百多兆了,這是由於docker hub所顯示大小是網絡傳輸中更關心的流量大小,而docker image ls顯示的是鏡像下載到本地展開後的各層所佔空間的綜合,由於鏡像下載到本地後,更關心的是磁盤空間佔用的大小.

另外一個須要注意問題是,docker image ls列表中的鏡像體積綜合並不是是全部鏡像實際硬盤消耗,因爲Docker鏡像是多層存儲結構,而且能夠繼承、複用,所以不一樣鏡像可能由於使用相同的基礎鏡像,從而擁有共同的層,因爲Docker使用UnionFS,相同的層只須要保存一份便可,所以實際佔用硬盤空間極可能比這個列表鏡像大小的總和小的多.

查看鏡像
docker system df				# 查看鏡像、容器、數據卷所佔用的空間.
docker images                                   # 查看已下載的鏡像
docker rm image_id                              # 刪除鏡像,指定鏡像id
docker images                                   # 查看已下載的鏡像
docker images -q                                # 只查看全部鏡像的id
docker inspect imageID                          # 查看鏡像詳情
刪除鏡像
docker rm image_id                              # 刪除鏡像,指定鏡像id
docker rmi RepositoryName --force               
# 刪除鏡像,指定鏡像名,<倉庫名>:<標籤> --force鏡像在使用中強制刪除
# 若是鏡像正在被未運行的容器使用,則須要強制刪除,可是若是正在被運行的容器使用,則強制刪除也沒法刪除

docker image ls -a			
# 這樣會看到不少無標籤的鏡像,這些無標籤鏡像不少都是中間層鏡像,
# 是其餘鏡像所須要依賴的鏡像,這些無標籤鏡像不該該刪除,不然會致使上層鏡像由於缺失依賴而出錯,
# 實際上也不必刪除,由於相同的層只會存一遍,而這些鏡像是別的鏡像的依賴,
# 所以並不會由於他們被列出來而多存了一份,不管如何你也會須要他們,
# 刪除那些依賴他們的鏡像,這些中間層鏡像也會被連帶刪除.

# 刪除全部倉庫名爲redis的鏡像:
docker image rm $(docker image ls -q redis)

# 刪除全部鏡像
# none 默認爲 docker.io
docker rmi $(docker images | grep none | awk '{print $3}' | sort -r)
docker rmi $(docker images -q)

容器管理

啓動容器有兩種方式,一種基於鏡像新建一個容器並啓動,另一個是將在終止狀態(stopped)的容器從新啓動.

由於docker的容器過輕量級了,不少時候用戶都是隨時刪除和重建.

建立容器
# 容器就像是一個類的實例(好比一個基於CentOS7鏡像啓動的虛擬機)
# 鏈接進行進入命令行模式,exit命令退出。
docker run -t -i nginx:latest /bin/bash
-i                      # 交互式操做,讓容器的標準輸入保持打開.
-t                      # 讓docker分配一個僞終端(pseudo-tty)並綁定到容器的標準輸入上
nginx:latest            # 基於centos構建的nginx鏡像
/bin/bash               # 放在鏡像後的命令,這裏咱們但願有個交互式shell,所以用的是/bin/bash
# 當咱們基於鏡像啓動一個實例的時候,此時他就是容器了.
# 就比如CentOS7.iso鏡像和已經運行了的CentOS7虛擬機同樣.

# 同一個鏡像能夠啓動多個容器  
# 建立運行容器且鏈接到容器  
docker run -it --rm -d --cidfile="id.txt" centos /bin/bash  
-i                            # 捕獲標準輸入輸出,保持交互式的意思  
-t                            # 分配一個終端或控制檯,每個控制檯都要伴隨一個shell  
--rm  # 退出時就刪除該容器,默認狀況下,每一個容器在退出時,他的文件系統會保存下來,這樣一方面有利於調試,
# 由於能夠經過查看日誌等方式來肯定最終狀態;另外一方面,也能夠報錯容器所產生的數據,  
# 若是僅僅須要短暫的運行一個容器,且不須要保存容器中的數據,
# 就能夠在exit容器時自動清理掉容器及產生的數據,但此選項不能與-d共用  
/bin/bash                     # 容器運行起來以後運行的程序,也能夠是任何的命令,/bin/echo  hello  
--cidfile                     # 指定容器運行以後container長id的存放文件位置
-d			      # 若是不使用-d參數運行容器,容器會把輸出的結果(STDOUT)打印到宿主機上面,
# 若是使用了-d參數會返回一個id,也能夠經過docker ps 查看容器信息.
# 要獲取容器的輸出信息,能夠經過docker container logs命令查看
# 容器可否長久運行是和docker run指定的命令有關,和-d參數無關.

當利用docker run來建立容器時,Docker在後臺運行的標準操做包括:

# 1. 檢查本地是否有指定的鏡像,不存在就從公有倉庫下載
# 2. 利用鏡像建立並啓動一個容器
# 3. 分配一個文件系統,並在只讀的鏡像層外面掛載一層可讀寫層.
# 4. 從宿主主機配置的網橋接口中橋接一個虛擬接口道容器中去.
# 5. 從地址池中配置一個ip地址給容器.
# 6. 執行用戶指定的應用程序.
# 7. 執行完畢後容器被終止.
Docker容器服務管理
docker start my-nginx                       # 啓動一個已經存在的容器  
docker restart my-nginx                     # 重啓容器  
docker stop my-nginx                        # 中止運行一個容器  
docker kill my-nginx                        # 殺死一個運行中的容器  
docker rename my-nginx new-nginx            # 重命名容器  
docker rm new-nginx                         # 刪除容器
docker stop $(docker ps -q) & docker rm $(docker ps -aq) # 停掉全部容器並刪除
docker container prune			    # 刪除全部處於終止狀態的容器.
docker logs [containerID/Names]             # 查看日誌
docker logs my-nginx                        # 查看 my-nginx 容器日誌

# 使用docker exec命令進入一個已經在運行的容器
docker exec -it [containerID/Names] /bin/bash    # 進入容器
docker attach 7968b44369    # 會附加該容器的標準輸出到當前命令行   
    
# 啓動狀態的容器,執行任務   
# 經過exec命令能夠建立兩種任務:後臺型任務和交互型任務   
# 後臺型任務:docker exec -it test /bin/bash   
# 交互型任務:docker attach 7968

docker run centos echo "hello world"             # 在docker容器中運行hello world!
docker run centos yum install -y wget            # 在docker容器中,安裝wget軟件
docker ps                                        # 列出包括未運行的容器
docker ps -a                                     # 查看全部容器(包括正在運行和已中止的)
docker ps -a -q                                  # 查看全部容器的ID
docker ps -s                                     # 查看容器使用了多少內存
docker ps -qf status=running                     # 查看某種狀態的容器ID
docker ps -l                                     # 列出最近一次啓動的容器
docker inspect  7657b3785bcf      
# 查看容器詳細配置信息,包含容器名,環境變量,運行命令,主機配置,網絡配置,數據卷配置等,json格式;
docker inspect -f {{.State.Pid}} 44fc0f0582d9    # 獲取id爲 44fc0f0582d9 的PID進程編號
docker inspect --format  '{{.Config.Image}}' 7657b3485    # 獲取當前運行鏡像版本
docker inspect --format='{{.NetworkSettings.IPAddress}}' 7657b3485    # 獲取當前運行鏡像的IP地址
# 打印該容器輸出
docker run -it -d --name test centos /bin/bash -c "while true; do echo hello world;sleep 2;done"
docker logs test
# 監控容器運行
docker logs container_id/container_name
--tail:            # 選項能夠指定查看最後幾條日誌
-t:                # 選項則能夠對日誌條目附加時間戳
-f:                # 選項能夠跟蹤日誌的輸出,直到手動中止

# 運行遠程機器上的容器
docker run -it -d -h 39.108.140.0 daocloud.io/centos:7

# 斷開容器
# 斷開與容器的鏈接,而且關閉容器
[root@7968b4436989 /]# exit
[root@7968b4436989 /]# docker stop 7968b443

# 只斷開和容器的鏈接而不關閉容器
# 快捷鍵: ctrl+p+q

# 關閉運行中的容器
# 若是此時有其餘終端正在對他進行交互會自動中斷
# docker stop contrainer_id/name        //發送SIGTERM信號,可忽略,15信號
# docker kill contrainer_id/name        //發送SIGKILL信號,9信號
容器的導入導出
# 導出容器
# 鏡像打包
# 方案一: export
#    利用export把正在運行的容器直接導出爲tar包的鏡像文件,能夠用-o或>
docker run --name my-nginx -d -p 8080:80 some-centent-nginx:1.2
docker export my-nginx > youmen_nginx.tar  &&  docker export -o youmen_nginx.tar my-nginx
scp youmen_nginx.tar 120.77.248.31:
docker import youmen_nginx.tar
docker tag 121d8 mynginx:1                            # 設置鏡像名字
docker import youmen_nginx.tar mynginx:1.1            # 導入時即設置鏡像名字

方案二: 利用save直接把鏡像打包出來
docker save -o suibian.tar library/centos:latest
scp suibian.tar 192.168.135.161:
docker load < suibian.tar                # 導入以後使用原名

# 導入也能夠經過指定URL或者某個目錄來導入
docker import http://example.com/exampleimage.tgz example/imagerepo

------------------------------------區別介紹-------------------------------------
# docker save:將一個鏡像導出爲文件,保存的是該鏡像的全部歷史記錄;
# docker export:將一個容器導出爲文件,保存的是容器當時的狀態,即容器快照;
# docker load:將鏡像存儲文件導入到本地鏡像庫;
# docker import:導入一個容器快照到本地鏡像庫;

docker save和docker export之間的區別:
    1> docker save是將鏡像保存爲tar包,且會保存該鏡像的父層、標籤、全部歷史等信息;
       docker export是將容器文件系統保存爲tar包,僅僅保存的是容器當時的狀態(快照);
    2> docker save能夠同時指定多個鏡像名稱;docker export只能指定一個容器名稱;
    3> docker save保存的鏡像文件tar包使用docker load命令加載還原;
       docker export保存的容器快照tar包使用docker import命令導入還原;
    4> docker save保存的tar包文件一般比docker export導出的文件要大;

docker load和docker import之間的區別:
    1)docker load將鏡像存儲文件導入到本地鏡像庫;docker import將容器快照文件導入到本地鏡像庫;
    2)docker load不能指定url;而docker import能夠指定url來進行導入;

容器服務管理及開機啓動設置

# Docker容器開機啓動設置
sudo docker run --restart=always -it centos /bin/bash
--restart=always # 默認狀況下docker重啓以後全部容器會被關閉,這個選項的意思是容器隨docker engine自啓動
# 若是建立時候未指定--restart=always,可經過docker  update命令設置:
docker update --restart=always  7b5f30fe77c0    

# 注意Docker服務開啓啓動
# restart參數介紹
# no:容器退出時候,不重啓容器
# on-failure: 只有在非0狀態退出時才從新啓動容器
# always:不管退出狀態是如何,都重啓容器
# unless-stopped: 在容器退出時老是重啓容器,可是不考慮在Docker守護進程啓動時就已經中止了的容器
# 在使用on-failure策略時,指定Docker將嘗試從新啓動容器的最大次數;
# 默認狀況下,Docker將嘗試永遠從新啓動容器
# sudo docker run --restart=on-failure:5  <image>
相關文章
相關標籤/搜索