當前位置:首頁 » 編程軟體 » dockerfile腳本

dockerfile腳本

發布時間: 2022-12-09 14:01:40

A. DOCKER 總結

Docker 是一個開源的 應用容器引擎 ,讓 開發者可以打包他們的應用以及依賴包到一個可移植的鏡像中,然後發布到任何流行的 linux或Windows 機器上,也可以實現虛擬化 。容器是完全使用沙箱機制,相互之間不會有任何介面。

由於本地開發好的程序往往都需要部署到伺服器上進行運行,這就導致了程序需要運行在不同的環境上,這通常是一個令人頭痛的事情。在過去,開發團隊需要清楚的告訴運維部署團隊,其所使用的全部配置文件+所有軟體環境。不過,即便如此,仍然常常發生部署失敗的狀況。

於是乎, 虛擬化 技術應運而生。開發團隊將開發好的程序在虛擬機上運行,這樣就能解決運維的問題。但是由於虛擬機技術過重的特性導致了其 資源佔用多、冗餘步驟多以及啟動慢的缺陷 。而這個時候 一種新的虛擬化技術搭配上容器化的思想 的產品便出現了,而它就是Docker。

下圖是虛擬機技術和容器化技術架構的對比。我們可以得出以下總結:

[圖片上傳失敗...(image-efadd2-1643314980201)]
]( https://upload-images.jianshu.io/upload_images/646931-4b1431b77887632f.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 )

於是乎相比於虛擬機技術,容器化技術具有以下 優勢:

相關網站

如下圖所示,Docker使用客戶端-伺服器(C/S)架構模式,使用遠程API來管理和創建Docker容器。伺服器端分為Docker daemon, Image和Container三個部分。此外還有Docker Registry。

下面首先來介紹一下Docker中的主要概念

Docker的運行原理如下:客戶端可以將docker命令發送到伺服器端的Docker daemon上,再由Docker damon根據指令創建、選擇或者從Docker倉庫中拉取(pull)鏡像。接著客戶端可以通過鏡像創建容器。當我們需要使用程序時,運行相應的容器即可。

小結

需要正確的理解倉儲/鏡像/容器這幾個概念 :

在外面使用容器的時候,我們不希望容器中的數據在容器被刪除後也一並刪除了,這時候我們就可以 通過使用容器數據卷,將數據儲存在本地並用Docker將其掛載到容器中,這樣我們即使刪除了容器,數據也依舊存在伺服器中,也就實現了數據持久化。

特點

容器數據卷掛載命令(-v)

Dockerfile 掛載容器數據卷

我們除了可以從倉庫中拉取鏡像以外,我們也可以 自己創建鏡像 ,這就要用到Docerfile。

dockerfile是用來構建Docker鏡像的構建文件,是由一系列命令和參數構成的腳本

構建步驟:

基礎知識:

流程:

說明:

在實際場景中,我們會遇到 多個Container之間通訊 的問題。而Docker網路就是用於解決此問題的技術。docker會給每個容器都分配一個ip,且容器和容器之間是可以互相訪問的。

Docker網路原理

每一個安裝了Docker的linux主機都有一個docker0的虛擬網卡。這是個橋接網卡,使用了 veth-pair 技術 。Docker使用Linux橋接,在宿主機虛擬一個Docker容器網橋(docker0),Docker啟動一個容器時會根據 Docker網橋的網段分配給容器一個IP地址,稱為Container-IP,同時Docker網橋是每個容器的默認網 關。因為在同一宿主機內的容器都接入同一個網橋,這樣容器之間就能夠通過容器的Container-IP直接通信。

Docker容器網路就很好的利用了Linux虛擬網路技術,在本地主機和容器內分別創建一個虛擬介面,並 讓他們彼此聯通(這樣一對介面叫veth pair);

Docker中的網路介面默認都是虛擬的介面。虛擬介面的優勢就是轉發效率極高(因為Linux是在內核中 進行數據的復制來實現虛擬介面之間的數據轉發,無需通過外部的網路設備交換),對於本地系統和容 器系統來說,虛擬介面跟一個正常的乙太網卡相比並沒有區別,只是他的速度快很多。

[圖片上傳中...(image-41d42a-1642627027452-2)]

Docker Compose是一個用於定義並運行多容器應用的工具

Docker Compose的 步驟如下

NOTE: Compose :重要的概念。

docker-compose.yml編寫

Note: docker-compose會自動為多容器之間創建網路,保證通訊。

Docker Swarm 是Docker 的集群管理工具。 它將 Docker 主機池轉變為單個虛擬 Docker 主機。 Docker Swarm 提供了標準的 Docker API,所有任何已經與 Docker 守護程序通信的工具都可以使用 Swarm 輕松地擴展到多個主機。

Docker 是一個開源的 應用容器引擎 ,它的出現大大簡化了運維的難度,提高了運維效率。過去我們需要在伺服器上安裝程序所需要的所有依賴,而如今我們只需要編寫好docker-compose和Dockefile的腳本,就可以使程序一鍵跑通。在企業級的應用中,我們必然會驚顫使用到Docker和容器化技術。

狂神說

B. Docker multi-stage build機制

摘要: 隨著17.05版本的發布,Docker對於鏡像構建這塊也作了一項重要更新,那就是 multi-stage build(多階段構建),這對於長期因為構建鏡像太大而困擾的小夥伴們來說真是雪中送炭。

隨著17.05版本的發布,Docker對於鏡像構建這塊也作了一項重要更新,那就是 multi-stage build(多階段構建),這對於長期因為構建鏡像太大而困擾的小夥伴們來說真是雪中送炭。

在17.05版本之前,我們構建Docker鏡像時,通常會採用兩種方式:

這里以一個簡單的java項目鏡像構建為例來說明這兩種構建方式,該項目僅僅包含一個App.java類:

這里是將所有的構建流程都編寫在同一個Dockerfile中,但為了盡可能地減小鏡像層次,我們將多個執行命令合並到同一個 RUN 指令中,同時我們需要自行清理掉源碼目錄文件以及編譯後的臨時目錄文件,以防止源碼泄露。

這里我們需要分為兩個階段:
1)編譯打包 Dockerfile.2.1

2)構建鏡像 Dockerfile.2.2

3)整合兩個構建階段 build.sh

這里我們編寫了兩個Dockerfile和一個Shell腳本,通過兩階段將最終鏡像構建出來,但可預見的一個問題是,假若有多個項目彼此關聯和依賴,就需要我們維護多個Dockerfile,或者需要編寫更復雜的build.sh腳本,導致後期維護成本很高。

在Docker 17.05 多階段構建推出之後,我們就可以很容易規避前面遇到的這些問題,並且只需要維護一個Dockerfile即可:

對於上面的Dockerfile是不是很熟悉,它僅僅是將第二種方式中的兩個Dockerfile合並到同一個Dockerfile中,同時在構建過程中自動幫您完成了build.sh的流程。

對於multi-stage build,其關鍵點主要有兩點:

同理,多階段構建同樣可以很方便地將多個彼此依賴的項目通過一個Dockerfile就可輕松構建出期望的容器鏡像,而不用擔心鏡像太大、源碼泄露等風險。

C. docker基於mysql:5.7構建鏡像並初始化腳本

遇到的問題:內網環境,安裝docker
解決方式:參考 https://segmentfault.com/a/1190000022982415

一、開始構建(編寫Dockerfile)

二、構建

三、運行

四、驗證數據腳本是否成功初始化(psp)

五、自動化執行腳本(init_mysql.sh)

D. Docker:容器管理(啟動參數,查看容器和日誌,進入和修改容器)

摘要: Docker

容器是一個精簡版的操作系統,一般一個容器只運行一個應用,容器通過鏡像創建,使用 docker run 命令創建,容器起到了 隔離 作用,容器和容器之間獨享空間和網路等

容器的基本操作包括創建(啟動),停止,重啟,查看,檢查等,容器通過鏡像創建,使用 docker run 命令創建,需要指定run參數,鏡像名,容器執行命令,語句格式如下

在實際使用中啟動一個鏡像,例如

-e 設置環境變數,格式是 -e k1=v1 -e k2=v2 ,使得在docker鏡像中的程序能夠直接訪問到環境變數,同時可以作為配置參數放在docker run啟動鏡像的時候設置,而不是寫死在dockerfile在build的過程中,-e和dockerfile中的 ENV 變數作用相同,當變數重名時-e替換ENV,下面測試一些-e參數,在Dockerfile指定環境變數

直接構建成容器

開啟一個終端啟動容器內部,列印指定的環境變數a

此時在run指令中增加-e設置環境變數,可見-e替換了Dockerfile中指定的環境變數

因為一個鏡像可以啟動多個容器,所以可以通過設置不同-e達到設置不同配置參數的目的,比如下一個例子在Dockerfile中設置和將環境變數寫入yaml文件再供Python調用,執行的內容為列印yaml配置文件的參數內容,比如下面這個例子先看下目錄結構

其中config.yml是一個空配置文件,在run.sh中先使用echo寫入追加配置參數到config.yml在執行Python腳本

Dockerfile中啟動run.sh腳本作為容器執行命令

在啟動容器時,使用-e指定環境變數,在run.sh中echo將環境變數拿到和寫入配置文件,測試多次以不同的配置參數啟動容器如下

-v 設置掛載運行,將宿主機當前目錄下的文件掛載到容器中/home目錄下,例如

如果掛載的目錄和Dockerfile中的COPY的目錄不一致, -v會替代COPY或者ADD ,例如現在Docker中COPY一個文件到容器/home目錄下

同目錄下start.sh內容是列印1

構建鏡像結束後,指定-v啟動,起始掛載另外一個目錄,目錄下start.sh內容是列印2

docker run參數中最後的COMMAND會覆蓋Dockerfile中指定的 CMD ,例如執行echo 2替換原始Dockerfile中的CMD echo 1,輸出結果是2且執行完畢後退出

對於Dockerfile中的 ENTRYPOINT 指定的啟動命令docker run的COMMAND不會覆蓋,如果要覆蓋Docker中的ENTRYPOINT需要指定docker run中的 --entrypoint 參數,格式是

測試一個Dockerfile輸出1

在docker run中使用--entrypoint覆蓋Dockerfile中的ENTRYPOINT

容器啟動後通過 docker ps 或者 docker container ls 查看容器,可以增加額外參數比如 -a 顯示所有容器,默認只顯示運行的容器,可以增加 --no-trunc 參數使得顯示結果不截斷,例如

顯示結果分別顯示了容器的ID,鏡像,執行命令,創建時間,狀態,埠映射(宿主機->容器)和容器名稱。對於已經運行的容器可以使用 docker stop 停止,如果在docker run時增加--rm參數則停止的容器保留不會自動刪除,例如

除了docker stop命令還有一種停止容器的命令 docker kill ,相比於docker stop,docker kill是 強制立即停止 ,而docker stop是先給了容器10秒(默認)的時間,使得容器有一定的時間處理、保存程序執行現場, 優雅的退出程序 ,例如

在容器停止之後可以使用 docker start 再啟動一個停止的容器,例如

除此之外可以使用 docker restart ,此時容器可以使停止的也可以是在運行中的,例如

查看容器詳情使用 docker inspect ,比如

在以上截取的內容中展示了容器詳情,包括容器id,創建時間,執行命令和參數,執行狀態,容器pid,落腳點,環境變數,網路設置,埠映射等,也可以使用Go語言風格輸出指定的詳情,比如分別只看容器的pid和容器的執行命令

容器是一個操作系統,可以進入這個操作系統查看容器的運行情況,有多種方式進入容器,其中主要是使用 docker exec 進入容器,在一個運行中的容器中執行一個命令,使用 -it 並帶有 /bin/bash 命令就可以進入容器,比如

除了/bin/bash也可以是其他命令掛載exec後面則可以直接對一個運行中的容器執行命令,比如查看容器的進入落腳點路徑,容器中的內存情況

當容器以後台 -d 運行時,日誌運行在容器內部,可以進入容器內部查看日誌,也可以使用 docker logs 查看日誌,以一個flask api介面的容器為例,日誌寫入文件,同時也會輸出在flask的控制台

創建Dockerfile以及構建鏡像,啟動容器

啟動一個腳本不斷請求api介面

進入容器內部查看日誌

另一種方式是直接使用 docker logs 命令,比如使用 -f 追蹤輸出,並且從最後的第1行開始輸出

此時宿主機的logs目錄下為空,容器中的logs目錄下存在detail.log文件,如果使用 -v 將宿主機目錄掛載到容器作為容器寫入的目錄,則容器中數據的變動會同步到本地,這樣可以直接在本地查看日誌,修改容器啟動為 -v 掛載的形式

此時本地logs目錄下開始產生日誌,且這個日誌和容器內的logs目錄下一致

如果容器內的內容改變了,此時刪除容器從鏡像重新啟動容器則改動的內容將不會存在,如果相對修改過的容器保留下來則可以從容器生成新的鏡像,先測試以下容器內修改在刪除的容器後將不再生效,在已有容器中使用pip安裝Python包

此時退出容器,並且刪除容器,最後從鏡像重新生成容器

此時進入容器檢查,並不存在pymongo包

如果要容器變化保存下來需要以這個新容器生成一個鏡像,使用 docker commit ,語法如下

以新安裝pymongo的容器為例,對新容器使用docker commmit

新生成的鏡像叫做xiaogp/my_image_test:v2

從新鏡像啟動容器並進入容器查看存在新安裝的pymongo

E. 基於docker的持續開發流程

相關步驟說明如下
(1) 開發。根據需求開發應用程序。
(2) 編寫Dockerfile文件,Dockerfile是由一系列命令和參數組成的腳本,用來構建Image。
(3) 創建自定義鏡像,基於docker build 命令構建
(4) 定義docker-compse,用來定義和運行多個docker應用程序。
(5) 啟動docker應用,docker run。
(6) 測試,基於容器進行廁所,隨時部署或銷毀。
(7) 部署或繼續開發。

(1) FROM: 它媽是誰(基礎鏡像)
(2) RUN: 開始動起來(執行命令,可以多次)
(3) COPY: 復制文件目錄
(4) ADD: COPY加強版,支持遠程復制和解壓
(5) WORKDIR: CD偽裝者(設置當前工作目錄)
(6) CMD: 執行配置命令,如果多個,僅僅執行最後一個
(7) ENTRYPOINT: 容器啟動後執行
(8) ENV: 環境變數
(9) EXPOSE: 專業敲牆打洞(開放埠)

F. 如何使用Docker構建運行時間較長的腳本

問題
讓我們從這個我試圖解決的問題開始。我開發了一個會運行很長時間的構建腳本,這個腳本中包含了很多的步驟。
這個腳本會運行1-2個小時。
它會從網路下載比較大的文件(超過300M)。
後面的構建步驟依賴前期構建的庫。
但最最煩人的是,運行這個腳本真的需要花很長的時間。
文件系統是固有狀態
我們一般是通過一種有狀態的方式與文件系統進行交互的。我們可以添加、刪除或移動文件。我們可以修改文件的 許可權或者它的訪問時間。大部分獨立的操作都可以撤銷,例如將文件移動到其它地方後,你可以將文件恢復到原來的位置。但我們不會通過快照的方式來將它恢復到 原始狀態。這篇文章我將會介紹如何在耗時較長的腳本中充分利用快照這一特性。
使用聯合文件系統的快照
Docker使用的是聯合文件系統叫做AUFS(譯者註:簡單來說就是支持將不同目錄掛載到同一個虛擬文件系統下的文件系統)。聯合文件系統實現了Union mount。顧名思義,也就是說不同的文件系統的文件和目錄可以分層疊加在單個連貫文件系統之上。這是通過分層的方式完成的。如果一個文件出現在兩個文件系統,那最高層級的文件才會顯示(該文件其它版本也是存在於層級中的,不會改變,只是看不到的)。
在Docker中,每一個在Union mount轉哦給你的文件系統都被稱為layers(層)。使用這種技術可以輕松實現快照,每個快照都是所有層的一個Union mount。
生成腳本的快照
使用快照可以幫助構建一個長時運行的腳本。總的想法是,將一個大的腳本分解為許多小的腳本(我喜歡稱之為 scriptlets),並單獨運行這些小的腳本,腳本運行後為其文件系統打一個快照 (Docker會自動執行此操作)。如果你發現一個scriptlet運行失敗,你可以快速回退到上次的快照,然後再試一次。一旦你完成腳本的構建,並且 可以保證腳本能正常工作,那你就可以將它分配給其它主機。
回過頭來再對比下,如果你沒有使用快照功能了?當你辛辛苦苦等待了一個半小時後,腳本卻構建失敗了,我想除了少部分有耐心的人外,很多人是不想再來一次了,當然,你也會盡最大努力把系統恢復到失敗前的狀態,比如可以刪除一個目錄或運行make clean。
但是,我們可能沒有真正地理解我們正在構建的組件。它可能有復雜的Makefile,它會把把文件放到文件系統中我們不知道的地方,唯一真正確定的途徑是恢復到快照。
使用快照構建腳本的Docker
在本節中,我將介紹我是如何使用Docker實現GHC7.8.3 ARM交叉編譯器的構建腳本。Docker非常適合做這件事,但並非完美。我做了很多看起來沒用的或者不雅的事情,但都是必要的,這都是為了保證將開發腳本的總時間降到最低限度。構建腳本可以在這里找到。
用Dockerfile構建
Docker通過讀取Dockerfile來構建鏡像。Dockerfile會通過一些命令來具體指定應該執行哪些動作。具體使用說明可以參考這篇文章。在我的腳本中主要用到WORKDIR、ADD和RUN。ADD命令非常有用因為它可以讓你在運行之前將外部文件添加到當前Docker鏡像中然後轉換成鏡像的文件系統。你可以在這里看到很多scriptlets構成的構建腳本。
設計
1. 在RUN之前ADD scriptlets
如果你很早就將所有的scriptletsADD在Dockerfile,您可能會遇到以下問題:如果你的腳本構建失敗,你回去修改scriptlet並再次運行docker build。但是你發現,Docker開始在首次加入scriptlets的地方構建!這樣做會浪費了大量的時間並且違背了使用快照的目的。
出現這種情況的原因是由於Docker處理它的中間鏡像(快照)的方式。當Docker通過Dockerfile構建鏡像時,它會與中間鏡像比較當前命令是否一致。然而,在ADD命令的情況下被裝進鏡像的文件里的內容也會被檢查。如果相對於現有的中間鏡像,文件已經改變,那麼Docker也別無選擇,只能從這點開始建立一個新的鏡像。因為Docker不知道這些變化會不會影響到構建。
此外,使用RUN命令要注意,每次運行時它都會導致文件系統有不同的更改。在這種情況下,Docker會發現中間鏡像並使用它,但是這將是錯誤的。RUN命令每次運行時會造成文件系統相同的改變。舉個例子,我確保在我的scriptlets我總是下載了一個已知版本的文件與一個特定MD5校驗。
對Docker 構建緩存更詳細的解釋可以在這里找到。
2.不要使用ENV命令來設置環境變數,請使用scriptlet。
它似乎看起來很有誘惑力:使用ENV命令來設置所有構建腳本需要的環境變數。但是,它不支持變數替換的方式,例如 ENV BASE=$HOME/base 將設置BASE的值為$HOME/base著很可能不是你想要的。
相反,我用ADD命令添加一個名為set-env.sh文件。此文件會包含在後續的scriptlet中:
THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source $THIS_DIR/set-env-1.sh
如果你沒有在第一時間獲取set-env.sh會怎麼樣呢?它很早就被加入Dockerfile並不意味著修改它將會使隨後的快照無效?
是的,這會有問題。在開發腳本時,我發現,我已經錯過了在set-env.sh添加一個有用的環境變數。解決方案是創建一個新的文件set-env-1.sh包含:
THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source $THIS_DIR/set-env.sh
if ! [ -e "$CONFIG_SUB_SRC/config.sub" ] ; then
CONFIG_SUB_SRC=${CONFIG_SUB_SRC:-$NCURSES_SRC}
fi
然後,在所有後續的scriptlets文件中包含了此文件。現在,我已經完成了構建腳本,我可以回去解決這個問題了,但是,在某種意義上,它會破壞最初的目標。我將不得不從頭開始運行構建腳本看看這種變化是否能成功。
缺點
一個主要缺點是這種方法是,所構建的鏡像尺寸是大於它實際需求的尺寸。在我的情況下尤其如此,因為我在最後刪除了大量文件的。然而,這些文件都仍然存在於聯合掛載文件系統的底層文件系統內,所以整個鏡像是大於它實際需要的大小至少多餘的是刪除文件的大小。
然而,有一個變通。我沒有公布此鏡像到Docker Hub Registry。相反,我:
使用docker export導出內容為tar文件。
創建一個新的Dockerfile簡單地添加了這個tar文件的內容。
產生尺寸盡可能小的鏡像。
結論
這種方法的優點是雙重的:
它使開發時間降至最低,不再做那些已經構建成功的子組件。你可以專注於那些失敗的組件。
這非常便於維護構建腳本。構建可能會失敗,但只要你搞定Dockerfiel,至少你不必再從頭開始。
此外,正如我前面提到的Docker不僅使寫這些構建腳本更加容易,有了合適的工具同樣可以在任何提供快照的文件系統實現。

G. docker 一鍵腳本安裝

Docker 官方提供了便捷的安裝腳本,通過腳本自動完成安裝.官方社區版本安裝腳本一共有三種版本.第一個版本是主分支的Docker CE, Edge 更新渠道,每月更新一次;第二個版本是候選版本的DockerCE, Test 更新渠道,提供候選功能,候選功能不一定出現在主分支的DockerCE中,第三個版本是實驗性的Docker CE版本,Experimental 更新渠道, 提供實驗性功能比Test 更新渠道更加激進.

然後執行 systemctl daemon-reload 重啟 daemon, 以及重啟Docker 進程 sudo systemctl restart docker, 然後查看 Docker 版本信息即可

H. 解決 Docker 數據卷掛載的文件許可權問題

Docker 提供了數據卷 綁定掛載 的機制(volume bind mounts)來將主機上的文件 (file) 或者目錄 (directory) 掛載進容器 (container)。也就是 docker run 命令中熟知的 -v 參數。根據 Docker 官方文檔,綁定掛載一般適合於 三種場景 :

但是實際使用時,會遇到文件許可權問題:

譬如執行如下命令創建一個容器,掛載當前目錄到容器內,並在容器內向主機當前目錄創建 tmp.txt:

主機當前目錄出現了容器內創建的 tmp.txt,但是其許可權、用戶和組均是 root,其他用戶不可寫。

常見解決方法是可以通過 Docker 提供的 User 命令、 --user 參數 來指定容器內部的用戶和組的 id,譬如:

可以看到輸出,current_user 處會顯示主機當前用戶的名字,所以解決了主機用戶對掛載的卷沒有許可權的問題。

user 參數的缺陷
使用 user 參數有一些缺陷,如果你進入容器內部的 terminal,會顯示如下內容:

bash 的用戶名會顯示 I have no name!,這是因為我們通過 --user 參數指定了容器內部的用戶 id,但該 id 不存在於容器內的 /etc/passwd 文件中。

除此之外,使用 user 參數仍然存在許可權問題:

除了綁定掛載的主機路徑之外的所有路徑,對於容器內部的用戶都沒有寫許可權。
這也是不可接受的,因為容器運行過程中我們可能會進行一些臨時文件的寫入,這些臨時文件我們並不想要寫到主機的掛載目錄,但除了掛載路徑之外的任何路徑容器都沒有寫入許可權。

譬如我們在主機上創建 models 目錄。

我們使用 Docker 掛載 models 目錄,然而在 Docker 容器內部除了 models 文件夾都沒有訪問許可權。

這可以通過增加掛載路徑:

這樣容器運行過程往 /project 寫的臨時文件都會出現在主機上。

可見, user 參數並不能解決所有問題。它存在兩個問題:

我們需要一種手段,既可以像 user 參數一樣在容器運行時可以將用戶切換到和主機相同的用戶,又希望 Docker 容器保留 root 用戶,並給主機用戶想要訪問的目錄授權(對特定目錄 chown 、 chmod 等)。

Docker 官方文檔對 Entrypoint 介紹時給出了 一種最佳實踐 。

編寫如下的 Dockerfile:

該 Dockerfile 中安裝了一個 gosu 的工具,並設置了程序的 Entrypoint。由於 Docker 內使用 sudo 可能導致一些不可預知的 TTY 和信號轉發問題,所以 Docker 官方推薦了使用 gosu 這個工具,用於保持容器在 root 用戶下運行,並用 sudo 來切換到指定用戶。

其中 docker-entrypoint.sh 內容如下:

可以看到 docker-entrypoint.sh 中創建了一個名為 user 的用戶,該用戶的 uid 由 docker run 的參數傳入,這里利用了 linux 系統的一個特點,容器內外用戶許可權的記錄和用戶的名字無關,只和 uid 有關,因此容器內我們將用戶命名為 user 沒有影響。docker-entrypoint.sh 最後一行調用 gosu 來切換到 user 用戶並執行 Dockerfile 中的用戶命令。

有了如上兩個腳本,我們構建鏡像並執行:

運行容器時指定 LOCAL_USER_ID 參數:

可見不僅容器內往掛載目錄 /project/models 寫入的文件 model.txt 所有者是主機用戶,而且在容器內往非掛載目錄 /project/tmp.txt 寫入文件也不會遇到許可權問題。

Docker 運行時容器內默認使用 root 用戶運行,但是我們不是總是想要用 root 用戶,因為有時候我們希望容器計算產生一些文件,並通過 volume 的綁定掛載在主機上獲取。特別是我們用 jenkins 等工具寫一些持續集成的腳本時候。容器內用 root 用戶運行會導致產生的文件也是 root 用戶的,主機上沒有讀取許可權。因此我們需要讓容器在運行的時候切換到主機上的用戶。

Docker 對於這種情況仍然沒有提供足夠便利的基礎設施,我們採用了 Docker 官方目前推薦的一個方式,通過編寫一個 docker-entrypoint.sh 腳本作為 Dockerfile 的 Entrypoint,腳本中創建和主機上相同 uid 的用戶,並通過 gosu 工具切換到該用戶執行命令。 uid 需要在 docker run 階段通過參數傳入。我們在腳本中設置了預設 uid ,上面的腳本隨機選擇了一個 9001,注意要將該預設值避免設置成和 Docker 鏡像中存在的用戶沖突的 uid。

參考鏈接:

I. dockerfile是什麼類型文件

Dockerfile是由一系列命令和參數構成的腳本,這些命令應用於基礎鏡像並最終創建一個新的鏡像。它們簡化了從頭到尾的流程並極大的簡化了部署工作。Dockerfile從FROM命令開始,緊接著跟隨者各種方法,命令和參數。其產出為一個新的可以用於創建容器的鏡像。

#
#VERSION2-EDITION1
#Author:docker_user
#Commandformat:Instruction[arguments/command]..

#1、第一行必須指定基礎鏡像信息
FROMubuntu

#2、維護者信息
[email protected]

#3、鏡像操作指令
RUNecho"debhttp://archive.ubuntu.com/ubuntu/raringmainuniverse">>/etc/apt/sources.list
RUNapt-getupdate&&apt-getinstall-ynginx
RUNecho" daemonoff;">>/etc/nginx/nginx.conf

#4、容器啟動執行指令
CMD/usr/sbin/nginx

Dockerfile 分為四部分:基礎鏡像信息、維護者信息、鏡像操作指令、容器啟動執行指令。
一開始必須要指明所基於的鏡像名稱,接下來一般會說明維護者信息。
後面則是鏡像操作指令,例如 RUN 指令。RUN 指令將對鏡像執行跟隨的指令。每執行一條RUN 指令,鏡像添加新的一層,並提交
最後是 CMD 指令,來指明運行容器時的操作命令。

FROM 指令:格式: FROM <images> 或者 FROM<image>:<tag>。第一條指令必須是 FROM 指令。並且,如果在同一個Dockerfile中創建多個鏡像時,可以使用多個 FROM 指令。
MAINTAINER 指令:指定維護者信息。
RUN 指令:格式:RUN <command> 或者 RUN ["executable","param1","param2"]

另外通過直接下載程序鏡像(Nginx)也可以創建一個容器,並將容器運行起來。

(1) 從中央倉庫下載鏡像:docker pull nginx:1.9
(2) docker run 命令啟動容器,docker run -d -p 8080:80 nginx:1.9,把容器內的nginx的80埠,映射到當前伺服器(Centos系統的ip地址)的8080埠,我當前伺服器的ip是192.168.1.10,這樣在瀏覽器輸入192.168.1.10:8080/,發現nginx已啟動。
(3) 再啟動多一個容器,docker run -d -p 8085:80 nginx:1.9,瀏覽器輸入http:/192.168.1.10:8085/,就可以看到另外一個nginx已啟動。

J. 項目構建--Gradle--Docker打包(五)

如果添加了 application 插件的話,默認 gradle-docker 插件會添加一個 distDocker 的 gradle task,用來構建一個 包含所有程序文件 的 docker 鏡像。

配置鏡像名稱和版本號

其中鏡像的 tag 默認的構成為:項目組/應用名稱:版本號

project.group:標準的 gradle 屬性,如果不進行定義,插件默認會 省略 ${project.group} 這個屬性。
applicationName:應用被容器化時的 名稱。
tagVersion:可選屬性,會作為鏡像的 標簽。默認值為 project.version,如果未指定 project.version,則使用 latest 作為標記。
配置docker構建基礎信息:

其中,baseImage 相當於 Dockerfile 中聲明的 FROM。聲明了在 構建鏡像 是基於的 Image,maintainer 相當於 MAINTAINER ,聲明了 鏡像作者。如果聲明了 registry 地址,插件在 鏡像射生成後 可以自動 push 到該地址。其他的配置還包括 docker hub 的 地址、用戶名 和 密碼。

taskBuilder 的任務配置:

構建完成以後,項目根目錄的 build/docker 文件夾下面會出現 Dockerfile 和 spring-boot-gradle-for-docker-1.0.jar 文件。其中,以上的 task 等同於以下的 Dockerfile。

如果覺的在 task 中編寫 Dockerfile 替換腳本 非常別扭,也可以直接在 task 中指定 Dockfile 的 文件路徑,直接使用已有的文件來生成鏡像:

通過 file() 指定 task 使用位於 項目根目錄 的 Dockerfile 來生產鏡像。

gradle 首先會運行 本地測試,然後進行項目打包,進一步根據 docker-gradle 插件進行鏡像構建。
等待出現 BUILD SUCCESSFUL 就表明任務運行成功。可以觀察到鏡像的名稱為:

運行 docker images 查看本地鏡像,進一步驗證鏡像構建成功。

在工程根目錄下新建Dockerfile文件,內容如下:

熱點內容
linuxi2c驅動 發布:2024-03-29 18:09:56 瀏覽:671
junit源碼下載 發布:2024-03-29 18:00:10 瀏覽:525
本田雅閣壓縮機不工作 發布:2024-03-29 17:59:13 瀏覽:600
溯源碼可以偽造嗎 發布:2024-03-29 17:54:45 瀏覽:56
北京編程傳 發布:2024-03-29 17:54:44 瀏覽:435
編程畫曲線 發布:2024-03-29 17:48:59 瀏覽:59
簡單存儲服務s3 發布:2024-03-29 17:48:46 瀏覽:336
安卓手機的usb功能在哪裡設置 發布:2024-03-29 17:46:27 瀏覽:758
配置文件ini如何寫 發布:2024-03-29 17:31:05 瀏覽:997
如何更改微信密碼修改 發布:2024-03-29 17:24:49 瀏覽:588