記錄我們遷移到Docker的挑戰和經驗教訓

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"幾周之前,我們宣佈了"},{"type":"link","attrs":{"href":"https:\/\/www.artifakt.com\/blog\/product\/artifakt-any-app-platform-powered-by-container-technology\/","title":"xxx","type":null},"content":[{"type":"text","text":"最新的產品"}]},{"type":"text","text":"發佈,以及由容器技術和Docker支持的Artifakt平臺的全新的任意App功能。"}]},{"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":"在過去幾年中,Artifakt一直專注於PHP棧。但PHP並不是Web應用程序的唯一語言。通過使用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":"基於應用程序打包的事實標準來重新調整我們的PaaS,對於各種形式和規模的開發團隊來說都是一個好消息。"}]},{"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":"在這個版本中,你會發現許多額外的功能,在代碼、更改可跟蹤性、運行時性能和客戶價值等方面,現在是加入容器友好型PaaS基礎設施的最佳時機。更不用說,Docker是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":"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":"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":"PaaS解決方案非常方便。我相信任何從本地部署服務或IaaS遷移其應用程序到PaaS的人都會同意。"}]},{"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":"其中很方便的一點是虛擬機(Virtual Machines,VM)的使用。這是一款很好的軟件,幾十年來至今,都非常安全和成熟。現在沒有人做事情能離得開它們,所以它們是非常必要的。儘管如此,這還不夠。"}]},{"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":"現在,面對痛苦的現實:虛擬機已經不再適應雲基礎設施。目前的條件對它們來說是苛刻的,可能採用嚴格的規章制度。儘管科技領域不斷髮展,但虛擬機仍然建立在20年前相同的原則上。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"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":"你應該時刻記住所有可能出錯的情況並做好準備。讓我們看一看容器遷移過程中可能出現的幾個問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"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":"text","text":"我們以前都聽過,速度是所有戰鬥之母。不僅是在戰略上,而且從構思到執行都是如此。變化需要快速發生,跟上生態系統的快速進化。正如通用電氣前CEO傑克·韋爾奇(Jack Welch)所說:“如果外部變化的速度超過內部變化的速度,終結就不遠了。”"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/9f\/9ff4ddbf5ece1fea88d7c8a707ced6e9.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":null,"origin":null},"content":[{"type":"text","text":"不是大喫小,而是快喫慢。擁有好主意,但是執行慢,意味着死刑。擁有糟糕的主意,但是執行良好,意味着你仍然可以調整和實驗直到適應市場獲得成功。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"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":"如果你在一個軟件項目中聽過“但是......它在我的筆記本電腦上可以運行!”,請舉手——我懷疑我會看到很多人舉手。當然,我們有代碼、持續集成和所有現代機器等基礎設施。別誤會,有一些本地優化確實非常有用。但真正有用的是打破侷限,將團隊提升到足夠高的成熟度水平,以便“誰構建誰運行”。"}]},{"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":"我們不希望PaaS成爲新的“運維問題”和“支持問題”。還記得“災難女孩”咒語嗎?黑暗運維更加危險,你不希望開發團隊自己運行容器,"},{"type":"link","attrs":{"href":"https:\/\/blog.newsblur.com\/2021\/06\/28\/story-of-a-hacking\/","title":"xxx","type":null},"content":[{"type":"text","text":"並在你的防火牆上戳洞"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"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":"回想20世紀,全球化是通過一個非常具體的物質變化實現的:一個通用的箱子來移動汽車、食品等等。這就是我們今天所知道的“多式聯運(inter-modal transportation)”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/4d\/4d6f47084ded8817b3a32fde7c164a04.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":"center","origin":null},"content":[{"type":"text","text":"圖片來源:Docker Inc."}]},{"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":"自2014年以來,軟件容器在Docker Inc.公司旗下的事實解決方案中迅速成熟,並有一個簡單卻有效的承諾:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"“無論底層執行系統是什麼,Docker都可以使用完全相同的代碼逐字節運行它。”"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/9f\/9fac5ee09c18f018dbe206e00d131a44.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":"center","origin":null},"content":[{"type":"text","text":"圖片來源:Docker Inc."}]},{"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":"我們敢說,在Artifakt,容器已經在後臺運行了好幾個月,即使是有狀態的東西。我們現在可以在幾秒中內運行不同的配置更改,而不是需要10到30分鐘的虛擬機配置。"}]},{"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":"在我們的下一個主要控制檯版本中,Artifakt將容器作爲部署單元公開。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"轉變與見證:我們如何讓Magento 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":"你可以想象Docker遷移對我們日常工作的開創性影響。協調虛擬機需要與我們的雲提供商在某種專有技術上進行強耦合。對於AWS來說,是CloudFormation和OpsWorks。我們花了很多時間消化雲的複雜性,這樣我們親愛的客戶就不必這麼做了。"}]},{"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、docker-compose.yaml 和穩定的Docker API。"}]},{"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":"在筆記本上運行完全相同的Magento 2棧並將其投入生產如何?這在Artifakt是可能的。"}]},{"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":"Magento 2是自7月早些時候發佈"},{"type":"link","attrs":{"href":"https:\/\/headwayapp.co\/artifakt-updates\/stack-5-0-with-docker-inside-201413","title":"xxx","type":null},"content":[{"type":"text","text":"Stack v5"}]},{"type":"text","text":"以來我們正式支持的九個運行時的一部分。在許多方面,這個發佈版本將所有挑戰集中在一個地方:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"crontab管理"}]}]},{"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":"ISO生產環境本地堆棧"}]}]}]},{"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遷移部分 I: 好的方面先從Docker的好處開始。我們已經意識到在PaaS環境中容器化的好處。有些方面真的很容易實現。成熟度足夠高,生態系統蓬勃發展,雲供應商已經爲未來幾年鋪平了道路。"}]},{"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":"我們不可能一一講述所有的好處,很多好處在2021年講都會很無聊,所以讓我把重點放在最有啓發性的事情上。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"好處 #1:使用Argo的工作流引擎"}]},{"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:\/\/argoproj.github.io\/argo-workflows\/","title":"xxx","type":null},"content":[{"type":"text","text":"Argo Workflows"}]},{"type":"text","text":"是實現響應式GitOps管道的一個非常好的工具。要講的有很多,讓我們拆開來一個個講。GitOps使團隊能夠執行Git中的更改,而不僅僅是代碼更改,比如基礎設施、網絡、存儲等。機器的每一個部分,創建、升級或停用,都可以鏈接到一個Git提交。"}]},{"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":"感覺興奮嗎?我們確實很興奮!我們的工作流很好地隱藏在Argo中,可以爲許多不同的堆棧和語言運行部署任務等基礎操作。"}]},{"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":"在未來,我們也期待着嘗試Argo CD以及它爲像Artifakt這樣的PaaS產品提供的許多機會。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"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":"事實證明,Docker鏡像有很多出錯的方式。由於自動測試在代碼中是一種很好的實踐,同樣的原則也適用於Dockerfiles。官方文檔已經確保了Dockerfile的正確性:所有命令都應該返回0,否則構建將失敗。"}]},{"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":"我們可以只使用本機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":"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":"對於簡單的語法格式化,我們使用hadolint,這是針對Dockerfiles的一種格式化工具。它功能強大,很容易上手,可以與持續集成\/持續部署很好地集成,並得到了積極的維護。當然,它本身就存在於一個Docker鏡像中!讓我們看一下基本選項:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"hadolint - Dockerfile Linter written in Haskell\n\n\nUsage: hadolint [-v|--version] [--no-fail] [--no-color] [-c|--config FILENAME]\n \t[-V|--verbose] [-f|--format ARG] [DOCKERFILE...]\n \t[--error RULECODE] [--warning RULECODE] [--info RULECODE]\n \t[--style RULECODE] [--ignore RULECODE]\n \t[--trusted-registry REGISTRY (e.g. docker.io)]\n \t[--require-label LABELSCHEMA (e.g. maintainer:text)]\n \t[--strict-labels] [-t|--failure-threshold THRESHOLD]\n \t[--file-path-in-report FILEPATHINREPORT]\n Lint Dockerfile for errors and best practices"}]},{"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":"要在持續集成中包含hadolint ,我們建議以下三個步驟:"}]},{"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":"使用--no-fail 調用hadolint ,並在不中斷當前流的情況下安全地評估結果。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"在使用選項並找到恰當的平衡點後,對測試的Dockerfile進行必要的修復。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"刪除--no-fail 選項,並將hadolint 作爲強制步驟啓用。"}]}]}]},{"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":"爲了演示hadolint 有多好,讓我們看一下我們的Docker基礎鏡像中的這條簡單命令:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"$ docker run --rm -i hadolint\/hadolint:v2.6.0 hadolint - < .\/akeneo\/5-apache\/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":"接着會給出一個附帶嚴重程度(從style到error)的建議列表,附帶有具體的行號,非常整潔。例如:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"-:16 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using \/bin\/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to \/bin\/ash, or disable this check\n-:17 DL3008 warning: Pin versions in apt get install. Instead of `apt-get install ` use `apt-get install =`\n-:17 DL3059 info: Multiple consecutive `RUN` instructions. Consider consolidation."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所有規則,70多條,都在"},{"type":"link","attrs":{"href":"https:\/\/github.com\/hadolint\/hadolint\/wiki","title":"xxx","type":null},"content":[{"type":"text","text":"官方庫的wiki中"}]},{"type":"text","text":"有參考和解釋。它們包括非常基礎的簡單檢查(“不要使用apt-get upgrade”)到高度專業化的用例(“運行yarn install之後,沒有運行yarn cache clean”)。"}]},{"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":"結合在一起,hadolint 選項更加強大。看看這個命令:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"docker run --rm -i hadolint\/hadolint:v2.6.0 hadolint --require-label author:text --ignore=DL4006 --failure-threshold=warning - .\/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":"在這段代碼中,我們告訴hadolint 去掃描我們的Dockerfile文件,通過檢查一個強制標籤author ,除了DL4006規則,最後,只有在反饋包含警告時纔會失敗,從而忽略style 和info 級別。"}]},{"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":"對於開發人員來說,hadolint 還支持Dockerfile中的#ignore 內聯註解,這使得在一組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":"總而言之,這爲我們的測試提供了一個良好的開端。稍後,當我們準備好應用更高級別的良好實踐時,我們可以降低錯誤閾值到notice 。"}]},{"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鏡像是非常棒的。現在,我們還需要檢查內容的有效性。畢竟,PaaS產品應該有一套應用的內部規則。"}]},{"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:\/\/github.com\/GoogleContainerTools\/container-structure-test","title":"xxx","type":null},"content":[{"type":"text","text":"container-structure-test"}]},{"type":"text","text":"。它是Github上GoogleContainerTools命名空間的一部分,在這個命名空間下還託管了一些你可能已經知道或使用過的著名項目:Skaffold、distroless、Jib和Kaniko。"}]},{"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":"Container-structure-test是一個開源項目,讀取測試套件並對照現有的Docker鏡像進行檢查。它有一個命令:test 。注意,這與hadolint 不同,hadolint只需要一個純文本的Dockerfile文件就足夠了。Container-structure-test需要一個二進制構件:Docker鏡像或者一個導出爲.tar的文件。和hadolint 一樣,測試也是用普通的YAML編寫的,這似乎是雲生態系統中第二有用的技能(僅次於Git,對吧?)。下面是用YAML編寫的一個有意思的聲明式測試示例:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"schemaVersion: '2.0.0'\nmetadataTest:\n labels:\n\t- key: 'vendor'\n \tvalue: 'Artifakt'\n\t- key: 'author'\n \tvalue: \"^\\\\w+([-+.']\\\\w+)*@\\\\w+([-.]\\\\w+)*\\\\.\\\\w+([-.]\\\\w+)*$\"\n \tisRegex: true\n volumes: []\n entrypoint: [\"\/usr\/local\/bin\/docker-entrypoint.sh\"]\n\n\nfileExistenceTests:\n- name: 'bash'\n path: '\/bin\/bash'\n shouldExist: true\n permissions: '-rwxr-xr-x'\n uid: 0\n gid: 0\n isExecutableBy: 'any'\n\n\ncommandTests:\n - name: \"debian based server\"\n\tcommand: \"which\"\n\targs: [ \"apt-get\"]\n\texpectedOutput: ['\/usr\/bin\/apt-get']"}]},{"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":"在這個代碼塊中,我們測試了一個鏡像的元數據、文件和命令結果,分別由metadataTest 、fileExistenceTests 和commandTests 三個主鍵定義。"}]},{"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":"但是爲什麼container-structure-test需要一個預先存在的構建步驟呢?因爲,在後臺,它在活躍容器上使用docker exec 命令來運行每一個測試。最重要的是,由於一個容器只能運行一個測試,所以測試也保證是隔離的。"}]},{"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":"當你運行測試時使用--save 選項來保持容器,這個行爲就很容易查看。讓我們在一個官方鏡像上運行如下測試:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"container-structure-test test --image registry.artifakt.io\/sylius:1.10-apache --save --config .\/global.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":"檢查保存的容器:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"caae8bd3159c \t678b262bc2d6 \t\"NOOP_COMMAND_DO_NOT…\" 2 minutes ago \tCreated \tpractical_einstein\n3b63b4f5fcd1 \tregistry.artifakt.io\/sylius:1.10-apache \"NOOP_COMMAND_DO_NOT…\" 2 minutes ago \tCreated \tadmiring_solomon\n44497e1d88cf \td10ef6baba46 \t\"which apt-get\" \t2 minutes ago \tExited (0) 2 minutes ago \tbold_tesla\n6e87be191af3 \tregistry.artifakt.io\/sylius:1.10-apache \"NOOP_COMMAND_DO_NOT…\" 2 minutes ago \tCreated \tangry_bouman"}]},{"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 logs 或docker diff 檢查保存的容器以及它們如何受影響時,這非常有用。使用最後一個命令,我們可以輕鬆編寫一個測試來確保我們的容器是足夠無狀態的,或者不會泄露意料外的文件,或者對活躍容器進行任何其它評估。"}]},{"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":"正如我們在第一個示例中已經提到的,container-structure-test評估三類開箱即用的檢查:鏡像元數據(labels、volumes和entrypoints等等)、文件是否存在、任意命令結果。"}]},{"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":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"fileExistenceTests:\n- name: 'forbid gcc'\n path: '\/usr\/bin\/gcc'\n shouldExist: false"}]},{"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":"最後,另一個有用的選項是將setup 關鍵詞與測試命令結合使用。有些測試只在Docker入口點運行之後纔有意義。我們使用setup 鍵來處理這種情況。請看下面的示例:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"- name: \"check mounted folder private\"\n\tsetup: [[\"\/usr\/local\/bin\/docker-entrypoint.sh\"]]\n\tcommand: \"ls\"\n\targs: [ \"-la\", \"\/opt\/drupal\/web\/sites\/default\/private\"]\n\texpectedOutput: [ 'lrwxrwxrwx 1 www-data www-data .+ \/opt\/drupal\/web\/sites\/default\/private -> \/data\/web\/sites\/default\/private' ]"}]},{"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":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Docker遷移部分 II:壞的方面(和有趣的方面!)"}]},{"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":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"挑戰 #1:crontab集成"}]},{"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":"我們最完整的運行時是Magento 2和Akeneo,它們是cron任務的重度用戶:索引、緩存、鏡像大小調整、導入\/導出等等。"}]},{"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 101中衆所周知,你不能在與主進程相同的容器中運行cron。"}]},{"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":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Swarm cronjob"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"cron job containers"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Docker exec bridge"}]}]}]},{"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剛剛升級了Swarm編排層來運行cron作業,就像Kubernetes那樣。這可能行得通,但是Swarm不在我們最初的路線圖上。"}]},{"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":"其次,我們可以爲每個cron作業運行額外的容器,在節點級別使用一個cron守護進程。這個方法有利有弊。由於時間和計劃的限制,我們不得不加快步伐。"}]},{"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":"最後,我們可以聲明將crontab保持在節點級別,並使用docker exec 將命令運行到活躍的容器中。這可能起作用,因爲我們仍然在每個服務器上運行一個應用程序容器,所以現在這是有意義的。"}]},{"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":"我們選擇了最後一個選項,結果是簡單、優化,並且尊重我們熱愛的Linux精神。下面是將cron作業注入到活躍容器的三個簡單步驟:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"步驟 1"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"編寫一個docker exec 包裝器,其中實際上有2行代碼足以指向 容器。"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"#!\/bin\/bash\nsudo docker exec -t sh -c \"$2\""}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"步驟 2"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"將包裝器保存在crontab用戶空間的某個地方(我們將其命名爲dockercron.sh)。"}]},{"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":"用你的腳本添加\/替換默認的contab SHELL env. var :"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"### Crontab Managed By Artifakt ###\nSHELL=\/home\/ec2-user\/dockercron.sh\n5\/* * * * * uptime > \/tmp\/uptime.txt"}]},{"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":"步驟 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 events 並檢查crontab是否正在調用應用程序容器:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"2021-07-28T13:55:02.338665047Z container exec_create: sh -c uptime > \/tmp\/uptime.txt a360afb6e (artifakt.io\/image=616787838396.dkr.ecr.eu-west-1.amazonaws.com\/sylius, execID=8b14a4e96eb5175c74b689260e1b692af34f22260e9572fbd2bb2c2b663a3c1e, image=616787838396.dkr.ecr.eu-west-1.amazonaws.com\/sylius:1.10, vendor=Artifakt)\n2021-07-28T13:55:02.339417333Z container exec_start: sh -c uptime > \/tmp\/uptime.txt a360afb6e (artifakt.io\/image=616787838396.dkr.ecr.eu-west-1.amazonaws.com\/sylius, execID=8b14a4e96eb5175c74b689260e1b692af34f22260e9572fbd2bb2c2b663a3c1e, image=616787838396.dkr.ecr.eu-west-1.amazonaws.com\/sylius:1.10, vendor=Artifakt)\n2021-07-28T13:55:02.822814763Z container exec_die a360afb6e (artifakt.io\/image=616787838396.dkr.ecr.eu-west-1.amazonaws.com\/sylius, execID=8b14a4e96eb5175c74b689260e1b692af34f22260e9572fbd2bb2c2b663a3c1e, exitCode=0, image=616787838396.dkr.ecr.eu-west-1.amazonaws.com\/sylius:1.10, vendor=Artifakt)"}]},{"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":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"挑戰 #2:取消OpsWorks"}]},{"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":"從OpsWorks到Docker的轉變,需要將移除過去的平臺規則,並轉移到編寫docker-compose YAML和bash腳本。結果是我們所有的部署都是一個獨特的分支。"}]},{"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":"經過快速的多次提交,並經過許多嘗試和錯誤後,OpsWorks現在所做的就是安裝Docker Engine以及屈指可數的一些容器依賴項。"}]},{"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 API操作,由普通的過去的OpsWorks作業觸發,比以往任何時候都更可預測。"}]},{"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":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"挑戰 #3:本地運行HTTPS"}]},{"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":"當我們接近發佈時間時,我們的CEO看了看我們的demo,說:“嘿,如果開發者可以用HTTPS本地運行他們的應用程序,那就太好了”。作爲開發者,團隊中的每個人都馬上理解了這個機遇。"}]},{"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":"工作站越接近生產環境,我們送出的bug就越少。這是表達"},{"type":"link","attrs":{"href":"https:\/\/12factor.net\/","title":"xxx","type":null},"content":[{"type":"text","text":"12因素應用程序"}]},{"type":"text","text":"的"},{"type":"link","attrs":{"href":"https:\/\/12factor.net\/dev-prod-parity","title":"xxx","type":null},"content":[{"type":"text","text":"第10章"}]},{"type":"text","text":"——“dev\/prod對等”的另一種方式。"}]},{"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":"下面是我們如何做到的。只需要2個附加組件(容器!):"},{"type":"link","attrs":{"href":"https:\/\/github.com\/nginx-proxy\/nginx-proxy\/","title":"xxx","type":null},"content":[{"type":"text","text":"Nginx-proxy"}]},{"type":"text","text":"和"},{"type":"link","attrs":{"href":"https:\/\/github.com\/sebastienheyd\/docker-self-signed-proxy-companion","title":"xxx","type":null},"content":[{"type":"text","text":"Cert companion"}]},{"type":"text","text":"。我們使用它們修改了原始的docker-compose.yaml ,除此之外沒有修改其它代碼:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"version: '3'\nservices:\n proxy:\n\timage: jwilder\/nginx-proxy\n\tcontainer_name: base-wordpress-proxy\n\trestart: always\n\tports:\n \t - \"8000:80\"\n \t - \"8443:443\"\n\tvolumes:\n \t - \/var\/run\/docker.sock:\/tmp\/docker.sock:ro\n \t - .\/certs:\/etc\/nginx\/certs\n\n\n proxy-companion:\n\timage: nginx-proxy-companion:latest\n\trestart: always\n\tenvironment:\n \t - \"NGINX_PROXY_CONTAINER=base-wordpress-proxy\"\n\tvolumes:\n \t - \/var\/run\/docker.sock:\/var\/run\/docker.sock:ro\n \t - .\/certs:\/etc\/nginx\/certs"}]},{"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":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":" app:\n\timage: base-wordpress:5-apache\n\tvolumes:\n \t - \".:\/var\/www\/html\"\n\tenvironment:\n \t VIRTUAL_HOST: \"localhost\"\n \t SELF_SIGNED_HOST: \"localhost\""}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在第一次運行時,nginx 尋找一個ca.cert ,如果不存在就在線爲你生成一個。然後,我們必須告訴瀏覽器要像信任其它CA一樣信任這個ca.cert 。遺憾的是,這仍然需要一次手工設置。"}]},{"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":"我們嘗試了Let's Encrypt等各種方案,但沒有開箱即用的解決方案。"},{"type":"link","attrs":{"href":"https:\/\/letsencrypt.org\/docs\/certificates-for-localhost\/","title":"xxx","type":null},"content":[{"type":"text","text":"你不能使用Let's Encrypt作爲一個CA來提供本地主機證書。"}]}]},{"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":"最後,還需要一些額外的步驟,通常會弄亂本地的根證書。下面是我們爲開發人員找到的一條最短路徑,即一次性安裝本地證書頒發機構並在所有本地開發堆棧上使用它。請注意,以下步驟僅適用於Google Chrome。"}]},{"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":"打開Chrome設置並搜索“certificates”。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"打開Manage Certificates菜單,它會彈出密鑰鏈入口。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"在System密鑰鏈,打開Certificate選項卡,將ca.cert從Nginx-Proxy Companion中刪除。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"雙擊Nginx-proxy Companion證書爲Always Trust。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/37\/37c9621647b35de8e968cf9debb50d5f.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":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Docker 遷移部分 III:"}]},{"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","marks":[{"type":"strong"}],"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":"我們嚴重依賴AWS持久化數據。這已經"},{"type":"link","attrs":{"href":"https:\/\/www.artifakt.com\/blog\/cloud\/building-scalable-resilient-applications-using-aws\/","title":"xxx","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","marks":[{"type":"strong"}],"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":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代理依賴管理器(例如composer、npm、maven)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Docker層緩存,而不是原始構建環境"}]}]},{"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":"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鏡像需要一個實時數據庫來完成構建階段。這聽起來有點兒奇怪,但我們經常看到這樣的情況。我們正考慮以下幾條實例:"}]},{"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":"當兼容的時候,使用SQLite作爲卷——不需要服務器"}]}]}]},{"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的經歷。如果你當前正在遷移到容器或者希望遷移到容器,我希望你能夠在本文中找到一些有用的點子。"}]},{"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:\/\/feedback.artifakt.io\/tabs\/5-coming-soonhttps:\/\/feedback.artifakt.io\/tabs\/5-coming-soon","title":"xxx","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","marks":[{"type":"strong"}],"text":"作者介紹:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Djalal Elbe"}]},{"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","marks":[{"type":"strong"}],"text":"原文鏈接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/www.artifakt.com\/blog\/cloud\/documenting-our-migration-to-docker","title":"xxx","type":null},"content":[{"type":"text","text":"Documenting our migration to Docker—challenges and lessons learned"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章