Docker運行容器前須要本地存在對應的鏡像,若是本地不存在該鏡像,Docker會從鏡像倉庫下載該鏡像。
從Docker鏡像倉庫獲取鏡像的命令是docker pull
,其命令格式爲:php
docker pull [選項] [Docker Registry 地址[:端口號]/]倉庫名[:標籤]
如:nginx
$ docker pull ubuntu:16.04 16.04: Pulling from library/ubuntu 297061f60c36: Pull complete e9ccef17b516: Pull complete dbc33716854d: Pull complete 8fe36b178d25: Pull complete 686596545a94: Pull complete Digest: sha256:1dfb94f13f5c181756b2ed7f174825029aca902c78d0490590b1aaa203abc052 Status: Downloaded newer image for ubuntu:16.04
上面的命令中沒有給出Docker鏡像倉庫地址,所以將會從Docker Hub獲取鏡像(若是配置鏡像加速器,則從鏡像加速器上拉取鏡像)。而鏡像名稱是ubuntu:16.04,所以將會獲取官方鏡像library/ubuntu倉庫中標籤爲16.04的鏡像。
從下載過程當中能夠看到咱們以前說起的分層存儲的概念,鏡像是由多層存儲所構成。下載也是一層層的去下載,並不是單一文件。下載過程當中給出了每一層的ID前12位,而且下載結束後,給出該鏡像完整的sha256的摘要,以確保下載一致性。git
使用命令:docker run
從鏡像啓動容器實例。github
$ docker run -it --rm ubuntu:16.04 bash
docker run
就是運行容器的命令,簡要的說明一下上面用到的參數。
-it:這是2個參數,一個是-i:交互式操做,一個-t:終端。
--rm:這個參數說明容器退出以後隨之將其刪除。默認狀況,不使用--rm參數啓動的容器在退出以後不會當即刪除,除非使用命令明確刪除:docker rm
ubuntu:16.04:指定使用ubuntu:16.04這個鏡像爲基礎啓動容器
bash:放在鏡像名以後的是命令,即:啓動容器以後在容器中執行的命令web
使用exit命令退出容器。docker
使用docker image ls
命令列出當前已經下載到本地的鏡像。shell
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu 16.04 0b1edfbffd27 4 days ago 113MB hello-world latest e38bc07ac18e 2 weeks ago 1.85kB
輸出列表中包含了倉庫名,標籤,鏡像ID,建立時間和所佔用的空間。
鏡像ID則是鏡像的惟一標識,一個鏡像能夠對應多個標籤(不一樣標籤下的同一個鏡像的ID值相同)。json
$ docker image rm <鏡像id>
鏡像的定製實際上就是定製每一層所添加的配置和文件,定製鏡像有2種方式:commit,Dockerfile。ubuntu
使用鏡像啓動容器實例以後,在容器內部作的全部修改,均可以使用commit命令將容器存儲層保存爲鏡像。如:bash
$ docker commit --author "zhangsan@xxx.com" --message "modify default index page content" webserver nginx:v2
--author
指定修改的做者,而--message
則是記錄本次修改的內容,webserver
爲容器名稱,nginx:v2
爲須要保存爲的鏡像倉庫名和標籤。
慎用docker commit
命令保存鏡像!製做鏡像應該使用Dockerfile實現。使用docker commit
命令保存鏡像存在一些缺陷:
首先,在對容器進行配置時,會涉及多個文件的修改或添加,但其實有些文件是不須要保存爲鏡像的,若是不進行當心清理,會致使最終保存的鏡像文件過於臃腫。
其次,使用命令方式意味着全部對鏡像的操做都是黑箱的,不利於重現鏡像製做的步驟,以及後期的維護。
經過Dockerfile定製鏡像就是把每一層修改、安裝、構建、操做的命令都寫入一個腳本,用這個腳原本構建、定製鏡像,那麼以前說起的沒法重複的問題、鏡像構建透明性的問題、體積的問題就都會解決。
Dockerfile是一個文本文件,其內包含了一條條的指令,每一條指令構建一層,所以每一條指令的內容,就是描述該層應當如何構建。
使用了docker build
命令進行鏡像構建,其格式爲:
docker build [選項] <上下文路徑/URL/->
例如: $ docker build -t nginx:v3 .
docker build
的工做原理首先咱們要理解docker build
的工做原理。Docker在運行時分爲Docker引擎(也就是服務端守護進程)和客戶端工具。Docker的引擎提供了一組REST API,被稱爲Docker Remote API,而如docker命令這樣的客戶端工具,則是經過這組API與Docker引擎交互,從而完成各類功能。所以,雖然表面上咱們好像是在本機執行各類Docker功能,但實際上,一切都是使用的遠程調用形式在服務端(Docker 引擎)完成的。也由於這種C/S設計,讓咱們操做遠程服務器的Docker引擎變得垂手可得。
當咱們進行鏡像構建的時候,並不是全部定製都會經過RUN指令完成,常常會須要將一些本地文件複製進鏡像,好比經過COPY指令,ADD指令等。而docker build
命令構建鏡像,其實並不是在本地構建,而是在服務端,也就是Docker引擎中構建的。那麼在這種C/S架構中,如何才能讓服務端得到本地文件呢?這就引入了上下文的概念。當構建的時候,用戶會指定構建鏡像上下文的路徑,docker build
命令得知這個路徑後,會將路徑下的全部內容打包,而後上傳給Docker引擎。這樣Docker引擎收到這個上下文包後,展開就會得到構建鏡像所需的一切文件。若是在Dockerfile中這麼寫:「COPY ./package.json /app/」,這並非要複製執行docker build
命令所在的目錄下的package.json ,也不是複製Dockerfile所在目錄下的 package.json ,而是複製上下文(context)目錄下的package.json。所以,COPY這類指令中的源文件的路徑都是相對路徑。這也是初學者常常會問的爲何「COPY ../package.json /app」或者「COPY /opt/xxxx /app」沒法工做的緣由,由於這些路徑已經超出了上下文的範圍,Docker引擎沒法得到這些位置的文件。若是真的須要那些文件,應該將它們複製到上下文目錄中去。
如今就能夠理解剛纔的命令docker build -t nginx:v3 .
中的這個.其實是在指定上下文的目錄,docker build
命令會將該目錄下的內容打包交給Docker引擎以幫助構建鏡像。
若是觀察docker build
輸出,咱們其實已經看到了這個發送上下文的過程:
$ docker build -t nginx:v3 . Sending build context to Docker daemon 2.048 kB ...
理解構建上下文對於鏡像構建是很重要的,避免犯一些不該該的錯誤。好比有些初學者在發現COPY /opt/xxxx /app
不工做後,因而乾脆將Dockerfile放到了硬盤根目錄去構建,結果發現docker build
執行後,在發送一個幾十GB的東西,極爲緩慢並且很容易構建失敗。那是由於這種作法是在讓docker build
打包整個硬盤,這顯然是使用錯誤。
通常來講,應該將Dockerfile置於一個空目錄下,或者項目根目錄下。若是該目錄下沒有所需文件,那麼應該把所需文件複製一份過來。若是目錄下有些東西確實不但願構建時傳給Docker引擎,那麼能夠用.gitignore同樣的語法寫一個.dockerignore
,該文件是用於剔除不須要做爲上下文傳遞給Docker引擎的。那麼爲何會有人誤覺得「.」是指定Dockerfile所在目錄呢?這是由於在默認狀況下,若是不額外指定Dockerfile的話,會將上下文目錄下的名爲「Dockerfile」的文件做爲構建鏡像須要的Dockerfile。這只是默認行爲,實際上Dockerfile的文件名並不要求必須爲Dockerfile,並且並不要求必須位於上下文目錄中,好比能夠用「-f ../Dockerfile.php」參數指定某個文件做爲Dockerfile 。
固然,通常你們習慣性的會使用默認的文件名Dockerfile,以及會將其置於鏡像構建上下文目錄中。
docker build
的用法docker build
的基本語法爲:docker build [選項] <上下文路徑/URL/->
,從語法中能夠很明顯地看出該命令支持多種構建方式.
1.從本地文件系統構建
$ docker build -t nginx:v3 .
上述構建操做包含2個參數:
"-t"指定鏡像標籤名稱
"."指定構建上下文路徑
2.從Git倉庫構建
$ docker build https://github.com/nuccch/docker_test#:8.14
這行命令指定了構建所需的Git倉庫,而且指定默認的master分支,構建目錄爲/8.14/,而後Docker就會本身去 git clone這個項目、切換到指定分支、並進入到指定目錄後開始構建。
說明: 從Git倉庫中構建Docker鏡像是在實際項目中使用得比較多的方式,開發者只須要將代碼提交到指定Git倉庫的指定分支,測試只須要從該倉庫的分支上構建Docker鏡像便可.
3.用給定的tar壓縮包構建
$ docker build http://server/context.tar.gz
若是所給出的URL不是個Git倉庫,而是個tar壓縮包,那麼Docker引擎會下載這個包,並自動解壓縮,以其做爲上下文,開始構建。
4.從標準輸入中讀取Dockerfile進行構建
$ docker build - < Dockerfile
或者
$ cat Dockerfile | docker build -
若是標準輸入傳入的是文本文件,則將其視爲Dockerfile ,並開始構建。
注意: 這種形式因爲直接從標準輸入中讀取Dockerfile的內容,它沒有上下文,所以不能夠存在像其餘方法那樣能夠將本地文件COPY進鏡像之類的事情。
5.從標準輸入中讀取上下文壓縮包進行構建
$ docker build - < context.tar.gz
若是發現標準輸入的文件格式是gzip,bzip2以及xz的話,將會使其爲上下文壓縮包,直接將其展開,將裏面視爲上下文,並開始構建。
【參考】 http://blog.daocloud.io/principle-of-docker-image/ 深刻分析 Docker 鏡像原理 https://yq.aliyun.com/articles/68477 Docker鏡像原理和最佳實踐