Docker能作些什麼?java
1.docker可以解決虛擬機可以解決的問題linux
2.隔離應用依賴web
3.建立應用鏡像並複製docker
4.建立容易分發的即啓即用的應用shell
5.docker的想法是建立軟件程序可移植的輕量容器apache
鏡像ubuntu
1.docker的鏡像相似虛擬機的快照vim
2.在現有鏡像的基礎上建立鏡像windows
容器瀏覽器
1.能夠從鏡像中建立容器
2.容器和虛擬機同樣是隔離的,它也擁有一個惟一ID和惟一供讀人的名字,docker容許公開容器的公開端口
3.容器是被來設計運行一個應用的 而不是一臺機器
4.容器應該是短暫和一次性的
連接:
1.容器啓動時將會被分配一個私有IP,其餘容器可使用這個IP與其進行通信,所以,容器能夠共享一個本地網絡
2.docker容許你在建立一個新容器時引用其餘現存容器,在你剛建立的容器中被引用的容器會得到一個別名,咱們就能夠定義 ,這兩個容器連接在了一塊兒。
3.好比一個DB容器已經在運行,咱們建立web容器的時候引用這個DB容器,給它起一個別名叫作dbapp,那麼在這個新建的web容器中,咱們能夠在任什麼時候候使用主機名dbapp和DB通訊
docker的兩樣法寶
Cgroups
做用:
限制linux進程組的資源佔用
爲進程組製做PIDS,UTS,IPC,網絡和裝載命名空間
Cgroup建立一個環境,進程能夠在其中運行,並與操做系統的其餘進程進行隔開
容器runtime是容器真正運行的地方,runtime須要和操做系統kernel緊密結合,爲容器提供運行環境。
好比說,java程序比做一個容器,JVM就是runtime。JVM爲java程序提供運行環境。
因此容器只能在runtime裏面運行
lxc、runc 和 rkt 是目前主流的三種容器 runtime。
lxc 是 Linux 上老牌的容器 runtime。Docker 最初也是用 lxc 做爲 runtime。
runc 是 Docker 本身開發的容器 runtime,符合 oci 規範,也是如今 Docker 的默認 runtime。
rkt 是 CoreOS 開發的容器 runtime,符合 oci 規範,於是可以運行 Docker 的容器。
除了運行環境,使用者也得須要工具來管理容器。容器管理工具對內與runtime交互,對外爲用戶提供interface.
lxd是lxc對應的容器管理工具;runc的管理工具是docker engine。docker engine 包含後臺 deamon 和 cli 兩個部分。咱們一般提到 Docker,通常就是指的 docker engine。rkt 的管理工具是 rkt cli。
容器定義工具容許用戶定義容器的內容屬性,這樣容器就可以被保存,共享和重建
docker image 是 docker 容器的模板,runtime 依據 docker image 建立容器。
dockerfile 是包含若干命令的文本文件,能夠經過這些命令建立出 docker image。
ACI (App Container Image) 與 docker image 相似,只不過它是由 CoreOS 開發的 rkt 容器的 image 格式。
容器是經過image建立的,須要一個倉庫統一存放image,這個倉庫就叫作Registy
企業能夠用 Docker Registry 構建私有的 Registry。
Docker Hub(https://hub.docker.com )是 Docker 爲公衆提供的託管 Registry,上面有不少現成的 image,爲 Docker 用戶提供了極大的便利。
Quay.io(https://quay.io/ )是另外一個公共託管 Registry,提供與 Docker Hub 相似的服務。
由於容器有runtime,因此幾乎全部的linux、MAC OS和windows均可以運行容器
容器 OS 是專門運行容器的操做系統。與常規 OS 相比,容器 OS 一般體積更小,啓動更快。由於是爲容器定製的 OS,一般它們運行容器的效率會更高。
目前已經存在很多容器 OS,CoreOS、atomic 和 ubuntu core 是其中的傑出表明。
容器核心技術可以讓讓容器在單個主機上運行,容器平臺技術可以讓容器做爲集羣在分佈式環境中運行。容器平臺技術以下圖:
分爲容器編排技術、容器管理平臺、基於容器的PaaS。
基於容器的應用通常會採用微服務架構。在這中間架構下,應用被劃分紅不一樣的組件,並以服務的方式運行在各個容器中,經過API對外提供服務,爲了保證服務的高可用,每一個組件會運行多個相同的容器。
這些容器會組成集羣,集羣中的容器會根據業務動態的建立、遷移和銷燬。
這樣基於微服務架構的系統其實是一個動態可伸縮的系統。容器編排引擎就排上用場了。
編排(orchestration),一般包括容器管理、調度、集羣定義和服務發現。經過容器編排引擎、容器被有機的組合成微服務應用,實現業務需求。
docker swarm 是 Docker 開發的容器編排引擎。
kubernetes 是 Google 領導開發的開源容器編排引擎,同時支持 Docker 和 CoreOS 容器。
mesos 是一個通用的集羣資源調度平臺,mesos 與 marathon 一塊兒提供容器編排引擎功能。
以上三者是當前主流的容器編排引擎。
容器管理平臺是在容器編排引擎之上的一個更爲通用的平臺。一般容器管理平臺可以支持多個編排引擎,抽象了編排引擎的底層實現細節。
好比:application catalog和一鍵應用部署
Rancher和Containership是容器管理平臺的典型表明
容器使得網絡變得複雜,用戶須要專門的解決方案來管理容器與容器,容器與其餘實體之間的連通性和隔離性。
docker network是docker原生的解決方案。
微服務的最大特色是動態變化,當負載增長時,集羣會自動建立新的容器;負載減少,多餘的容器就會被銷燬。容器也會根據主機的資源狀況在不一樣主機上遷移,容器的IP和端口也隨之改變。
在這種狀況下,必需要讓客戶端可以知道如何訪問容器提供的服務。這就是服務發現的工做。
服務發現會保存集羣中全部微服務的最新信息,好比IP和端口,對外提供的API,提供服務和查詢等。
比較主流的是etcd,consul,zookeeper。
製做第一個容器
1.一個Ubuntu系統
2.這個系統可以聯網,最起碼ping www.baidu.com是能夠的
這些準備條件準備好了,接下來就開始作準備工做。
Docker 分爲開源免費的 CE(Community Edition)版本和收費的 EE(Enterprise Edition)版本。下面咱們將按照文檔,經過如下步驟在 Ubuntu 16.04 上安裝 Docker CE 版本。
這裏下載的是CE版本。
打開ubuntu虛擬機,ping 一下百度
OK,能夠的,由於製做容器的過程當中須要聯網,這個條件是必要的。
1.安裝包,容許 apt
命令 HTTPS 訪問 Docker 源。執行命令:
sodo apt-get install apt-transport-https ca-certificate curl software-properties-common
而後會下載一些東西,等待下載完成便可
2.添加 Docker 官方的 GPG
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
3.將Docker的源添加到/etc/apt/source.list
sodu add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
4.刷新apt源
sudo apt-get update
5.安裝Docker
sudo apt-get install docker-ce
這步完成以後,Docker也就安裝完成了,是否是很簡單,接下來就是如何使用Dokcer的問題了。
下載你的第一個容器:
docker run -d -p 80:80 httpd
這個過程是,首先docker發現主機上沒有http,而後就會去下載(鏡像中已經安裝好了 Apache HTTP Server),下載完畢以後再運行運行,將容器的80端口映射到主機的80端口。
接下來檢測一下容器是否正常運行,瀏覽器中輸入該主機的IP,我這裏是192.168.90.71
OK,web服務器運行成功!
Docker的第一個helloworld也就大功告成!
容器是一個自包含,可移植,輕量級的軟件打包技術。是應用程序在任何地方几乎以相同方式運行。開發人員在開發機上建立好容器,無需任何修改就能在虛擬機,雲服務器或公有云主機上運行。
容器有兩部分組成:
1.應用程序自己
2.應用程序所依賴的環境,庫
容器在主機中運行,與操做系統中其餘的進程隔離,這一點區別於虛擬機。
傳統的虛擬機技術,如:vmvare,他是建立一個完整的虛擬機,爲了運行應用程序,部署系統,還須要安裝整個操做系統(幾十GB),
下圖展現了二者的區別:
從右圖中能夠看見,全部容器都共享一個系統,對於虛擬機來講,都是一個單獨的系統。
啓動容器不須要啓動整個系統,因此容器部署和啓動速度更快,開銷更小,也更容易遷移。
由於方便。這取決於容器使得軟件具有超強的可移植能力。
現現在軟件開發的部署相對於之前來講,要複雜不少,開發人員須要使用多種服務構建和組裝應用,並且系統還可能會部署到不一樣的環境中。
並且這個服務都有本身依賴的庫和環境,還有可能存在着動態遷移到不一樣的環境中。
你們作過軟件開發的都知道,軟件部署是一件很麻煩的事情,那麼有沒有一種技術使得軟件部署很平滑呢?
開發人員受到了集裝箱的啓發。
之前運送貨物,會擔憂貨物類型不一樣而擔憂損失,好比運送的食物被其餘貨物壓壞了。後來人們發明了集裝箱,標準集裝箱能夠被高效地裝卸、重疊和長途運輸。現代化的起重機能夠自動在卡車、輪船和火車之間移動集裝箱。集裝箱被譽爲運輸業與世界貿易最重要的發明。
Docker 將集裝箱思想運用到軟件打包上,爲代碼提供了一個基於容器的標準化運輸系統。Docker 能夠將任何應用及其依賴打包成一個輕量級、可移植、自包含的容器。容器能夠運行在幾乎全部的操做系統上。
容器意味着環境隔離和可重複性。開發人員只需爲應用建立一次運行環境,而後打包成容器即可在其餘機器上運行。另外,容器環境與所在的 Host 環境是隔離的,就像虛擬機同樣,但更快更簡單。
Docker的核心組件:
1.Docker客戶端 - Client
2.Docker服務器 - Docker deamon
3.Docker鏡像 - Image
4.倉庫 - Registry
5.Docker容器 - Container
Docker架構圖以下:
Docker採用的是C/S架構,客戶端向服務器發送請求,服務器負責建立、運行和分發容器。
Docker客戶端的命令以下:
Docker deamon是服務器組件,以Linux後臺服務方式運行。
Docker daemon 運行在 Docker host 上,負責建立、運行、監控容器,構建、存儲鏡像。
默認配置下,Docker daemon 只能響應來自本地 Host 的客戶端請求。若是要容許遠程客戶端請求,須要在配置文件中打開 TCP 監聽,步驟以下:
1.編輯配置文件 /etc/systemd/system/multi-user.target.wants/docker.service,在環境變量 -H tcp://0.0.0.0
,容許來自任意 IP 的客戶端鏈接。
2.重啓 Docker daemon。
3.服務器 IP 爲 192.168.56.102,客戶端在命令行里加上 -H 參數,便可與遠程服務器通訊
可將Docker鏡像當作一個只讀模板。一個鏡像裏可能含有一個系統,或者一個Tomcat。
鏡像有多種生成方法:
能夠從無到有開始建立鏡像
也能夠下載並使用別人建立好的現成的鏡像
還能夠在現有鏡像上建立新的鏡像
咱們能夠將鏡像的內容和建立步驟描述在一個文本文件中,這個文件被稱做 Dockerfile,經過執行 docker build <docker-file>
命令能夠構建出 Docker 鏡像。
Docker容器就是Docker運行的環境。對於軟件而言,鏡像像是生命週期的構建和打包階段,容器則是啓動和運行階段。
鏡像有多種生成方法:
能夠從無到有開始建立鏡像
也能夠下載並使用別人建立好的現成的鏡像
還能夠在現有鏡像上建立新的鏡像
咱們能夠將鏡像的內容和建立步驟描述在一個文本文件中,這個文件被稱做 Dockerfile,經過執行 docker build <docker-file>
命令能夠構建出 Docker 鏡像.
docker pull 命令是從Registry下載鏡像
docker run命令是先下載鏡像 而後再啓動容器
下面看一個運行實例:
Docker 客戶端執行 docker run
命令。
Docker daemon 發現本地沒有 httpd 鏡像。
daemon 從 Docker Hub 下載鏡像。
下載完成,鏡像 httpd 被保存到本地。
Docker daemon 啓動容器。
docker images 能夠看下已經下載到本地的鏡像。
dokcer ps 能夠查看哪些容器正在運行
鏡像的分層結構:
實際上,Docker Hub 中 99% 的鏡像都是經過在 base 鏡像中安裝和配置須要的軟件構建出來的。好比咱們如今構建一個新的鏡像,Dockerfile 以下:
① 新鏡像再也不是從 scratch 開始,而是直接在 Debian base 鏡像上構建。
② 安裝 emacs 編輯器。
③ 安裝 apache2。
④ 容器啓動時運行 bash。
構建過程以下圖所示:
能夠看到,新鏡像是從 base 鏡像一層一層疊加生成的。每安裝一個軟件,就在現有鏡像的基礎上增長一層。
問什麼 Docker 鏡像要採用這種分層結構呢?
最大的一個好處就是 - 共享資源。
好比:有多個鏡像都從相同的 base 鏡像構建而來,那麼 Docker Host 只需在磁盤上保存一份 base 鏡像;同時內存中也只需加載一份 base 鏡像,就能夠爲全部容器服務了。並且鏡像的每一層均可以被共享,咱們將在後面更深刻地討論這個特性。
這時可能就有人會問了:若是多個容器共享一份基礎鏡像,當某個容器修改了基礎鏡像的內容,好比 /etc 下的文件,這時其餘容器的 /etc 是否也會被修改?
答案是不會!
修改會被限制在單個容器內。由於容器的Copy-on-Write特性
可寫的容器層
當容器啓動時,一個新的可寫層被加載到鏡像的頂部。
這一層一般被稱做「容器層」,「容器層」之下的都叫「鏡像層」。
全部對容器的改動 - 不管添加、刪除、仍是修改文件都只會發生在容器層中。
添加文件
在容器中建立文件時,新文件被添加到容器層中。
讀取文件 在容器中讀取某個文件時,Docker 會從上往下依次在各鏡像層中查找此文件。一旦找到,當即將其複製到容器層,而後打開並讀入內存。
修改文件 在容器中修改已存在的文件時,Docker 會從上往下依次在各鏡像層中查找此文件。一旦找到,當即將其複製到容器層,而後修改之。
刪除文件 在容器中刪除文件時,Docker 也是從上往下依次在鏡像層中查找此文件。找到後,會在容器層中記錄下此刪除操做。
只有當須要修改時才複製一份數據,這種特性被稱做 Copy-on-Write。可見,容器層保存的是鏡像變化的部分,不會對鏡像自己進行任何修改。
這樣就解釋了咱們前面提出的問題:容器層記錄對鏡像的修改,全部鏡像層都是隻讀的,不會被容器修改,因此鏡像能夠被多個容器共享。
使用現成鏡像的好處除了省去本身作鏡像的工做量外,更重要的是能夠利用前人的經驗。特別是使用那些官方鏡像,由於 Docker 的工程師知道如何更好的在容器中運行軟件。
固然,某些狀況下咱們也不得不本身構建鏡像,好比:
找不到現成的鏡像,好比本身開發的應用程序。
須要在鏡像中加入特定的功能,好比官方鏡像幾乎都不提供 ssh。
因此本節咱們將介紹構建鏡像的方法。同時分析構建的過程也可以加深咱們對前面鏡像分層結構的理解。
Docker 提供了兩種構建鏡像的方法:
docker commit 命令
Dockerfile 構建文件
Docker官方推薦使用Dockerfile構建鏡像。
Docker 會緩存已有鏡像的鏡像層,構建新鏡像時,若是某鏡像層已經存在,就直接使用,無需從新建立。
Dockerfile 中每個指令都會建立一個鏡像層,上層是依賴於下層的。不管何時,只要某一層發生變化,其上面全部層的緩存都會失效。
也就是說,若是咱們改變 Dockerfile 指令的執行順序,或者修改或添加指令,都會使緩存失效。
Dockerfile指令說明 |
||
指令 |
說明 |
用法 |
FROM |
指定base鏡像 |
兩種用法: 1.FROM <image> 指定基礎image爲該image的最後修改的版本 2.FROM <image>:<tag> 指定基礎image爲該image的一個tag版本。 |
MAINTAINER |
設置鏡像的做者,用於將image的製做者相關的信息寫入到image中 |
MAINTAINER <name> |
RUN |
在容器中運行制定的命令, 通常用於裝軟件 |
兩種格式: 1.RUN <command> (the command is run in a shell - `/bin/sh -c`) 2.RUN ["executable", "param1", "param2" ... ] (exec form) |
CMD |
(設置container啓動時執行的操做) |
三種方式
第三種方式:當指定了ENTRYPOINT,那麼使用下面的格式 CMD ["param1","param2"] (as default parameters to ENTRYPOINT) |
ENTRYPOINT |
配置容器啓動後執行的命令,而且不可被 docker run 提供的參數覆蓋。
每一個 Dockerfile 中只能有一個 ENTRYPOINT,當指定多個時,只有最後一個起效。 |
ENTRYPOINT ["executable", "param1", "param2"] (like an exec, the preferred form) ENTRYPOINT command param1 param2 (as a shell) 該指令的使用分爲兩種狀況,一種是獨自使用,另外一種和CMD指令配合使用。
當獨自使用時,若是你還使用了CMD命令且CMD是一個完整的可執行的命令,那麼CMD指令和ENTRYPOINT會互相覆蓋只有最後一個CMD或者ENTRYPOINT有效。 # CMD指令將不會被執行,只有ENTRYPOINT指令被執行 CMD echo 「Hello, World!」 ENTRYPOINT ls -l
另外一種用法和CMD指令配合使用來指定ENTRYPOINT的默認參數,這時CMD指令不是一個完整的可執行命令,僅僅是參數部分;ENTRYPOINT指令只能使用JSON方式指定執行命令,而不能指定參數。 FROM ubuntu CMD ["-l"] ENTRYPOINT ["/usr/bin/ls"] |
EXPOSE |
設置指令,該指令會將容器中的端口映射成宿主機器中的某個端口。當你須要訪問容器的時候,能夠不是用容器的IP地址而是使用宿主機器的IP地址和映射後的端口。要完成整個操做須要兩個步驟,首先在Dockerfile使用EXPOSE設置須要映射的容器端口,而後在運行容器的時候指定-p選項加上EXPOSE設置的端口,這樣EXPOSE設置的端口號會被隨機映射成宿主機器中的一個端口號。 |
EXPOSE <port> [<port>...] |
ENV |
用於設置環境變量 |
設置了後,後續的RUN命令均可以使用,容器啓動後,能夠經過docker inspect查看這個環境變量,也能夠經過在docker run --env key=value時設置或修改環境變量。 假如你安裝了JAVA程序,須要設置JAVA_HOME,那麼能夠在Dockerfile中這樣寫: ENV JAVA_HOME /path/to/java/dirent |
ADD |
從src複製文件到容器的dest路徑 若是是一個目錄,那麼會將該目錄下的全部文件添加到容器中,不包括目錄;若是文件是可識別的壓縮格式,則docker會幫忙解壓縮(注意壓縮格式) |
ADD <src> <dist> <src>是相對被構建的源目錄的相對路徑,能夠是文件或目錄的路徑,也能夠是一個遠程的文件url; <dist>是容器的絕對路徑 |
VOLUMN |
設置指令,使容器中的一個目錄具備持久化存儲數據的功能,該目錄能夠被容器自己使用,也能夠共享給其餘容器使用。咱們知道容器使用的是AUFS,這種文件系統不能持久化數據,當容器關閉後,全部的更改都會丟失。當容器中的應用有持久化數據的需求時能夠在Dockerfile中使用該指令。 |
VOLUME ["<mountpoint>"] 例: FROM unbuntu VOLUMN [「/tmp/data」]運行經過該Dockerfile生成image的容器,/tmp/data目錄中的數據在容器關閉後,裏面的數據還存在。
|
WORKDIR
|
能夠屢次切換(至關於cd命令),對RUN,CMD,ENTRYPOINT生效。 |
例:# 在 /p1/p2 下執行 vim a.txt WORKDIR /p1 WORKDIR p2 RUN vim a.txt |