之前我們用到的鏡像,無論是ubuntu鏡像還是busybox鏡像,都是來自於官方Docker Hub中的鏡像。直接使用這些鏡像是可以滿足一定的需求,而當這些鏡像無法直接滿足需求時,就需要在這些鏡像的基礎上修改,來定製符合實際需求的鏡像。
以定製一個Web服務器鏡像爲例子講述如何定製一個鏡像。
在nginx鏡像的基礎上,定製一個以“Hello Docker”爲nginx歡迎界面的新鏡像nginx:v1.0。
對容器做出修改
首先使用docker pull nginx:latest
從Docker Hub中拉取一個nginx:latest鏡像,其中Nginx是一款自由的、開源的、高性能的HTTP和反向代理服務器。
在Docker中,我們無法直接查看一個鏡像的內容,而且因爲鏡像是隻讀的,所以也無法對鏡像做出任何修改。但是如果以鏡像爲基礎創建並啓動一個容器,該容器會擁有鏡像的全部內容,也就通過容器查看鏡像的內容。除此以外,容器是可讀寫的!
nginx歡迎界面的內容保存在/usr/share/nginx/html/index.html
中,如果想要將nginx歡迎界面的內容修改爲“Hello Docker”,只需要將/usr/share/nginx/html/index.html
替換爲“Hello Docker”即可了。
執行docker run --name webserver -d -p 80:80 nginx
命令,這條命令以nginx基礎鏡像創建了一個名爲webserver的容器,在這條命令中出現了一個以前沒有介紹的命令選項-p,-p用於端口映射,以此條命令爲例,-p 80:80代表將宿主機的80端口映射到容器的80端口,這意味着可以直接通過訪問宿主機ip:80訪問到容器的80端口!
容器創建完成後,執行docker exec -it webserver /bin/bash
進入webserver容器。並且將/usr/share/nginx/html/index.html
的內容修改爲Hello Docker!。如下所示:
[root@localhost Desktop]# docker exec -it webserver /bin/bash
root@da9d93718c3d:/# echo '<h1>Hello Docker!</h1>' > /usr/share/nginx/html/index.html
root@da9d93718c3d:/# cat /usr/share/nginx/html/index.html
<h1>Hello Docker!</h1>
在瀏覽器中訪問localhost:80,歡迎界面變成了“Hello Docker”。
將“對容器的修改”保存爲鏡像
在Docker中提供了一個命令docker commit,該命令會把對容器的修改提交成一個鏡像。換句話說,就是在原有鏡像的基礎上,再疊加上容器的存儲層(該存儲層僅僅保存了容器所做的修改),將這些內容構成一個新的鏡像。docker commit的基本語法如下:
docker commit [OPTIONS] CONTAINER [鏡像名]
其中:
- docker commit:Docker拉取鏡像的命令關鍵詞;
- [OPTIONS]:命令選項,其中–author指定作者,–message制定commit的信息;
- CONTAINER:需要commit的容器;
- 鏡像名:新鏡像的名字,以<倉庫名>:<標籤>的方式來指定。如果不顯示設置,將默認爲None:None。(這個代表沒有指定鏡像名)
現在將對webserver容器做出的修改提交爲一個新鏡像nginx:v1,只需要執行docker commit webserver nginx:v1。
現在驗證nginx:v1鏡像的歡迎界面的內容是否變成了“Hello Docker”
首先執行docker commit webserver nginx:v1,將對webserver容器做出的修改提交爲一個新鏡像nginx:v1。然後執行docker run -p 50:80 nginx:v1 cat /usr/share/nginx/html/index.html,以nginx:v1爲基礎鏡像創建啓動一個新容器,並將宿主機的50端口映射到容器的80端口。可以看到nginx歡迎界面的內容爲Hello Docker!,這說明我們成功了!!
[root@localhost Desktop]# docker commit webserver nginx:v1
sha256:081c446e9b657ac966dd7466fd93614a71a945600f9fe182435168554351c236
[root@localhost Desktop]# docker run -p 50:80 nginx:v1 cat /usr/share/nginx/html/index.html
<h1>Hello Docker!</h1>
使用commit定製鏡像的缺陷
在實際的環境中,我們一般不會使用Commit去構建一個鏡像,因爲它存在很多的缺陷:
首先,由於commit會將對容器做出所有的修改都保存爲鏡像,這就意味着我們可能會保存許多不必要的文件變化,例如我僅僅只是爲了修改nginx的歡迎頁,但是我新增了一些文件,那麼這些文件也會跟着保存到鏡像中去,顯然它們是多餘的。
此外,docker commit意味着所有對鏡像的操作都是黑箱操作,生成的鏡像也被稱爲黑箱鏡像,換句話說,就是除了製作鏡像的人知道執行過什麼命令、怎麼生成的鏡像,別人根本無從得知。而且,即使是這個製作鏡像的人,過一段時間後也無法記清具體在操作的。雖然docker diff或許可以告訴得到一些線索,但是遠遠不到可以確保生成一致鏡像的地步。這種黑箱鏡像的維護工作是非常痛苦的。
既然docker commit存在這麼多缺陷,是不是有更好的替代方法呢?沒錯,不要着急。後面我們會介紹更好的定製鏡像的方法:Dockerfile!!