玩轉Docker(一):基本概念

容器技術是繼大數據和云計算之后又一炙手可熱的技術,而且未來相當一段時間內都會非常流行。

本文將對其基本概念和基本使用做出介紹。包括容器生態系統、容器的原理、怎樣運行第一個容器、容器技術的概念與實踐、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 rundocker builddocker 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日

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/904949.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/904949.shtml
英文地址,請注明出處:http://en.pswp.cn/news/904949.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

計算機視覺與深度學習 | 基于數字圖像處理的裂縫檢測與識別系統(matlab代碼)

???????????????????????????????? 基于數字圖像處理的裂縫檢測與識別系統 ??????????????????????????**系統架構設計****1. 圖像預處理**目標:消除噪聲+增強裂縫特征**2. 圖像分割**目標:提取裂縫區域**3. 特征…

推薦一款免費開源工程項目管理系統軟件,根據工程項目全過程管理流程開發的OA 辦公系統

在當今的工程項目管理領域&#xff0c;許多企業和團隊面臨著諸多難題。傳統的管理方式往往依賴于人工記錄和分散的工具&#xff0c;導致項目進度難以實時把控&#xff0c;任務分配不夠清晰&#xff0c;合同管理混亂&#xff0c;事件提醒不及時&#xff0c;財務管理缺乏系統性&a…

Proser:在使用中改進

上位機接收到下位機發送的協議&#xff0c;解析出工作模式&#xff0c;然后依據此模式切換到相應的界面。為了調試這個功能&#xff0c;由Proser提供的Block與Sequence生成器相當有用&#xff1a; 使用Block生成器&#xff1a;忽略掉不感興趣的數據使用Sequence生成器&#xf…

C語言_程序的段

在 C 語言程序中,內存通常被分為多個邏輯段,每個段存儲不同類型的數據。理解這些段的結構和功能,有助于你更高效地編寫、調試和優化程序。以下是 C 語言程序中主要的內存段及其特點: 1. 代碼段(Text Segment) 存儲內容:編譯后的機器指令(程序代碼)。特性: 只讀:防止…

【桌面】【輸入法】常見問題匯總

目錄 一、麒麟桌面系統輸入法概述 1、輸入法介紹 2、輸入法相關組件與服務 3、輸入法調試相關命令 3.1、輸入法診斷命令 3.2、輸入法配置重新加載命令 3.3、啟動fcitx輸入法 3.4、查看輸入法有哪些版本&#xff0c;并安裝指定版本 3.5、重啟輸入法 3.6、查看fcitx進程…

Node.js 24.0 正式發布:性能躍升與開發體驗全面升級

Node.js v24.0.0 震撼發布&#xff01;V8 13.6、npm 11、權限模型穩定化等重磅更新 2025年5月6日 —— Node.js 社區迎來重大里程碑&#xff01;Node.js v24.0.0 正式發布&#xff0c;帶來一系列激動人心的新特性、性能優化和 API 改進。本次更新涵蓋 V8 JavaScript 引擎升級至…

MySQL 查詢優化全攻略:從原理到實戰

為什么查詢優化如此重要&#xff1f; 在當今數據驅動的時代&#xff0c;數據庫性能直接影響著用戶體驗和業務效率。根據統計&#xff0c;網頁加載時間每增加1秒&#xff0c;轉化率可能下降7%&#xff0c;而數據庫查詢往往是性能瓶頸的關鍵所在。作為最流行的開源關系型數據庫之…

《從零開始:構建你的第一個區塊鏈應用》

一、引言 區塊鏈技術&#xff0c;這個曾經只在金融領域被廣泛討論的技術&#xff0c;如今已經滲透到各個行業。從供應鏈管理到智能合約&#xff0c;區塊鏈的應用場景越來越豐富。對于開發者來說&#xff0c;理解區塊鏈的基本原理并構建一個簡單的區塊鏈應用&#xff0c;是進入這…

使用AES-CBC + HMAC-SHA256實現前后端請求安全驗證

AES-CBC HMAC-SHA256 加密驗證方案&#xff0c;下面是該方案二等 優點 與 缺點 表格&#xff0c;適用于文檔、評審或技術選型說明。 ? 優點表格&#xff1a;AES-CBC HMAC-SHA256 加密驗證方案 類別優點說明&#x1f510; 安全性使用 AES-CBC 對稱加密使用 AES-128-CBC 是可…

Veins同時打開SUMO和OMNeT++的GUI界面

進入 Veins 工程目錄&#xff08;即包含 sumo-launchd.py 的目錄&#xff09;&#xff0c;打開終端設置 SUMO_HOME 環境變量&#xff08;指向你安裝的 SUMO 路徑&#xff09;&#xff1a; export SUMO\_HOME/home/veins/src/sumo-1.11.0編譯 Veins 工程&#xff08;包含 OMNeT…

suricata之日志截斷

一、背景 在suricata的調試過程中&#xff0c;使用SCLogXXX api進行信息的輸出&#xff0c;發現輸出的日志被截斷了&#xff0c;最開始以為是解析邏輯有問題&#xff0c;沒有解析完整&#xff0c;經過排查后&#xff0c;發現SCLogXXX api內部進行了長度限制&#xff0c;最長2K…

navicat 如何導出數據庫表 的這些信息 字段名 類型 描述

navicat 如何導出數據庫表 的這些信息 字段名 類型 描述 數據庫名字 springbootmt74k 表名字 address SELECT COLUMN_NAME AS 字段名,COLUMN_TYPE AS 類型,COLUMN_COMMENT AS 描述 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA springbootmt74k AND TABLE_NAME a…

LVGL圖像導入和解碼

LVGL版本&#xff1a;8.1 概述 在LVGL中&#xff0c;可以導入多種不同類型的圖像&#xff1a; 經轉換器生成的C語言數組&#xff0c;適用于頁面中不常改變的固定圖像。存儲系統中的外部圖像&#xff0c;比較靈活&#xff0c;可以通過插卡或從網絡中獲取&#xff0c;但需要配置…

【Web前端開發】HTML基礎

Web前端開發是用來直接給用戶呈現一個一個的網頁&#xff0c;主要包含實現用戶的結構&#xff08;HTML&#xff09;、樣式&#xff08;CSS&#xff09;、交互&#xff08;JavaScript&#xff09;。然而一個軟件通常是由后端和前端完成的。可以查閱文檔&#xff1a;HTML 教程 (w…

MySQL 8.0 單節點部署與一主兩從架構搭建實戰

前言&#xff1a;在數據驅動的時代&#xff0c;數據庫作為數據存儲與管理的核心組件&#xff0c;其架構的選擇與配置對系統的性能、可用性和擴展性至關重要。MySQL 作為一款廣泛應用的開源關系型數據庫&#xff0c;憑借其穩定的性能和豐富的功能&#xff0c;深受開發者和企業的…

數據庫故障排查全攻略:從實戰案例到體系化解決方案

一、引言&#xff1a;數據庫故障為何是技術人必須攻克的 "心腹大患" 在數字化時代&#xff0c;數據庫作為企業核心數據資產的載體&#xff0c;其穩定性直接決定業務連續性。據 Gartner 統計&#xff0c;企業每小時數據庫 downtime 平均損失高達 56 萬美元&#xff0…

牛客周賽round91

C 若序列為1 4 5 7 9 1 2 3&#xff0c;1 9一定大于1 1或1 4...所以只需要記錄當前數之前數字的最大值&#xff0c;然后遍歷取max即可&#xff0c;所以對于上面的序列有效的比較為1 9&#xff0c;2 9&#xff0c;3 9取max 代碼 //求大于當前數的最大值&#xff0c;然后…

【MCAL】TC397+EB-tresos之I2c配置實戰(同步、異步)

I2C總線是Philips公司在八十年代初推出的一種串行、半雙工的總線&#xff0c;主要用于近距離、低速的芯片之間的通信。本篇文章首先從理論講起&#xff0c;介紹了英飛凌TC3x系列芯片對應MCAL中對I2C驅動的定義與介紹&#xff0c;建議讀者在閱讀本篇文章之前對I2C有個簡單的認識…

深拷貝與淺拷貝:理解 Python 中的對象復制機制

深拷貝與淺拷貝&#xff1a;理解 Python 中的對象復制機制 在 Python 編程中&#xff0c;對象的復制是一個常見的操作。然而&#xff0c;很多初學者在處理對象復制時會遇到困惑&#xff0c;尤其是在涉及到復雜數據結構&#xff08;如列表、字典、自定義對象等&#xff09;時。…

BeanPostProcessor和AOP

BeanPostProcessor Spring中有一個接口Oredr的getOrder()方法&#xff0c;這個方法返回值是一個int類型&#xff0c;Spring容器會根據這個方法的返回值 對容器的多個Processor對象從小到大排序&#xff0c;創建Bean時候依次執行他們的方法&#xff0c;也就是說getOrder()方法的…