Docker最全教程——從理論到實(shí)戰(zhàn)(三)

寫在前面

容器是應(yīng)用走向云端之后必然的發(fā)展趨勢,因此筆者非常樂于和大家分享我們這段時(shí)間對(duì)容器的理解、心得和實(shí)踐。

本教程持續(xù)編寫了2個(gè)星期左右并且一直在完善、補(bǔ)充具體的細(xì)節(jié)和實(shí)踐,預(yù)計(jì)全部完成需要1到2個(gè)月的時(shí)間。由于編寫的過程中極其費(fèi)時(shí),并且還需要配合做一些實(shí)踐(有些實(shí)踐存在一些坑,而且極其費(fèi)時(shí)費(fèi)事)。因此目前產(chǎn)出的速度已經(jīng)跟不上發(fā)布的速度了,后續(xù)的發(fā)布節(jié)奏會(huì)放慢,請(qǐng)大家多多理解和多多包含。

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

前言

內(nèi)容發(fā)出來之后,有部分小伙伴有些疑惑。這里我特別說明下,Docker for windows 指的是docker官方提供的windows的安裝包,并不是指的基于windows鏡像開發(fā)。筆者推薦的方式是——在windows上開發(fā)和調(diào)測,托管到Linux。

Docker持續(xù)開發(fā)工作流

Docker改變了開發(fā)以及產(chǎn)品交付流程,以下是一般情況下的Docker應(yīng)用程序的內(nèi)部循環(huán)的持續(xù)開發(fā)工作流,本工作流只關(guān)注在開發(fā)人員的計(jì)算機(jī)上進(jìn)行的開發(fā)工作,不包括設(shè)置環(huán)境等初始步驟,因?yàn)檫@些步驟只需進(jìn)行一次。

應(yīng)用程序一般由開發(fā)人員自己的服務(wù)代碼和附加庫(依賴項(xiàng))組成,以下是生成 Docker 應(yīng)用程序時(shí)常用的基本步驟,具體如下圖所示:

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

Magicodes.Admin,是心萊科技團(tuán)隊(duì)打造的一套高效率、易擴(kuò)展、基礎(chǔ)設(shè)施強(qiáng)大、代碼生成完備、理念和技術(shù)先進(jìn)的敏捷開發(fā)框架,同時(shí)也是一套分布式(即將提供微服務(wù)架構(gòu)參考)、跨平臺(tái)(linux、Docker容器支持)、多終端(包括Android、IOS、H5、小程序、微信公眾號(hào))支持的統(tǒng)一開發(fā)框架和解決方案??蚣芑?NET Core 2.1、Angular、Ionic、EF Core、ABP和ASP.NET Zero,并在其基礎(chǔ)上進(jìn)行了封裝和完善,并且編寫了相關(guān)的工具(代碼生成)、組件(云存儲(chǔ)、支付、微信等等)、生成服務(wù)。

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


在開始之前,我們先需要準(zhǔn)備好相關(guān)環(huán)境和代碼。比如:

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

相關(guān)環(huán)境以及前期準(zhǔn)備大家可以參閱公眾號(hào)”magiccodes“中的教程,這里就不多贅述了。


開發(fā)

開發(fā)過程其實(shí)和傳統(tǒng)開發(fā)一樣,也就是說,開發(fā)Docker 應(yīng)用的方式與開發(fā)非Docker應(yīng)用的方式類似。二者的主要區(qū)別在于,開發(fā) Docker 應(yīng)用程序時(shí),是在本地環(huán)境中的Docker容器中部署和測試,該容器可以是Linux容器或Windows 容器。


一般情況下,我們搭建好框架代碼之后,就需要針對(duì)需求進(jìn)行開發(fā),以滿足業(yè)務(wù)為目的,也就是這個(gè)開發(fā)過程并沒有什么改變,這里我們假設(shè)所有代碼均已就緒,開始下一步。


創(chuàng)建Dockerfile

本節(jié)內(nèi)容很多,我們希望大家能夠了解和使用好Dockerfile。

關(guān)于dockerfile

雖然我們可以通過docker commit命令來手動(dòng)創(chuàng)建鏡像,但是通過Dockerfile文件,可以幫助我們自動(dòng)創(chuàng)建鏡像,并且能夠自定義創(chuàng)建過程。本質(zhì)上,Dockerfile就是由一系列命令和參數(shù)構(gòu)成的腳本,這些命令應(yīng)用于基礎(chǔ)鏡像并最終創(chuàng)建一個(gè)新的鏡像。它簡化了從頭到尾的構(gòu)建流程并極大的簡化了部署工作。使用dockerfile構(gòu)建鏡像有以下好處:

像編程一樣構(gòu)建鏡像,支持分層構(gòu)建以及緩存;

可以快速而精確地重新創(chuàng)建鏡像以便于維護(hù)和升級(jí);

便于持續(xù)集成;

可以在任何地方快速構(gòu)建鏡像


Dockerfile指令

我們需要了解一些基本的Dockerfile 指令,Dockerfile 指令為 Docker 引擎提供了創(chuàng)建容器映像所需的步驟。這些指令按順序逐一執(zhí)行。以下是有關(guān)一些基本 Dockerfile 指令的詳細(xì)信息。

1.FROM

FROM 指令用于設(shè)置在新映像創(chuàng)建過程期間將使用的容器映像。

格式:FROM?

示例:

FROM nginx

FROM microsoft/dotnet:2.1-aspnetcore-runtime


2.RUN

RUN?指令指定將要運(yùn)行并捕獲到新容器映像中的命令。 這些命令包括安裝軟件、創(chuàng)建文件和目錄,以及創(chuàng)建環(huán)境配置等。

格式:

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"]

注意:每一個(gè)指令都會(huì)創(chuàng)建一層,并構(gòu)成新的鏡像。當(dāng)運(yùn)行多個(gè)指令時(shí),會(huì)產(chǎn)生一些非常臃腫、非常多層的鏡像,不僅僅增加了構(gòu)建部署的時(shí)間,也很容易出錯(cuò)。因此,在很多情況下,我們可以合并指令并運(yùn)行,例如:RUN apt-get update && apt-get install -y libgdiplus。在命令過多時(shí),一定要注意格式,比如換行、縮進(jìn)、注釋等,會(huì)讓維護(hù)、排障更為容易,這是一個(gè)比較好的習(xí)慣。使用換行符時(shí),可能會(huì)遇到一些問題,具體可以參閱下節(jié)的轉(zhuǎn)義字符。


3.COPY

COPY?指令將文件和目錄復(fù)制到容器的文件系統(tǒng)。文件和目錄需位于相對(duì)于?Dockerfile?的路徑中。

格式:

COPY

如果源或目標(biāo)包含空格,請(qǐng)將路徑括在方括號(hào)和雙引號(hào)中。


COPY ["", ""]

示例:

COPY . .

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

COPY . /usr/share/nginx/html

COPY hom* /mydir/


4.ADD

ADD 指令與 COPY 指令非常類似,但它包含更多功能。除了將文件從主機(jī)復(fù)制到容器映像,ADD 指令還可以使用 URL 規(guī)范從遠(yuǎn)程位置復(fù)制文件。

格式:

ADD<source> <destination>

示例:

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

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


5.WORKDIR

WORKDIR?指令用于為其他?Dockerfile?指令(如?RUN、CMD)設(shè)置一個(gè)工作目錄,并且還設(shè)置用于運(yùn)行容器映像實(shí)例的工作目錄。

格式:

WORKDIR

示例:

WORKDIR /app


6.CMD

CMD指令用于設(shè)置部署容器映像的實(shí)例時(shí)要運(yùn)行的默認(rèn)命令。例如,如果該容器將承載?NGINX Web?服務(wù)器,則?CMD?可能包括用于啟動(dòng)Web服務(wù)器的指令,如?nginx.exe。 如果?Dockerfile?中指定了多個(gè)CMD?指令,只會(huì)計(jì)算最后一個(gè)指令。

格式:

CMD ["<executable", "

CMD

示例:

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

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


7.ENTRYPOINT

配置容器啟動(dòng)后執(zhí)行的命令,并且不可被?docker run?提供的參數(shù)覆蓋。每個(gè)?Dockerfile?中只能有一個(gè)ENTRYPOINT,當(dāng)指定多個(gè)時(shí),只有最后一個(gè)起效。

格式:

ENTRYPOINT ["", ""]

示例:

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


8.ENV

ENV命令用于設(shè)置環(huán)境變量。這些變量以”key=value”的形式存在,并可以在容器內(nèi)被腳本或者程序調(diào)用。這個(gè)機(jī)制給在容器中運(yùn)行應(yīng)用帶來了極大的便利。

格式:

ENV==...

示例:

ENV VERSION=1.0 DEBUG=on \

NAME="Magicodes"


9.EXPOSE

EXPOSE用來指定端口,使容器內(nèi)的應(yīng)用可以通過端口和外界交互。

格式:

EXPOSE

示例:

EXPOSE 80


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


轉(zhuǎn)義字符

在許多情況下,Dockerfile 指令需要跨多個(gè)行;這可通過轉(zhuǎn)義字符完成。 默認(rèn) Dockerfile 轉(zhuǎn)義字符是反斜杠 \。 由于反斜杠在 Windows 中也是一個(gè)文件路徑分隔符,這可能導(dǎo)致出現(xiàn)問題。

以下示例顯示使用默認(rèn)轉(zhuǎn)義字符跨多個(gè)行的單個(gè) 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


要修改轉(zhuǎn)義字符,必須在 Dockerfile 最開始的行上放置一個(gè)轉(zhuǎn)義分析程序指令。 如以下示例所示:

# 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

注意,只有兩個(gè)值可用作轉(zhuǎn)義字符:\ 和 ` 。


優(yōu)化

篇幅有限,我們這里只進(jìn)行簡單講解,后續(xù)結(jié)合實(shí)際案例再進(jìn)行細(xì)說。但是有幾點(diǎn)值得注意的是:

不能忽視dockerfile的優(yōu)化,通常情況下,我們可以忽略那些細(xì)小的優(yōu)化,但是我們需要知道優(yōu)化的原理,為什么要優(yōu)化

不能為了優(yōu)化而優(yōu)化。鏡像的構(gòu)建過程視業(yè)務(wù)情況情況不同,指令就有多到少的區(qū)別,在很多情況下,我們先要以滿足業(yè)務(wù)目標(biāo)為準(zhǔn),而不是鏡像層數(shù)。如果需要減少鏡像的層數(shù),我們一定要選擇合適的基礎(chǔ)鏡像,或者創(chuàng)建符合我們需要的基礎(chǔ)鏡像。

下面是一些優(yōu)化的準(zhǔn)則:

1、選擇合適的基礎(chǔ)鏡像

這點(diǎn)相對(duì)最為重要。為什么這么說,我們結(jié)合現(xiàn)實(shí)社會(huì)也可以看到,在大部分情況下,一個(gè)人一生的成就更多的是看出身。很多情況下,基因和出身決定了你的高度和終點(diǎn),這點(diǎn)拿到技術(shù)層面來說,也是有很大道理的,因此我們需要選擇合適的父母——一個(gè)合適的鏡像。

一個(gè)合適的基礎(chǔ)鏡像是指能滿足運(yùn)行應(yīng)用所需要的最小的鏡像,理論上是能用小的就不要用大的,能用輕量的就不要用重量級(jí)的,能用性能好的就不要用性能差的。這里有時(shí)候還需要考慮那些能夠減少我們構(gòu)建層數(shù)的基礎(chǔ)鏡像。


2、優(yōu)化指令順序

Docker會(huì)緩存Dockerfile中尚未更改的所有步驟,但是,如果更改任何指令,將重做其后的所有步驟。也就是指令3有變動(dòng),那么4、5、6就會(huì)重做。因此,我們需要將最不可能產(chǎn)生更改的指令放在前面,按照這個(gè)順序來編寫dockerfile指令。這樣,在構(gòu)建過程中,就可以節(jié)省很多時(shí)間。比如,我們可以把WORKDIR、ENV等命令放前面,COPY、ADD放后面。


3、合并指令

前面其實(shí)我們提到過這點(diǎn),甚至還特地講到了轉(zhuǎn)義字符,其實(shí)主要是為此服務(wù)。前面我們說到了,每一個(gè)指令都會(huì)創(chuàng)建一層,并構(gòu)成新的鏡像。當(dāng)運(yùn)行多個(gè)指令時(shí),會(huì)產(chǎn)生一些非常臃腫、非常多層的鏡像,不僅僅增加了構(gòu)建部署的時(shí)間,也很容易出錯(cuò)。因此,在很多情況下,我們可以合并指令并運(yùn)行,例如:RUN apt-get update && apt-get install -y libgdiplus。在命令過多時(shí),一定要注意格式,比如換行、縮進(jìn)、注釋等,會(huì)讓維護(hù)、排障更為容易,這是一個(gè)比較好的習(xí)慣。


刪除多余文件和清理沒用的中間結(jié)果

這點(diǎn)很易于理解,通常來講,體積更小,部署更快!因此在構(gòu)建過程中,我們需要清理那些最終不需要的代碼或文件。比如說,臨時(shí)文件、源代碼、緩存等等。


4、使用 .dockerignore

.dockerignore文件用于忽略那些鏡像構(gòu)建時(shí)非必須的文件,這些文件可以是開發(fā)文檔、日志、其他無用的文件。例如:

說了這么多,其實(shí)我們更多的還是需要根據(jù)命令的實(shí)際執(zhí)行情況來進(jìn)行調(diào)整。


Visual studio和dockerfile

如上所示,要生成自定義鏡像,需為每個(gè)自定義鏡像提供一個(gè) Dockerfile。無論是從Visual Studio 自動(dòng)部署,還是使用 Docker CLI(docker run 和 docker-compose 命令)手動(dòng)部署,都需為每個(gè)要部署的容器提供一個(gè) Dockerfile。如果應(yīng)用程序只包含一個(gè)自定義服務(wù),則只需要一個(gè) Dockerfile。如果應(yīng)用程序包含多個(gè)服務(wù)(如在微服務(wù)體系結(jié)構(gòu)中),則每個(gè)服務(wù)都需要一個(gè) Dockerfile。Dockerfile文件需要放在應(yīng)用程序或服務(wù)的根文件夾中。

但是,對(duì)于.NET開發(fā)人員來說,利用Visual Studio只需單擊幾次鼠標(biāo)即可完成此任務(wù)。如下圖所示:

還可通過在 Visual Studio 中右鍵單擊項(xiàng)目文件,選擇“添加 Docker 項(xiàng)目支持”選項(xiàng),為新項(xiàng)目或現(xiàn)有項(xiàng)目啟用 Docker 支持:

對(duì)項(xiàng)目(如 ASP.NET Web 應(yīng)用程序或 Web API 服務(wù))應(yīng)用此操作后,系統(tǒng)會(huì)向含有所需配置的項(xiàng)目添加 Dockerfile。

在更多的情況下,筆者建議大家選擇下面的菜單——容器業(yè)務(wù)流程協(xié)調(diào)程序支持:

因?yàn)闀?huì)向整個(gè)解決方案添加 docker-compose.yml 等文件。整個(gè)過程,Visual Studio 代為執(zhí)行了操作,但是,我們也需要了解 Dockerfile中的內(nèi)容,否則遇到問題,會(huì)抓蝦,哦,是抓瞎。

啟用了之后,我們就可以看到頂部的菜單欄出現(xiàn)了一些便捷操作:

不僅支持一鍵啟動(dòng),還能夠調(diào)試?。?!這對(duì)于大部分開發(fā)者來說,簡直是天籟之音哈!

接下來,我們以Magicodes.Admin為例。在Magicodes.Admin中,存在多個(gè)應(yīng)用,比如后臺(tái)服務(wù)和后臺(tái)UI,目前框架中已經(jīng)提供了多個(gè)dockerfile的配置,分別在相應(yīng)的工程目錄之中。


.net core后臺(tái)服務(wù)的dockerfile

文件所在目錄如下所示:

相關(guān)指令我在注釋中進(jìn)行了一一說明,不過,由于Excel的導(dǎo)出在Linux環(huán)境需要libgdiplus庫的支持,以設(shè)置字體,因此我們需要在dockerfile中配置安裝此庫。同時(shí),我們還推薦使用以下簡化的dockerfile:

其中,包還原、編譯、單元測試運(yùn)行以及發(fā)布等過程我們通過腳本進(jìn)行了實(shí)現(xiàn),因此在Dockerfile中,命令比較簡單干凈,關(guān)鍵是整個(gè)過程我們能夠在本地進(jìn)行更多的自定義——比如執(zhí)行單元測試并再通過之后才進(jìn)行部署和推送。當(dāng)然,使用第一個(gè)配置能夠讓我們可以更好地和線上的CI工具配套使用。

注意:這里我們并沒有使用其他web服務(wù)器,我們直接在代碼中使用了Kestrel服務(wù)器進(jìn)行托管。



后臺(tái)前端應(yīng)用的dockerfile

文件所在目錄如下所示:

后臺(tái)前端應(yīng)用使用nginx web服務(wù)器進(jìn)行托管,同時(shí)執(zhí)行了copy命令復(fù)制相關(guān)配置、靜態(tài)文件和ssl證書。其中nginx.conf的配置如下所示:

關(guān)于dockerfile的相關(guān)內(nèi)容,我們先講述到這里,希望大家對(duì)此有個(gè)全面的了解。如果你有疑問或者建議,歡迎討論交流。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容