本文介紹如何利用dockerfile來創建鏡像。下面介紹具體的操作過程:
一、創建構建環境
操作示例如下:
xxx@ubuntu:~$ pwd /home/xxx xxx@ubuntu:~$ mkdir myweb xxx@ubuntu:~$ cd myweb xxx@ubuntu:~/myweb$ touch Dockerfile
上面命令在當前用戶(xxx)的主目錄下創建了一個myweb目錄,並在該目錄下建立了一個空的文件名為Dockerfile文件。
這個目錄就是我們的構建環境(或上下文)。
二、編寫Dockerfile文件內容
Dockerfile文件中,是一系列的指令組成。每條指令,包括指令名(必須大寫)和指令所需的參數。看一個例子:
# version:0.0.1 FROM ubuntu MAINTAINER XXX "xxx@test.com" RUN apt-get update RUN apt-get install -y nginx RUN echo 'hello, i am a web image' > /usr/share/nginx/html/index.html EXPOSE 80
文件的第一行是一條注釋,在dockfile文件中,以#開頭的表示注釋。
當執行dockerfile文件時(如何執行,后面會介紹),其流程如下:
1、從基礎鏡像運行一個容器(第一條FROM指令的參數用於指定一個已經存在的基礎鏡像,每個dockerfile文件的第一條指令都是FROM)
2、在上面創建的容器中,執行一條指令,對容器做出修改(一般指令總會對容器進行一些改變,否則該指令就不需要了)
3、執行類似docker commit命令,提交一個新的鏡像層(該層的內容就是上面指令造成的變化內容)
4、基於剛提交的鏡像運行一個新的容器。
5、重復2~4步驟,逐個執行dockerfile中的所有指令。
看到這里大家可以有個疑問,為何每條指令都要創建鏡像和容器呢,而不是只只在開始創建一次容器,然后基於該容器執行所有指令,完成所有修改后,再提交生成一個鏡像呢?
這正是docker鏡像分層特點的優勢。可以想象一下,采用這種放的好處是,即使因為某種原因導致某條指令失敗,但我們還是可以得到一個可用的鏡像,然后我們就可以通過該鏡像運行一個容器,在該容器中執行失敗的指令,從而方便的進行調試,找到失敗原因。
下面我們來介紹上面dokcerfile文件中每一行的意義:
1、第一行上面已經介紹,以#開頭,是注釋。
2、第二行FROM指令,用於指定基礎鏡像。是所有dockerfile的第一條命令。因為所有新的鏡像都會基於該基礎鏡像基礎上變化來的。
3、第三行 MAINTAINER指令,是標識鏡像的作者和聯系方式(這里是電子郵件),以方便鏡像使用者和作者聯系。
4、第四~六行RUN指令,用於在容器中執行參數指定的命令。上面的例子第4行是更新已經安裝的APT倉庫,第5行是下載安裝nginx包,第6行是生成一個html文件,文件中只包含簡單的一句話。
5、最后一行EXPOSE指令,告訴docker守護進程,容器的應用將使用指定的端口號(EXPOSE指令的參數,這個例子是80)。
三、構建鏡像
通過docker build命令運行dockerfile文件,最后生成需要的鏡像。命令如:
docker build -t="jene/myweb" .
參數-t指定生成鏡像的所屬用戶名和倉庫名,也可以有tag標識(這個例子沒寫,默認為latest)。 命令的最后點 不是結束符,而是表示Dockerfile文件在當前路徑下。也可以指定一個git倉庫的地址(只要該地址下有Dockerfile),則會利用git倉庫中的dockerfile文件來構建鏡像。
執行的過程會詳細 輸出每條指令執行的詳細信息。
構建成功后,我們就可以用 docker images命令查看新構建的鏡像,也可以用docker history命令查看新構建鏡像的構建歷史。
四、創建容器和啟動容器中的web服務
docker run -d -p 80 --name myweb 1311399350/myweb nginx -g "daemon off;"
上面命令創建和運行了容器,並將nginx服務啟動了。
上面命令除 -p參數外,其它參數前面文章都介紹過了。-d表示是 容器。 --name指定容器名,這里是myweb。 后面的是鏡像名。以及要執行的命令(這里是啟動nginx服務)。 -p參數我們下面詳細介紹。
下面我們來通過curl工具測試這個web服務是否可用。
1、先進入容器內訪問
docker exec -i -t myweb /bin/bash //進入容器的交互式shell
curl localhost:80 //可能容器中沒有curl工具
輸出如下內容
hello, i am a web image
2、在主機上訪問容器內的服務
首先查看容器內的80端口與主機上的端口的映射關系
運行 docker port myweb 80 顯示信息如下
0.0.0.0:32768
這里可以看出,映射的端口是32768.
我們在主機執行:
curl localhost:32768
輸出
hello, i am a web image
3、在主機以外的局域網內的其它機器訪問
先用ifconfig查看dokcer主機的ip地址,如 192.168.142.138
在其它機器上通過 http://192.168.142.138:32768/ 一樣可以訪問到 index.html網頁。
五、容器的端口配置
方法一:自動映射
docker run -d -p 80 --name myweb 1311399350/myweb nginx -g "daemon off;"
上面的 -p 80 ,將在docker主機上隨機打開一個端口(可利用docker port命令查看,或者docker ps也能看到,這里是32768)映射到容器中的80端口上。
方法二:指定映射
除了自動映射外,還可以指定映射關系,如:
docker run -d -p 80:80 --name myweb 1311399350/myweb nginx -g "daemon off;"
docker port myweb 80
0.0.0.0:80
可以看出,主機上的80端口映射到容器的80端口。
這樣指定的方式有好有懷,壞處是,第一無法運行多個同樣的容器,第二容易與主機上的應用沖突。好處是端口是已知的。需要小心使用。
方法三:公開dockerfile中EXPOSE指令指定的端口
docker run -d -P --name myweb 1311399350/myweb nginx -g "daemon off;"
利用大些的-P參數,將dockerfile中EXPOSE指令指定的端口(容器內端口)對本地宿主主機公開,並隨機綁定到本地宿主主機的端口上。
docker port myweb 80
0.0.0.0:32771
注意: 在docker run命令中通過 -p標記暴露的容器端口,並不一定需要在dockerfile文件中用EXPOSE指令配置。
在dockerfile文件中用EXPOSE指令配置端口,其好處是在docker run命令中可以用-P標記來全部暴露,省去了在docker run命令中用-p來逐個指定。