戰(zhàn):從安裝配置到前后端開(kāi)發(fā)環(huán)境容器化)
做前后端開(kāi)發(fā)這幾年我見(jiàn)過(guò)太多“上來(lái)先裝環(huán)境再配版本最后跑不起來(lái)”的場(chǎng)景。明明半個(gè)小時(shí)能動(dòng)手寫(xiě)代碼的事裝數(shù)據(jù)庫(kù)、緩存、消息中間件就能耗掉一下午。直到后來(lái)團(tuán)隊(duì)里強(qiáng)制推行Docker我才算是把“環(huán)境適配”這件破事徹底甩了出去。而這個(gè)系列一直拖著沒(méi)寫(xiě)、但實(shí)在繞不開(kāi)的一環(huán)就是今天要聊的 Docker Desktop——它不光是給Windows和macOS用戶一個(gè)圖形界面更是讓前后端開(kāi)發(fā)者在本地搭起一套完整依賴棧的關(guān)鍵底座。這篇內(nèi)容不玩虛的從Docker Desktop怎么安裝配置、怎么配合命令行干活到前后端項(xiàng)目里最常見(jiàn)的三個(gè)落地場(chǎng)景再把實(shí)戰(zhàn)里踩過(guò)的坑原樣攤開(kāi)說(shuō)清楚。無(wú)論你是剛接觸容器的新手還是被環(huán)境問(wèn)題反復(fù)折騰的資深開(kāi)發(fā)這份筆記應(yīng)該都能幫你少走幾趟彎路。1. Docker Desktop 在前后端開(kāi)發(fā)里的真正定位1.1 它到底替你解決了哪些“臟活”開(kāi)發(fā)過(guò)程中最耗耐心的事情往往不是寫(xiě)代碼本身而是“搞定環(huán)境”。后端同事用的MySQL版本和你不一樣跑起來(lái)報(bào)個(gè)字符集錯(cuò)誤前端本地裝Node版本和CI流水線不一致打包出來(lái)的產(chǎn)物行為完全不同項(xiàng)目里還要掛Redis、Elasticsearch、RabbitMQ每個(gè)都要求特定版本手動(dòng)裝一遍再切換配置真的能把人磨到懷疑人生。Docker Desktop 解決的第一個(gè)問(wèn)題就是讓這些依賴變成“可以隨手拉起來(lái)、用完就扔的黑盒”。你不再需要在本機(jī)裝一堆重型的數(shù)據(jù)庫(kù)軟件只需要一條 pull run容器起來(lái)了端口映射到位業(yè)務(wù)代碼就能連上。版本不對(duì)換tag再拉一次端口沖突換一個(gè)映射就完事。這種把“系統(tǒng)級(jí)安裝”降維成“應(yīng)用級(jí)運(yùn)行”的思路才是Docker Desktop 對(duì)前后端日常開(kāi)發(fā)最核心的價(jià)值。第二個(gè)問(wèn)題是項(xiàng)目隔離。我以前遇到過(guò)本地同時(shí)維護(hù)三四個(gè)項(xiàng)目的場(chǎng)景一個(gè)要Node 16一個(gè)要Node 18還有一個(gè)依賴Java 8環(huán)境。沒(méi)有容器隔離的時(shí)候要么切換系統(tǒng)環(huán)境變量要么裝一堆管理工具復(fù)雜且脆弱。到Docker Desktop 這里每個(gè)項(xiàng)目有獨(dú)立的鏡像和容器互不干擾理論基礎(chǔ)就是操作系統(tǒng)的進(jìn)程和文件系統(tǒng)隔離能力。你可以把容器理解成“一棟樓里的獨(dú)立房間”共用樓里的水電但裝修各搞各的誰(shuí)也不影響誰(shuí)。第三個(gè)問(wèn)題是讓“我這邊能跑”真正變成“哪里都能跑”。容器鏡像把項(xiàng)目運(yùn)行所需的全部依賴打包進(jìn)去隊(duì)友拉下來(lái)看到的運(yùn)行結(jié)果和你完全一致。對(duì)于前后端協(xié)作而言這直接消滅了“前端說(shuō)接口沒(méi)問(wèn)題后端說(shuō)前端沒(méi)傳參”這類(lèi)扯皮場(chǎng)景。1.2 為什么選擇 Docker Desktop 而不是裸裝 Docker有Linux服務(wù)器經(jīng)驗(yàn)的開(kāi)發(fā)者可能會(huì)問(wèn)我明明可以直接裝 Docker Engine 和 docker CLI為什么還要專(zhuān)門(mén)用 Docker Desktop因?yàn)槿粘1镜亻_(kāi)發(fā)大部分發(fā)生在 Windows 和 macOS 上這兩類(lèi)系統(tǒng)本身不是原生Linux容器引擎需要一個(gè)輕量級(jí)的Linux虛擬機(jī)來(lái)運(yùn)行。Docker Desktop 把這一套底層環(huán)境、虛擬機(jī)資源調(diào)度、文件共享、端口轉(zhuǎn)發(fā)全都封裝好了裝完啟動(dòng)就能用不需要手動(dòng)維護(hù)一個(gè)容易被折騰到崩潰的Linux虛擬機(jī)。它自帶的可視化面板也是加分項(xiàng)??慈萜鞯膯⑼顟B(tài)、翻日志、進(jìn)容器終端、清理孤兒容器全部能在界面里一鍵完成。對(duì)于不習(xí)慣純命令行的小伙伴這點(diǎn)很友好。但這里我必須強(qiáng)調(diào)一下Docker Desktop 與命令行輸出命令和參數(shù)并沒(méi)有被閹割安裝它之后 docker CLI 照樣完整可用本質(zhì)上它是引擎加圖形管理界面不是替代品。另外Docker Desktop 對(duì)開(kāi)發(fā)資源的消耗也比較可控。雖然是虛擬機(jī)方案但做了很多內(nèi)建優(yōu)化日常跑一兩個(gè)數(shù)據(jù)庫(kù)容器加一個(gè)前端構(gòu)建容器內(nèi)存占用大概在2到3GB以內(nèi)。相比手動(dòng)搞虛擬機(jī)再用端口映射來(lái)接服務(wù)哪個(gè)折騰用過(guò)的人心里都有數(shù)。選型上還可以提一句Linux 用戶可以直接裝 docker-ce不需要 DesktopWindows 用戶強(qiáng)烈建議開(kāi)啟 WSL2 后端不要用舊版 Hyper-V 的后端。具體原因后面在安裝配置里展開(kāi)。2. 安裝與初始配置別讓第一步就卡住2.1 安裝前的系統(tǒng)準(zhǔn)備Docker Desktop 的安裝包去官網(wǎng)下載對(duì)應(yīng)系統(tǒng)的版本即可。真正容易卡住的是系統(tǒng)層面的前置條件。Windows 這邊建議提前裝好 WSL2。原因不復(fù)雜WSL2 采用的是輕量級(jí)虛擬機(jī)方案和 Docker 引擎配合起來(lái)文件讀寫(xiě)速度遠(yuǎn)快于舊版 Hyper-V 虛擬化方案。啟動(dòng)文件掛載的時(shí)候兩者的性能差距尤其明顯。安裝步驟其實(shí)很機(jī)械先在PowerShell里執(zhí)行兩條命令啟用虛擬機(jī)和Linux子系統(tǒng)功能重啟再去商店裝一個(gè)你習(xí)慣的發(fā)行版比如 Ubuntu最后執(zhí)行內(nèi)核更新包。裝完 Docker Desktop 第一次啟動(dòng)時(shí)會(huì)要求登錄并選擇“使用 WSL2 而非 Hyper-V”作為后端照著做就行。macOS 這邊新版本的 Docker Desktop 默認(rèn)使用 Apple 芯片的原生虛擬化框架性能表現(xiàn)不錯(cuò)。如果你是 Intel 芯片的舊機(jī)器系統(tǒng)版本最好保持在官方支持范圍內(nèi)避免安裝環(huán)節(jié)莫名報(bào)錯(cuò)。另外要注意Docker Desktop 在 macOS 上不能直接裝到移動(dòng)硬盤(pán)或者非系統(tǒng)盤(pán)強(qiáng)行遷移后經(jīng)常遇到正在同步期的異常問(wèn)題老老實(shí)實(shí)放在“應(yīng)用程序”目錄就好。安裝完成后第一次啟動(dòng)會(huì)在菜單欄或者系統(tǒng)托盤(pán)出現(xiàn)鯨魚(yú)圖標(biāo)右鍵能打開(kāi)工作的 Dashboard 面板。開(kāi)機(jī)自啟是我個(gè)人非常推薦的選項(xiàng)因?yàn)楸镜亻_(kāi)發(fā)時(shí)容器服務(wù)的啟停頻率實(shí)在太高每次開(kāi)機(jī)手動(dòng)開(kāi)引擎過(guò)幾天就會(huì)嫌煩。2.2 啟動(dòng)后的關(guān)鍵設(shè)置Docker Desktop 不是裝完就完事有兩項(xiàng)配置建議第一時(shí)間改掉。第一項(xiàng)是資源限制。Settings 里的 Resources 設(shè)置項(xiàng)能限制CPU、內(nèi)存和Swap。很多人的手機(jī)會(huì)在跑多個(gè)容器時(shí)變得卡頓其實(shí)未必是電腦不夠強(qiáng)而是 Docker 默認(rèn)把內(nèi)存用得太松。個(gè)人經(jīng)驗(yàn)是如果宿主機(jī)內(nèi)存是16GB分配給Docker的WSL后端控制在4GB左右6到8GB會(huì)明顯感覺(jué)日常切換應(yīng)用和編譯都變慢如果你要并行跑的服務(wù)確實(shí)多可以在6到8GB之間取舍勤看看資源監(jiān)控再動(dòng)態(tài)調(diào)。設(shè)置內(nèi)存、CPU配額最明顯的意義是避免容器無(wú)限占用宿主機(jī)資源拖垮整臺(tái)機(jī)器。第二項(xiàng)是鏡像倉(cāng)庫(kù)的加速配置。很多新手拉取鏡像時(shí)卡在進(jìn)度條長(zhǎng)時(shí)間不動(dòng)大概率不是網(wǎng)絡(luò)本身壞了而是默認(rèn)倉(cāng)庫(kù)地址訪問(wèn)路徑較慢。Docker Desktop 里可以在 Docker Engine 的配置文件daemon.json中加入加速地址各主流云服務(wù)商都提供免費(fèi)的容器鏡像加速服務(wù)登錄控制臺(tái)就能拿到專(zhuān)屬地址。把 registry-mirrors 數(shù)組配置好點(diǎn)擊 Apply Restart 之后拉鏡像的速度通常會(huì)有非常明顯的提升。注意這里說(shuō)的是“加速地址”不是任何特殊網(wǎng)絡(luò)工具屬于基礎(chǔ)開(kāi)發(fā)配置。順帶提一句登錄問(wèn)題。Docker Desktop 初次使用會(huì)讓登錄賬號(hào)很多人以為必須登錄才能用這是誤讀創(chuàng)建本地容器、拉公共鏡像都不強(qiáng)制登錄。登錄只影響拉取私有鏡像和部分高級(jí)功能。如果對(duì)賬號(hào)體系沒(méi)有需求可以直接跳過(guò)。3. 常用操作GUI 和 CLI 怎么配合干活3.1 從 Dashboard 看容器、鏡像、卷與日志Docker Desktop 的圖形界面本質(zhì)上給開(kāi)發(fā)者一個(gè)“不背命令也能用”的入口但它并不幼稚很多操作在面板上反而更直觀。鏡像管理頁(yè)里列出所有本地鏡像支持搜索、拉取、刪除還能對(duì)某個(gè)鏡像直接點(diǎn)擊 Run 來(lái)創(chuàng)建容器。這一點(diǎn)在處理臨時(shí)驗(yàn)證類(lèi)的任務(wù)時(shí)非常爽比如我突然想看看某個(gè)鏡像的默認(rèn)環(huán)境變量直接 Run 起來(lái)再進(jìn)終端看就行不需要臨時(shí)想 docker run 那一長(zhǎng)串參數(shù)。容器列表頁(yè)展示所有容器的狀態(tài)、端口映射、使用時(shí)長(zhǎng)。點(diǎn)進(jìn)任意容器右上方有 Start、Restart、Stop、Delete 按鈕再往下的區(qū)域還能直接打開(kāi)終端進(jìn)入容器內(nèi)部執(zhí)行命令、查看日志文件。這里的日志面板和 docker logs 有一致的滾動(dòng)流前端調(diào)試后端接口時(shí)我一般會(huì)把負(fù)責(zé)后端的容器日志面板固定在副屏實(shí)時(shí)觀察比反復(fù)敲命令方便得多。卷Volumes的管理也在界面上完成。清理項(xiàng)目時(shí)經(jīng)常用到的是“把關(guān)聯(lián)的Volume一并刪掉”這個(gè)在面板里選起來(lái)很明確。當(dāng)然以后和同事配合時(shí)大多還是用命令直接操作面板更多是查狀態(tài)和做快速操作。3.2 前后端開(kāi)發(fā)一定會(huì)用到的 CLI 命令裝好 Docker Desktop 后在終端里敲 docker 就能直接用。日常開(kāi)發(fā)最頂層的命令組合說(shuō)來(lái)說(shuō)去就那么幾個(gè)。docker ps 查運(yùn)行狀態(tài)加 -a 參數(shù)能看到所有容器包括已停止的。docker logs -f 容器名或ID 追蹤容器日志是排查后端服務(wù)報(bào)錯(cuò)的一線工具。docker exec -it 容器名 /bin/sh 進(jìn)入容器內(nèi)部適合查看配置文件是否生效或者手動(dòng)執(zhí)行腳本。docker pull 鏡像名:版本 顯式拉鏡像明確版本總比無(wú)腦latest好。docker stop / start / restart 控制服務(wù)生命周期。docker rm 配合 -f 刪除容器排查卡死容器時(shí)幾乎必用。docker image prune 和 docker system prune 清理懸空鏡像和廢棄資源這是磁盤(pán)告急的救星。這些命令看著零散但用順了之后能解決絕大多數(shù)本地容器管理場(chǎng)景。有一個(gè)建議是給高頻命令配置簡(jiǎn)寫(xiě)比如把 docker compose 寫(xiě)成 dcdocker ps 寫(xiě)成 dps。不過(guò)按照?qǐng)F(tuán)隊(duì)協(xié)作的習(xí)慣我更推薦在項(xiàng)目文檔里記錄完整命令自己終端里隨便加別名就好別讓別名成為換機(jī)器后的負(fù)擔(dān)。CLI 相比 GUI 的優(yōu)勢(shì)是腳本化。有人喜歡把“重置開(kāi)發(fā)環(huán)境”寫(xiě)成一串 shell 命令一鍵完成停止容器、刪除容器、清理卷和鏡像再重建這樣交付給同事時(shí)團(tuán)隊(duì)能少踩很多環(huán)境坑。4. 前后端項(xiàng)目里最常見(jiàn)的三個(gè)實(shí)操場(chǎng)景4.1 場(chǎng)景一把 MySQL 和 Redis 當(dāng)獨(dú)立容器跑起來(lái)很多后端開(kāi)發(fā)的啟動(dòng)流程是先在本地啟動(dòng)一個(gè) MySQL再啟動(dòng)一個(gè) Redis最后啟動(dòng)應(yīng)用服務(wù)。用 Docker Desktop 之后我的習(xí)慣是寫(xiě)一個(gè)固定的啟動(dòng)命令把基礎(chǔ)設(shè)施直接作為容器跑。就拿MySQL來(lái)說(shuō)一條完整的 docker run 命令一般是docker run -d \ --name order-mysql \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDdev_root_123 \ -e MYSQL_DATABASEorder_dev \ -v order-mysql-data:/var/lib/mysql \ mysql:8.0命令行參數(shù)里包含四個(gè)關(guān)鍵要素-d 表示后臺(tái)運(yùn)行--name 指定容器名-p 把宿主機(jī)的3306端口映射到容器的3306端口-e 設(shè)置環(huán)境變量初始密碼和創(chuàng)建的數(shù)據(jù)庫(kù)名-v 掛載數(shù)據(jù)卷保證容器重建后數(shù)據(jù)不丟失。Redis 同理唯一需要注意的是如果不設(shè)置密碼容器默認(rèn)只監(jiān)聽(tīng)本地映射端口生產(chǎn)環(huán)境直接用會(huì)有風(fēng)險(xiǎn)但本地開(kāi)發(fā)夠用。前后端聯(lián)調(diào)時(shí)后端的配置文件里數(shù)據(jù)庫(kù)連接地址不再寫(xiě) localhost要寫(xiě)成 127.0.0.1因?yàn)槿萜鞫丝谟成浯_實(shí)監(jiān)聽(tīng)在宿主機(jī)回環(huán)地址如果后端服務(wù)本身也在容器里跑那就別用 localhost要用容器的名字或者內(nèi)部網(wǎng)絡(luò)IP。這個(gè)細(xì)節(jié)剛接觸時(shí)經(jīng)常踩坑。4.2 場(chǎng)景二用 docker compose 編排整套服務(wù)棧如果你不想記住每個(gè)命令一眼看全項(xiàng)目的依賴關(guān)系更推薦用 docker compose。它和 docker run 的最大區(qū)別是用一個(gè) YAML 文件聲明多個(gè)服務(wù)啟動(dòng)、停止、重建都只需要針對(duì)整個(gè)文件操作。下面是一個(gè)典型的后端開(kāi)發(fā)環(huán)境編排示例version: 3.9 services: mysql: image: mysql:8.0 container_name: order-mysql environment: - MYSQL_ROOT_PASSWORDdev_root_123 - MYSQL_DATABASEorder_dev ports: - 3306:3306 volumes: - order-mysql-data:/var/lib/mysql healthcheck: test: [CMD, mysqladmin, ping, -h, localhost] interval: 5s retries: 10 redis: image: redis:7-alpine container_name: order-redis ports: - 6379:6379 backend: build: ./backend container_name: order-backend ports: - 8080:8080 depends_on: mysql: condition: service_healthy redis: condition: service_started volumes: - ./backend:/app volumes: order-mysql-data:寫(xiě)這個(gè)文件的時(shí)候有幾點(diǎn)要額外解釋。healthcheck 的作用是告訴 compose “MySQL 還沒(méi)完全就緒別急著啟動(dòng)后端”否則后端啟動(dòng)時(shí)連不上庫(kù)會(huì)直接崩潰退出而實(shí)際上數(shù)據(jù)庫(kù)只是還在初始化。depends_on 配合 condition 可以實(shí)現(xiàn)真正的依賴等待這一點(diǎn)很多新手沒(méi)有意識(shí)到。啟動(dòng)方式也很簡(jiǎn)單docker compose up -d docker compose ps docker compose logs -f backend docker compose downdown 命令會(huì)停掉所有服務(wù)但不會(huì)刪除卷里的數(shù)據(jù)這對(duì)開(kāi)發(fā)環(huán)境是很理想的行為。如果想徹底重置再去面板或者命令里把對(duì)應(yīng)卷刪掉。4.3 場(chǎng)景三前端項(xiàng)目也用容器跑有些前端開(kāi)發(fā)者覺(jué)得后端用容器合理前端只要一個(gè) Node 環(huán)境好像沒(méi)必要。但我在聯(lián)調(diào)時(shí)遇到的效率問(wèn)題恰恰來(lái)自這里多人合作時(shí) Node 版本不統(tǒng)一導(dǎo)致依賴鎖文件失效、npm 版本不同導(dǎo)致安裝策略不同甚至有個(gè)同事的 npm 配了國(guó)內(nèi)源裝出來(lái)的 lock 都有差異。容器化之后能把這些差異直接抹平。給前端項(xiàng)目造鏡像很簡(jiǎn)單寫(xiě)一個(gè) DockerfileFROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm config set registry https://registry.npmmirror.com npm ci COPY . . RUN npm run build FROM nginx:alpine COPY --frombuilder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80這個(gè) Dockerfile 用了多階段構(gòu)建。第一階段用帶 Node 的鏡像完成依賴安裝和打包第二階段把構(gòu)建產(chǎn)物拷入一個(gè)輕量的 Nginx 鏡像直接作為靜態(tài)資源服務(wù)。這樣做的好處是最終運(yùn)行的鏡像里沒(méi)有源代碼和 node_modules體積更小安全風(fēng)險(xiǎn)也更低。開(kāi)發(fā)環(huán)境則不需要這么厚重通常直接掛載源碼運(yùn)行 dev server。比如:docker run -d -p 5173:5173 \ -v $(pwd):/app \ -w /app \ node:18-alpine \ sh -c npm install npm run dev這里 -w 指定工作目錄-v 同步宿主代碼容器內(nèi)改完代碼宿主也同步反之亦然。不過(guò)要注意文件監(jiān)聽(tīng)在 WSL2 上的兼容問(wèn)題具體怎么處理下一節(jié)會(huì)展開(kāi)。5. 實(shí)戰(zhàn)中踩過(guò)的坑與排查案例5.1 高頻問(wèn)題速查表問(wèn)題現(xiàn)象可能原因處理辦法引擎一直顯示 running卻無(wú)法操作容器后端虛擬機(jī)異常常見(jiàn)于 Windows右鍵 Docker 圖標(biāo)選擇 Restart或者重啟系統(tǒng)端口無(wú)法訪問(wèn)容器端口映射被占用先 docker ps 確認(rèn)映射再檢查宿主端口 netstat 占用容器內(nèi)連接 MySQL 失敗使用了 localhost改成 docker compose 服務(wù)名或宿主 IP掛載卷沒(méi)有生效路徑寫(xiě)法不對(duì)Windows 下推薦使用當(dāng)前目錄 $(pwd)macOS 下用 $PWD磁盤(pán)空間迅速被占滿鏡像構(gòu)建緩存和舊容器累積執(zhí)行 docker system prune -a定期清理文件改動(dòng)沒(méi)有觸發(fā)熱更新WSL2 文件監(jiān)聽(tīng)兼容問(wèn)題將項(xiàng)目目錄放進(jìn) WSL2 文件系統(tǒng)內(nèi)不要放在 /mnt/c 下拉鏡像超時(shí)默認(rèn)倉(cāng)庫(kù)訪問(wèn)慢配置 registry-mirrors 加速地址這個(gè)表格不能解決所有問(wèn)題但確實(shí)是高頻問(wèn)題的集合作剩下的基本都是上面幾個(gè)場(chǎng)景的組合變化。5.2 兩個(gè)印象深刻的排障實(shí)錄第一個(gè)是端口沖突。有一次我在本地跑一個(gè)微服務(wù)模塊容器一直正常啟動(dòng)但接口請(qǐng)求全部超時(shí)。dips 查下來(lái)容器狀態(tài)是 Up端口映射也顯示 8080:8080可 curl 就是沒(méi)響應(yīng)。折騰了半小時(shí)才發(fā)現(xiàn)宿主機(jī)的8080端口被另一個(gè)進(jìn)程占用Docker 面板里顯示的映射是虛擬的實(shí)際流量根本沒(méi)有送進(jìn)容器。解決辦法是把容器的宿主機(jī)端口改成 8081重新映射就好了。所以排查端口類(lèi)問(wèn)題第一步一定是確認(rèn)宿主機(jī)端口沒(méi)被別的進(jìn)程占用。第二個(gè)是磁盤(pán)被 Build 緩存吃光。連著開(kāi)發(fā)了幾天系統(tǒng)磁盤(pán)掉了將近20個(gè)G。查了一圈發(fā)現(xiàn)罪魁禍?zhǔn)资?docker build 產(chǎn)生的懸空鏡像層和構(gòu)建緩存。長(zhǎng)時(shí)間使用 docker compose 頻繁重建服務(wù)鏡像層會(huì)產(chǎn)生大量中間產(chǎn)物docker system df 一查就能看到 build cache 占據(jù)了很大的空間。定期執(zhí)行 docker system prune -a 可以有效釋放不過(guò)這個(gè)命令會(huì)把未使用的鏡像全刪拉取時(shí)間成本能接受的話完全可以定期執(zhí)行。5.3 幾條可以少走彎路的個(gè)人習(xí)慣容器命名要規(guī)范。我習(xí)慣用“項(xiàng)目-組件”的格式比如order-backend、order-mysql看名字就能定位省去每次 docker ps 對(duì)著隨機(jī)字符串發(fā)愣的時(shí)間。鏡像版本要寫(xiě)死。開(kāi)發(fā)環(huán)境要是腦門(mén)一熱全用 latest某天基礎(chǔ)鏡像上游更新了第二天所有同事的本地環(huán)境一起出現(xiàn)兼容問(wèn)題排查得想罵人。鎖住版本升級(jí)要有意識(shí)去做別被動(dòng)踩坑。開(kāi)發(fā)數(shù)據(jù)默認(rèn)用卷。哪怕只是本地調(diào)試MySQL的數(shù)據(jù)掛一個(gè)命名卷也比讓容器自生自滅強(qiáng)。容器刪了重建數(shù)據(jù)還在省掉一堆初始化流程。最后說(shuō)點(diǎn)個(gè)人體會(huì)Docker Desktop 這個(gè)東西看著像是一個(gè)開(kāi)發(fā)小工具實(shí)際上它改變的是我對(duì)“環(huán)境”這兩個(gè)字的理解。以前遇到環(huán)境問(wèn)題第一反應(yīng)是“這臺(tái)機(jī)器有問(wèn)題”現(xiàn)在遇到環(huán)境問(wèn)題第一反應(yīng)是“哪個(gè)變量沒(méi)寫(xiě)對(duì)、哪個(gè)卷沒(méi)掛對(duì)”。前后端協(xié)作時(shí)一個(gè)問(wèn)題能復(fù)現(xiàn)才能有資格被解決——而容器給了所有人一個(gè)統(tǒng)一的復(fù)現(xiàn)場(chǎng)景。拿我自己來(lái)說(shuō)用 Docker Desktop 時(shí)間越長(zhǎng)越喜歡在“認(rèn)真看面板狀態(tài)”和“勇敢敲命令行”之間來(lái)回切換。圖形界面負(fù)責(zé)概覽和直覺(jué)命令行負(fù)責(zé)精確和腳本化兩者缺少一個(gè)日常效率都要打折。后來(lái)我還把一套完整的 docker compose 配置模板分享給了團(tuán)隊(duì)新同學(xué)入職之后拉下項(xiàng)目倉(cāng)庫(kù)敲一條 docker compose up -d整個(gè)依賴環(huán)境就緒“這只在我機(jī)器上能跑”這句話也就徹底成了過(guò)去式。