戰(zhàn)指南)
拿 Docker 快速開始這個(gè)標(biāo)題來說網(wǎng)上教程一抓一大把但大部分都卡在裝完 Docker Desktop 就不知道怎么往下走這個(gè)環(huán)節(jié)。要么是安裝報(bào)錯(cuò)直接把人勸退要么是跑起來之后完全不懂容器和鏡像的關(guān)系遇到 MySQL 起不來、網(wǎng)絡(luò)不通、權(quán)限拒絕這類問題只能干瞪眼。這篇東西我打算換個(gè)寫法直接從新手最常見的真實(shí)場景切入把安裝、踩坑、跑通第一個(gè)容器、部署 MySQL 和 Redis、排查日常故障這幾件事串成一條完整的鏈路命令直接給理由也講清楚。先說清楚一個(gè)容易誤導(dǎo)人的概念Docker 不是虛擬機(jī)。很多第一次接觸的人會以為 Docker 是那種裝一個(gè)操作系統(tǒng)鏡像啟動一個(gè)完整系統(tǒng)的東西這是錯(cuò)的。Docker 里的容器共享宿主機(jī)內(nèi)核只是把進(jìn)程、文件系統(tǒng)、網(wǎng)絡(luò)、環(huán)境變量隔離在各自的命名空間里所以一個(gè)容器往往只有幾十 MB 到幾百 MB啟動時(shí)間以毫秒級計(jì)算同樣一臺機(jī)器能跑的容器數(shù)量和虛擬機(jī)完全不是一個(gè)量級。這也是為什么有人能用 N100 這種低功耗小主機(jī)跑二十個(gè) Docker 容器——每個(gè)容器本身就只是幾個(gè)進(jìn)程而已而不是二十個(gè)操作系統(tǒng)。1.1 容器和虛擬機(jī)的本質(zhì)區(qū)別判斷自己到底有沒有理解容器可以問一個(gè)問題容器里的 Ubuntu 有內(nèi)核嗎答案是沒有。你執(zhí)行uname -r看到的其實(shí)是宿主機(jī)的內(nèi)核版本。容器鏡像里攜帶的是 rootfs根文件系統(tǒng)和用戶態(tài)的程序比如 bash、glibc、MySQL 服務(wù)本身內(nèi)核用的是宿主機(jī)的。這帶來的直接后果是容器天然輕量、啟動快、資源占用低但也意味著容器里不能隨便改內(nèi)核參數(shù)、不能加載內(nèi)核模塊遇到依賴特定內(nèi)核版本的應(yīng)用會比較尷尬。虛擬機(jī)就不一樣每個(gè)虛擬機(jī)都有獨(dú)立的 Guest OS有自己完整的內(nèi)核隔離性更強(qiáng)但啟動要幾十秒到幾分鐘鏡像動輒幾個(gè) GB運(yùn)行時(shí)要預(yù)分配內(nèi)存和 CPU。所以 Docker 適合微服務(wù)、CI/CD、應(yīng)用打包交付VM 適合需要強(qiáng)隔離、跨內(nèi)核的場景。這倆不是替代關(guān)系但在快速開始這個(gè)語境下Docker 確實(shí)是當(dāng)下部署應(yīng)用最主流的姿勢。1.2 Docker 解決的核心痛點(diǎn)結(jié)合熱搜詞里docker是干什么的這個(gè)問題我用一句大白話回答Docker 讓你的應(yīng)用打包一次到處運(yùn)行。以前部署一個(gè) MySQL你得下載安裝包、處理依賴庫、配配置文件、設(shè)系統(tǒng)服務(wù)到了另一臺機(jī)器這套流程要再來一遍。用 Docker 之后鏡像里已經(jīng)把 MySQL 和它需要的一切都打包好了你只需要docker run服務(wù)就起來了。開發(fā)環(huán)境、測試環(huán)境、生產(chǎn)環(huán)境全都用同一個(gè)鏡像杜絕了在我電腦上是好的這種甩鍋現(xiàn)場。另外 Docker 還解決了環(huán)境隔離和快速清理的問題。想裝一個(gè) GitLab、裝一個(gè)青龍面板、跑一個(gè) DVWA 靶場練手直接拉官方鏡像跑起來不用了就docker rm -f刪掉宿主機(jī)干干凈凈不會像傳統(tǒng)安裝方式那樣留下一堆殘留文件。2. 安裝 Docker 之前需要搞明白的三件事安裝本身不難但很多報(bào)錯(cuò)其實(shí)是安裝前的平臺理解出了問題。這里把三個(gè)關(guān)鍵決策點(diǎn)說透能避開后面 80% 的坑。2.1 你的系統(tǒng)平臺決定了走哪條安裝路線Docker 的安裝方式基本分成兩大流派帶圖形界面的 Docker Desktop適合 Windows 和 macOS以及純命令行安裝 Docker Engine適合 Linux 服務(wù)器。Windows 裝 Docker Desktop 需要 WSL2 或 Hyper-V 支持Mac 上有 Apple Silicon 和 Intel 兩種芯片的區(qū)分Linux 又分為 apt/yum/dnf 不同包管理器。選錯(cuò)路線最常見的后果就是裝完了啟動不了然后陷入virtualization support not detected這類報(bào)錯(cuò)循環(huán)。如果你用的是 Ubuntu 或者 CentOS 這類 Linux 服務(wù)器就直接裝 Docker Engine不要裝 Docker Desktop。Docker Engine 就是服務(wù)器上跑的守護(hù)進(jìn)程dockerd加客戶端docker CLI沒有 GUI但對服務(wù)器部署來說完全夠用。Ubuntu 走 aptCentOS 7 走 yumCentOS 8 以上走 dnf。具體命令我放到后面先記住一個(gè)原則服務(wù)器環(huán)境永遠(yuǎn)優(yōu)先 Docker Engine桌面環(huán)境圖省事才選 Docker Desktop。2.2 Windows 用戶繞不開的 WSL2 / Hyper-V 前置Windows 裝 Docker Desktop 的報(bào)錯(cuò)里出現(xiàn)頻率最高的就是 Docker Desktop failed to start because virtualisation support wasnt detected也就是熱搜詞里反復(fù)出現(xiàn)的那條。這不是 Docker 本身的問題而是 Windows 的虛擬化功能沒開全。Docker Desktop 在 Windows 上需要虛擬機(jī)支持來跑 Linux 容器這個(gè)能力來自 WSL2 或者 Hyper-V。排查鏈路應(yīng)該是這樣的第一步打開任務(wù)管理器 - 性能 - CPU看右下角虛擬化是否顯示已啟用。如果顯示已啟用說明 BIOS 層面的虛擬化是開著的如果顯示已禁用需要進(jìn) BIOS 開啟 Intel VT-x 或 AMD SVM。注意Windows 的虛擬化是否啟用除了 BIOS還取決于啟用 Windows 功能里的虛擬機(jī)平臺和 Hyper-V 有沒有勾上。第二步以管理員身份打開 PowerShell執(zhí)行wsl --status查看 WSL 版本如果提示沒有 WSL需要先安裝 WSL2執(zhí)行wsl --install即可。第三步確認(rèn) Windows 功能里適用于 Linux 的 Windows 子系統(tǒng)和虛擬機(jī)平臺這兩項(xiàng)都是勾選狀態(tài)然后用bcdedit /set hypervisorlaunchtype auto確保 Hyper-V 啟動類型是自動。我見過大量案例BIOS 虛擬化開著、WSL 也裝了Docker Desktop 還是啟動失敗最后發(fā)現(xiàn)是虛擬機(jī)平臺這個(gè)功能沒開。這三步必須挨個(gè)排查任何一環(huán)斷了Docker Desktop 都起不來。2.3 Linux 用戶最穩(wěn)的 Docker Engine 安裝路徑Linux 安裝 Docker Engine 的方式里最推薦的是配置官方 apt 源后安裝。以 Ubuntu 為例安裝基礎(chǔ)工具和證書sudo apt-get update sudo apt-get install ca-certificates curl gnupg lsb-release然后添加 Docker 官方 GPG 密鑰和倉庫地址sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null更新索引后直接安裝sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin安裝完成后執(zhí)行sudo systemctl enable docker sudo systemctl start docker再用sudo docker run hello-world驗(yàn)證。為什么不用一條 curl 腳本裝官方那個(gè)get.docker.com的一鍵腳本適合快速實(shí)驗(yàn)但生產(chǎn)環(huán)境我建議手動加源安裝因?yàn)楹罄m(xù)換鏡像源、升級版本時(shí)路徑更清晰也方便排查問題。CentOS 7 的坑主要是默認(rèn)的 yum 源里 Docker 版本太老必須用官方源或阿里云源不然裝出來的可能還是 Docker 1.13。3. Docker Desktop 安裝實(shí)戰(zhàn)與啟動失敗排查Docker Desktop 是 Windows 和 macOS 上最容易上手的方式但也是報(bào)錯(cuò)重災(zāi)區(qū)。這里把完整的安裝流程和兩類高頻啟動失敗問題的排查鏈路寫出來照做就行。3.1 Windows 和 macOS 的安裝步驟詳解Windows 的安裝流程比 Linux 復(fù)雜完整步驟是開啟 Windows 功能控制面板 - 程序 - 啟用或關(guān)閉 Windows 功能勾選適用于 Linux 的 Windows 子系統(tǒng)、虛擬機(jī)平臺、Hyper-V三項(xiàng)其中完整版 Docker Desktop 依賴 Hyper-VWSL2 模式下只依賴前兩項(xiàng)。安裝 WSL2 內(nèi)核執(zhí)行wsl --update更新內(nèi)核然后執(zhí)行wsl --set-default-version 2確保以后創(chuàng)建的發(fā)行版默認(rèn)走 WSL2。從 Docker 官網(wǎng)下載 Docker Desktop Installer.exe雙擊安裝安裝過程中如果提示是否使用 WSL2選“是”。安裝完成后重啟系統(tǒng)啟動 Docker Desktop等右下角鯨魚圖標(biāo)變穩(wěn)定狀態(tài)。macOS 的步驟類似從官網(wǎng)下載 Docker.dmg 拖入 Applications 即可。Apple SiliconM1/M2/M3芯片的 Mac 默認(rèn)走虛擬化框架不需要額外裝虛擬機(jī)軟件Intel 芯片的老 Mac 需要確認(rèn)是否支持 HyperKit不過 Docker Desktop 新版已經(jīng)統(tǒng)一用 Apple 的 Virtualization.framework這點(diǎn)基本不用操心了。注意下 Mac 需要 macOS 11 Big Sur 或更高版本太老的系統(tǒng)裝不上新版的 Docker Desktop。3.2 virtualization support not detected報(bào)錯(cuò)的完整排查鏈路這條報(bào)錯(cuò)幾乎天天有人問完整排查思路按優(yōu)先級排列第一步確認(rèn) BIOS 虛擬化開關(guān)。重啟進(jìn) BIOS找 Intel Virtualization Technology 或 SVM Mode設(shè)為 Enabled。注意有些品牌機(jī)的 BIOS 里這個(gè)選項(xiàng)叫法不同比如 Dell 叫 VirtualizationHP 叫 Virtualization Technology聯(lián)想部分機(jī)型要在 Security - Virtualization 里開。第二步確認(rèn) Windows 功能。執(zhí)行systeminfo | findstr Hyper-V如果顯示 Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed. 說明 Hyper-V 已經(jīng)在跑如果顯示 Virtualization Enabled In Firmware: Yes說明固件虛擬化正常但 Hyper-V 組件可能沒裝。這時(shí)去啟用或關(guān)閉 Windows 功能里勾上虛擬機(jī)平臺和Hyper-V。第三步核對 WSL2 狀態(tài)。執(zhí)行wsl -l -v如果版本顯示為 1需要wsl --set-version 發(fā)行版名 2升級。如果提示沒有已安裝的發(fā)行版用wsl --install -d Ubuntu裝一個(gè)。第四步檢查 Docker Desktop 的配置。打開 Settings - General確保勾選了 Use the WSL 2 based engine。如果用的是 Hyper-V 模式在 Settings - Resources - Advanced 里確認(rèn)沒有把內(nèi)存設(shè)置得太低。這套鏈路走完至少能解決 95% 的啟動失敗。剩下的情況多半是 Windows 老版本的問題比如 Win10 的 1903 以下版本對 WSL2 支持不完整建議直接升級系統(tǒng)。3.3 failed to start docker application container engine的原因與處理這條報(bào)錯(cuò)常見于 Linux 上 Docker 服務(wù)啟動失敗以及在 Windows 上 Docker Desktop 已經(jīng)能打開但內(nèi)部引擎沒跑起來。Linux 下先執(zhí)行sudo systemctl status docker看具體失敗原因。最常見的是配置了鏡像加速器地址但寫錯(cuò)了格式或者/etc/docker/daemon.json文件里的 JSON 語法錯(cuò)誤導(dǎo)致 dockerd 啟動崩掉。排查方法是先移走配置文件再啟動sudo mv /etc/docker/daemon.json /etc/docker/daemon.json.bak sudo systemctl start docker如果這樣啟動了說明問題出在 daemon.json。重新編輯時(shí)注意配置格式鏡像加速地址要加上https://前綴多個(gè)地址用數(shù)組。Windows 下的同類問題多數(shù)是退出 Docker Desktop 后重新啟動、徹底重置 WSL 的 Docker 數(shù)據(jù)來解決不要一上來就卸載重裝先試wsl --shutdown再啟動 Docker Desktop成功率很高。4. 第一次跑容器的完整流程從 hello-world 到 Nginx安裝完 Docker接下來的流程才是快速開始的意義所在。這一節(jié)帶你走一遍完整的驗(yàn)證環(huán)境 - 拉鏡像 - 跑容器 - 操作容器鏈路。4.1 用 docker info 和 hello-world 驗(yàn)證環(huán)境是否真正可用裝好 Docker 后第一件事不是急著部署應(yīng)用而是確認(rèn)環(huán)境正常。執(zhí)行docker info如果看到Server Version和Storage Driver都正常顯示說明 dockerd 守護(hù)進(jìn)程在跑。如果看到ERROR: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock這是熱搜詞里的另一個(gè)高頻問題說明當(dāng)前用戶不在 docker 用戶組里執(zhí)行sudo usermod -aG docker $USER然后注銷重登或重啟系統(tǒng)。然后跑官方提供的測試鏡像docker run hello-world這個(gè)鏡像很小只有幾 KB作用是打印一段說明文字表示 Docker 端到端工作正常。如果你在服務(wù)器上沒有 sudo 權(quán)限記得所有 docker 命令前加 sudo如果你已經(jīng)加入了 docker 用戶組可以不用 sudo。這里提醒一句能用用戶組解決就不要用 sudo 執(zhí)行 docker 命令sudo 會把文件權(quán)限搞得很難受而且在某些自動化的腳本環(huán)境里容易出現(xiàn)雞生蛋問題。4.2 拉取鏡像和運(yùn)行容器Nginx 實(shí)例拆解hello-world 只是驗(yàn)證真正跑一個(gè)有實(shí)際意義的服務(wù)用 Nginx 最合適。先把鏡像拉到本地docker pull nginx:latestdocker pull的動作是拉鏡像鏡像是什么本質(zhì)上是一層一層的只讀文件系統(tǒng)的集合里面包含了 Nginx 的程序文件、配置文件、依賴庫。拉下來之后本地會有這份鏡像緩存下次docker run直接用本地鏡像不會再去遠(yuǎn)程倉庫拉。然后啟動一個(gè)前臺運(yùn)行用于觀察輸出或者后臺運(yùn)行daemonized的容器docker run -d --name my-nginx -p 8080:80 nginx命令拆解-d表示后臺運(yùn)行--name my-nginx給容器起名-p 8080:80把宿主機(jī)的 8080 端口映射到容器內(nèi)的 80 端口nginx是要運(yùn)行的鏡像名。映射端口的邏輯很多人第一次犯迷糊記住一句話左邊是宿主機(jī)端口右邊是容器內(nèi)端口。瀏覽器訪問http://localhost:8080宿主機(jī)把流量轉(zhuǎn)發(fā)給容器里的 80 端口Nginx 接收之后返回默認(rèn)頁面。驗(yàn)證容器狀態(tài)docker ps如果能看到一個(gè)狀態(tài)為 Up 的 my-nginx 容器說明第一個(gè)真實(shí)服務(wù)已經(jīng)跑起來了。這條命令的意義相當(dāng)于進(jìn)程管理器的 Docker 版列出所有正在運(yùn)行的容器它只顯示運(yùn)行中的容器已經(jīng)停止的用docker ps -a查看。兩者之間的差別是新手最容易忽略的docker ps -a會把停止?fàn)顟B(tài)的容器也列出來排查問題的時(shí)候永遠(yuǎn)先用-a看全貌。4.3 進(jìn)入容器內(nèi)部查看文件系統(tǒng)與日志跑起來之后你需要具備的三種最基本的觀察能力查看容器日志docker logs my-nginx這一步對應(yīng)的是傳統(tǒng)方式下 tail 日志文件的習(xí)慣。docker logs會把容器的 stdout/stderr 全部打出來所以平時(shí)寫應(yīng)用時(shí)記得把日志打到 stdout而不是寫到容器內(nèi)的日志文件里——否則用docker logs看什么都是空的。進(jìn)入容器內(nèi)部docker exec -it my-nginx bashexec表示在運(yùn)行中的容器里執(zhí)行命令-it是分配交互終端bash是要執(zhí)行的 shell。進(jìn)去之后執(zhí)行l(wèi)s /usr/share/nginx/html就能看到 Nginx 默認(rèn)網(wǎng)頁的存放位置。這個(gè)能力對應(yīng)的是傳統(tǒng)方式下 SSH 到服務(wù)器上排查但在容器里你沒有 systemd、沒有 init 進(jìn)程也沒有完整系統(tǒng)工具包很多命令不存在是很正常的事別慌。退出用exit。把宿主機(jī)的文件復(fù)制進(jìn)容器docker cp index.html my-nginx:/usr/share/nginx/html/這個(gè)是臨時(shí)改容器內(nèi)文件的做法但不建議長期依賴。容器的文件系統(tǒng)是臨時(shí)的容器被刪除后一切改動都會消失正確的做法是用數(shù)據(jù)卷volume掛載這部分在后面 MySQL 實(shí)例里具體講。5. 每個(gè)新手都逃不過的兩個(gè)部署實(shí)例MySQL 8.0 與 Redis 主從熱搜詞里docker安裝mysql失敗、docker安裝mysql8.0并使用、docker安裝redis主從占了很大比例說明數(shù)據(jù)庫類應(yīng)用是新手最普遍的實(shí)戰(zhàn)場景。這兩個(gè)實(shí)例跑通你基本就能理解 Docker 在數(shù)據(jù)持久化、端口映射、多容器協(xié)作上的核心用法。5.1 用 MySQL 8.0 理解端口映射和數(shù)據(jù)持久化先看一個(gè)新手最常見的失敗案例。很多人在 Docker 里裝 MySQL 失敗錯(cuò)誤信息是docker: Error response from daemon: driver failed programming external connectivity on endpoint查了半天發(fā)現(xiàn)是端口被占用。宿主機(jī)的 3306 已經(jīng)被本地安裝的 MySQL 占了Docker 再映射 3306 自然沖突。解決辦法很簡單把宿主機(jī)的映射端口換掉docker run -d \ --name mysql8 \ -p 3307:3306 \ -e MYSQL_ROOT_PASSWORDyourpassword \ -e MYSQL_DATABASEtestdb \ -v mysql_data:/var/lib/mysql \ mysql:8.0這里有幾個(gè)關(guān)鍵點(diǎn)要講透第一-e環(huán)境變量是 MySQL 鏡像的配置入口。MYSQL_ROOT_PASSWORD設(shè)置 root 密碼MYSQL_DATABASE在首次啟動時(shí)自動創(chuàng)建數(shù)據(jù)庫。如果忘了設(shè)置 root 密碼容器啟動后你是進(jìn)不去的到時(shí)候又要查一堆初始化方法所以這一步最好在run時(shí)想清楚。第二-v mysql_data:/var/lib/mysql是數(shù)據(jù)卷掛載。mysql_data是命名卷Docker 會把容器里/var/lib/mysql目錄的數(shù)據(jù)存到宿主機(jī)一個(gè)專門管理的目錄下。這樣即使容器被刪除數(shù)據(jù)還在下次用同一個(gè)卷名啟動新容器數(shù)據(jù)自動接上。這一點(diǎn)極其重要容器的文件系統(tǒng)是臨時(shí)的不加數(shù)據(jù)卷rm 掉容器等于刪除數(shù)據(jù)庫。啟動后連接測試docker exec -it mysql8 mysql -uroot -p輸入密碼進(jìn)入 MySQL 命令行后你可以執(zhí)行show databases;看到 testdb 已經(jīng)創(chuàng)建。如果想從宿主機(jī)外部訪問要確認(rèn)宿主機(jī)的 3307 端口能被連接防火墻問題不在這里展開但記住 MySQL 8.0 的默認(rèn)認(rèn)證插件是 caching_sha2_password老客戶端連不上會報(bào)Authentication plugin caching_sha2_password cannot be loaded需要客戶端升級或用ALTER USER root% IDENTIFIED WITH mysql_native_password BY password;兼容。用docker inspect mysql8可以查看容器的 IP 和掛載信息排查網(wǎng)絡(luò)和數(shù)據(jù)卷問題時(shí)這條命令很有用新手往往不知道容器有獨(dú)立的 IP總以為容器和宿主機(jī)共享網(wǎng)絡(luò)棧。5.2 Docker 里搭建 Redis 主從理解容器網(wǎng)絡(luò)的入門Redis 主從搭建是熱搜詞里另一個(gè)高頻需求。用 Docker 裝兩個(gè) Redis 容器讓一個(gè)當(dāng)主節(jié)點(diǎn)、一個(gè)當(dāng)從節(jié)點(diǎn)套路和物理機(jī)差不多但關(guān)鍵區(qū)別在于容器之間的網(wǎng)絡(luò)通信。先創(chuàng)建 Docker 網(wǎng)絡(luò)這一步經(jīng)常被忽略docker network create redis-net為什么要手動創(chuàng)建網(wǎng)絡(luò)因?yàn)槟J(rèn)的 bridge 網(wǎng)絡(luò)里容器可以通過 IP 互訪但 IP 是動態(tài)的重啟可能就變了。自定義網(wǎng)絡(luò)的好處是提供了內(nèi)置 DNS 解析容器之間可以用容器名互相訪問比如從庫配置里寫replicaof redis-master 6379就可以了IP 變了也不影響。這是在 Docker 里玩多容器協(xié)作時(shí)最重要的基建認(rèn)知。啟動主節(jié)點(diǎn)docker run -d --name redis-master --network redis-net -p 6379:6379 redis:7 redis-server --appendonly yes啟動從節(jié)點(diǎn)docker run -d --name redis-slave --network redis-net -p 6380:6379 redis:7 redis-server --replicaof redis-master 6379注意最后一段是覆蓋容器默認(rèn)啟動命令的寫法。redis:7是鏡像后面redis-server --replicaof redis-master 6379是自定義啟動參數(shù)意思是讓這個(gè) Redis 實(shí)例作為 6379 端口主節(jié)點(diǎn)的從庫。通過docker exec -it redis-slave redis-cli info replication可以看到role:slave和master_link_status:up。這一步跑通說明你已經(jīng)理解了 Docker 多容器通信的基本方式后面部署微服務(wù)、一般的前后端分離項(xiàng)目都用這個(gè)套路。5.3 Docker Compose把多容器配置固化下來手動docker run兩個(gè) Redis 容器已經(jīng)能跑了但如果這個(gè)服務(wù)要復(fù)制到別的機(jī)器或者團(tuán)隊(duì)里別人也要搭一套手敲命令顯然不優(yōu)雅。Docker Compose 的價(jià)值就是用 YAML 文件把多容器編排固化下來。先寫一個(gè)docker-compose.yml文件version: 3.8 services: redis-master: image: redis:7 container_name: redis-master command: redis-server --appendonly yes ports: - 6379:6379 networks: - redis-net redis-slave: image: redis:7 container_name: redis-slave command: redis-server --replicaof redis-master 6379 ports: - 6380:6379 depends_on: - redis-master networks: - redis-net networks: redis-net: driver: bridge然后執(zhí)行docker compose up -dCompose 會按照文件定義自動創(chuàng)建網(wǎng)絡(luò)、拉鏡像、啟動容器。注意depends_on只是控制啟動順序并不保證主節(jié)點(diǎn)已經(jīng)完全就緒所以在一些需要依賴就緒的場景下還要配合健康檢查healthcheck使用。這是從能用走向好用的關(guān)鍵一步。MySQL 也可以加進(jìn) Compose順便把前面的數(shù)據(jù)卷、端口映射、環(huán)境變量都寫在文件里。以后部署一整套環(huán)境只需docker compose up -d一條命令這就是 Docker 對開發(fā)運(yùn)維體驗(yàn)改變最大的地方。6. 日常使用高頻故障排查手冊實(shí)測記錄這部分全部來自實(shí)際使用中踩過的坑按出現(xiàn)頻率排序每一條都給出判斷思路和解決方法。6.1 權(quán)限錯(cuò)誤permission denied while trying to connect to the Docker daemon socket這是提問率最高的報(bào)錯(cuò)之一出現(xiàn)在 Linux 上執(zhí)行 docker 命令時(shí)。完整報(bào)錯(cuò)通常是permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock意思是當(dāng)前用戶沒有訪問 Docker 守護(hù)進(jìn)程 socket 的權(quán)限。解決方案前面提過把用戶加進(jìn) docker 組sudo usermod -aG docker $USER執(zhí)行后必須注銷當(dāng)前會話或者重啟系統(tǒng)組權(quán)限才會生效。有時(shí)候groups命令已經(jīng)顯示你在 docker 組里了但當(dāng)前 shell 的權(quán)限緩存還沒更新需要重啟 shell 或重新登錄。另外有一種變體是docker: permission denied伴隨/var/run/docker.sock掛載卷的情況通常是容器里要訪問宿主機(jī)的 Docker socket但 socket 文件權(quán)限是 660 且屬主是 root:docker容器內(nèi)用戶無權(quán)限時(shí)的處理方式是要么用 root 用戶運(yùn)行容器要么把 socket 文件的組權(quán)限放開——不過后者有安全風(fēng)險(xiǎn)一般不推薦。6.2 鏡像下載慢的根治思路docker鏡像下載慢幾乎是所有國內(nèi)用戶必經(jīng)的坎。核心思路是換鏡像加速源。Docker Engine 和 Docker Desktop 都要改daemon.jsonLinux 路徑是/etc/docker/daemon.jsonDocker Desktop 在 Settings - Docker Engine 里編輯 JSON。一個(gè)可行的配置示例{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com, https://docker.mirrors.ustc.edu.cn ] }改完重啟 Docker。不同加速源的穩(wěn)定性波動很大如果一個(gè)鏡像源拉不動換另一個(gè)。注意國內(nèi)鏡像加速源并不能加速所有倉庫比如某些小眾倉庫可能不在加速列表里這時(shí)可以用代理或換源方案。另外拉取不存在的鏡像名時(shí)也會表現(xiàn)為下載慢或者一直轉(zhuǎn)圈用docker pull前先到 Docker Hub 上確認(rèn)鏡像名拼寫正確。6.3 容器網(wǎng)絡(luò)不通的定位方法docker網(wǎng)絡(luò)不通涵蓋的情況很多但新手最常見的是三種宿主機(jī)訪問容器端口不通、容器訪問外網(wǎng)不通、容器之間互相不通。宿主機(jī)訪問容器端口不通時(shí)先用docker ps確認(rèn)真實(shí)端口映射。有時(shí)候你自己敲了-p 8080:80但容器里面 Nginx 監(jiān)聽的是 8000這時(shí)候訪問當(dāng)然不通。用docker port my-nginx查看當(dāng)前映射關(guān)系一目了然。容器訪問外網(wǎng)不通時(shí)先在容器里執(zhí)行docker exec -it my-nginx ping 8.8.8.8如果 ping 不通但宿主機(jī)能上網(wǎng)多半是 Docker 默認(rèn) bridge 網(wǎng)絡(luò)的 iptables 規(guī)則被清了或者開了防火墻。檢查/etc/docker/daemon.json里的iptables: false是否被誤設(shè)以及sysctl net.ipv4.ip_forward是否為 1。有些云服務(wù)器廠商的鏡像默認(rèn)把 ip_forward 關(guān)了導(dǎo)致容器無法上網(wǎng)這個(gè)坑比較隱蔽。容器之間互相不通時(shí)檢查它們是否在同一個(gè)網(wǎng)絡(luò)里。前面強(qiáng)調(diào)過自定義網(wǎng)絡(luò)有 DNS 解析如果兩個(gè)容器一個(gè)在默認(rèn) bridge 網(wǎng)、一個(gè)在自定義網(wǎng)絡(luò)用容器名是 ping 不通的。解決時(shí)把它們放到同一網(wǎng)絡(luò)docker network connect redis-net my-nginx6.4 服務(wù)啟動失敗failed to start docker application container engine這條報(bào)錯(cuò)在前面 Docker Desktop 小節(jié)提過但在純 Docker Engine 環(huán)境下也常見。排查順序是sudo systemctl status docker sudo journalctl -u docker --no-pager | tail -50日志里如果出現(xiàn)failed to start daemon: error while opening volume store metadata多半是/var/lib/docker目錄權(quán)限損壞修復(fù)方式是sudo chown -R root:root /var/lib/docker sudo chmod -R 755 /var/lib/docker但注意這只在確認(rèn)數(shù)據(jù)不重要時(shí)才建議操作。如果日志里出現(xiàn)overlay2 is not supported說明當(dāng)前文件系統(tǒng)不支持 OverlayFS 存儲驅(qū)動可以改用 vfs 或 fuse-overlayfs但性能會受影響。反復(fù)遇到服務(wù)啟動失敗的話建議把daemon.json暫時(shí)移走用默認(rèn)配置啟動確認(rèn)是不是自己的配置導(dǎo)致的問題。這一步成本很低能排除掉大部分配置型故障。6.5 容器退出狀態(tài)的快速判斷docker ps -a看到 Exited(0) 和 Exited(1) 的意義完全不同。Exited(0) 是正常退出比如docker run --rm hello-world打印完內(nèi)容就退出這是正?,F(xiàn)象。Exited(1) 或非零狀態(tài)碼說明程序運(yùn)行時(shí)出錯(cuò)??焖俨榭赐顺鰰r(shí)的日志用docker logs 容器名查看即可。有一種常見情況是前臺進(jìn)程跑完就退出比如啟動一個(gè)容器但命令是bash沒有任何交互進(jìn)程容器立刻退出。這時(shí)候加上-it交互終端就能保持運(yùn)行或者用-d跑一個(gè)自帶常駐進(jìn)程的鏡像如nginx。個(gè)人實(shí)際經(jīng)驗(yàn)里Docker 排查問題的大原則是先看日志、再看網(wǎng)絡(luò)、最后才考慮重啟和重裝。很多新手一遇到問題就docker rm -f再來一遍這樣不僅學(xué)不到東西還可能把數(shù)據(jù)卷里的數(shù)據(jù)一并刪掉。先理解報(bào)錯(cuò)信息在說什么再動手這個(gè)習(xí)慣能幫你省非常多的無用功。最后再補(bǔ)充一個(gè)實(shí)用的小技巧如果你經(jīng)常在一臺機(jī)器上同時(shí)跑多個(gè)項(xiàng)目盡量不要讓所有容器都在默認(rèn) bridge 網(wǎng)絡(luò)上按照項(xiàng)目維度創(chuàng)建各自的網(wǎng)絡(luò)配合 Compose 文件管理這樣端口不沖突、容器名不沖突、網(wǎng)絡(luò)也清晰。等你真正熟悉了這套操作就會理解為什么很多人說Docker 用好了部署一個(gè)服務(wù)真的只需要一條命令。