一、鏡像管理 1、拉取鏡像 -- Docker 鏡像倉庫地址 :一般是 功能變數名稱或者IP[:埠號]。預設地址是 Docker Hub -- 倉庫名 :兩段式名稱,即 用戶名/軟體名。對於Docker Hub,如果不給出用戶名,則預設為 library,也就是官方鏡像。 從下載過程中可以看到我們之前 提 ...
一、鏡像管理
1、拉取鏡像
docker pull [選項] [Docker Registry 地址[:埠號]/]倉庫名[:標簽]
-- Docker 鏡像倉庫地址 :一般是 功能變數名稱或者IP[:埠號]。預設地址是 Docker Hub
-- 倉庫名 :兩段式名稱,即 用戶名/軟體名。對於Docker Hub,如果不給出用戶名,則預設為 library,也就是官方鏡像。
從下載過程中可以看到我們之前 提及的分層存儲的概念,鏡像是由多層存儲所構成。下載也是一層一層的去下載,並非單一文件。
tips:Docker Hub 註冊的時候要FQ,否則那個註冊按鈕點擊不了~
2、查看鏡像
docker image ls docker images
列表包含了 倉庫名、標簽、鏡像ID、創建時間 以及 所占用的空間。
3、運行鏡像
docker run -it --rm -d -p 8888:8080 tomcat:8.0 -i:互動式操作 -t:終端 -rm:容器退出後隨之將其刪除,可以避免浪費空間 -p :埠映射 -d :容器在後臺運行
指明瞭 -d 運行鏡像,會返回容器的 id;如果不指明 -d 運行鏡像,會列印出 catalina.out 的 日誌,在 [crtl +c] 後,容器即停止運行。
至於容器啟動後,如果關閉容器進程,查看系統日誌等,會在下一篇文章中說明~
4、刪除鏡像
docker image rm IMAGE_ID(不需要全部的id字元,足夠區分別的鏡像就可以了) docker image rm 鏡像名(REPOSITORY:TAG)
tips:要註意鏡像和容器依賴的問題。如果用這個鏡像啟動的容器存在(即使容器沒有運行),那麼同樣不可以刪除這個鏡像,因為容器是以鏡像為基礎,再加一層容器存儲層,組成的多層結構去運行的。所以刪除 image 前要刪除 container 中的引用。
二、製作鏡像
鏡像的定製實際上就是定製每一層所添加的配置、文件。我們通常把每一層修改、安裝、構建、操作的命令都寫入一個腳本,用這個腳本來構建、定製鏡像,這個腳本就是 Dockerfile。
之前說過,鏡像是分層存儲的,Dockerfile 中每一個指令都會構建一層。鏡像構建時,一定要確保每一層只添加真正需要添加的東西,任何無關的東西都應該清理掉,避免鏡像的臃腫。
現在我們來研究下 Dockerfile 的命令(不推薦使用的命令不做介紹),然後再用個 Demo 來說明:
FROM:制定基礎鏡像,鏡像的定製一定是以一個鏡像為基礎,在其上進行定製。FROM 是必備的命令,而且必須是第一條指令。FROM scratch 意味著你不以任何鏡像為基礎,接下來所寫的指令將作為鏡像第一層開始存在。
RUN:用來執行命令行命令的。有兩種格式:
-- shell 格式:RUN <命令>,就像直接在命令行中輸入的命令一樣。
-- exec 格式:RUN ["可執行文件", "參數1", "參數2"],這更像是函數調用中的格式。
WORKDIR:指定工作目錄,以後各層的當前目錄就被改為指定的目錄,如該目錄不存在,WORKDIR 會幫你建立目錄。
-- 格式:WORKDIR <工作目錄路徑>
USER:USER 指令和 WORKDIR 相似,都是改變環境狀態並影響以後的層。
-- USER <用戶名>
COPY:將從 <源路徑>(上下文路徑) 的文件/目錄複製到新的一層的鏡像內的 <目標路徑> (可以容器內的絕對路徑或者相對於 WORKDIR 的相對路徑)位置,源文件的各種元數據都會保留,比如讀、寫、執行許可權等。
-- COPY <源路徑> <目標路徑>
-- COPY ["<源路徑1>",... "<目標路徑>"]
CMD:用於指定預設的容器主進程的啟動命令的(執行目標鏡像中包含的軟體),只能出現一次,CMD 後面的命令可被運行時 [ docker run xxxx:1.0 參數 ] 中的參數取代。對於容器而言,其啟動程式就是容器應用進程,容器就是為了主進程而存在的,主進程退出,容器就失去了存在的意義,從而退出,其它輔助進程不是它需要關心的東西。
-- shell 格式:CMD <命令>
-- exec 格式:CMD ["可執行文件", "參數1", "參數2"...]
-- 參數列表格式:CMD ["參數1", "參數2"...]。在指定了 ENTRYPOINT 指令後,用 CMD 指定具體的參數。用來和 ENTRYPOINT 指令搭配使用
ENTRYPOINT:目的和 CMD 一樣,都是在指定容器啟動程式及參數,只能出現一次。主要有兩點不同,一是 ENTRYPOINT 可以在啟動時,為其之後的命令添加自定義的參數。二 就是與 CMD 的交互,當 Dockerfile 文件中指定了ENTRYPOINT 時,CMD 中的內容就變成了 ENTRYPOINT的參數。
-- shell 格式:ENTRYPOINT <命令>
-- exec 格式:ENTRYPOINT ["可執行文件", "參數1", "參數2"]
ENV:設置環境變數,無論是後面的其它指令,還是運行時的應用,都可以直接使用這裡定義的環境變數($KEY)
-- ENV <key> <value>
-- ENV <key1>=<value1> <key2>=<value2>...
ARG:和 ENV 的效果一樣,都是設置環境變數。所不同的是,ARG 所設置的構建環境的環境變數,在將來容器運行時是不會存在這些環境變數的。而且該值可以在構建命令 docker build 中用 --build-arg <參數名>=<值> 來覆蓋。
-- ARG <參數名>[=<預設值>]
VOLUME:指定某些目錄掛載為匿名捲,這樣在運行時如果用戶不指定掛載,其應用也可以正常運行,不會向容器存儲層寫入大量數據。
-- VOLUME ["<路徑1>", "<路徑2>"...]
-- VOLUME <路徑>
EXPOSE:聲明運行時容器提供服務埠,這隻是一個聲明,在運行時並不會因為這個聲明應用就會開啟這個埠的服務。主要是為了鏡像使用者在宿主開啟埠服務時,可以映射到容器的埠。
-- EXPOSE <埠1> [<埠2>...]
HEALTHCHECK:告訴 Docker 應該如何進行判斷容器的狀態是否正常,當在一個鏡像指定了 HEALTHCHECK 指令後,用其啟動容器,初始狀態會為 starting,在 HEALTHCHECK 指令檢查成功後變為 healthy,如果連續一定次數失敗,則會變為 unhealthy。
-- HEALTHCHECK [選項] CMD <命令>:設置檢查容器健康狀況的命令
--interval=<間隔>:兩次健康檢查的間隔,預設為 30 秒;
--timeout=<時長>:健康檢查命令運行超時時間,如果超過這個時間,本次健康檢查就被視為失敗,預設 30 秒;
--retries=<次數>:當連續失敗指定次數後,則將容器狀態視為 unhealthy,預設 3 次。
-- HEALTHCHECK NONE:如果基礎鏡像有健康檢查指令,使用這行可以屏蔽掉其健康檢查指令
ONBUILD: 是一個特殊的指令,它後面跟的是其它指令,比如 RUN, COPY 等,而這些指令,在當前鏡像構建時並不會被執行。只有當以當前鏡像為基礎鏡像,去構建下一級鏡像的時候才會被執行。
-- ONBUILD <其它指令>
tips:在指令格式上,一般推薦使用 exec 格式,這類格式在解析時會被解析為 JSON 數組,因此一定要使用雙引號 ",而不要使用單引號。
簡單瞭解完這些命令後,讓我們來試著製作一個web工程的鏡像吧!為此,查了很多網上製作鏡像的教程,結果都不是很盡人意,很多竟然都是通過 docker commit 來製作的(不推薦使用 docker commit 來製作鏡像,會添加進很多編譯的文件,造成鏡像的臃腫),還有一些雖然是通過 Dockerfile 文件的方式來製作鏡像,但是 Dockerfile 的語法卻不是很規範(比如將多個 Linux 命令寫在多行,造成 鏡像無謂的分層,因為Dockerfile 一條命令就是一層結構)。
所以就自己著手寫一個 Dockerfile 文件吧!第一次自己琢磨著寫鏡像,有點小激動,連晚飯都忘記吃了...思路是這樣的,首先先寫一個基礎環境鏡像,基於 centos 伺服器,安裝好 jdk 環境和 Tomcat;然後基於這個基礎環境鏡像構建web鏡像 — 將 war 包拷貝進 webapps 目錄,啟動 Tomcat。
基礎鏡像文件 Dockerfile:
FROM centos #1、指定工作目錄 WORKDIR /usr/local #2、指定版本信息 ENV JAVA=jdk-8u181-linux-x64 TOMCAT=apache-tomcat-8.0.53 #3、創建目錄,多個命令儘量在一個Dockerfile 命令中完成,避免構建多層,做好清理工作 RUN mkdir java \ && mkdir tomcat \ && cd java \ && yum -y install wget \ && wget -q -O jdk-linux.rpm --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u181-b13/96a7b8442fe848ef90c96a2fad6ed6d1/${JAVA}.rpm \ && rpm -ivh jdk-linux.rpm \ && rm -rf jdk-linux.rpm \ && cd ../tomcat \ && wget -q http://apache.claz.org/tomcat/tomcat-8/v8.0.53/bin/${TOMCAT}.tar.gz \ && tar -zxv -f ${TOMCAT}.tar.gz \ && rm -rf ${TOMCAT}.tar.gz \ && rm -rf ${TOMCAT}/webapps/ROOT \ && yum -y remove wget; #4、把上下文目錄中的 war 複製進來 ONBUILD COPY *.war ./tomcat/${TOMCAT}/webapps/ #5、啟動容器 ONBUILD ENTRYPOINT ["/usr/local/tomcat/apache-tomcat-8.0.53/bin/catalina.sh","run"] #6、基礎環境構建完畢 CMD ["sh","-c","echo Environment construction completed"]
然後運行構建鏡像,註意docker build 最後面的那個點,表示的是鏡像的上下文目錄,COPY 命令的上下文目錄指的就是這個。
這個鏡像製作的,額,差強人意吧,竟然有600多兆。不過,最開放我思維的是那兩個 ONBUILD 命令,就像上文提到的 ONBUILD 命令本次鏡像不會被執行,只有以這個鏡像為基礎鏡像的時候才會被執行。所以,大家想想看,有了這個基礎鏡像後,我們將打好的 war 包放在上下文目錄,然後就可以運行起來任意的 web 工程啦!
接下來,來看看 web 鏡像是怎麼製作出來的吧!已經進展到了這一步,你會發現出奇的簡單~
FROM myenv:1.0
是的,你沒有看錯,整個 Dockerfile 就只要這行命令就夠了,然後構建的時候,會幫你把 war 包放進 webapps 目錄(ONBUILD 的效果),接著構建運行起來吧~
#構建(--no-cache=true 表示不使用鏡像緩存)
docker build -t myweb .
#運行
docker run -p 7575:8080 myweb
哈哈,折騰了一個周末,終於成功了!小激動小激動~~ 寫的兩個鏡像已經上傳到了 Docker hub,喜歡的點個推薦吧!
Dockerfile 的一些書寫建議:
1、使用 Dockerfile 構建鏡像時最好是將 Dockerfile 放置在一個新建的空目錄下。然後將構建鏡像所需要的文件添加到該目錄中。
2、應該保證在一個容器只運行一個進程。將多個應用解耦到不同容器中,保證容器的橫向擴展和復用。例如 web 應用應該包含三個容器:web應用、資料庫、緩存。
3、FROM:推薦使用 Alpine 鏡像,因為它被嚴格控制並保持最小尺寸(目前小於 5 MB),但它仍然是一個完整的 Linux 發行版。
4、多行命令用反斜杠 \ 分割成多行,增加可讀性。
5、不要使用 RUN apt-get upgrade 或 dist-upgrade,因為許多基礎鏡像中的「必須」包不會在一個非特權容器中升級。
6、永遠將 RUN apt-get update 和 apt-get install 組合成一條 RUN 聲明,將 apt-get update 放在一條單獨的 RUN 聲明中會導致緩存問題以及後續的 apt-get install 失敗。
7、應該避免使用 sudo,因為它不可預期的 TTY 和信號轉發行為可能造成的問題比它能解決的問題還多。
Docker hub 地址:https://hub.docker.com/u/jmcui/
參考資料:《Docker — 從入門到實踐》