一:什么是Docker
(1)基本概念
Docker 是一種開源的 容器化平臺,用于快速構建、部署和運行應用程序。它通過將應用程序及其依賴項打包到輕量級的、可移植的容器中,實現了環境一致性,解決了“在我機器上能運行,但在其他環境不行”的問題。其最核心思想是
-
標準化 (Standardization):Docker 通過引入鏡像 (Image) 的概念,將應用程序及其所有依賴項(代碼、運行時環境、系統工具、庫等)打包成一個獨立的、可執行的單元。這個鏡像在任何支持 Docker 的環境中都能以相同的方式運行,確保了“一次構建,隨處運行 (Build once, run anywhere)”的承諾。這解決了傳統環境中“在我機器上能跑”但在其他環境就出問題(“依賴地獄”或“環境差異”)的痛點。
-
隔離 (Isolation):Docker 利用 Linux 內核的特性(主要是 cgroups 和 namespaces),為每個應用程序創建了一個獨立的、輕量級的運行環境,稱為容器 (Container)。容器之間相互隔離,互不影響,即使一個容器出現問題,也不會影響到其他容器或宿主機。這種隔離性使得應用程序的部署更加安全可靠,也簡化了依賴管理。
Docker解決的問題:
-
環境一致性問題:通過鏡像和容器,保證了開發、測試、生產環境的一致性,消除了“在我機器上能跑”的問題。
-
依賴管理復雜性:將應用程序及其所有依賴打包在容器內,簡化了依賴管理,避免了版本沖突。
-
部署效率低下:容器的快速啟動和輕量級特性使得應用程序的部署和擴展變得非常高效。
-
資源利用率低:相比于虛擬機,容器共享宿主機的操作系統內核,更加輕量級,啟動速度更快,占用資源更少,提高了服務器的資源利用率。
-
應用隔離性不足:容器提供了進程級別的隔離,增強了應用的安全性,避免了應用間的相互影響。
-
微服務架構的流行:Docker 是微服務架構的理想載體,每個微服務都可以獨立地打包成一個容器,便于部署、擴展和管理。
Docker簡單來說就是用容器化技術給應用程序封裝獨立的運行環境,每個運行環境就是一個容器,運行容器的計算機被稱為宿主機。Docker容器域虛擬機最大區別是Docker容器之間共用同一個系統內核。而每個虛擬機都包含一個操作系統的完整內核。所以Docer容器比虛擬機更輕、更小,啟動速度更快。
(2)關鍵術語
鏡像(Image):
定義:鏡像是容器的模板,是只讀的模板,包含了運行應用程序所需的所有文件系統內容、環境變量、以及啟動應用程序的命令。可以理解為應用程序及其運行環境的“快照”或“藍圖”。
Registry (倉庫):
Docker倉庫就是用來存放分享鏡像的地方。每個人都可以把自己的鏡像分享到倉庫里面。Docker Hub 是官方的公共鏡像倉庫,用戶可以在其中查找、下載和分享鏡像。企業也可以搭建私有倉庫來管理內部鏡像。
容器(Container):
-
定義:容器是鏡像的一個運行實例。當鏡像被啟動時,就會創建一個容器。容器是輕量級、可移植、自給自足的,并且與其他容器和宿主機隔離。
-
生命周期:容器擁有自己的生命周期,可以啟動、停止、暫停、重啟和刪除。
-
讀寫層:容器在運行時會在鏡像的頂層添加一個可寫的讀寫層。所有對容器內文件系統的修改都會記錄在這個讀寫層上,而不會修改底層鏡像。這也是容器可以被刪除而不會影響鏡像的原因。
Dockerfile:
-
定義:Dockerfile 是一個文本文件,包含了構建 Docker 鏡像所需的所有指令。它是一種自動化構建鏡像的方式。
-
作用:通過編寫 Dockerfile,開發者可以清晰地定義應用程序的環境、依賴和啟動方式,從而實現鏡像構建的自動化、可重復和版本化。
Docker Engine:
-
定義:Docker Engine 是 Docker 平臺的核心組件,負責構建和運行容器。它是一個客戶端-服務器 (Client-Server) 架構的應用程序。
-
組成:
Docker Daemon (守護進程):運行在宿主機上的后臺服務,負責管理 Docker 對象(鏡像、容器、網絡、數據卷)。
Docker CLI (命令行接口):用戶與 Docker Daemon 交互的工具,通過命令行發送指令給 Daemon。
REST API:Docker Daemon 提供 REST API 接口,允許其他程序或工具與 Docker 進行交互。
二:Docker安裝
注意:
-
Docker 容器技術最初就是為 Linux 設計的,因此在 Linux 系統上運行 Docker 具有最高的原生性能和最少的抽象層。這意味著容器的啟動速度更快,資源占用更少,效率更高。
-
由于 Docker 容器的核心技術依賴于 Linux 內核特性,Windows 上的 Docker(Docker Desktop)并不是直接在 Windows 內核上運行 Linux 容器。它主要通過WSL 2(Windows Subsystem for Linux 2) 實現的
下文以Linux安裝為例,Windows可自行查閱
?# 下載安裝腳本curl -fsSL https://get.docker.com -o install-docker.sh?# 執行腳本sudo sh install-docker.sh?# 驗證是否安裝成功docker --versiondocker run hello-world
以上執行時如果本地沒有hello-word鏡像就會先pull鏡像,然后再運行。
然后安裝docker desktop或者安裝portainer管理docker資源,以portainer為例
?# 拉取docker pull portainer/portainer-ce:latest# 或docker pull registry.cn-hangzhou.aliyuncs.com/portainer/portainer-ce:latest?# Portainer數據目錄mkdir -p /opt/portainer/data?# 運行 Portainer(綁定 9000 端口)docker run -d \--name portainer \-p 9000:9000 \-v /var/run/docker.sock:/var/run/docker.sock \-v /opt/portainer/data:/data \--restart=always \portainer/portainer-ce:latest?# 訪問http://IP:9000
三:使用Docker
(1)鏡像
A:拉取鏡像
docker pull密令用來從倉庫下載鏡像。一個鏡像下載命令后面有4部分內容。
docker pull docker.io/library/nginx:latest
docker.io這部分是docker倉庫的注冊表地址,docker.io表示這是docker hub的官方倉庫。如果使用官方倉庫可以省略這部分。library是命名空間,公共倉庫每個人可以上傳自己的鏡像,上傳下載鏡像時需要加上作者名,也就是命名空間namespace,library命名空間是官方命名空間,由官方管理。如果一個鏡像屬于官方管理的,那么這部分也可以省略。latest是鏡像的標簽名(版本),用于區分不同版本。
省略不寫時表示最新版本。所以這條命令可以縮寫成:
docker pull nginx
docker官方倉庫地址:https://hub.docker.com/
想要什么鏡像可以搜索一下。docker official images代表官方維護鏡像,點開可以看到好多版本,也可以看到使用說明。這個網站不需要登錄就可以使用。
docker pull docker.io/library/nginx:latest
docker.io/library/nginx 這些部分組合起來就是一個repository,也就是一個鏡像庫,一個鏡像庫存放著一個鏡像的不同版本。
國內某些原因無法正常訪問,可以使用鏡像站。
?# 編輯配置文件sudo vi /etc/docker/daemon.json?# 輸入源{"registry-mirrors": ["https://docker.m.daocloud.io","https://docker.1panel.live","https://hub.rat.dev"]}?# 重啟dockersudo service docker restart
docker pull
:當你在本地需要使用一個 Docker 鏡像來創建容器時,如果本地沒有這個鏡像,Docker 會自動嘗試拉取。但你也可以提前使用該命令手動下載鏡像,以便后續使用
基本語法:
?docker pull [OPTIONS] NAME[:TAG|@DIGEST]
-
NAME
: 鏡像的名稱。通常包含注冊表地址(默認為docker.io/library/
,即 Docker Hub 的官方鏡像)、用戶名/組織名(對于非官方鏡像)和倉庫名。例如,ubuntu
(等同于docker.io/library/ubuntu
-
TAG
(可選): 鏡像的標簽,通常代表鏡像的版本。如果未指定,默認會拉取latest
標簽的鏡像。ubuntu:22.04
(拉取 Ubuntu 22.04 版本) -
DIGEST
(可選): 鏡像的 SHA256 摘要。通過摘要拉取可以確保你拉取到的是一個精確的、不可變的鏡像版本,這對于確保環境一致性非常有用。ubuntu@sha256:12345abcdef...
(拉取指定摘要的 Ubuntu 鏡像)
常用選項:
-
-a
,--all-tags
: 下載指定倉庫中的所有標簽的鏡像。如果你想下載一個鏡像倉庫(Repository)下的所有版本,這個選項非常有用。例如docker pull --all-tags alpine
-
--disable-content-trust
: 跳過鏡像的簽名驗證。默認情況下,Docker 會進行內容信任驗證,以確保下載的鏡像沒有被篡改。但在某些情況下,你可能需要禁用此驗證(請注意潛在的安全風險)。 -
--platform
: 設置平臺。當鏡像支持多種架構時(例如amd64
、arm64
),你可以指定拉取特定架構的鏡像。例如docker pull --platform=arm64 ubuntu
-
-q
,--quiet
: 靜默模式。只顯示鏡像 ID,不顯示詳細的拉取過程信息。
使用示例:
?# 拉取最新版 Ubuntu 鏡像(默認 latest 標簽)docker pull ubuntu?# 拉取特定版本的 Nginx 鏡像docker pull nginx:1.23.0?# 從非默認注冊表拉取鏡像docker pull my.private.registry.com/myimage:v1.0?# 拉取某個倉庫的所有標簽鏡像docker pull --all-tags busybox
B:關于鏡像的其他命令
推薦在portainer管理
相關命令介紹如下
?# 查看鏡像docker images # 查看所有鏡像docker images -q # 只顯示鏡像id?# 構建鏡像(后面介紹)docker build -t my-app:latest . # 需要有Dockerfile?# 標記鏡像docker tag my-app:latest username/my-app:v1.0?# 刪除鏡像docker rmi my-app:latest?# 推送鏡像(后面介紹,需登錄)docker push username/my-app:v1.0?# 離線保存和加載鏡像docker save -o my-app.tar my-app:latest # 保存鏡像到文件docker load -i my-app.tar # 手動加載鏡像?# 查看鏡像詳細信息docker inspect my-app:latest
(2)容器
A:從鏡像構建容器
docker run
:它的主要作用是從一個 Docker 鏡像創建并啟動一個新的容器
基本語法:
?docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
-
IMAGE
: 你想用來創建容器的 Docker 鏡像的名稱或 ID。如果本地沒有這個鏡像,Docker 會首先嘗試從鏡像倉庫(如 Docker Hub)拉取 (pull
) 它。 -
COMMAND
(可選): 在容器內部要執行的命令。如果省略,Docker 會使用鏡像在 Dockerfile 中定義的默認命令。 -
ARG...
(可選): 傳遞給COMMAND
的參數。
常用選項:
docker run
有非常多的選項來控制容器的行為。這里列舉一些最常用且重要的:
-
-d
,--detach
:在后臺(分離)模式運行容器。容器會啟動,然后 Docker 會打印出容器 ID 并退出,讓你能繼續使用終端。這對于運行長時間運行的服務至關重要。-
示例:
docker run -d nginx
(在后臺啟動一個 Nginx Web 服務器)。
-
-
-p
,--publish host_port:container_port
:將容器的端口發布到宿主機。這會將你宿主機上的一個端口映射到容器內部的一個端口,從而使容器中的服務可以通過宿主機訪問。-
示例:
docker run -p 8080:80 nginx
(將宿主機 8080 端口映射到容器 80 端口,這樣你就可以通過http://localhost:8080
訪問 Nginx)。
-
-
-it
:交互式和偽終端。這是兩個選項的組合:-
-i
,--interactive
: 即使沒有附加到容器,也保持 STDIN 開放。對于需要用戶輸入的交互式進程至關重要。 -
-t
,--tty
: 分配一個偽終端。這能讓你在容器內部獲得一個命令行界面。 -
示例:
docker run -it ubuntu bash
(啟動一個 Ubuntu 容器并進入其 Bash shell)。
-
-
--name NAME
:為容器指定一個特定的名稱。如果你不指定名稱,Docker 會生成一個隨機名稱。使用名稱可以方便地后續引用容器。例如:?docker stop NAMEdocker logs NAME
-
示例:
docker run --name my-web-server -p 8080:80 nginx
-
-
-v
,--volume host_path:container_path
:將宿主機上的路徑(目錄或文件)掛載到容器內部。這對于數據持久化(數據在容器刪除后仍然保留)和輕松地向容器提供配置或應用程序代碼至關重要。
-
示例:
docker run -v /my/app/data:/var/lib/mysql mysql
(將本地目錄掛載到 MySQL 容器中用于數據存儲)。
-
有2種掛在卷的方式,第二種 創建存儲空間的方式是在docker里命名卷,第二部可以直接使用卷名掛載。
-
在宿主機的路徑可以使用以上命令查看。命名卷的一個特別功能是第一次使用時,docker會把容器的文件夾同步到命名卷進行初始化。
命令可以查看所有創建過的命名卷。
docker volume rm nginx_html可以刪除命名卷。docker volume prune -a 刪除所有沒有任何容器在使用的卷。
-
--env KEY=VALUE
,-e KEY=VALUE
:在容器內部設置環境變量。這對于向應用程序傳遞配置值非常有用。傳遞mongodb的用戶名和密碼
-
示例:
docker run -e MY_ENV_VAR=hello my-app
-
-
--rm
:容器退出時自動刪除容器。這對于臨時容器或批處理任務非常有用,可以防止你的系統積累大量已退出的容器。-
示例:
docker run --rm ubuntu bash -c "echo Hello World"
-
-
--network NAME
:將容器連接到特定的 Docker 網絡。這使得同一網絡中的容器可以通過名稱相互通信。-
示例:
docker run --network my-app-network my-app
-
使用示例: 我們希望 Nginx 在后臺運行,并且能通過宿主機的 80
端口訪問到容器內部的 80
端口(Nginx 默認監聽 80 端口)。
首先準備宿主機目錄和文件
?# 創建 Nginx 配置和網頁內容的根目錄mkdir -p ~/nginx-data/conf.dmkdir -p ~/nginx-data/html?# 創建自定義的 Nginx 配置文件# 注意:確保文件名為 default.conf,因為 Nginx 通常會加載這個目錄下的 .conf 文件cat <<EOF > ~/nginx-data/conf.d/default.confserver {listen ? ? ? 80;server_name localhost;?location / {root ? /usr/share/nginx/html; # 這是容器內部的路徑index index.html index.htm;}}EOF# 創建自定義的網頁內容cat <<EOF > ~/nginx-data/html/index.html<!DOCTYPE html><html><head><title>我的自定義Nginx頁面</title><style>body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; background-color: #f0f0f0; }h1 { color: #333; }p { color: #666; }</style></head><body><h1>歡迎來到我的Docker Nginx!</h1><p>這個頁面來自宿主機的自定義文件。</p></body></html>EOF
運行命令
?docker run -d \-p 80:80 \--name my-custom-nginx \-v ~/nginx-data/html:/usr/share/nginx/html \-v ~/nginx-data/conf.d:/etc/nginx/conf.d \--restart always \nginx:1.23.0
解釋
-
docker run
: 啟動一個新的 Docker 容器。 -
-d
: 讓容器在后臺運行。這樣它就不會霸占你的終端。 -
-p 80:80
: 將宿主機的 80 端口映射到容器的 80 端口。這樣你就能通過http://localhost
訪問到 Nginx 服務。 -
--name my-custom-nginx
: 給容器起一個易于識別的名字,方便后續管理(如docker stop my-custom-nginx
)。 -
-v ~/nginx-data/html:/usr/share/nginx/html
: 這是第一個卷掛載。它將你宿主機家目錄下的nginx-data/html
文件夾,映射到容器內部 Nginx 默認的網頁文件目錄。這意味著你可以把你的 HTML 文件放在宿主機的~/nginx-data/html
里,容器會自動使用它。 -
-v ~/nginx-data/conf.d:/etc/nginx/conf.d
: 這是第二個卷掛載。它將你宿主機家目錄下的nginx-data/conf.d
文件夾,映射到容器內部 Nginx 加載額外配置文件的目錄。這樣你可以在宿主機編輯 Nginx 的配置文件。 -
--restart always
: 設置重啟策略。容器退出或 Docker 服務重啟時,Docker 會自動嘗試重新啟動這個容器。這在生產環境中非常有用。 -
nginx:1.23.0
: 使用上面步驟中拉取的鏡像
查看運行中的容器
驗證服務(編碼問題)
停止與刪除容器(可選)
-
即使你刪除了容器,你宿主機上的
~/nginx-data
目錄及其內容(你的自定義配置和網頁文件)仍然會保留,下次你可以用相同的命令再次啟動一個 Nginx 容器,它會加載你之前的數據。
?# 停止容器docker stop my-custom-nginx?# 刪除容器docker rm my-custom-nginx?# 刪除正在運行中的容器(強制刪除)docker rm -f my-custom-nginx
B:Docker掛載卷
之前使用的方式掛載方式為綁定掛載。實際上,Docker 還提供了一種更抽象、更易管理的持久化數據方式,那就是 Docker 卷 (Docker Volume)
Docker卷:Docker 卷是 Docker 管理的數據存儲區域。它不直接暴露在宿主機文件系統的某個特定路徑下(盡管它最終還是存儲在宿主機上),而是由 Docker 引擎來創建、管理和維護。
?# 創建一個名為 `nginx_html_data` 的卷,用于存放 Nginx 的網頁文件docker volume create nginx_html_data docker volume create nginx_conf_data?# 查看掛載卷docker volume ls?# 使用掛載卷docker run -d \-p 80:80 \--name my-nginx-with-volume \-v nginx_html_data:/usr/share/nginx/html \ ?# 使用命名卷掛載網頁內容-v nginx_conf_data:/etc/nginx/conf.d \ ? ? # 使用命名卷掛載配置--restart always \nginx:latest
注意:當一個空卷掛載到一個非空目錄的容器時,容器目錄中的內容會被復制到卷中。這意味著,如果你第一次運行 Nginx 容器時,/usr/share/nginx/html
目錄里有默認的 Nginx 歡迎頁面,這些頁面就會被復制到 nginx_html_data
卷中。之后,你對卷的修改都會持久化。
另外,在portainer中也可以管理這部分內容
C:其他參數介紹
--it
:用于進行容器內部進行調試。這里的 -i
是指保持 STDIN 打開,即使沒有附加到容器,-t
是指分配一個偽終端。
?docker run -it --rm ubuntu:latest bash
-
-it
: 讓你能夠進入容器的命令行界面。 -
--rm
: 這個參數非常有用!它表示容器退出時自動刪除容器。這對于這種一次性交互式任務非常方便,避免留下大量已退出的容器。 -
bash
: 這是在容器啟動后要執行的命令。它會打開一個 Bash Shell。
--memory
、--cpus
:生產環境中,為容器分配合適的資源非常重要,可以防止單個容器耗盡宿主機資源或相互影響。
-
--memory [SIZE]
: 限制容器可以使用的內存大小。支持的單位有b
,k
,m
,g
。 -
--cpus [COUNT]
: 限制容器可以使用的 CPU 核心數(或核心的份額)。
?docker run -d \--name limited-nginx \-p 8080:80 \--memory 512m \ # 容器最多只能使用 512 兆字節的內存。--cpus 0.5 \ # 容器最多只能使用 0.5 個 CPU 核心(即一個核心的一半計算能力)。nginx:latest
--env
:注入環境變量,環境變量是向容器內的應用程序傳遞配置信息的一種非常常用和靈活的方式。-e KEY=VALUE
, --env KEY=VALUE
: 設置容器內的環境變量。
假設你有一個 Node.js 應用程序,它根據 NODE_ENV
環境變量來決定是開發模式還是生產模式。
?docker run --rm -e NODE_ENV=production my-nodejs-app:latest
--network
:將容器連接到特定的 Docker 網絡。這使得同一網絡中的容器可以通過名稱相互通信。
-
--network host
: 容器直接使用宿主機的網絡棧,不進行網絡隔離。容器會共享宿主機的 IP 地址和端口空間。這在某些高性能場景下有用,但會犧牲隔離性。
?docker run --network my-app-network my-app
--rm
:適用于臨時運行、測試或一次性任務的容器。容器退出時自動刪除
例如,運行一個完成任務后自動清理的容器
?docker run --rm alpine:latest echo "This container will be gone after printing this message!"
D:其他關于容器的命令
?# 查看運行中或所有容器docker ps?#查看所有容器,包括已經停止的容器docker ps -a?# 停止容器docker stop [容器名或容器ID]?# 開啟容器docker start [容器名或容器ID]?# 重啟容器docker restart [容器名或容器ID]?# 查看容器詳細信息docker inspect [容器名或容器ID]?# 創建容器但不運行docker create [容器名或容器ID] # 和docker run參數差不多?
每創建一個容器會自動生成一個id,接下來image表示從哪個鏡像生成的容器,names是容器的名字,可以指定,不指定會自動生成一個。
--restart,用來配置容器在停止時的重啟策略。always,只要停止了就會立即重啟。unless-stopped,手動停止的容器不會嘗試重啟。
docker run命令是從鏡像創建并且運行容器,也就意味著每一次執行docker run都會創建一個全新的容器。
docker inspect <容器ID>
是一個用于查看 Docker 容器詳細信息的命令。它會返回關于容器的配置、網絡設置、掛載卷、狀態等全面的元數據,格式為 JSON。
使用示例:
?# 查看指定ID的容器詳情docker inspect abc123456?# 只查看容器的IP地址(通過--format過濾)docker inspect --format '{{ .NetworkSettings.IPAddress }}' abc123456?# 查看容器的掛載信息docker inspect --format '{{ .Mounts }}' abc123456
docker create 命令之創建容器,不啟動。
docker logs命令可以查看容器的日志。
(3)隔離技術原理
Dokcer利用了linux內核的兩大原生功能實現容器化。cgroups用來限制和隔離進程的資源使用,可以為每個容器設置CPU、內存、網絡帶寬等資源上限。namespaces用來隔離進程的資源視圖,使容器只能看到自己內部的進程ID、網絡資源和文件目錄。
容器本質上還是一個特殊的進程,當我們進入到容器內部,看起來就像一個獨立的操作系統。
在容器內執行一條命令。
進入交互模式在容器內執行命令。
可以在容器內安裝命令。
(4)Dockerfile
A:介紹
Dockerfile 是一個文本文件,其中包含了一系列命令和指令,Docker 引擎可以讀取這些指令并自動構建 Docker 鏡像。其核心作用如下
-
自動化構建: 無需手動一步步操作,只要有 Dockerfile,Docker 就能自動重復構建出完全相同的鏡像。
-
版本控制: Dockerfile 本身是文本文件,可以像代碼一樣進行版本控制(例如,使用 Git),方便追蹤鏡像的變更歷史。
-
可移植性: Dockerfile 定義了鏡像的構建過程,確保了在不同環境中構建出一致的鏡像。
-
透明性: 任何查看 Dockerfile 的人都能清楚地知道鏡像中包含了什么,以及它是如何構建的。
B:常用指令
Dockerfile 由一行行指令組成,每條指令都構建鏡像的一“層”(layer)。當 Dockerfile 中的指令執行完畢后,所有這些層組合起來就形成了一個完整的 Docker 鏡像。
FROM(基礎鏡像): 指定基礎鏡像,你的新鏡像將基于它來構建。這是 Dockerfile 的第一個非注釋指令。
?FROM <image>[:<tag>]
例如
?FROM ubuntu:22.04 ?# 基于 Ubuntu 22.04 構建FROM alpine:latest # 基于輕量級的 Alpine Linux 構建
RUN(執行命令): 在鏡像構建過程中執行命令行命令。每個 RUN
指令都會在鏡像中創建一個新層。
?RUN <command>或RUN ["executable", "param1", "param2"]
例如
?RUN apt-get update && apt-get install -y \nginx \curl \&& rm -rf /var/lib/apt/lists/* # 更新并安裝 Nginx 和 curl,然后清理 APT 緩存
COPY(復制文件/目錄): 從構建上下文(通常是 Dockerfile 所在的目錄)復制文件或目錄到鏡像中。
?COPY <src>... <dest>
例如
?COPY . /app ? ? ?# 將構建上下文中的所有文件和目錄復制到鏡像的 /app 目錄COPY myapp.conf /etc/nginx/conf.d/ # 復制單個配置文件
ADD(復制文件/目錄,并支持 URL 和解壓): 類似于 COPY
,但功能更強大。src
可以是一個 URL,Docker 會自動下載文件。如果 src
是一個壓縮文件(tar, gzip, bzip2 等),并且 dest
是一個目錄,ADD
會自動解壓。
-
盡管
ADD
功能多,但通常推薦使用COPY
,因為它的行為更可預測,不易出錯。只有在需要自動解壓或從 URL 下載時才考慮ADD
。
?ADD <src>... <dest>
例如
?ADD https://example.com/latest.tar.gz /app/ # 下載并解壓ADD myapp.tar.gz /app/ # 解壓本地壓縮包
WROKDIR(設置工作目錄): 后續的 RUN
, CMD
, ENTRYPOINT
命令設置工作目錄。如果該目錄不存在,WORKDIR
會自動創建它。
?WORKDIR /path/to/workdir
例如
?WORKDIR /app # 將 /app 設為工作目錄,后續命令都在 /app 下執行RUN npm install
EXPOSE(聲明暴露端口): 聲明容器運行時會監聽的端口。這只是一個文檔化的聲明,并不會自動發布端口。實際的端口映射需要在 docker run
命令中使用 -p
參數。
?EXPOSE <port> [<port>/<protocol>...]
例如
?EXPOSE 80 # 聲明容器的 80 端口將會被監聽EXPOSE 80/tcp 443/tcp # 同時聲明 TCP 的 80 和 443 端口
ENV(設置環境變量): 這些變量會在鏡像構建過程中以及容器運行時對所有后續指令和應用程序生效。
?ENV <key> <value>或ENV <key>=<value> ...
例如
?ENV NODE_ENV production # 設置一個環境變量ENV PORT 8080
CMD(容器啟動時默認執行命令): 指定容器啟動時將要執行的默認命令。一個 Dockerfile 中只能有一個 CMD
指令,如果有多條,只有最后一條會生效。
-
注意:如果在
docker run
命令中指定了命令,CMD
的指令會被覆蓋。
?CMD command param1 param2或CMD ["executable", "param1", "param2"]
例如
?CMD ["nginx", "-g", "daemon off;"] # 容器啟動時運行 NginxCMD ["node", "app.js"] ? ? ? ? ? ? # 容器啟動時運行 Node.js 應用
ENTRYPOINT (容器啟動時執行的入口點): 供一個容器的入口點。ENTRYPOINT
后的命令不會被 docker run
命令行中的命令覆蓋,而是將 docker run
命令中的參數作為自身的參數。常用于構建可執行的應用程序鏡像,或者將容器作為一個命令來使用。
?ENTRYPOINT ["executable", "param1", "param2"]
需要注意CMD 與 ENTRYPOINT 的組合使用
-
如果同時存在,
CMD
的內容會作為ENTRYPOINT
的默認參數。 -
這使得鏡像既有一個固定的執行入口,又可以通過
docker run
提供靈活的參數。
例如
?ENTRYPOINT ["/usr/bin/super_app"]CMD ["--help"] # 默認執行 /usr/bin/super_app --help?# 當運行 docker run my_image --version 時,實際執行的是 /usr/bin/super_app --version
ARG(構建參數): 定義在鏡像構建時可以傳遞的變量。這些變量只在構建過程中可用,不會保留在最終的鏡像中作為環境變量(除非你用 ENV
指令將其顯式地設為環境變量)。在 docker build
命令中使用 --build-arg
來設置其值
?ARG <name>[=<default value>]
例如
?ARG APP_VERSION=1.0.0 # 定義一個構建參數,并設置默認值RUN echo "Building version $APP_VERSION"?# 構建時可以這樣傳遞參數:# docker build --build-arg APP_VERSION=2.0.0 -t myapp .
C:構建
**創建一個簡單的 Dockerfile 來構建一個包含自定義網頁內容的 Nginx 鏡像
?# 1. 指定基礎鏡像:使用官方 Nginx 鏡像的最新穩定版本FROM nginx:stable-alpine?# 2. 設置作者信息 (可選,但推薦)LABEL maintainer="Your Name <your.email@example.com>"?# 3. 將宿主機上的自定義 HTML 文件復制到 Nginx 容器的默認網頁目錄# 假設在 Dockerfile 同級目錄下有一個名為 'html' 的文件夾,里面放著你的 index.html 等文件COPY html/ /usr/share/nginx/html/?# 4. (可選)如果你有自定義的 Nginx 配置文件,也可以復制進去# 假設在 Dockerfile 同級目錄下有一個名為 'config' 的文件夾,里面放著你的 default.conf 文件# COPY config/default.conf /etc/nginx/conf.d/default.conf?# 5. 聲明容器會監聽的端口 (最佳實踐,不實際發布端口)EXPOSE 80?# 6. 設置容器啟動時執行的命令 (Nginx 鏡像通常自帶,這里只是示例)# CMD ["nginx", "-g", "daemon off;"]
構建過程
-
將上述 Dockerfile 內容保存為名為
Dockerfile
的文件。 -
在
Dockerfile
同級目錄下創建一個html
文件夾,并在其中放入你的index.html
文件。 -
打開終端,進入
Dockerfile
所在的目錄。 -
執行構建命令:
-
-t my-custom-nginx-image:1.0
: 為構建的鏡像指定名稱和標簽。 -
.
: 表示 Dockerfile 和構建上下文在當前目錄。
-
?docker build -t my-custom-nginx-image:1.0 .
D:推送
1:登錄Docker鏡像倉庫。如果你要推送到 Docker Hub,就登錄 Docker Hub;如果你要推送到私有倉庫,就登錄你的私有倉庫。
?# 輸入后登錄Docker Hubdocker login ?# 推送私有倉庫docker login your.private.registry.com
2:Docker 鏡像的標簽 (tag) 非常重要,它決定了鏡像推送時會去哪個倉庫,以及在倉庫中的名稱和版本。一個完整的鏡像標簽通常包含 [倉庫地址/][用戶名或組織名/]鏡像名稱[:標簽]
-
倉庫地址/
(可選):如果你要推送到 Docker Hub 的個人倉庫,通常可以省略。但如果推送到私有倉庫或 Docker Hub 的組織倉庫,就需要包含。 -
用戶名或組織名/
(必需):對于推送到 Docker Hub 上的個人或組織倉庫,這是必需的,它決定了鏡像歸屬于誰。 -
鏡像名稱
:鏡像的名稱。 -
:
:分隔符。 -
標簽
:通常是版本號(例如1.0
,latest
,dev
)。
使用 docker tag
打標簽,語法如下
?docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
例如
?docker tag my-custom-nginx-image:1.0 yourusername/my-custom-nginx-image:v1.0
3:使用 docker push
推送鏡像
?docker push NAME[:TAG]
例如
?docker push yourusername/my-custom-nginx-image:v1.0
(5)Docker網絡
A:介紹
Docker 通過網絡驅動來實現不同的網絡功能。當你運行一個容器時,如果沒有明確指定網絡,它通常會連接到 Docker 默認創建的某個網絡。
-
網絡隔離:每個 Docker 容器都擁有自己的獨立網絡棧,包括 IP 地址、網絡接口、路由表等。這意味著容器在網絡層面是相互隔離的,除非你明確地將它們連接起來或進行端口映射。
-
DOS服務發現:在同一個 Docker 網絡中的容器,可以通過容器名或服務名進行相互通信,而不是必須使用 IP 地址。Docker 內置了 DNS 服務,可以自動解析這些名稱到對應的 IP 地址。這極大地簡化了多容器應用的配置。
B:網絡類型
bridge
(橋接網絡 - 默認和最常用): 當你安裝 Docker 時,它會默認創建一個名為 bridge
(或 docker0
)的虛擬網橋。所有未指定網絡的容器默認都會連接到這個橋接網絡。每個連接到橋接網絡的容器都會獲得一個私有 IP 地址,它們可以相互通信。
容器可以通過端口映射 (-p
參數) 將其內部端口暴露給宿主機。宿主機以及外部網絡可以通過宿主機的 IP 地址和映射的端口訪問容器內的服務。
自定義 bridge
網絡 (推薦): 雖然 Docker 有一個默認的 bridge
網絡,但強烈建議你創建自己的自定義橋接網絡。這是因為
-
更好的隔離: 將你的應用程序容器放在一個獨立的網絡中,與默認網絡中的其他無關容器隔離。
-
自動 DNS 服務發現(非常好用): 在自定義橋接網絡中,容器可以通過容器名稱互相解析和通信。這是默認橋接網絡不具備的功能(需要使用
--link
,但--link
已被棄用)。 -
更易管理: 清晰地組織你的容器網絡。
命令如下
?# 新建docker network create my-app-network?# 刪除docker network rm my-app-network
使用方法如下
-
在
web
容器可以直接通過db
這個名字訪問到db
容器,反之亦然。
?docker run -d --name web --network my-app-network -p 80:80 my-web-imagedocker run -d --name db --network my-app-network my-db-image
host模式: 容器直接使用宿主機的網絡棧,不進行任何網絡隔離。容器將共享宿主機的 IP 地址和端口空間。這種方式對網絡性能有極高要求,且容器隔離性不那么重要的特殊場景,例如一些網絡監控工具或高性能代理。
-
優點:提供了最好的網絡性能,因為沒有額外的網絡虛擬化層。
-
缺點:
-
安全性低: 容器不再與宿主機網絡隔離,可能帶來安全風險。
-
端口沖突: 如果宿主機上已經有服務使用了某個端口,容器就不能再使用相同的端口。
-
使用方法如下
-
此時,如果
my-app-image
在容器內部監聽 8000 端口,那么你直接訪問宿主機的 8000 端口就能訪問到它。
?docker run -d --name my-app-host-mode --network host my-app-image
none(無網絡): 容器內部沒有網絡接口,除了 localhost
。當你不需要容器有任何網絡連接時,或者你想完全手動配置容器網絡時可以使用它,通常用于安全性極高或特殊測試的場景。
使用方法如下
-
進入容器后,你無法
ping
任何外部地址,也無法訪問互聯網。
?docker run -it --network none ubuntu bash
(6)docker compose
Docker Compose 是一個用于定義和運行多容器 Docker 應用程序的工具。簡單來說,如果你需要同時運行多個相互關聯的 Docker 容器(比如一個 Web 服務器、一個應用服務器和一個數據庫),那么 Docker Compose 就能派上用場了。它讓你能用一個 YAML 文件來配置你的應用服務,然后通過一個命令來啟動、停止和管理所有這些服務
注意:從 Docker Engine v20.10.0 開始,Docker 官方提供了 docker compose
(注意沒有 -
短橫線)作為 CLI 插件,直接集成在 Docker 里,無需額外安裝
A:介紹
docker-compose.yaml文件: 這是 Docker Compose 的核心。它是一個 YAML 格式的配置文件,用于定義應用程序的服務、網絡和數據卷。在該文件中
-
services
(服務):應用程序的各個組件,例如web
、app
、db
等。每個服務都對應一個 Docker 容器。你可以指定每個服務使用的鏡像、構建方式、端口映射、數據卷、環境變量等。 -
networks
(網絡):定義容器之間用于通信的自定義網絡。Compose 會為你的應用創建一個默認網絡,但你也可以定義自己的網絡以便更好地隔離或組織服務。 -
volumes
(數據卷):定義用于持久化數據的命名卷。
命令:
-
啟動所有服務:
docker-compose up
(-d
后臺運行,-f
指定配置文件) -
停止所有服務:
docker-compose down
-
構建服務鏡像:
docker-compose build
-
查看服務狀態:
docker-compose ps
-
查看服務日志:
docker-compose logs
B:案例分析
項目介紹:構建一個PHP-Mysql項目,該項目結構如下
1:編寫文件
docker-compose.yaml
?services:nginx:# 直接使用官方Nginx鏡像,不再需要單獨的 Dockerfile-nginximage: nginx:latestcontainer_name: php-nginxports:- "80:80" # 將宿主機80端口映射到容器80端口volumes:- ./public:/var/www/html # 掛載PHP應用代碼- ./conf/nginx.conf:/etc/nginx/nginx.conf # 掛載自定義 Nginx 配置depends_on:- php # 依賴php服務,確保php-fpm啟動后nginx才啟動networks:- app-network?php:build:context: .dockerfile: Dockerfile-php # 自定義的PHP Dockerfilecontainer_name: php-fpmvolumes:- ./public:/var/www/html # 掛載PHP應用代碼networks:- app-network?mysql:image: mysql:5.7 # 使用官方的 MySQL 5.7 鏡像container_name: php-mysql-dbenvironment:MYSQL_ROOT_PASSWORD: mysecretpassword # 設置root用戶密碼MYSQL_DATABASE: mydatabase ? ? ? ? ? ?# 默認數據庫名稱MYSQL_USER: myuser ? ? ? ? ? ? ? ? ? ?# 默認用戶MYSQL_PASSWORD: mypassword ? ? ? ? ? ?# 默認用戶密碼volumes:- mysql_data:/var/lib/mysql # 掛載數據卷實現MySQL數據持久化networks:- app-network?networks:app-network: # 定義一個bridge網絡,讓所有服務能互相通信driver: bridge?volumes:mysql_data: # 定義一個命名卷用于MySQL數據持久化
Dockerfile-php
(PHP-FPM 容器的 Dockerfile)
?FROM php:7.4-fpm-alpine ?# 安裝 PHP 擴展和常用工具 (使用 Alpine 的 apk 包管理器)# --no-cache 選項可以在安裝后移除apk緩存,進一步減小鏡像大小RUN apk add --no-cache \php-mysqli \ ? ? ?# MySQLi 擴展用于數據庫連接php-pdo_mysql \ ? # PDO MySQL 驅動php-gd \ ? ? ? ? ?# 圖像處理,如果你的應用需要php-mbstring \ ? ?# 多字節字符串支持php-xml \ ? ? ? ? # XML 處理# 如果需要其他工具,比如 git 或常用的調試工具,可以在這里安裝# bash \# git \# nano \&& rm -rf /var/cache/apk/* # 清理 apk 緩存?# 配置 PHP-FPM 用戶和組,與 Nginx 容器內用戶匹配RUN sed -i 's/listen = 127.0.0.1:9000/listen = 9000/' /usr/local/etc/php-fpm.d/www.conf \&& sed -i 's/;listen.owner = nobody/listen.owner = www-data/' /usr/local/etc/php-fpm.d/www.conf \&& sed -i 's/;listen.group = nobody/listen.group = www-data/' /usr/local/etc/php-fpm.d/www.conf?# 暴露 PHP-FPM 端口 (Docker Compose 內部通信會用到)EXPOSE 9003?# 定義工作目錄WORKDIR /var/www/html?# 容器啟動時運行的命令 (php-fpm 鏡像通常已內置,如果需要自定義行為再寫)CMD ["php-fpm", "-F"]
conf/nginx.conf
?# conf/nginx.confuser www-data; # 確保與 PHP-FPM 容器中 user = www-data 匹配worker_processes ?1;?error_log /var/log/nginx/error.log warn;pid ? ? ? /var/run/nginx.pid;?events {worker_connections ?1024;}?http {include ? ? ? /etc/nginx/mime.types;default_type application/octet-stream;?log_format main ?'$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';?access_log /var/log/nginx/access.log main;?sendfile ? ? ? on;#tcp_nopush ? ? on;?keepalive_timeout ?65;?#gzip on;?server {listen ? ? ? 80;server_name localhost;root ? /var/www/html; # Nginx 默認的網頁文件根目錄?# 配置 PHP-FPMlocation ~ \.php$ {try_files $uri =404; # 如果PHP文件不存在,返回404fastcgi_pass ? php:9003; # 關鍵:通過php服務名和9003端口連接php-fpmfastcgi_index index.php;fastcgi_param SCRIPT_FILENAME ?$document_root$fastcgi_script_name;include ? ? ? fastcgi_params;}?# 任何非 PHP 文件直接提供服務location / {try_files $uri $uri/ /index.php?$query_string;}?error_page ? 500 502 503 504 /50x.html;location = /50x.html {root ? /usr/share/nginx/html;}}}
public/index.php
(PHP 應用程序入口文件)
?<?php// public/index.php?echo "<h1>Welcome to PHP in Docker!</h1>";echo "<p>PHP Version: " . phpversion() . "</p>";?// 數據庫連接配置$servername = "mysql"; // 在 Docker Compose 網絡中,服務名即為主機名$username = getenv('MYSQL_USER') ?: "myuser"; // 從環境變量獲取,或使用默認值$password = getenv('MYSQL_PASSWORD') ?: "mypassword";$dbname = getenv('MYSQL_DATABASE') ?: "mydatabase";?// 創建數據庫連接$conn = new mysqli($servername, $username, $password, $dbname);?// 檢查連接if ($conn->connect_error) {echo "<p style='color: red;'>Database Connection Failed: " . $conn->connect_error . "</p>";} else {echo "<p style='color: green;'>Successfully connected to MySQL database!</p>";?// 嘗試執行一個簡單的查詢$sql = "SELECT 1 as test_col";$result = $conn->query($sql);?if ($result) {$row = $result->fetch_assoc();echo "<p>Test Query Result: " . $row['test_col'] . "</p>";} else {echo "<p style='color: orange;'>Test Query Failed: " . $conn->error . "</p>";}?$conn->close();}??>
2:構建運行
構建
?docker-compose up --build -d
四 :總結
本文是觀看B站UP主技術爬爬蝦的《40分鐘的Docker實戰攻略,一期視頻精通Docker》做的學習筆記。前天看完感覺不過癮,又看一遍,有吧筆記整理了一下。內容涵蓋了Docker的所有常用功能與命令。 主要內容: 1. Docker的核心概念 2. 在Linux, windows 還有Mac電腦上安裝docker 3. 下載鏡像。配置鏡像站解決下載鏡像的網絡問題 4. dokcer run命令創建并且運行容器。 docker run命令的重要參數 5. 進入容器內部進行調試 6. Docker網絡,分別是bridge模式,創建子網,host模式與none模式 7. 輕量級的容器編排技術Docker Compose 8. AI輔助學習Docker。