6、Containerizing an app

containerizing,有時也叫Dockerizing,is the process of taking an application and configuring it to run as a container.java

容器一般是關於apps,特別是,它們使得app的構建、傳送(將image推送到Docker倉庫)、運行變的簡單。node

將應用程序裝箱的過程以下:git

一、編寫應用程序代碼;github

二、建立Dockerfile描述app、它的依賴以及如何運行它;web

三、將Dockerfile輸入到docker image 構建命令;docker

四、Docker將應用程序構建成Docker image。npm

上述過程的圖示以下:瀏覽器

 

接下來,將以一個簡單的單容器 Node.js web app爲例來進行裝箱,主要包含以下步驟:緩存

• 獲取app代碼
• 檢查Dockerfile
• 裝箱app
• 運行app
• 測試app
• 使用多階段構建轉移到生產環境
• 一些最佳實踐網絡

注:使用網上環境,地址:https://labs.play-with-docker.com/

一、獲取app代碼

從GitHubs上將https://github.com/nigelpoulton/psweb.git克隆到本地,psweb目錄下包含了全部的應用程序源代碼。以下圖所示:

二、檢查Dockerfile

psweb目錄下有一個文件叫Dockerfile,這個文件描述了應用程序,並告訴Docker如何把應用程序構建進鏡像。

包含應用程序的目錄被稱之爲構建上下文,將Dockerfile放在構建上下文的根目錄是一個通用實踐。

注意 Dockerfile以大寫字母D開始,是一個單詞,dockerfile和Docker file都是無效的。

Dockerfile的主要目的有兩個:描述應用程序和告訴Docker如何將應用程序裝箱(建立一個包含應用程序的鏡像)。此外,還能夠彌合開發和運營之間的鴻溝!

上述Dockerfile文件裏的內容可解釋爲:以alpine鏡像開始,增長nigelpoulton@hotmail.com做爲維護者(設置元數據,不會產生新的層),安裝Node.js和NPM,拷貝應用程序代碼,設置工做目錄(設置元數據,不會產生新的層),安裝依賴,記錄app網絡端口(設置元數據,不會產生新的層),設置app.js做爲運行的缺省應用程序。以下圖所示:

全部的Dockerfile都是以 FROM開始,這個是鏡像的基礎層,其餘的做爲附加層。

三、裝箱app

Dockerfile編寫完成後,就能夠開始構建鏡像。  構建完成後,用docker image ls查看構建的鏡像,應用程序已被裝箱。

能夠將鏡像推送到Docker Hub倉庫。前提是你必須得有一個Docker Hub帳號.

在推送鏡像到倉庫前,必須以特定的方式來對鏡像進行打標籤。當推送鏡像時,Docker須要下列全部信息:Registry、 Repository、Tag

通常狀況下,不須要指定Registry(默認docker.io)和Tag(默認latest),然而,Docker對於Repository也不須要一個缺省值,它從推送的鏡像中獲取「REPOSITORY」值。

對於上述構建的鏡像,docker image push將嘗試和 推送鏡像到docker.io/web:latest,但因爲沒有訪問web倉庫的權限,全部的鏡像都存在於二級命名空間,所以須要從新打標籤,命令爲 docker image tag <current-tag> <new-tag> ,這將會額外增長一個標籤,並不會覆蓋原始的。

四、運行app

輸入命令:docker container run -d --name c1 -p 80:8080 web:latest,來運行app,以下圖所示:

五、測試app

在瀏覽器輸入地址,出現以下界面,則app啓動成功,正在運行。

六、使用多階段構建轉移到生產環境

對於Docker鏡像來講,大是糟糕的。大意味着更多潛在的脆弱性和可能更大的攻擊面。

Docker鏡像應該小,它的目的是傳送僅包含所需原料的生產鏡像在生產環境運行app。
編寫Dockerfile的方式會影響鏡像的大小,由於每個RUN指令都會在鏡像裏增長一層。所以最佳實踐是在每個RUN指令裏包含多個命令。

另外一個問題是,咱們不會清除咱們本身。針對鏡像,咱們會運行一些命令在拉取build-time工具,當咱們傳送鏡像到生產環境時,這些工具遺留在鏡像裏,這不是理想的。

對於上述問題,大多數狀況下使用 builder pattern,但大多數都須要行爲準則而且增長了複雜度。

builder pattern要求至少兩個Dockerfile:一個生產環境,一個開發環境。在開發環境中,編寫Dockerfile.dev,能夠從一個大的基礎鏡像開始拉取任何須要的構建工具,而後構建app。而後從Dockerfile.dev構建鏡像,建立容器並運行它。在生產環境中,編寫Dockerfile.prod,從一個較小的基礎鏡像構建新鏡像,僅拷貝應用程序。全部的任何事都須要使用腳原本進行粘合。

這個方法是可行的,可是以複雜度爲代價的。

多階段構建能夠解決上述問題。

多階段構建是關於在不增長複雜性的狀況下優化構建的。

在多階段構建中,咱們須要一個單一的Dockerfile,包含多個FROM指令。每個FROM指令是一個新的構建階段 ,能夠輕鬆複製前述階段的產物。

Dockerfile文件內容以下:

從上述Dockerfile看,有3個FROM指令,每個FROM指令構成一個獨特的構建階段,好比 階段 0 叫storefront,階段 1 叫appserver,階段 2叫production。

storefront階段:拉取node:latest鏡像,設置工做目錄,拷貝APP代碼,使用兩個RUN指令執行npm,此鏡像有3個層,且size大。由於包含了大量的構建東西而非代碼。

appserver階段:拉取maven:latest鏡像,經過兩個COPY和兩個RUN指令增長了4個層,這產生了很是多的構建工具和不多的實際生產 代碼。

production階段:拉取java:8-jdk-alpine鏡像,此比node和maven鏡像小不少。它增長了用戶,設置工做目錄,從storefront階段產生的鏡像裏拷貝一些app代碼。此外,設置了一個不一樣的工做目錄,從appserver階段產生的鏡像裏拷貝一些應用程序代碼,最後,給鏡像設置了當它做爲容器啓動時的主運行程序。

對上述的Dockerfile進行構建,在上圖中輸入:"docker image build -t multi:stage .",完成後,輸入 docker image ls查看,以下:

其中node:latest是由storefront階段拉取的,maven:latest是由appserver階段拉取的,兩個<none>:<none>鏡像分別由storefront階段和appserver階段產生的(分別增長Dockerfile裏描述的層所組成)。java:8-jdk-alpine是multi:stage階段拉取的,multi:stage是由最後的構建階段所產生的鏡像,從上述看,此兩個鏡像比storefront階段和appserver階段產生的鏡像大小小不少。
七、 一些最佳實踐

  • 利用構建緩存(Leverage the build cache)
  • 壓縮鏡像(Squash the image,Docker遵循一個正常的過程來構建鏡像,最後增長了一個步驟將全部的東西壓縮成單一層)

  • 使用no-install-recommends(Use no-install-recommends)【使用apt包管理器時,須要在apt-get install命令後使用no-install-recommends標誌,這使得apt僅安裝主要依賴,其餘的不安裝】
  • 在Windows下,不要從MSI包進行安裝(Do not install from MSI packages (Windows))

 

• docker image build :讀取Dockerfile文件,將應用程序裝箱,-t 標籤標記鏡像,能夠聲明Dockerfile文件中的名稱和位置。• FROM 指令:爲新鏡像聲明base鏡像。  • RUN指令:容許在運行鏡像中的指令,其建立了一個新層。每個RUN指令建立一個單一新層。 • COPY指令:向鏡像中添加文件,並做爲一個新層。一般向鏡像中拷貝應用程序。 • EXPOSE指令:記錄應用程序使用的網絡端口。 • ENTRYPOINT指令:當鏡像做爲容器啓動時,將默認應用程序設置爲運行。 • 其餘的Dockerfile指令包括LABEL, ENV, ONBUILD, HEALTHCHECK, CMD燈。

相關文章
相關標籤/搜索