5種常見的Docker Compose錯誤

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在構建一個容器化應用程序時,開發人員需要一種方法來引導他們正在使用的容器去測試其代碼。雖然有幾種方法可以做到這一點,但Docker Compose是最流行的選擇之一。它讓你可以輕鬆指定開發期間要引導的容器,其次建立一個快速的“編碼-測試-調試”開發循環。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"願景是一個人編寫一個"},{"type":"codeinline","content":[{"type":"text","text":"docker-compose.yml"}]},{"type":"text","text":"文件,指定了開發中所需的一切,並將它提交到代碼倉庫。然後,每一個開發者只需運行"},{"type":"codeinline","content":[{"type":"text","text":"docker-compose up"}]},{"type":"text","text":",即可啓動測試其代碼需要的所有容器。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然而,要使"},{"type":"codeinline","content":[{"type":"text","text":"docker-compose"}]},{"type":"text","text":"設置達到最高性能,需要大量工作。我們見過最好的團隊"},{"type":"text","marks":[{"type":"strong"}],"text":"在不到一分鐘的時間內"},{"type":"text","text":"啓動他們的開發環境,並"},{"type":"text","marks":[{"type":"strong"}],"text":"在幾秒中內"},{"type":"text","text":"測試每個更改。考慮到每個開發人員每天花在測試代碼上的時間,小的改進會對開發人員的生產力產生巨大影響。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/21\/21a7ed4b2a503739443f21c2ef928e00.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"源自XKCD"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"錯誤1:頻繁的容器重建"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"docker build"}]},{"type":"text","text":"需要很長時間。如果每次想要測試一個代碼更改時都要重新構建你的容器,那麼你就有很大潛力來加速你的開發循環。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"處理非容器化應用程序的傳統工作流如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"編碼"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"構建"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些年來,通過使用針對編譯型語言的增量構建和熱加載之類的技巧,這個過程得到高度優化。它變得非常快。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當人們第一次採用容器時,他們傾向於採用現有的工作流程,只添加一個"},{"type":"codeinline","content":[{"type":"text","text":"docker build"}]},{"type":"text","text":"步驟。他們的工作流如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"編碼"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"構建"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"容器構建"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果做的不好,"},{"type":"codeinline","content":[{"type":"text","text":"docker build"}]},{"type":"text","text":"步驟會使所有優化都白費。另外,它還增加了一堆額外的耗時工作,例如使用apt-get重新安裝依賴。所有這些加起來,會使得我們的測試過程比使用Docker之前要慢得多。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:在Docker外運行你的代碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一種方案是在Docker Compose中啓動所有依賴項,但在本地運行你正在積極處理的代碼。這模仿了開發非容器化應用程序的工作流。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"只需要在"},{"type":"codeinline","content":[{"type":"text","text":"localhost"}]},{"type":"text","text":"上暴露你的依賴,並將你正在使用的服務指向"},{"type":"codeinline","content":[{"type":"text","text":"localhost:"}]},{"type":"text","text":"地址。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然而,這並不總是可行的,尤其是如果你正在處理的代碼依賴容器鏡像內置的東西,而這些東西不容易從你的筆記本電腦訪問。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:最大化緩存來優化Dockerfile"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果必須構建Docker鏡像,那麼編寫Dockerfile時,最大化緩存能將一個10分鐘的Docker構建變爲1分鐘。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"生產環境的Dockerfile文件的典型模式是通過將單個命令鏈接到一個"},{"type":"codeinline","content":[{"type":"text","text":"RUN"}]},{"type":"text","text":"語句中來減少層數。然而,鏡像大小在開發過程中並不重要。在開發過程中,你想要儘可能多的層數。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你的生產環境Dockerfile文件可能如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"RUN \\\n go get -d -v \\\n && go install -v \\\n && go build"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這對開發來說很糟糕,因爲每次重新運行該命令時,Docker都會重新下載所有的依賴並重新安裝它們。增量構建更加有效。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相反,你應該有一個專門用於開發環境的的Dockerfile文件。將每件事都分解成非常小的步驟,規劃好你的Dockerfile文件,這樣基於經常變化的代碼的步驟最後執行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最不頻繁更改的內容,例如拉取依賴,應該放在第一位。這樣,在重建Dockerfile時就不必構建整個項目。你只需要構建你剛剛修改的一小部分。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於這個的例子,請看下面我們用於"},{"type":"link","attrs":{"href":"https:\/\/blimpup.io\/","title":"","type":null},"content":[{"type":"text","text":"Blimp"}]},{"type":"text","text":"開發環境的Dockerfile。它遵循上面所述的技術,將繁重的構建過程縮短到幾秒鐘。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"FROM golang:1.13-alpine as builder\n\nRUN apk add busybox-static\n\nWORKDIR \/go\/src\/github.com\/kelda-inc\/blimp\n\nADD .\/go.mod .\/go.mod\nADD .\/go.sum .\/go.sum\nADD .\/pkg .\/pkg\n\nARG COMPILE_FLAGS\n\nRUN CGO_ENABLED=0 go install -i -ldflags \"${COMPILE_FLAGS}\" .\/pkg\/...\n\nADD .\/login-proxy .\/login-proxy\nRUN CGO_ENABLED=0 go install -i -ldflags \"${COMPILE_FLAGS}\" .\/login-proxy\/...\n\nADD .\/registry .\/registry\nRUN CGO_ENABLED=0 go install -i -ldflags \"${COMPILE_FLAGS}\" .\/registry\/...\n\nADD .\/sandbox .\/sandbox\nRUN CGO_ENABLED=0 go install -i -ldflags \"${COMPILE_FLAGS}\" .\/sandbox\/...\n\nADD .\/cluster-controller .\/cluster-controller\nRUN CGO_ENABLED=0 go install -i -ldflags \"${COMPILE_FLAGS}\" .\/cluster-controller\/...\n\nRUN mkdir \/gobin\nRUN cp \/go\/bin\/cluster-controller \/gobin\/blimp-cluster-controller\nRUN cp \/go\/bin\/syncthing \/gobin\/blimp-syncthing\nRUN cp \/go\/bin\/init \/gobin\/blimp-init\nRUN cp \/go\/bin\/sbctl \/gobin\/blimp-sbctl\nRUN cp \/go\/bin\/registry \/gobin\/blimp-auth\nRUN cp \/go\/bin\/vcp \/gobin\/blimp-vcp\nRUN cp \/go\/bin\/login-proxy \/gobin\/login-proxy\n\nFROM alpine\n\nCOPY --from=builder \/bin\/busybox.static \/bin\/busybox.static\nCOPY --from=builder \/gobin\/* \/bin\/"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後一點:通過最近引入的"},{"type":"link","attrs":{"href":"https:\/\/docs.docker.com\/develop\/develop-images\/multistage-build\/","title":"","type":null},"content":[{"type":"text","text":"多階段構建"}]},{"type":"text","text":",現在可以創建具有良好分層且鏡像很小的Dockerfile。我們在本文中對這一點不會過多討論,只能說上面顯示的Dockerfile就是這樣做的,因此它既用於"},{"type":"link","attrs":{"href":"https:\/\/blimpup.io\/","title":"","type":null},"content":[{"type":"text","text":"Blimp"}]},{"type":"text","text":"開發環境也用於生產環境。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:使用主機卷"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通常,最好的選擇是使用一個主機捲來直接將你的代碼加載到容器上。這使你能夠以本機速度運行代碼,同時仍然在包含運行時依賴項的Docker容器中運行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"主機卷將你筆記本電腦上的一個目錄鏡像到一個正在運行的容器中。當你在文本編輯器中編輯一個文件時,更改會自動同步到容器中,然後能立即在容器中執行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"大多數語言都有一種方法來監視你的代碼,並在代碼更改時自動重新運行。例如,"},{"type":"link","attrs":{"href":"https:\/\/www.npmjs.com\/package\/nodemon","title":"","type":null},"content":[{"type":"text","text":"nodemon"}]},{"type":"text","text":"是Javascript中的監視代碼的方法。請查看這篇關於如何設置這一點的"},{"type":"link","attrs":{"href":"https:\/\/blimpup.io\/blog\/docker-volumes-for-development\/","title":"","type":null},"content":[{"type":"text","text":"文章"}]},{"type":"text","text":"教程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"它最初需要一些工作,但結果是,你可以在1-2秒內看到你的代碼更改的結果,而一次Docker構建可能需要幾分鐘。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"錯誤2:主機卷速度慢"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果使用了主機卷,你可能已經注意到,在Windows和Mac上讀寫文件的速度非常慢。對於讀寫大量文件的命令來說,這是一個已知的問題,例如具有複雜依賴的Node.js和PHP應用程序。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這是因爲Docker是運行在Windows和Mac的一個虛擬機上。在進行主機卷加載時,必須經過大量的轉換才能將筆記本電腦上的文件夾加載到容器中,這有點兒類似網絡文件系統。這會增加大量負載,而在Linux本機上運行Docker時不會出現這些情況。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:放鬆強一致性"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中一個關鍵問題是,默認情況下,文件系統加載會保持強一致性。一致性是一個廣泛的話題,可以濃墨重彩地大書特書,但是簡而言之,它意味着所有特定文件的讀取者和寫入者都同意任何文件修改發生的順序,從而(最終,某種程度上)同意該文件的內容。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"問題是,強制實現強一致性是相當昂貴的,需要所有文件寫入者確保他們不會不恰當地破壞彼此的更改。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"雖然強一致性有時特別重要,例如,當在生產環境運行數據庫時。好消息是,在開發環境,它不是必需的。你的代碼文件只會有單個寫入者(你自己),和單個信源(你的代碼庫)。因此,衝突並不像在生產中那麼需要擔心。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"正是由於這個原因,Docker實現了在加載卷時放鬆一致性保證的功能。在Docker Compose中,你只需將"},{"type":"codeinline","content":[{"type":"text","text":"cached"}]},{"type":"text","text":"關鍵詞添加到卷加載中即可獲得顯著的性能保證。(不要在生產環境這麼做...)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"volumes:\n - \".\/app:\/usr\/src\/app\/app:cached\""}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:代碼同步"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另一種方案是設置代碼同步。你可以用一個工具來通知你的筆記本電腦和容器之間的更改,並複製文件來解決差異(類似於rsync),而不是加載一個卷。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Docker的下一個版本內置了"},{"type":"link","attrs":{"href":"https:\/\/mutagen.io\/","title":"","type":null},"content":[{"type":"text","text":"Mutagen"}]},{"type":"text","text":",作爲卷的緩存模式的一種替代。如果你感興趣,就等Docker發佈下一個版本再試試,不過你也可以直接下載Mutagen項目,不用等就可以直接使用。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:不要加載包"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於Node這樣的語言,大部分文件操作往往位於包目錄(例如"},{"type":"codeinline","content":[{"type":"text","text":"node_modules"}]},{"type":"text","text":")。因此,從卷中排除這些目錄會顯著提高性能。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在下面的例子中,我們有一個卷將代碼加載到一個容器中。然後用它自己乾淨的專用卷覆蓋了"},{"type":"codeinline","content":[{"type":"text","text":"node_modules"}]},{"type":"text","text":"目錄。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"volumes:\n - \".:\/usr\/src\/app\"\n - \"\/usr\/src\/app\/node_modules\""}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個額外的卷加載告訴Docker爲"},{"type":"codeinline","content":[{"type":"text","text":"node_modules"}]},{"type":"text","text":"目錄使用一個標準卷,這樣當"},{"type":"codeinline","content":[{"type":"text","text":"npm install"}]},{"type":"text","text":"運行時,它不會使用比較慢的主機加載。爲了使之生效,當容器首次啓動時,我們在"},{"type":"codeinline","content":[{"type":"text","text":"entrypoint"}]},{"type":"text","text":"運行"},{"type":"codeinline","content":[{"type":"text","text":"npm install"}]},{"type":"text","text":"來安裝我們的依賴並填充"},{"type":"codeinline","content":[{"type":"text","text":"node_modules"}]},{"type":"text","text":"目錄。像這樣:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"entrypoint:\n - \"sh\"\n - \"-c\"\n - \"npm install && .\/node_modules\/.bin\/nodemon server.js\""}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"克隆和下載上述示例代碼的完整說明,請參考"},{"type":"link","attrs":{"href":"https:\/\/blimpup.io\/docs\/#\/getting-started","title":"","type":null},"content":[{"type":"text","text":"此處"}]},{"type":"text","text":"。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"錯誤3:脆弱的配置"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"大多數Docker Compose文件都是有組織地演化的。我們通常會看到大量的複製粘貼代碼,這使得代碼修改非常困難。一個乾淨的Docker Compose文件可以更容易地在生產環境變化時進行定期更新。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:使用env文件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"env文件將環境變量從主Docker Compose配置中分離出來。這有助於:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使密鑰不會保存在git歷史中"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使每個開發者擁有稍微不同的設置變得容易。例如,每個開發者可能有一個唯一的access密鑰。將配置保存在一個"},{"type":"codeinline","content":[{"type":"text","text":".env"}]},{"type":"text","text":"文件中意味着他們不必修改提交的"},{"type":"codeinline","content":[{"type":"text","text":"docker-compose.yml"}]},{"type":"text","text":"文件,並在這個文件更新時處理衝突。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要使用env文件,只需增加一個"},{"type":"codeinline","content":[{"type":"text","text":".env"}]},{"type":"text","text":"文件,或者使用"},{"type":"codeinline","content":[{"type":"text","text":"env_file"}]},{"type":"text","text":"字段顯式設置路徑。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:使用override文件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/docs.docker.com\/compose\/extends\/","title":"","type":null},"content":[{"type":"text","text":"Override文件"}]},{"type":"text","text":"讓你有一個基本配置,然後在不同文件中指定修改。如果你使用Docker Swarm,並且有一個生產環境的YAML文件,這將非常有用。你可以在"},{"type":"codeinline","content":[{"type":"text","text":"docker-compose.yml"}]},{"type":"text","text":"中存儲自己的生產環境配置,然後在一個override文件中指定開發環境所需的任何更改,例如使用主機卷。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:使用"},{"type":"codeinline","content":[{"type":"text","text":"extends"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你正在用Docker Compose v2,你可以使用"},{"type":"codeinline","content":[{"type":"text","text":"extends"}]},{"type":"text","text":"關鍵字在多個地方導入YAML片段。例如,你可能有一個定義,你公司的所有服務在開發環境的Docker Compose文件中都有這5個特定的配置項。你可以定義一次,然後使用"},{"type":"codeinline","content":[{"type":"text","text":"extends"}]},{"type":"text","text":"關鍵詞來將它放到任何需要的地方,這就提供了一些模塊化特性。我們不得不在YAML中這樣做是很痛苦的,但我們能夠少寫一個程序來生成它還是最好的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Compose v3移除了對"},{"type":"codeinline","content":[{"type":"text","text":"extends"}]},{"type":"text","text":"關鍵詞的支持。然而,你可以使用"},{"type":"link","attrs":{"href":"https:\/\/support.atlassian.com\/bitbucket-cloud\/docs\/yaml-anchors\/","title":"","type":null},"content":[{"type":"text","text":"YAML anchors"}]},{"type":"text","text":"獲得類似的結果。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:程序生成Compose文件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們已經和一些使用"},{"type":"link","attrs":{"href":"https:\/\/blimpup.io\/","title":"","type":null},"content":[{"type":"text","text":"Blimp"}]},{"type":"text","text":"的工程團隊一起工作過,他們在開發環境的Docker Compose文件中有上百個容器。如果他們使用單個巨大的Docker Compose文件,就需要數千行無法維護的YAML代碼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"隨着擴展,可以編寫一個腳本,來基於一些高級別的規範生成Docker Compose文件。這對於具有非常大的開發環境的工程團隊來說是很常見的。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"錯誤4:脆弱的引導"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"docker-compose up"}]},{"type":"text","text":"是不是隻有一半時間工作?你是不是不得不使用"},{"type":"codeinline","content":[{"type":"text","text":"docker-compose restart"}]},{"type":"text","text":"來啓動崩潰的服務?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"大多數開發者都想要寫代碼,不想做DevOps工作。調試一個壞的開發環境是非常令人沮喪的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"docker-compose up"}]},{"type":"text","text":"應該每一次都好好工作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏的大多數問題都與服務啓動順序錯誤有關。例如,你的Web應用可能依賴一個數據庫,如果Web應用啓動時數據庫還沒有就緒,那麼它就會崩潰。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:使用"},{"type":"codeinline","content":[{"type":"text","text":"depends_on"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"depends_on"}]},{"type":"text","text":"使你能控制啓動順序。 默認地,"},{"type":"codeinline","content":[{"type":"text","text":"depends_on"}]},{"type":"text","text":"會等待依賴被創建,而不等待處於“healthy”狀態的依賴。然而,Docker Compose v2支持將depends_on與健康狀態檢查結合起來。(不幸的是,這個功能在Docker Compose v3中被移除了。你可以使用一個類似"},{"type":"link","attrs":{"href":"https:\/\/github.com\/vishnubob\/wait-for-it","title":"","type":null},"content":[{"type":"text","text":"wait-for-it.sh"}]},{"type":"text","text":"的腳本來手動實現類似功能)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Docker文檔建議不要使用類似"},{"type":"codeinline","content":[{"type":"text","text":"depends_on"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"wait-for-it.sh"}]},{"type":"text","text":"之類的方案。而且,我們同意,在生產環境,要求爲容器指定特定的引導順序是脆弱架構的一種標誌。然而,作爲一名試圖完成工作的開發人員,修復整個工程組織中的每一個容器可能是不可行的。因此,對於開發環境,我們認爲這是可以的。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"錯誤5:資源管理不善"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要確保Docker擁有它流暢運行所需的資源,而不會完全超出你的筆記本電腦負擔,可能是比較棘手的。如果你覺得自己的開發工作流由於Docker沒有以峯值容量運行而變得遲緩,那麼可以參考以下幾點。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:修改Docker Desktop分配"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Docker Desktop需要大量RAM和CPU,尤其是在Mac和Windows上它是一個虛擬機時。默認的Docker Desktop配置往往沒有分配足夠的RAM和CPU,因此我們一般建議調整設置到過度分配。我傾向於在開發時給Docker分配大約8GB RAM和4 CPU(在不使用Docker Desktop時,我會將它關掉,來使之可行)"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:刪除未使用的資源"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"人們在使用Docker時,經常會無意識地泄漏資源。人們擁有成百上千的卷、舊的容器鏡像以及如果不小心有時還會運行的容器,這並不少見。這就是爲什麼我們推薦偶爾運行"},{"type":"codeinline","content":[{"type":"text","text":"docker system prune"}]},{"type":"text","text":",刪除當前沒有使用的所有卷、容器和網絡。這會釋放大量資源。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解決方案:在雲上運行"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後,在某些情況下,即使有上述提示,也不可能在你的筆記本上運行所需的所有容器。如果是這樣的話,可以看看"},{"type":"link","attrs":{"href":"https:\/\/blimpup.io\/","title":"","type":null},"content":[{"type":"text","text":"Blimp"}]},{"type":"text","text":",這是一種在雲上運行Docker Compose文件的簡單方法。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"你應該做什麼?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了提升Docker Compose上的開發者體驗,我鼓勵你"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"最小化容器重新構建"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"使用主機卷"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"力求可維護的compose文件,就像代碼一樣。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"使你的引導可靠"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"用心管理資源"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文鏈接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/blimpup.io\/blog\/common-docker-compose-mistakes\/","title":null,"type":null},"content":[{"type":"text","text":"https:\/\/blimpup.io\/blog\/common-docker-compose-mistakes\/"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章