1.概述
Docker是一種優秀的開源的容器化平臺。用于部署、運行應用程序,它通過將應用及其依賴打包成輕量級、可移植的容器,實現高效一致的運行效果,簡單來說,Docker就是一種輕量級的虛擬技術。
2.核心概念
2.1.容器(Container)
容器是獨立運行的進程單元,包含應用程序代碼、運行時環境、系統工具和依賴庫。
1.每個容器相互隔離,共享主機操作系統內核
2.啟動速度快,資源占用低
2.2.鏡像(Image)
鏡像是容器啟動的靜態模板,包含創建容器所需的分層文件系統
1.通過Dockerfile定義構建步驟(例如指定基礎鏡像,安裝依賴)
2.支持版本管理和共享(如Docker hub共享倉庫)
2.3.倉庫(Registry)
用于倉儲和分發鏡像的平臺(如Docker Hub、私有倉庫)
3.核心功能
3.1.容器化技術
- 應用隔離:將應用及其依賴打包到獨立的容器中
- 環境一致性:保證開發、測試、生產環境的一致性
- 快速部署:秒級啟動和停止容器
3.2.鏡像管理
- 分層存儲:鏡像采用分層結構,共享基礎層,節省存儲空間
- 版本控制:支持鏡像的版本管理和回滾
- 鏡像倉庫:Docker Hub等平臺提供鏡像共享和分發
3.3.資源管理
- 資源限制:可以限制容器的CPU、內存、磁盤IO等資源
- 網絡管理:提供多種網絡模式(bridge、host等)
- 存儲管理:支持數據卷,綁定掛載等持久化存儲方案
4.容器化&虛擬化
- Infrastructure:基礎設施,可以是個人電腦、主機服務器
- Host Operating system:運行的主操作系統,例如windows、mac、Linux
- Hypervisor:虛擬機管理器,可以虛擬出多個硬件,然后再安裝操作系統,再部署應用
- Guest OS:從操作系統,有Hypervisor虛擬出來
- BINS/LIBS:二進制文件(Binaries)/庫文件(Libraries),例如應用程序相關的編譯后的可以執行的二進制文件,提供給應用程序調用的同樣功能的庫文件
- Docker Daemon:Docker守護進程,代替了虛擬機的Hypervisor,docker守護進程本質是運行在主操作系統上的一個進程,直接與操作系統進行交互,這也是Docker 容器比較快的原因。
雖然虛擬機比較笨重但是也不是沒有優勢,可以講服務器比作一個碼頭,擁有各種設備和場地(服務器硬件資源),服務器虛擬化類似在碼頭上有好多個倉庫,倉庫可以完全獨立,每個倉庫有各自的管理人員,Docker容器類似倉庫里面的集裝箱,每個集裝箱各自獨立,靈巧,方便遷移,但是隔離性比較差,多個集裝箱統一由一個管理者進行管理,所有集裝箱信息就暴露給一個管理人員,而倉庫則可以有各自的用戶,例如云服務提供者,通過虛擬出一個獨立的虛擬機,有自己的用戶,即租戶管理自己的虛擬機。
# Docker 架構
+-------------------------------------------------------+
| Application A |
| Application B |
| Application C |
+-------------------------------------------------------+
| Docker Engine |
+-------------------------------------------------------+
| Host Operating System |
+-------------------------------------------------------+
| Physical Hardware |
+-------------------------------------------------------+# 虛擬機架構
+-----------+ +-----------+ +-----------+
| App A | | App B | | App C |
+-----------+ +-----------+ +-----------+
| Guest OS | | Guest OS | | Guest OS |
+-----------+ +-----------+ +-----------+
| Hypervisor |
+-------------------------------------------------------+
| Host Operating System |
+-------------------------------------------------------+
| Physical Hardware |
+-------------------------------------------------------+
4.1.詳細對比
特性 | Docker (容器) | 虛擬機 (VM) |
---|---|---|
啟動速度 | 秒級啟動 | 分鐘級啟動 |
性能 | 接近原生性能 | 有性能損耗(5-15%) |
資源占用 | 輕量(MB級別) | 重量(GB級別) |
隔離性 | 進程級別隔離 | 完整的系統級別隔離 |
安全性 | 相對較低(共享內核) | 較高(完全隔離) |
鏡像大小 | 通常為 MB 級別 | 通常為 GB 級別 |
部署密度 | 高(單機可運行數百容器) | 低(單機通常10-20個VM) |
兼容性 | 依賴宿主機內核 | 任何支持虛擬化的系統 |
遷移性 | 跨平臺有限制 | 跨平臺性好 |
系統開銷 | 低(無額外OS開銷) | 高(每個VM需要完整OS) |
4.1.技術實現對比
技術層面 | Docker | 虛擬機 |
---|---|---|
虛擬化類型 | 操作系統級虛擬化 | 硬件級虛擬化 |
虛擬化技術 | Namespaces, Cgroups | Hypervisor (KVM, VMware, Hyper-V) |
Guest OS | 不需要,共享主機內核 | 每個VM需要完整的Guest OS |
資源分配 | 動態分配,按需使用 | 預先分配固定資源 |
鏡像構建 | Dockerfile,分層構建 | 模板或快照,整體構建 |
5.Docker使用場景
使用Docker容器開發、測試、部署服務:因為Docker本身非常輕量化,所以本地開發人員可以構建、運行并分享Docker容器。容器可以在開發環境中創建,然后再提交到測試,最終進入生產環境。
創建隔離的運行環境:在很多企業應用中,同一服務的不同版本可能服務于不同的用戶,那么使用Docker非常容易創建不同的生成環境來運行不同的服務。
搭建測試環境:由于Docker的輕量化,所以開發者很容易利用Docker在本地搭建測試環境,用來測試程序在不用系統下的兼容性;甚至搭建集群的部署測試。
構建多用戶的平臺即服務(PaaS)基礎設施。
提供軟件即服務(SaaS)應用程序。
高性能、超大規模的宿主機部署。
5.1.Docker組成
5.2.Docker 客戶端 / 守護進程
Docker是C/S架構的程序:Docker客戶端向Docker服務器端,也就是Docker的守護進程發出請求,守護進程處理完所有的請求工作并返回結果。Docker 客戶端對服務器端的訪問既可以是本地也可以通過遠程來訪問。
5.3.Docker Image 鏡像
鏡像是Docker容器的基石,容器基于鏡像啟動和運行。鏡像就好比容器的源代碼,保存了用于啟動容器的各種條件。
Docker的鏡像是一個層疊的只讀文件系統,最低端是一個引導文件系統(即bootfs),第二層是root文件系統(即rootfs),它位于bootfs之上,可以是一種或多種操作系統,比如Ubuntu或者CentOS。在Docker中,root文件系統永遠只能是只讀狀態,并且docker運用聯合加載技術又會在root文件系統之上加載更多的只讀文件系統,聯合加載指的是一次加載多個文件系統,但是在外面看起來只能看到一個文件系統,聯合加載會將各層文件系統疊加到一起,這樣最終的文件系統會包含所有的底層文件和目錄,docker將這樣的文件系統稱為鏡像。
5.4.Docker Container 容器
容器是從鏡像創建的運行實例。它可以被啟動、開始、停止、刪除。每個容器都是相互隔離的、保證安全的平臺。可以把容器看做是一個簡易版的 Linux 環境(包括root用戶權限、進程空間、用戶空間和網絡空間等)和運行在其中的應用程序。
當一個容器啟動時,Docker會在該鏡像的最頂層加載一個讀寫文件系統,也就是一個可寫的文件層,我們在Docker運行的程序,就是在這個層中進行執行的,當Docker第一次啟動一個容器時,初始的讀寫層是空的,當文件系統發生變化時,這些變化都會應用到這一層上,比如像修改一個文件,該文件首先會從讀寫層下面的只讀層復制到該讀寫層,該文件的只讀版本依然存在,但是已經被讀寫層中的該文件副本所隱藏,這就是Docker的一個重要技術:寫時復制(copy on write)。每個只讀鏡像層都是只讀的,永遠不會變化,當創建一個新容器時,Docker會構建出一個鏡像棧,
5.5.Docker Registry 倉庫
Registry倉庫是集中存放Docker鏡像文件的場所。人們有時候會把Repository倉庫和Registry倉庫混為一談,并不嚴格區分。實際上,Registry倉庫上往往存放著多個Repository倉庫,每個Repository倉庫中又包含了多個Docker鏡像,每個Docker鏡像有不同的標簽(tag)。
Registry倉庫分為公開倉庫(Public)和私有倉庫(Private)兩種形式。最大的公開倉庫是 Docker Hub,存放了數量龐大的鏡像供用戶下載。 國內的公開倉庫包括 Docker Pool 等,可以提供大陸用戶更穩定快速的訪問。
6.Dockerfile
Dockerfile 是用于構建 Docker 鏡像的文本文件,包含一系列指令。每個指令在鏡像中創建一個新層,最終形成可運行的容器環境。
6.1.Dockerfile 是什么
- ? ? 文本文件: 純文本文件,通常命名為 Dockerfile (首字母大寫,無擴展名是慣例)。
- ? ? 指令集合: 包含一系列按順序執行的指令 (INSTRUCTION arguments)。
- ? ? 構建藍圖: 描述了如何從基礎組件(通常是基礎鏡像)一步步組裝成一個新的、可運行的鏡像。
- ? ? 自動化構建: 執行 docker build 命令時,Docker 引擎讀取 Dockerfile 并執行其中的指令,最終生成一個鏡像。
- ? ? 可重復性 & 版本控制: Dockerfile 本身可以被版本控制(如 Git),確保鏡像構建過程透明、可審計、可重復。
6.2.Dockerfile 的核心組成部分
指令 | 目的 | 說明 | 示例 | 最佳實踐 |
FROM | 基礎鏡像 | 必須是第一個指令,指定構建新鏡像所屬的現有鏡像 | FROM ubuntu:22.04 FROM python:3.9-slim-buster | 使用官方、輕量級、具體版本的基礎鏡像。 |
RUN | 執行命令 | 在構建期間,在新鏡像的文件系統層中執行命令 | RUN apt-get update && apt-get install -y nginx RUN pip install -r requirements.txt | 合并命令減少層數;清理緩存;命令失敗時應返回非零。 |
COPY | 復制文件 | 從構建上下文復制文件或目錄到鏡像指定路徑 | COPY ./app /usr/src/app COPY requirements.txt . | 優先使用 COPY ;明確復制目標目錄。 |
ADD | 復制與解壓 | 類似COPY,單增加了功能;自動解壓本地.tar文件,支持URL源 | ADD ./app.tar.gz /opt/ ADD https://example.com/file /tmp/ | 除非需要解壓或 URL 下載,否則優先用 COPY 。 |
CMD | 容器默認命令 | 知道容器啟動運行的默認命令及參數每個Dockerfile只能有一個CMD可被docker run覆蓋 | CMD ["nginx", "-g", "daemon off;"] CMD ["python", "app.py"] | 使用exec形式避免shell進程;僅指定主進程 |
ENTRYPOINT | 容器入口點 | 定義容器啟動時可執行程序,CMD作為參數傳遞給ENTRYPOINT,可被 docker run --entrypoint 覆蓋 | ENTRYPOINT ["python"] CMD ["app.py"] | 常與CMD配合使用;優先exec形式;用于固定入口 |
WORKDIR | 設置工作目錄 | 設置后續指令(RUN、CMD)的工作目錄 | WORKDIR /app RUN pwd # 輸出 /app | 為清晰路徑設置,替代 RUN cd ... ;用絕對路徑。 |
EXPOSE | 申明端口 | 文檔性說明容器在運行時監聽哪些網絡端口,不實際發布端口 | EXPOSE 80 EXPOSE 8000/tcp | 說明服務監聽的端口;真實端口映射在 docker run 時指定。 |
ENV | 設置環境變量 | 設置環境變量,可以在構建和運行期間使用 | ENV PYTHONUNBUFFERED=1 ENV APP_HOME=/app | 配置服務行為;使用變量簡化 Dockerfile。 |
ARG | 構建時變量 | 定義僅在構建過程中有效的變量,可用docker build --build -arg 傳入 | ARG VERSION=latest RUN apt-get install package=$VERSION | 用于參數化構建;不同默認值于不同階段。 |
VOLUME | 定義匿名卷 | 在鏡像中創建一個掛載點,用于關聯外部存儲 | VOLUME /var/lib/mysql | 聲明需要持久化或共享數據的目錄。 |
USER | 切換用戶 | 設置后續指令(RUN、CMD)運行時的用戶及用戶組 | USER www-data USER 1000:1000 | 避免 root 用戶運行應用;提高安全性。 |
LABEL | 添加元數據 | 為鏡像添加描述性元數據,如維護者信息,許可證等 | LABEL maintainer="dev@example.com" LABEL version="1.0" | 記錄鏡像相關信息。 |
ONBUILD | 延遲指令 | 將指令標記為延遲執行,當該鏡像被作為另一個構建的基礎時才觸發。 | ONBUILD COPY . /app/src | 用于構建基礎鏡像。 |
7.最佳實踐
- 精簡基礎鏡像: 使用 alpine、slim 等小型基礎鏡像減少攻擊面和最終鏡像大小。
- 合并 RUN 指令: 將多個 RUN 命令(特別是 apt-get update && install && clean)合并為一個,減少層數并清理包管理器緩存。
- 合理利用緩存: 將更改頻率低的指令(如安裝核心依賴)放前面,更改頻率高的指令(如復制應用代碼)放后面。
- 使用 .dockerignore 文件: 明確忽略構建上下文中的不必要文件。
- 優先使用 COPY 而非 ADD: 除非明確需要解壓縮或從 URL 下載,否則用更簡單直接的 COPY。
- 指定版本標簽: FROM 和依賴安裝時使用明確版本,避免因 latest 標簽更新導致的意外行為。
- 減少鏡像層數: 雖然層本身開銷不大,但過多小層不利于管理,合并相關操作有益。
- 設置非 root 用戶: 在 RUN 用戶級步驟后使用 USER,避免容器以 root 權限運行應用,提高安全性。
- 使用多階段構建: 分離構建環境和運行環境,大幅減小最終生產鏡像體積(見示例)。
- 明確暴露端口: 使用 EXPOSE 聲明容器監聽的端口。
- 優先 exec 格式: 對 CMD 和 ENTRYPOINT 使用 JSON 數組格式 ["executable", "param1", "param2"] (exec 格式),避免不必要的 shell 進程并確保信號正確處理。
- 添加元數據: 使用 LABEL 提供鏡像信息。
- 設置工作目錄: 用 WORKDIR 替代 RUN cd ... && ...,使用絕對路徑。
- 考慮安全性: 定期更新基礎鏡像和依賴包修復漏洞;避免在 Dockerfile 或鏡像中存儲硬編碼的機密信息,使用 ARG 或 secrets(在運行時通過環境變量或卷傳入)。
- 包含健康檢查: 對關鍵服務使用 HEALTHCHECK 幫助編排系統管理容器狀態。