本文在我的技術博客不一樣步發佈,詳情可猛戳
亦可掃描屏幕右側二維碼關注我的公衆號,公衆號內有我的聯繫方式,等你來撩...java
上週對象忽然心血來潮說想養個小寵物,我問想養啥她又說隨便,你看着辦!!!這我真的比較難辦啊!可是我們程序員能有個對象就不錯了,還不趕忙寵着,我只能照辦咯!mysql
我去到了一家寵物店,半天也沒有找到合適的目標。正在我猶豫彷徨之時,看到了老闆門口魚缸裏面的金魚游來游去還挺順眼!因而我問老闆
我:老闆,金魚多少錢?
老闆:加魚缸一塊兒100塊錢不講價!
我:這...便宜一點咯!
老闆:小夥子看你骨骼驚奇,定是個養魚的奇才,2塊錢賣給你吧!可是魚缸可不能給你!
我:那,你幫我打包一條吧,幫我拿個袋子裝着就行了!linux
因而我興高采烈的拎着小金魚就回家了,找了個大罐子養着!對象看到我買的小金魚後露出了幸福的笑容~
次日早上對象把我從睡夢中搖醒:「嚶嚶嚶,人家的小魚動不了了,你賠~~~ 」。因而我很憤怒的跑去寵物店找老闆索賠!
我:大家家賣的魚有問題,回去就不行了!
老闆:不可能,昨天在咱們這都活蹦亂跳的!
我:就是大家家的魚有問題!
老闆:確定是你本身買的魚缸有問題!
我:手持兩把錕斤拷,口中疾呼燙燙燙。
老闆:腳踏千朵屯屯屯,笑看萬物鍩鍩鍩?nginx
這一幕,似曾相識!像極了咱們在開發中
測試:xx,你的代碼在生產環境上運行有問題。
我:不可能,我本地都運行得好好的。
測試:你本身上生產環境上看。
我:我不看,個人代碼在本地沒問題,確定是運維的鍋,你去找運維!git
或許不少開發人員都有過上面的經歷,程序在本地運行都很正常,一上到生產環境就崩了。這是由於程序跟小金魚同樣也會「水土不服」!而致使程序水土不服的緣由通常就是環境和配置的差別!加上如今互聯網高併發、大流量的訪問,一個應用每每須要部署到集羣的多臺機器上,而且集羣擴容縮容的需求也比較頻繁。若是按照傳統的方式部署,那每一臺服務器上都須要裝各類軟件...而後進行各類配置...我彷彿看到了「工做996,生病ICU」在向運維工程師招手!程序員
那有沒有一種方案不只能屏蔽環境的差別,而且還能快速部署呢?既然「水土不服」那我把程序及整個「水土」都打包遷移,就看你服不服。而docker就是這樣的一種讓你服技術!web
昂,上面的對象是我本身new的(* ̄︶ ̄)...redis
Docker是什麼呢?百度百科是這樣跟我說的:Docker 是一個開源的應用容器引擎,讓開發者能夠打包他們的應用以及依賴包到一個可移植的鏡像中,而後發佈到任何流行的 Linux或Windows 機器上,也能夠實現虛擬化。容器是徹底使用沙箱機制,相互之間不會有任何接口。sql
這段話已經很歸納的描述了docker是什麼,docker能幹嗎,docker的基本特性!相信剛開始接觸docker的你跟我也同樣,看了幾遍都很懵逼!不要緊,看徹底文再回頭看這段話,或許就有不同的體會了!咱們先看看docker官方給出的「定妝照」
docker
若是非要我用一句話描述這張圖片,還在上幼兒園的我會說:「一條可愛的鯨魚揹着多個集裝箱,暢遊在大海里 」!而如今我會說:「docker是一個運行在操做系統上的軟件,這個軟件上面能夠運行多個相互隔離的容器」!不一樣的表述,同一個意思!這條可愛的鯨魚就是我們的docker,而大海就是咱們的操做系統,多個集裝箱就是在docker上運行的容器!什麼是容器我們後面會說~
假如你想漂洋過海來看我,你能夠選擇本身造一條船,這樣你就得本身備足不少乾糧,還得準備不少一些其餘的必需品才能出發!可是如今有一條鯨魚游過來對你說,我這裏有不少集裝箱,裏面有你所須要的一切,你選一個適合你的進來就能夠了,我會帶你乘風破浪的!
看到這裏,你是否對docker有個初步的印象了呢?至少知道了:一、docker是什麼?二、爲何須要docker?
前面咱們說過docker能夠實現虛擬化,那docker與咱們平時用的虛擬機有什麼區別和聯繫呢?在那些年咱們還買不起雲服務器的時候,若是咱們想學linux那就得先安裝一個建立虛擬機的軟件,而後在軟件上面建立虛擬機,而後分配內存、分配磁盤、安裝linux操做系統等等一系列的操做,而後等個分把鍾讓虛擬機運行起來~
爲何傳統虛擬機啓動會那麼慢呢?由於傳統虛擬機技術是虛擬出一套硬件後,在其上面運行一個完整的操做系統,而後在該系統上面再運行所須要的應用程序,而且虛擬機的資源須要提早分配,一旦分配這些資源將所有被佔用。可是docker容器內的應用程序是直接運行於宿主的內核,容器沒有本身的內核,更加不會對硬件進行虛擬。所以docker容器比傳統的虛擬機更爲輕便!可是docker容器技術也是參考虛擬機一步一步的迭代優化過來的!咱們來看看官方給出的docker容器和傳統虛擬機的對比圖:
圖中也能看出來,docker就是一個運行在操做系統上的軟件!之後若是想在windows上面學習Linux,只須要在本地安裝一個windows版本的docker,而後看完本文的剩下的部分,就能輕輕鬆鬆的玩轉linux啦!不過在windows上安裝docker也須要先安裝一個虛擬機~
前面對docker的基本概念有了個大體印象,可是到目前爲止,可能你對docker的認識還比較空泛,那下面部分咱們就從docker的基本組成要素來更深刻的走進docker!docker是一個client-server的結構!先看看官網給出的架構圖:
這張圖裏面歸納了docker的全部的元素!咱們就逐一分析docker客戶端、docker服務、倉庫、鏡像、容器等概念!
最左邊是docker的客戶端,相似咱們操做mysql的工具navcat,只不過咱們這裏的是沒有圖形化界面的命令終端。docker客戶端是用戶與docker服務交互的窗口!咱們能看到圖中就是各類操做的命令!
中間的是docker後臺運行的服務,一個稱爲docker daemon的守護進程。能夠理解爲咱們mysql的服務,咱們的操做命令都是在這部分進行處理!docker deamon監聽着客戶端的請求,而且管理着docker的鏡像、容器、網絡、磁盤(圖中只列出了鏡像與容器)等對象。一樣,docker的客戶端與服務能夠運行在同一機器上,也能夠用某臺機器上的客戶端遠程鏈接另外一臺機器上的docker服務,這跟咱們的mysql同樣的呢。
右邊部分是註冊倉庫,在遠古時代作開發的都知道,咱們之前須要一個第三方包的時候須要去網上下載對應的jar包,很麻煩不說,還容易下的包是不穩定的版本。有了maven以後,咱們只要在maven配置文件中引入對應的依賴,就能夠直接從遠程倉庫中下載對應版本的jar包了。docker中的倉庫與maven的倉庫是一個概念,能夠遠程下載經常使用的鏡像,也能夠push包到遠程倉庫(如圖中的redis、nginx等鏡像),同一個鏡像又能夠有多個版本,在docker中稱爲tag!
前面咱們有屢次提到鏡像和容器,這是docker裏面很核心的兩個概念。那鏡像和容器分別是什麼呢?鏡像和容器的關係是什麼呢?
鏡像
官方給出的定義是:docker鏡像是一個只讀模板,能夠用來建立docker容器。鏡像是一種輕量級的、可執行的獨立軟件包,用來打包軟件運行環境和基於運行環境開發的軟件。它包含運行某個軟件所須要的全部的內容,包括代碼、運行時、庫、環境變量、配置文件等。咱們開發的web應用須要jdk環境、須要tomcat容器、須要linux操做系統,那咱們能夠把咱們所須要的一切都進行打包成一個總體(包括本身開發的web應用+jdk+tomcat+centos/ubuntu+各類配置文件)。打包後的鏡像在某臺機器上能運行,那它就可以在任何裝有docker的機器上運行。
任何鏡像的建立會基於其餘的父鏡像,也就是說鏡像是一層套一層,好比一個tomcat鏡像,須要運行在centos/ubuntu上,那咱們的tomcat鏡像就會基於centos/ubuntu鏡像建立(在後面的操做部分咱們能夠經過命令查看),這樣的結構就相似於咱們吃的洋蔥,若是你願意一層一層一層地剝開個人心~
容器
官方給出的定義是:docker的容器是用鏡像建立的運行實例,docker能夠利用容器獨立運行一個或一組應用。咱們可使用客戶端或者API控制容器的啓動、開始、中止、刪除。每一個容器之間是相互隔離的。上一步咱們構建的鏡像只是一個靜態的文件,這個文件須要運行就須要變爲容器,咱們能夠把容器看作是一個簡易版的linux系統和運行在其中的應用程序!就是前面看到的鯨魚背上的一個一個的集裝箱,每一個集裝箱都是獨立的!
鏡像與容器關係
上面的概念很抽象,能夠理解爲容器就是鏡像的一個實例,相信你們都寫過相似下面的代碼:
public void Dog extends Animal{ ...... } ...... Dog dog = new Dog()
咱們在代碼中定義了一個Dog類,這個類就至關於一個鏡像,能夠根據這個類new出不少的實例,new出來的實例就至關於一個個的容器。鏡像是靜態的文件,而容器就是有生命的個體!Dog類能夠繼承父類Animal,若是不顯式的指定繼承關係,Dog類就默認繼承Object類。一樣上面也說到過docker中的鏡像也有繼承關係,一個鏡像能夠繼承其餘的鏡像建立,添加新的功能!
看到這裏的你是否是對docker有了更多的瞭解了呢?咱們再回頭看看百度百科對docker的描述,可能你又會有更深的印象:
Docker 是一個開源的應用容器引擎,讓開發者能夠打包他們的應用以及依賴包到一個可移植的鏡像中,而後發佈到任何流行的 Linux或Windows 機器上,也能夠實現虛擬化。容器是徹底使用沙箱機制,相互之間不會有任何接口。
上面說到容器是一個簡易版的linux系統和運行在其中的應用程序,那咱們的應用程序產生的數據(好比操做日誌、異常日誌、數據)也是在容器內的系統中存放的,默認不會作持久化,咱們能夠進入到容器中查看。可是萬一有一天,docker這條鯨魚不滿人類的壓迫,反抗了...老子打爛你的集裝箱!
隨着容器的關閉,容器內的數據也會丟失,從新開啓的容器不會加載原來的數據(簡單說就是容器從新啓動又是另一個實例了)。那對容器內的數據須要持久化到宿主機上就頗有必要了,這就須要瞭解咱們的容器數據卷~
容器數據卷的設計目的就是作數據的持久化和容器間的數據共享,數據卷徹底獨立於容器的生命週期,也就是說就算容器關閉或者刪除,數據也不會丟失。簡單點說就將宿主機的目錄掛在到容器,應用在容器內的數據能夠同步到宿主機磁盤上,這樣容器內產生的數據就能夠持久化了。關於容器卷的命令咱們後面會有操做實例!
上面說了那麼多,下面就到了我們的實操環節啦!這一節的內容會經過一些經常使用的命令讓你們更進一步的瞭解docker,注意!!這裏只是一些經常使用的命令來加深理解,而不是命令大全!若是沒有安裝docker的小夥伴能夠本身按照官網的文檔進行安裝,本文不會講到這部分的內容!因此我假設你在本身的服務器上已經裝好了docker!
一、docker version
查看docker客戶端和服務的版本。
二、docker info
查看docker的基本信息,若有多少容器、多少鏡像、docker根目錄等等。
三、docker --help
查看docker的幫助信息,這個命令能夠查看全部docker支持的命令~
這幾個命令很是簡單,有過一點linux基礎的小夥伴應該很容易理解!
一、docker images
查看本地主機上全部的鏡像。注意是本地主機的!這裏能看到鏡像的名稱、版本、id、大小等基本信息,注意這裏的image ID是鏡像的惟一標識!還能夠經過docker images tomcat
指定某個具體的鏡像查看對應信息。這裏還要注意的是centos的鏡像才200MB的大小,比咱們物理機器上裝的centos要小得多的多,這是由於centos的鏡像只保留了linux核心部分,這也是爲何docker虛擬化技術比虛擬機運行效率更高的緣由!那爲何tomcat的鏡像這麼大呢?那是由於咱們以前說過咱們的鏡像就像一個洋蔥同樣,是一層套一層的!tomcat的運行須要基於centos、jdk等等鏡像,tomcat在上層因此體積比較大啦!
二、docker rmi
刪除本地的鏡像,以下圖所示,能夠加上-f
參數進行強制刪除。這裏的rmi命令跟linux中的刪除命令就很像啦,只是這裏加了一個i表明image!
三、docker search
根據鏡像名稱搜索遠程倉庫中的鏡像!
四、docker pull
搜索到某個鏡像以後就能夠從遠程拉取鏡像啦,有點相似我們git中的pull命令,固然對應的還有個docker push的命令。如圖,若是咱們沒有指定tag,默認就會拉取latest版本,也能夠經過docker pull tomcat:1.7
的方式拉取指定版本!注意這裏在拉取鏡像的時候打印出來的信息有不少,這也是前面說到的鏡像是一層套一層,拉取一個鏡像也是一層一層的拉取!
經過鏡像命令咱們就能獲取鏡像、刪除鏡像等操做啦!鏡像有了下面天然就須要經過鏡像建立對應的實例啦,也就是咱們的容器。下面咱們以tomcat爲例:
一、docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
能夠基於某個鏡像運行一個容器,若是本地有指定的鏡像則使用本地鏡像,若是沒有則從遠程拉取對應的鏡像而後啓動!因爲這個命令很是重要,因此下面列出幾個比較重要的參數:
-d
:啓動容器,而且後臺運行(docker容器後臺運行,就必需要有一個前臺進程,容器運行的命令若是不是一直掛起的命令,容器啓動後就會自動退出);
-i
:以交互模式運行容器,一般與-t
同時使用;
-t
:爲容器從新分配一個僞輸入終端,一般與-i同時使用(容器啓動後進入到容器內部的命令窗口);
-P
:隨機端口映射,容器內部端口隨機映射到主機的高端口;
-p
:指定端口映射,格式爲:主機(宿主)端口:容器端口;
-v
:創建宿主機與容器目錄的同步;
--name="myTomcat"
: 爲容器指定一個名稱(若是不指定,則有個隨機的名字);
上面我經過命令啓動了一個tomcat的容器,因爲使用了 -t
的參數,因此容器啓動後就進入到了容器的內部的命令窗口,打印了不少tomcat啓動的日誌。而且使用 -p
參數指定了端口映射,也就是容器內tomcat運行的端口是8080,而且映射到了宿主機上的8888端口,這樣咱們在外部就能夠同過服務器的ip+8888端口 訪問到咱們容器內部tomcat部署的服務了。
前面咱們提到過容器內的數據會隨着容器的關閉而丟失。那咱們就須要有容器數據卷的技術能將容器內的數據持久化到宿主機。這裏須要用到 -v
參數!咱們看下面的截圖
這裏第一個要注意的是咱們用的 -d
參數,啓動後沒有進入到容器內部,仍是在宿主機。(能夠對比一下與上面 -it 參數的區別)。第二個要注意的是 -v /宿主機:/容器內目錄
實現了宿主機與容器內指定目錄的數據同步!容器啓動後就可使用 linux 的 ll 命令查看宿主機上已經同步到了容器內的文件。第三個要注意的是這裏的同步是雙向的,也就是說在宿主機上對文件的修改也會同步到容器內部!多個不一樣的容器映射到宿主機的同一個目錄,就能夠實現不一樣容器間的數據共享啦!
二、進入到容器後能夠經過exit
命令退出容器,也能夠經過ctrl+P+Q快捷鍵退出容器,這兩種方式的不一樣之處是exit
會退出而且關閉容器,而ctrl+P+Q快捷鍵只是單純的退出,容器還在運行,而且還能再次進入!
三、docker ps
咱們能夠經過該命令查看正在運行的容器的信息,這裏能看到容器的惟一id,啓動時間等等...這裏跟linux的ps命令相似,因此也能夠把容器理解爲一個運行在docker上的進程!docker ps -a
能夠查看運行中與中止的全部容器。
四、docker attach [OPTIONS] CONTAINER
上面說過經過ctrl+P+Q快捷鍵退出容器後容器還在後臺運行,那若是想再次進入容器怎麼辦呢?咱們就能夠經過attach
命令+容器的id再次進入容器!
五、docker exec [OPTIONS] CONTAINER
這個命令與attach同樣均可以再次進入後臺運行的容器,可是該命令能夠不進入容器而在運行的容器中執行命令!比attach
更增強大!
六、docker stop
docker kill
docker restart
這三個命令分別用來中止容器、強制中止容器和重啓容器,就跟咱們在linux上中止、強制中止和重啓某個進程同樣的啦,這裏就不作演示了!
七、docker rm
使用這個命令就能夠刪除某個容器,這裏跟刪除鏡像的區別是這裏少了一個 i 啦!須要注意的是經過stop和kill中止的容器還存在於docker中,而使用 rm 命令操做後的容器將再也不存在!
八、docker inspect
查看容器的詳情(也能查看鏡像詳情)。
前面咱們對docker以及相關概念、經常使用命令有了基本的瞭解,咱們也知道了能夠從遠程pull一個鏡像,那遠程的鏡像是怎麼來的呢?若是咱們想本身建立一個鏡像又該怎麼作呢?
對,Dockerfile!Dockerfile是一個包含用戶可以構建鏡像的全部命令的文本文檔,它有本身的語法以及命令,docker可以從dockerfile中讀取指令自動的構建鏡像!
咱們要想編寫本身的Dockerfiler並構建鏡像,那對Dockerfile的語法和命令的瞭解就是必須的,瞭解規則纔好辦事嘛!
FROM
FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]
FROM <image>[@<digest>] [AS <name>]
指定基礎鏡像,當前鏡像是基於哪一個鏡像建立的,有點相似java中的類繼承。FROM指令必是Dockerfile文件中的首條命令。
MAINTAINER
MAINTAINER <name>
鏡像維護者的信息,該命令已經被標記爲不推薦使用了。
LABEL
LABEL <key>=<value> <key>=<value> <key>=<value> ...
給鏡像添加元數據,能夠用LABEL命令替換MAINTAINER命令。指定一些做者、郵箱等信息。
ENV
ENV <key> <value>
ENV <key>=<value> ...
設置環境變量,設置的變量可供後面指令使用。跟java中定義變量差很少的意思!
WORKDIR
WORKDIR /path/to/workdir
設置工做目錄,在該指令後的RUN、CMD、ENTRYPOINT, COPY、ADD指令都會在該目錄執行。若是該目錄不存在,則會建立!
RUN
RUN <command>
RUN ["executable", "param1", "param2"]
RUN會在當前鏡像的最上面建立一個新層,而且能執行任何的命令,而後對執行的結果進行提交。提交後的結果鏡像在dockerfile的後續步驟中可使用。
ADD
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
從宿主機拷貝文件或者文件夾到鏡像,也能夠複製一個網絡文件!若是拷貝的文件是一個壓縮包,會自動解壓縮!
COPY
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
從宿主機拷貝文件或者文件夾到鏡像,不能複製網絡文件也不會自動解壓縮!
VOLUME
VOLUME ["/data"]
VOLUME用於建立掛載點,通常配合run命令的-v參數使用。
EXPOSE
EXPOSE <port> [<port>/<protocol>...]
指定容器運行時對外暴露的端口,可是該指定實際上不會發布該端口,它的功能是鏡像構建者和容器運行者之間的記錄文件。
回到容器命令中的run命令部分,run命令有-p和-P兩個參數,若是是-P就是隨機端口映射,容器內會隨機映射到EXPOSE指定的端口,若是是-p就是指定端口映射,告訴運維人員容器內須要映射的端口號。
CMD
CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2
指定容器啓動時默認運行的命令,在一個Dockerfile文件中,若是有多個CMD命令,只有一個最後一個會生效!一樣是能夠執行命令,可能你會以爲跟上面的RUN指令很類似,RUN指令是在構建鏡像時候執行的,而CMD指令是在每次容器運行的時候執行的!docker run命令會覆蓋CMD的命令!
ENTRYPOINT
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
這個指令與CMD指令相似,都是指定啓動容器時要運行的命令,若是指定了ENTRYPOINT,則CMD指定的命令不會執行!在一個Dockerfile文件中,若是有多個ENTRYPOINT命令,也只有一個最後一個會生效!不一樣的是經過docker run command
命令會覆蓋CMD的命令!執行的命令不會覆蓋ENTRYPOINT,docker run命令中指定的任何參數都會被當作參數傳遞給ENTRYPOINT!
RUN、CMD、ENTRYPOINT區別
一、RUN指令是在鏡像構建時運行,然後兩個是在容器啓動時執行!
二、CMD指令設置的命令是容器啓動時默認運行的命令,若是docker run
沒有指定任何的命令,而且Dockerfile中沒有指定ENTRYPOINT,那容器啓動的時候就會執行CMD指定的命令!有點相似代碼中的缺省參數!
三、若是設置了ENTRYPOINT指令,則優先使用!而且能夠經過docker run
給該指令設置的命令傳參!
四、CMD有點相似代碼中的缺省參數
USER
USER <user>[:<group>]
USER <UID>[:<GID>]
用於指定運行鏡像所使用的用戶。
ARG
ARG <name>[=<default value>]
指定在鏡像構建時可傳遞的變量,定義的變量能夠經過docker build --build-arg
ONBUILD
ONBUILD [INSTRUCTION]
當所構建的鏡像被當作其餘鏡像的基礎鏡像時,ONBUILD指定的命令會被觸發!
STOPSIGNAL
STOPSIGNAL signal
設置當容器中止時所要發送的系統調用信號!
HEALTHCHECK
HEALTHCHECK [OPTIONS] CMD command
(在容器內運行運行命令檢測容器的運行狀況)
HEALTHCHECK NONE
(禁止從父鏡像繼承檢查)
該指令能夠告訴Docker怎麼去檢測一個容器的運行情況!
SHELL
SHELL ["executable", "parameters"]
用於設置執行命令所使用的默認的shell類型!該指令在windows操做系統下比較有用,由於windows下一般會有cmd和powershell兩種shell,甚至還有sh。
Dockerfile執行順序是從上到下,順序執行!每條指令都會建立一個新的鏡像層,並對鏡像進行提交。編寫好Dockerfile文件後,就須要使用docker build命令對鏡像進行構建了。
docker build的格式:docker build [OPTIONS] PATH | URL | -
-f
:指定要使用的Dockerfile路徑,若是不指定,則在當前工做目錄尋找Dockerfile文件!
-t
: 鏡像的名字及標籤,一般name:tag
或者name
格式;能夠在一次構建中爲一個鏡像設置多個標籤。
例如咱們能夠docker build -t myApp:1.0.1 .
這樣來構建本身的鏡像,注意後面的 .
,用於指定鏡像構建過程當中的上下文環境的目錄。若是你們想了解那些官方鏡像的Dockerfile文件都是怎麼樣寫的,能夠上https://hub.docker.com/ 進行搜索,以tomcat鏡像爲例
能看到tomcat鏡像的父鏡像是openjdk鏡像,咱們再搜索openjdk的Dockerfile文件
openjdk鏡像的父鏡像又是oraclelinux鏡像,咱們再搜索oraclelinux的Dockerfile文件
openjdk鏡像的父鏡像是scratch,這是根鏡像,全部的鏡像都會依賴該鏡像,就像咱們代碼中全部的對象的父類都是Object!因此能看到tomcat鏡像就是這樣一層一層的構建出來的,這也是爲何前面經過docker images
查看到的tomcat鏡像爲何會有四百多兆的緣由啦!
看到這裏的你,是否對docker是什麼?爲何須要docker?docker鏡像、docker容器的概念是什麼?docker中經常使用的命令有哪些?Dockerfile有哪些指令?怎麼去構建本身的鏡像?這些問題都能明白了呢?