Docker最全教程——從理論到實戰(三)

雪雁發表於2018-12-03

往期連結:

https://www.cnblogs.com/codelove/p/10030439.html

https://www.cnblogs.com/codelove/p/10036608.html

 

 

寫在前面

容器是應用走向雲端之後必然的發展趨勢,因此筆者非常樂於和大家分享我們這段時間對容器的理解、心得和實踐。

本教程持續編寫了2個星期左右並且一直在完善、補充具體的細節和實踐,預計全部完成需要1到2個月的時間。由於編寫的過程中極其費時,並且還需要配合做一些實踐(有些實踐存在一些坑,而且極其費時費事)。因此目前產出的速度已經跟不上釋出的速度了,後續的釋出節奏會放慢,請大家多多理解和多多包含。

根據目前和大家的交流,筆者針對大家的情況進行了一些修改和補充,希望對大家有所幫助。另外,對於熟悉容器服務的你,也可以參與進來,讓我們一起打造這個系列教程,我們希望能夠多多交流,多多分享,以幫助更多的人。同時,我們也希望得到大家的支援。

前言

內容發出來之後,有部分小夥伴有些疑惑。這裡我特別說明下,Docker for windows 指的是docker官方提供的windows的安裝包,並不是指的基於windows映象開發。筆者推薦的方式是——在windows上開發和調測,託管到Linux。

Docker持續開發工作流

Docker改變了開發以及產品交付流程,以下是一般情況下的Docker應用程式的內部迴圈的持續開發工作流,本工作流只關注在開發人員的計算機上進行的開發工作,不包括設定環境等初始步驟,因為這些步驟只需進行一次。

應用程式一般由開發人員自己的服務程式碼和附加庫(依賴項)組成,以下是生成 Docker 應用程式時常用的基本步驟,具體如下圖所示:

在本篇教程中,我們以開源框架Magicodes.Admin為例進行講解。

Magicodes.Admin,是心萊科技團隊打造的一套高效率、易擴充套件、基礎設施強大、程式碼生成完備、理念和技術先進的敏捷開發框架,同時也是一套分散式(即將提供微服務架構參考)、跨平臺(linux、Docker容器支援)、多終端(包括Android、IOS、H5、小程式、微信公眾號)支援的統一開發框架和解決方案。框架基於.NET Core 2.1、Angular、Ionic、EF Core、ABP和ASP.NET Zero,並在其基礎上進行了封裝和完善,並且編寫了相關的工具(程式碼生成)、元件(雲端儲存、支付、微信等等)、生成服務。

程式碼地址:https://gitee.com/xl_wenqiang/Magicodes.Admin.Core

 

在開始之前,我們先需要準備好相關環境和程式碼。比如:

Git clone git@gitee.com:xl_wenqiang/Magicodes.Admin.Core.git

相關環境以及前期準備大家可以參閱公眾號”magiccodes“中的教程,這裡就不多贅述了。

 

開發

開發過程其實和傳統開發一樣,也就是說,開發Docker 應用的方式與開發非Docker應用的方式類似。二者的主要區別在於,開發 Docker 應用程式時,是在本地環境中的Docker容器中部署和測試,該容器可以是Linux容器或Windows 容器。

 

一般情況下,我們搭建好框架程式碼之後,就需要針對需求進行開發,以滿足業務為目的,也就是這個開發過程並沒有什麼改變,這裡我們假設所有程式碼均已就緒,開始下一步。

 

建立Dockerfile

本節內容很多,我們希望大家能夠了解和使用好Dockerfile。

關於dockerfile

雖然我們可以通過docker commit命令來手動建立映象,但是通過Dockerfile檔案,可以幫助我們自動建立映象,並且能夠自定義建立過程。本質上,Dockerfile就是由一系列命令和引數構成的指令碼,這些命令應用於基礎映象並最終建立一個新的映象。它簡化了從頭到尾的構建流程並極大的簡化了部署工作。使用dockerfile構建映象有以下好處:

  • 像程式設計一樣構建映象,支援分層構建以及快取;

  • 可以快速而精確地重新建立映象以便於維護和升級;

  • 便於持續整合;

  • 可以在任何地方快速構建映象

 

Dockerfile指令

我們需要了解一些基本的Dockerfile 指令,Dockerfile 指令為 Docker 引擎提供了建立容器映像所需的步驟。這些指令按順序逐一執行。以下是有關一些基本 Dockerfile 指令的詳細資訊。

1.FROM

FROM 指令用於設定在新映像建立過程期間將使用的容器映像。

格式:FROM 

示例:

FROM nginx

FROM microsoft/dotnet:2.1-aspnetcore-runtime

  

2.RUN

RUN 指令指定將要執行並捕獲到新容器映像中的命令。 這些命令包括安裝軟體、建立檔案和目錄,以及建立環境配置等。

格式:

RUN ["", "", ""]

RUN

示例:

RUN apt-get update

RUN mkdir -p /usr/src/redis

RUN apt-get update && apt-get install -y libgdiplus

RUN ["apt-get","install","-y","nginx"]

注意:每一個指令都會建立一層,並構成新的映象。當執行多個指令時,會產生一些非常臃腫、非常多層的映象,不僅僅增加了構建部署的時間,也很容易出錯。因此,在很多情況下,我們可以合併指令並執行,例如:RUN apt-get update && apt-get install -y libgdiplus。在命令過多時,一定要注意格式,比如換行、縮排、註釋等,會讓維護、排障更為容易,這是一個比較好的習慣。使用換行符時,可能會遇到一些問題,具體可以參閱下節的轉義字元。

 

3.COPY

COPY 指令將檔案和目錄複製到容器的檔案系統。檔案和目錄需位於相對於 Dockerfile 的路徑中。

格式:

COPY

如果源或目標包含空格,請將路徑括在方括號和雙引號中。

 

COPY ["", ""]

示例:

COPY . .

COPY nginx.conf /etc/nginx/nginx.conf

COPY . /usr/share/nginx/html

COPY hom* /mydir/

 

4.ADD

ADD 指令與 COPY 指令非常類似,但它包含更多功能。除了將檔案從主機複製到容器映像,ADD 指令還可以使用 URL 規範從遠端位置複製檔案。

格式:

ADD<source> <destination>

示例:

ADD https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe /temp/python-3.5.1.exe

此示例會將 Python for Windows下載到容器映像的 c:\temp 目錄。

 

5.WORKDIR

WORKDIR 指令用於為其他 Dockerfile 指令(如 RUN、CMD)設定一個工作目錄,並且還設定用於執行容器映像例項的工作目錄。

格式:

WORKDIR

示例:

WORKDIR /app

 

6.CMD

CMD指令用於設定部署容器映像的例項時要執行的預設命令。例如,如果該容器將承載 NGINX Web 伺服器,則 CMD 可能包括用於啟動Web伺服器的指令,如 nginx.exe。 如果 Dockerfile 中指定了多個CMD 指令,只會計算最後一個指令。

格式:

CMD ["<executable", "

CMD

示例:

CMD ["c:\\Apache24\\bin\\httpd.exe", "-w"]

CMD c:\\Apache24\\bin\\httpd.exe -w

 

7.ENTRYPOINT

配置容器啟動後執行的命令,並且不可被 docker run 提供的引數覆蓋。每個 Dockerfile 中只能有一個ENTRYPOINT,當指定多個時,只有最後一個起效。

格式:

ENTRYPOINT ["", ""]

示例:

ENTRYPOINT ["dotnet", "Magicodes.Admin.Web.Host.dll"]

 

8.ENV

ENV命令用於設定環境變數。這些變數以”key=value”的形式存在,並可以在容器內被指令碼或者程式呼叫。這個機制給在容器中執行應用帶來了極大的便利。

格式:

ENV==...

示例:

ENV VERSION=1.0 DEBUG=on \

NAME="Magicodes"

 

9.EXPOSE

EXPOSE用來指定埠,使容器內的應用可以通過埠和外界互動。

格式:

EXPOSE

示例:

EXPOSE 80

 

說了這麼多,我們可以用下圖來一言以蔽之:

 

轉義字元

在許多情況下,Dockerfile 指令需要跨多個行;這可通過轉義字元完成。 預設 Dockerfile 轉義字元是反斜槓 \。 由於反斜槓在 Windows 中也是一個檔案路徑分隔符,這可能導致出現問題。

以下示例顯示使用預設轉義字元跨多個行的單個 RUN 指令。

FROM microsoft/windowsservercore

 

RUN powershell.exe -Command \

$ErrorActionPreference = 'Stop'; \

wget https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile c:\python-3.5.1.exe ; \

Start-Process c:\python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait ; \

Remove-Item c:\python-3.5.1.exe -Force

 

要修改轉義字元,必須在 Dockerfile 最開始的行上放置一個轉義分析程式指令。 如以下示例所示:

# escape=`

 

FROM microsoft/windowsservercore

 

RUN powershell.exe -Command `

$ErrorActionPreference = 'Stop'; `

wget https://www.python.org/ftp/python/3.5.1/python-3.5.1.exe -OutFile c:\python-3.5.1.exe ; `

Start-Process c:\python-3.5.1.exe -ArgumentList '/quiet InstallAllUsers=1 PrependPath=1' -Wait ; `

Remove-Item c:\python-3.5.1.exe -Force

注意,只有兩個值可用作轉義字元:\ 和 ` 。

 

優化

篇幅有限,我們這裡只進行簡單講解,後續結合實際案例再進行細說。但是有幾點值得注意的是:

  1. 不能忽視dockerfile的優化,通常情況下,我們可以忽略那些細小的優化,但是我們需要知道優化的原理,為什麼要優化

  2. 不能為了優化而優化。映象的構建過程視業務情況情況不同,指令就有多到少的區別,在很多情況下,我們先要以滿足業務目標為準,而不是映象層數。如果需要減少映象的層數,我們一定要選擇合適的基礎映象,或者建立符合我們需要的基礎映象。

下面是一些優化的準則:

  • 選擇合適的基礎映象

    這點相對最為重要。為什麼這麼說,我們結合現實社會也可以看到,在大部分情況下,一個人一生的成就更多的是看出身。很多情況下,基因和出身決定了你的高度和終點,這點拿到技術層面來說,也是有很大道理的,因此我們需要選擇合適的父母——一個合適的映象。

    一個合適的基礎映象是指能滿足執行應用所需要的最小的映象,理論上是能用小的就不要用大的,能用輕量的就不要用重量級的,能用效能好的就不要用效能差的。這裡有時候還需要考慮那些能夠減少我們構建層數的基礎映象。

     

  • 優化指令順序

    Docker會快取Dockerfile中尚未更改的所有步驟,但是,如果更改任何指令,將重做其後的所有步驟。也就是指令3有變動,那麼4、5、6就會重做。因此,我們需要將最不可能產生更改的指令放在前面,按照這個順序來編寫dockerfile指令。這樣,在構建過程中,就可以節省很多時間。比如,我們可以把WORKDIR、ENV等命令放前面,COPY、ADD放後面。

     

  • 合併指令

    前面其實我們提到過這點,甚至還特地講到了轉義字元,其實主要是為此服務。前面我們說到了,每一個指令都會建立一層,並構成新的映象。當執行多個指令時,會產生一些非常臃腫、非常多層的映象,不僅僅增加了構建部署的時間,也很容易出錯。因此,在很多情況下,我們可以合併指令並執行,例如:RUN apt-get update && apt-get install -y libgdiplus。在命令過多時,一定要注意格式,比如換行、縮排、註釋等,會讓維護、排障更為容易,這是一個比較好的習慣。

     

  • 刪除多餘檔案和清理沒用的中間結果

    這點很易於理解,通常來講,體積更小,部署更快!因此在構建過程中,我們需要清理那些最終不需要的程式碼或檔案。比如說,臨時檔案、原始碼、快取等等。

      

  • 使用 .dockerignore

    .dockerignore檔案用於忽略那些映象構建時非必須的檔案,這些檔案可以是開發文件、日誌、其他無用的檔案。例如:

說了這麼多,其實我們更多的還是需要根據命令的實際執行情況來進行調整。

 

Visual studio和dockerfile

如上所示,要生成自定義映象,需為每個自定義映象提供一個 Dockerfile。無論是從Visual Studio 自動部署,還是使用 Docker CLI(docker run 和 docker-compose 命令)手動部署,都需為每個要部署的容器提供一個 Dockerfile。如果應用程式只包含一個自定義服務,則只需要一個 Dockerfile。如果應用程式包含多個服務(如在微服務體系結構中),則每個服務都需要一個 Dockerfile。Dockerfile檔案需要放在應用程式或服務的根資料夾中。

但是,對於.NET開發人員來說,利用Visual Studio只需單擊幾次滑鼠即可完成此任務。如下圖所示:

還可通過在 Visual Studio 中右鍵單擊專案檔案,選擇“新增 Docker 專案支援”選項,為新專案或現有專案啟用 Docker 支援:

對專案(如 ASP.NET Web 應用程式或 Web API 服務)應用此操作後,系統會向含有所需配置的專案新增 Dockerfile。

在更多的情況下,筆者建議大家選擇下面的選單——容器業務流程協調程式支援:

因為會向整個解決方案新增 docker-compose.yml 等檔案。整個過程,Visual Studio 代為執行了操作,但是,我們也需要了解 Dockerfile中的內容,否則遇到問題,會抓蝦,哦,是抓瞎。

啟用了之後,我們就可以看到頂部的選單欄出現了一些便捷操作:

不僅支援一鍵啟動,還能夠除錯!!!這對於大部分開發者來說,簡直是天籟之音哈!

接下來,我們以Magicodes.Admin為例。在Magicodes.Admin中,存在多個應用,比如後臺服務和後臺UI,目前框架中已經提供了多個dockerfile的配置,分別在相應的工程目錄之中。

 

.net core後臺服務的dockerfile

檔案所在目錄如下所示:

相關指令我在註釋中進行了一一說明,不過,由於Excel的匯出在Linux環境需要libgdiplus庫的支援,以設定字型,因此我們需要在dockerfile中配置安裝此庫。同時,我們還推薦使用以下簡化的dockerfile:

其中,包還原、編譯、單元測試執行以及釋出等過程我們通過指令碼進行了實現,因此在Dockerfile中,命令比較簡單幹淨,關鍵是整個過程我們能夠在本地進行更多的自定義——比如執行單元測試並再通過之後才進行部署和推送。當然,使用第一個配置能夠讓我們可以更好地和線上的CI工具配套使用。

注意:這裡我們並沒有使用其他web伺服器,我們直接在程式碼中使用了Kestrel伺服器進行託管。

 

 

後臺前端應用的dockerfile

檔案所在目錄如下所示:

後臺前端應用使用nginx web伺服器進行託管,同時執行了copy命令複製相關配置、靜態檔案和ssl證照。其中nginx.conf的配置如下所示:

關於dockerfile的相關內容,我們先講述到這裡,希望大家對此有個全面的瞭解。如果你有疑問或者建議,歡迎討論交流。

往期連結:

https://www.cnblogs.com/codelove/p/10030439.html

https://www.cnblogs.com/codelove/p/10036608.html

 

相關文章