容器技術是繼大數據和云計算之后又一炙手可熱的技術,而且未來相當一段時間內都會非常流行。
本文將對其基本概念和基本使用做出介紹。包括容器生態系統、容器的原理、怎樣運行第一個容器、容器技術的概念與實踐、Docker鏡像等等
目錄
一. 鳥瞰容器生態系統
1. 容器生態系統包含哪些不同層次的技術?
2. 先了解下Docker
3. 容器、鏡像、鏡像倉庫
4. Docker容器與虛擬機技術的區別和聯系
二. 運行第一個容器
三. 容器技術
1. What - 什么是容器?
2. Why - 為什么需要容器?
3. How - 容器是如何工作的
Docker架構
Docker服務器:Docker Daemon
Docker客戶端:Docker CLI
Docker鏡像:Image
Docker容器:Container
Registry:存放Docker鏡像的倉庫
4. 小結
四. Docker鏡像
1. 鏡像的內部結構
hello-world -- 最小的鏡像
base鏡像
支持運行多種LinuxOS
2. 鏡像的分層結構
3. 構建鏡像
docker commit
Dockerfile
RUN vs CMD vs ENTRYPOINT
一. 鳥瞰容器生態系統
1. 容器生態系統包含哪些不同層次的技術?
容器生態系統是基于Docker等各種容器的生態系統,包含的技術層次
容器生態系統包含核心技術、平臺技術和支持技術。
簡而言之:
- 核心技術:能夠讓 Container 在 host 上運行的那些技術。解決的是容器自身怎樣運行。
- 平臺技術:關注一組容器如何組織運行,管理這組容器的生命周期。
- 容器支持技術:支持基于容器的基礎設施。例如,容器網絡、服務發現、監控、數據管理、日志管理、安全性等等
2. 先了解下Docker
Docker是一種開源的容器化平臺,旨在簡化應用程序的開發、部署和運行過程。提供了一種輕量級、可移植和自包含的容器化環境,使開發人員能夠在不同計算機上以一致的方式構建、打包和分發應用程序
3. 容器、鏡像、鏡像倉庫
-
容器(Container):容器是Docker中運行應用程序的運行時實例。它是一個輕量級、可執行的軟件包,包含了運行某個應用程序所需的所有內容,包括代碼、運行時、系統工具、系統庫和設置等。容器基于鏡像創建,是鏡像的運行實例。容器可以處于以下幾種狀態:
- 運行中:容器正在運行應用程序
- 已停止:容器已經停止運行,但仍然存在于系統中,可以隨時重新啟動。
- 已刪除:容器被刪除后,其所有數據和狀態都會被清除。
-
鏡像(Image):鏡像是容器的模板,是只讀的。它包含了容器運行所需的文件系統和應用程序的初始狀態。鏡像是由一系列的分層文件系統組成的,每一層都包含了特定的修改或更新。
-
鏡像倉庫(Image Registry):鏡像倉庫是用于存儲和分發 Docker 鏡像的地方。最常用的公共鏡像倉庫是 Docker Hub,上面有大量的官方和社區共享的鏡像。此外,還可以搭建私有的鏡像倉庫,用于存放自己的鏡像。
-
Dockerfile:Dockerfile 是一種文本文件,用于定義 Docker 鏡像的構建過程。它包含了一系列的指令,用于指定基礎鏡像、安裝軟件、拷貝文件、配置環境等。通過 Dockerfile,可以自動化地構建鏡像,確保鏡像的一致性和可重復性。
4. Docker容器與虛擬機技術的區別和聯系
Docker容器和虛擬機都是用于隔離和運行應用程序的技術,但它們在實現方式、性能、資源占用、啟動速度等方面存在顯著差異。以下是它們的主要區別:
- Docker容器:容器是一種輕量級的隔離運行環境,基于宿主機的操作系統內核,共享內核但擁有獨立的文件系統、網絡接口和進程空間。容器啟動快(通常幾秒內完成),資源占用低,性能接近物理機,適合快速部署和運行應用程序,尤其適用于微服務架構和開發測試環境。
- 虛擬機:虛擬機通過虛擬化技術創建一個完整的虛擬計算機環境,運行獨立的操作系統和應用程序。它提供強隔離性,適合運行多個不同操作系統或需要高度安全隔離的場景。虛擬機啟動慢(通常幾分鐘),資源占用高,性能損耗較大,但可移植性強,適合長期運行且對隔離性要求高的應用。
5. 運行第一個容器
首先,請安裝Docker并配置Docker的apt源。
- 配置Docker的APT源主要是為了確保能夠從官方或可信的源中安裝和更新Docker軟件包,同時也能解決一些常見的問題,比如版本兼容性、軟件更新以及網絡訪問速度等。
- 由于Docker Hub的服務在國外,下載鏡像比較慢,最好配置成為免費的國內鏡像服務。
環境就緒,馬上運行第一個容器,執行命令:
docker run -d -p 80:80 httpd
結果如圖所示:
其過程可以簡單描述為:
1. 從Docker Hub下載httpd鏡像
2. 啟動httpd容器,并將容器的80端口映射到host的80端口
3. 下面可以通過瀏覽器驗證容器是否正常工作。在瀏覽器中輸入:http://[your ubuntu host ip]/
結果如圖所示:
二. 容器技術
容器技術,需要搞清楚 What、why 和 How三個方面:什么是容器、為什么使用容器、容器是如何工作的。其中容器是怎樣工作的,是容器核心知識的最主要部分。
1. What - 什么是容器?
容器是一種輕量級、可移植、自包含的軟件打包技術,使應用程序可以在幾乎任何地方以相同的方式運行。
容器與虛擬機
談到容器,就不得不將它與虛擬機進行對比,因為兩者都是為應用提供封裝和隔離。
- 容器由兩部分構成:應用程序本身、及其依賴(比如應用程序需要的庫或者其他軟件容器在Host操作系統的用戶空間中運行,與操作系統的氣壓進程隔離,這一點顯著區別于虛擬機)。
- 傳統的虛擬化技術:目標是創建完整的虛擬機。為了運行應用,除了部署應用本及其依賴,還得安裝整個操作系統。
由于所有容器共享一個host os,這使得容器在體積上要比虛擬機小很多。另外,啟動容器不需要啟動整個操作系統,所以容器部署和啟動更快、開銷更小也更容易遷移。
2. Why - 為什么需要容器?
為什么需要容器,容器到底解決了什么問題?簡要的答案是,容器使軟件具備了超強的移植能力。
就像集裝箱解決了貨物運輸過程中,不同種類的貨物相互影響、干擾的難題。
任何貨物,不論是鋼琴和保時捷,都被放到各自的集裝箱中。集裝箱在整個運輸過程中都是密封的,只有到達最終目的地才會被打開。集裝箱被譽為運輸界與世界貿易最重要的發明。(容器和集裝箱的英文單詞都是:Container)
Docker將集裝箱思想用到軟件打包上,為代碼提供了一個基于容器的標準化運輸系統。
Docker可以將任何應用以及依賴打包成一個輕量級、可移植、自包含的容器。容器可以運行在幾乎所有的操作系統上。
3. How - 容器是如何工作的
Docker架構
Docker的核心組件包括:
- Docker客戶端:Client
- Docker服務器:Docker daemon
- Docker鏡像:Image
- Registry
- Docker容器:Container
Docker架構如圖所示
Docker采用的是Client / Server架構。客戶端向服務器發送請求,服務器請求構建、運行和分發容器。客戶端和服務器可以運行在同一個Host上,客戶端也可以通過socket或REST API與遠程服務器通信。
Docker服務器:Docker Daemon
Docker 服務器是容器管理的核心,負責實際的容器生命周期管理和資源分配。
Docker服務器是Docker的后臺服務進程,通常定義為Docker守護進程。它負責管理Docker的生命周期,包括創建、運行、停止、刪除容器等操作。
功能:
- 容器管理:接收來自客戶端的指令,執行容器的創建、啟動、停止、刪除等操作。
- 鏡像管理:管理Docker鏡像的拉取、存儲和推送
- 網絡管理:配置容器的網絡環境,包括虛擬網絡、端口映射等。
- 存儲管理:管理容器的存儲卷,支持數據持久化。
- 資源隔離:通過 Linux 內核的命名空間(Namespaces)和控制組(Cgroups)技術,為容器提供隔離的運行環境。
運行方式:Docker服務器通常在后臺運行,監聽來自客戶端的請求,并執行相應的操作。
Docker客戶端:Docker CLI
Docker 客戶端是用戶與 Docker 服務器之間的橋梁,提供用戶友好的交互方式,方便用戶發送命令和管理容器。最常用的Docker客戶端是docker命令。通過docker我們可以方便地在Host上構建和運行容器。
- Docker客戶端是用戶與Docker服務器交互的工具,通常是一個命令行界面(CLI),用戶通過它發送命令來控制Docker服務器。
功能:
- 命令執行:用戶通過命令行輸入指令,如
docker run
、docker build
、docker stop
等,將這些指令發送給 Docker 服務器。 - 交互界面:提供用戶友好的交互方式,方便用戶管理容器和鏡像。
- 配置管理:允許用戶配置 Docker 的運行參數,如網絡設置、存儲驅動等。
運行方式:Docker 客戶端通常運行在用戶的本地機器上,通過網絡(默認是本地套接字)與 Docker 服務器通信。
Docker鏡像:Image
可將Docker鏡像看成只讀模板,通過它可以創建Docker容器。
鏡像有多種生成方法:
- 從無到有開始創建鏡像
- 下載并使用別人創建好的現成的鏡像
- 在現有鏡像上創建新的鏡像
可以將鏡像的內容和創建步驟描述在一個文本文件中,這個文件被稱為Dockerfile,通過執行docker build <docker-file> 命令可以構建出Docker鏡像。
Docker容器:Container
Docker容器就是Docker鏡像的運行實例。
用戶可以通過CLI(Docker)或是API啟動、停止、移動或刪除容器。可以這么認為:對于應用軟件,鏡像是軟件生命周期的構建和打包階段,而容器則是啟動和運行階段。
Registry:存放Docker鏡像的倉庫
Registry是存放Docker鏡像的倉庫,Registry分為私有和公有兩種。
Docker Hub(https://hub.docker.com/)是默認的Registry,由Docker公司維護,上面有數以萬計的鏡像,用戶可以自由下載和使用。
出于對速度或安全的考慮,用戶也可以創建自己的私有Registry。
- docker pull?命令可以從Registry下載鏡像。
- docker run 命令則是先下載鏡像(如果本地沒有),然后再啟動容器。
還記得我們運行的第一個容器嗎?現在通過它來體會一下Docker各個組件是如何協作的。容器啟動過程如下:
1. Docker客戶端執行docker run命令
2. Docker Daemon發現本地沒有httpd鏡像
3. daemon從Docker Hub下載鏡像
4. 下載完成,鏡像httpd被保存到本地
5. Docker daemon啟動容器。
docker images已經可以查看到httpd已經下載到本地
docker ps 或者 docker container ls?顯示容器正在運行。
4. 小結
Docker借鑒了集裝箱的概念。標準集裝箱將貨物運往世界各地,Docker將這個模型運用到自己的設計哲學中。唯一不同的是:集裝箱運輸貨物,Docker運輸軟件。
每個容器都有一個軟件鏡像,相當于集裝箱中的貨物。容器可以被創建、啟動、關閉和銷毀。和集裝箱一樣,Docker在執行這些操作時,并不關心容器里面到底裝的什么,它不管里面是Web Server,還是Data-base。用戶不需要關心容器最終在哪里運行,因為在哪里都可以運行
開發人員可以在筆記本上構建鏡像并上傳到Registry,然后QA人員將鏡像下載到物理或虛擬機做測試,最終容器會部署到生產環境。
使用Docker以及容器技術,我們可以快速的構建一個應用服務器、一個消息中間件、一個數據庫、一個持續集成的環境。因為Docker Hub上有我們能想到的幾乎所有的鏡像。
三. Docker鏡像
鏡像是Docker容器的基石,容器是鏡像的運行實例,有了鏡像才能啟動容器。
本章內容安排如下:首先通過研究幾個典型的鏡像,分析鏡像的內部結構;然后學習如何構建自己的鏡像;最后介紹怎樣管理和分發鏡像。
1. 鏡像的內部結構
為什么我們要討論鏡像的內部結構?如果只是使用鏡像,當然不需要了解,直接通過Docker命令下載和運行就可以了。
但如果我們想構建自己的鏡像,或者想理解Docker為什么是輕量級的,就非常有必要學習這部分知識了。
我們從一個最小的鏡像開始學習。
hello-world -- 最小的鏡像
hello-world是Docker官方提供的一個鏡像,通常用來檢驗Docker是否安裝成功。我們先通過docker pull 從Docker Hub下載它,如圖所示:
用 docker images 查看鏡像的信息,如圖所示:
hello-world竟然還不到2kb,通過docker run運行,如圖所示:
其實我們更關心 hello-world 鏡像包含了哪些內容。
Dockerfile是鏡像的描述文件,定義了如何構建Docker鏡像。Dockerfile的語法簡潔且可讀性強,后面我們會討論如何編寫Dockerfile。
hello-world 的 Dockerfile內容如下圖所示:
只有短短三條指令。
(1)From scratch鏡像是白手起家,從0開始構建
(2)COPY hello/ 將文件 “hello”復制到鏡像的根目錄
(3)CMD ["/hello"] 容器啟動時,執行 /hello
鏡像hello-world中就只有一個可執行文件 “hello”,其功能就是打印出 “Hello from Docker...”等信息。
/hello 就是文件系統的全部內容,連最基本的 /bin /usr /lib /dev 都沒有
hello-world雖然是一個完整的鏡像,但它并沒有什么實際用途。通常來說,我們希望鏡像能夠提供一個基本的操作系統環境,用戶可以根據需要安裝和配置軟件。
這樣的鏡像我們稱作 base鏡像。
base鏡像
base鏡像有兩層含義:
- 不依賴于其他鏡像,從scratch構建
- 其他鏡像可以以之為基礎進行擴展
所以,能稱作base鏡像的通常都是各種Linux發行版的Docker鏡像,比如Ubuntu、Debian、CentOS等。
我們以CentOS為基礎為例考察base鏡像包含哪些內容。
下載鏡像:
docker pull centos
查看鏡像信息,如下圖:
鏡像大小不到200MB
等一下!
一個CentOS才200MB?
平時我們安裝一個CentOS至少都有幾個GB,怎么可能才200MB!
相信這是幾乎所有 Docker 初學者都會有的疑問,包括我自己。下面我們來解釋這個問題。
Linux操作系統由內核空間和用戶空間組成,如下圖:
1. rootfs
內核空間是kernel,Linux剛啟動時會加載bootfs文件系統,之后bootfs會被卸載掉。
用戶空間的文件系統是rootfs,包含我們熟悉的 /dev /proc /bin等目錄
對于 base鏡像 來說,底層直接用 Host 的 kernel,自己只需要提供rootfs就行了。
- 而對于一個精簡的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序庫就可以了。相比其他的Linux發行版,CentOS的rootfs已經算臃腫的了,alpine還不到10MB
- 我們平時還會安裝的CentOS除了rootfs之外,還會選裝很多軟件、服務、圖形桌面等等,需要好幾個GB就不足為奇了。
2. base鏡像提供的是最小安裝的Linux發行版
CentOS鏡像的Dockerfile的內容如下圖所示:
第二行ADD指令添加到鏡像的 tar 包就是 CentOS 7 的rootfs,在制作鏡像時,這個tar包會自動解壓到 / 目錄下,生成 /dev、/proc、/bin等目錄。
支持運行多種LinuxOS
不同Linux發行版的區別主要就是rootfs,所以Docker可以同時支持多種Linux鏡像,模擬出多種操作系統環境。
上圖Debian和BusyBox(一種嵌入式Linux)上層提供各自的rootfs,底層共用Docker Host的kernel
2. 鏡像的分層結構
Docker支持通過擴展現有鏡像,創建新的鏡像。
實際上,Docker Hub中99%的鏡像都是通過在base鏡像中安裝和配置需要的軟件構建出來的。比如我們構建一個新的鏡像,Dockerfile 如下圖所示:
(1)新鏡像不再是從scratch開始,而是直接在Debian base鏡像上創建
(2)安裝 emacs 編輯器
(3)安裝 Apache2
(4)容器啟動時運行 bash
構建過程中如下圖:
可以看到,新鏡像是從base鏡像一層一層疊加生成的。每安裝一個軟件,就在現有鏡像的基礎上增加一層。
為什么Docker鏡像要采用這種分層結構呢?
最大的一個好處就是:共享資源。
3. 構建鏡像
對于Docker用戶來說,最好的情況是不需要自己創建鏡像。幾乎所有常用的數據庫、中間件、應用軟件等都有現成Docker官方鏡像或其他人和組織創建的鏡像,我們只需要稍作配置就可以直接使用。
使用現成鏡像的好處除了省去自己做鏡像的工作量外,更重要的是可以利用前人的經驗。特別是使用官方的鏡像,因為Docker工程師更知道如何更好地在容器中運行軟件。
當然,某些情況下我們也不得不自己構建鏡像,比如:
(1)找不到現成的鏡像,比如自己開發的應用程序。
(2)需要在鏡像中加入特定的功能,比如官方鏡像幾乎都不提供ssh
所以本節我們將介紹構建鏡像的方法。同時分析構建的過程也能夠加深我們對前面鏡像分層結構的理解。
Docker提供了兩種構建鏡像的方法:docker commit命令與Dockerfile構建文件。
docker commit
docker commit 命令是創建新鏡像最直觀的方法,其過程包含三個步驟:
- 運行容器
- 修改容器
- 將容器保存為新的鏡像
舉個例子:在Ubuntu base鏡像中安裝vi并保存為新鏡像。
(1)運行容器
如圖所示:
-it的作用是以交互模式進入容器,并打開終端。
(2)安裝vi
確認vi沒有安裝,如下圖所示:
安裝vi,如下圖所示:
(3)保存為新鏡像
在新窗口中查看當前運行的容器,如圖所示:
silly_goldberg是Docker為我們容器隨機分配的名字。
執行 docker commit 命令將容器保存為鏡像,如圖所示:
新鏡像命名為ubuntu-with-vi
查看新鏡像的屬性,如圖所示:
從size上看到鏡像因為安裝了軟件而變大了。
從新鏡像啟動容器,驗證 vi 已經可以使用,如圖所示:
以上演示了如何用 docker commit創建新鏡像。然而,Docker并不建議用戶通過這種方式構建鏡像。原因如下:
(1)這是一種手動創建鏡像的方式,容易出錯,效率低且可重復性若。比如要在 debian base鏡像中也加入vi,還得重復前面所有的步驟。
(2)更重要的:使用者并不知道鏡像是如何創建出來的,里面是否有惡意程序。也就是說無法對鏡像進行審計,存在安全隱患。
既然 docker commit不是推薦的方法,我們為什么還要花時間學習呢?原因是,即便是用Dockerfile(推薦方法)構建鏡像,底層也是docker commit一層一層構建新鏡像的。學習docker commit 能夠幫助我們更加深入地理解構建過程和鏡像的分層結構。
Dockerfile
Dockerfile是一個文本文件,記錄了鏡像夠簡單的所有步驟。
1. 第一個Dockerfile
用 Dockerfile 創建上節的 ubuntu-with-vi,其內容如圖所示:
下面我們運行 docker build 命令構建鏡像并詳細分析每個細節。
root@ubuntu:~# pwd ①/rootroot@ubuntu:~# ls ②Dockerfileroot@ubuntu:~# docker build -t ubuntu-with-vi-dockerfile . ③Sending build context to Docker daemon 32.26 kB ④Step 1 : FROM ubuntu ⑤---> f753707788c5Step 2 : RUN apt-get update && apt-get install -y vim ⑥---> Running in 9f4d4166f7e3 ⑦......Setting up vim (2:7.4.1689-3ubuntu1.1) ...---> 35ca89798937 ⑧Removing intermediate container 9f4d4166f7e3 ⑨Successfully built 35ca89798937 ⑩root@ubuntu:~#
① 當前目錄為 /root。
② Dockerfile準備就緒。
③ 運行docker build命令,-t將新鏡像命名為ubuntu-with-vi-dockerfile,命令末尾的.指明build context為當前目錄。Docker默認會從build context中查找Dockerfile文件,我們也可以通過-f參數指定Dockerfile的位置。
④ 從這步開始就是鏡像真正的構建過程。
首先Docker將build context中的所有文件發送給Docker daemon。build context為鏡像構建提供所需要的文件或目錄。 Dockerfile中的ADD、COPY等命令可以將build context中的文件添加到鏡像。此例中,build context為當前目錄 /root,該目錄下的所有文件和子目錄都會被發送給Docker daemon。 所以,使用build context就得小心了,不要將多余文件放到build context,特別不要把 /、/usr作為build context,否則構建過程會相當緩慢甚至失敗。
⑤ Step 1:執行FROM,將Ubuntu作為base鏡像。 Ubuntu鏡像ID為f753707788c5。
⑥ Step 2:執行RUN,安裝vim,具體步驟為 ⑦ ⑧ ⑨。
⑦ 啟動ID為9f4d4166f7e3的臨時容器,在容器中通過apt-get安裝vim。
⑧ 安裝成功后,將容器保存為鏡像,其ID為35ca89798937。 這一步底層使用的是類似docker commit的命令。
⑨ 刪除臨時容器9f4d4166f7e3。
⑩ 鏡像構建成功。
通過docker images查看鏡像信息,如圖3-21所示。 [插圖] 圖3-21 鏡像ID為35ca89798937,與構建時的輸出一致。 在上面的構建過程中,我們要特別注意指令RUN的執行過程 ⑦ ⑧ ⑨。Docker會在啟動的臨時容器中執行操作,并通過commit保存為新的鏡像。
2. 查看鏡像的分層結構
ubuntu-with-vi-dockerfile 是通過在base鏡像的頂部增加一個新的鏡像層而得到的,如圖所示:
這個新鏡像層的內容由 RUN apt-get update && apt-get in stall -y vim 生成。這一點我們可以通過docker history命令驗證,如圖所示:
docker history會顯示鏡像的構建歷史,也就是Dockerfile的執行過程。
ubuntu-with-vi-dockerfile 與 Ubuntu 鏡像相比,確實只是多了頂部的一層35ca89798937,由apt-get命令創建,大小為97.07MB。docker history向我們展示了鏡像的分層結構,每一層由上至下排列。
注:missing表示無法獲取IM-AGE ID,通常從 Docker Hub 下載的鏡像會有這個問題。
3. 鏡像的緩存特征
我們接下來看Docker鏡像的緩存特征。
Docker會緩存已有鏡像的鏡像層,構建新鏡像時,如果某鏡像直接存在,就直接使用,無需重新創建。
例如,如果在Dockerfile中添加一點新內容,往鏡像中復制一個文件:
(1)確保 testfile 已存在
(2)由于之前已經運行過相同的 RUN 命令,這次直接使用緩存中的鏡像層 35ca89798937
(3)執行 COPY 命令
其過程是啟動臨時容器,復制 testfile,提交新的鏡像層 8d02784a78f4,刪除臨時容器。
在ubuntu-with-vi-dockerfile 鏡像上直接添加一層就得到了新的鏡像 ubuntu-with-vi-docker-file-2,如圖所示:
如果我們希望在構建鏡像時不使用緩存,可以在 docker build 命令中加上 no-cache 參數。
Dockerfile每一個指令就會創建一個鏡像層,上層是依賴于下層的。無論什么時候,只要某一層發生變化,其上面所有層的緩存都會失效。?
也就是說,如果我們改變 Dockerfile 的執行順序,或者修改或者添加指令,都會使緩存失效。舉例說明:
- 如果交換前面 RUN 和 COPY 的順序,如圖所示:
- 雖然在邏輯上這種改動對鏡像的內容沒有影響,但由于分層的結構特征,Docker必須重建受影響的鏡像層。
- 從執行過程可以看到,生成了新的鏡像層,緩存已經失效。
除了構建時使用緩存,Docker在下載鏡像時也會使用。
4. 調試Dockerfile
總結一下通過 Dockerfile 構建鏡像的過程:
(1)從base鏡像運行一個容器
(2)執行一條指令,對容器做修改
(3)執行類似docker commit的操作,生成一個新的鏡像
(4)Docker再基于剛剛提交的鏡像運行一個新容器
(5)重復2~~4步,直到Dockerfile中的所有指令執行完畢
5. Dockerfile 常用指令
是時候系統學習Dockerfile了
- FROM:指定base鏡像
- MAINTAINER:設置鏡像作者,可以是任意字符串
- COPY:
- 將文件從build context復制到鏡像
- COPY支持兩種形式:COPY src dest 與 COPY ["src", "dest"]
- 注意,src只能指定 build context 中的文件或目錄
- ADD:
- 與COPY類似,從 build context 復制文件到鏡像。不同的是,如果 src 是歸檔文件(tar、zip、tgz、xz等),文件會被自動解壓到dest
- ENV:
- 設置環境變量,環境變量可以被后面的指令使用。例如:
-
ENV MY_VERSION 1.3 RUN apt-get install -y mypackage=$MY_VERSION
-
EXPOSE:
-
指定容器中的進程會監聽某一個端口,Docker可以將該端口暴露出來。
-
-
VOLUMN:
-
將文件或者目錄聲明為volume
-
-
WORKDIR:
-
為后面的RUN、CMD、ENTRY-POINT、ADD或COPY指令設置鏡像中的當前工作目錄
-
-
RUN
-
在容器中執行指定的命令
-
-
CMD
-
容器啟動時運行指定的命令
-
Dockerfile可以有多個CMD指令,但只有最后一個生效。CMD可以被 docker run 之后的參數替換。
-
-
ENTRYPOINT
-
設置容器啟動時運行的命令。
-
Dockerfile中可以有多個ENTRYPOINT指令,但只有最后一個生效。CMD 或 docker run之后的參數會被當做參數傳遞給 ENRTYPOINT。
-
這是一個比較全面的Dockerfile(注:Dockerfile支持以 “#” 開頭的注釋)
構建鏡像,如下圖:
(1)構建前確保build context中存在需要的文件
(2)依次執行Dockerfile指令,完成構建
(3)運行容器,驗證鏡像內容,如下圖
1. 進入容器,當前目錄即為WORKDIR
如果WORKDIR不存在,Docker會自動幫我們創建
2. WORKDIR中保存了我們希望的文件和目錄
目錄bunch:由ADD指令從build context復制的歸檔文件bunch.tar.gz,已經自動解壓。 文件tmpfile1:由RUN指令創建。 文件tmpfile2:由COPY指令從build context復制。
3. ENV指令定義的環境變量已經生效。
RUN vs CMD vs ENTRYPOINT
RUN、CMD和ENTRYPONIT這三個Dockerfile指令看上去很類似,很容易混淆。
簡單地說:
(1)RUN:執行命令并創建新的鏡像層,RUN經常用于安裝軟件包
(2)CMD:設置容器啟動后默認執行的命令及其參數,但CMD能夠被 docker run 后面接的命令行替換
(3)ENTRYPOINT:配置容器啟動時運行的命令
最佳實踐:
1. 使用RUN命令安裝應用和軟件包,構建鏡像
2. 如果docker鏡像的用途是運行應用程序或服務,比如運行一個MySQL,應該使用Exec格式的ENTRYPOINT指令。CMD可為ENTRYPONIT提供額外的默認參數,同時可以利用 docker run 命令行替換默認參數,同時可以利用 docker run 命令行替換默認參數。
3. 如果想為容器設置默認的啟動命令,可使用CMD指令,用戶可在 docker run 命令中替換此默認命令。
4. 小結
本章我們學習了Docker鏡像。首先討論了鏡像的分層結構,然后學習了如何構建鏡像,最后實踐使用Docker Hub和本地registry。
下面是鏡像的常用操作子命令:
- images:顯示鏡像列表。
- history:顯示鏡像構建歷史。
- commit:從容器創建新鏡像。
- build:從Dockerfile構建鏡像。
- tag:給鏡像打tag。
- pull:從registry下載鏡像。
- push:將鏡像上傳到registry。
- rmi:刪除Docker host中的鏡像。
- search:搜索Docker Hub中的鏡像。
以上是 docker 技術的基本概念,其余知識明日繼續連載
Good night~~
-- 2025年5月2日