應用運維需要考慮的一個重要問題就是遷移, 在不同機器、機房、環境間遷移。遷移的原因有很多, 比如硬體過保(硬體故障), 機房遷移, 應用擴縮容等。
應用遷移的核心需求是:
簡單。遷移操作必須足夠簡單, 沒有學習成本, 點選一下即可。
快速。遷移過程能在極短的時間内完成。
無損。遷移之後應用與原應用一模一樣, 不丢失任何配置和資料。遷移之後應用功能和業務邏輯與原部署應用一模一樣,無任何業務風險。
許多公司還在使用古老的 rhel 5/6 和 linux 2.6.x 核心, 難以充分發揮現代作業系統和硬體的能力, 部分原因也是受制于應用遷移技術不成熟, 不能保證快速無損遷移應用, 不敢遷移。
具備快速遷移的能力, 同樣可将應用快速切換到任意版本, 實作快速復原。
<a></a>
我們看一下一個基于 tomcat 部署的 java webapp 應用部署結構如下:
其主要分為兩個部分:
靜态二進制檔案。包含 <code>bin/</code>, <code>lib/</code>。這部分是三方軟體包 tomcat 自帶的内容。對應用而言, 這部分内容是隻讀通路的, 不會修改。
外部配置和資料。包含 <code>conf/</code>, <code>logs/</code>, <code>temp/</code>, <code>webapps/</code>, <code>work/</code>。這裡的“外部”是指從 tomcat 軟體包的角度來看, 對應用來說, 這部分才是真正的應用軟體包。
注意: tomcat 軟體包也包含 <code>conf/</code>。但應用可能會對 <code>conf/</code> 進行修改, 是以應用使用了一個獨立維護的 <code>conf/</code> 副本, 而不是 tomcat 軟體包自帶的 <code>conf/</code> 内容。
很顯然, 要遷移這個應用, 隻需要遷移第 2 部分, 即外部配置和資料即可。為了簡化遷移, 許多應用被設計為無狀态的, 即 <code>logs/</code>, <code>temp/</code>, <code>work/</code> 等外部資料目錄不包含任何影響應用功能的配置或資料, 這部分内容不需要遷移。隻需要遷移 <code>conf/</code>, <code>webapps/</code> 目錄, 這部分内容可打包為應用軟體包。
這樣, 在新環境部署應用, 隻需要安裝 tomcat 軟體包和應用軟體包即可。
在新環境上完成應用部署, 有兩種玩法:
列一個軟體包清單 (如上例中的 tomcat 和應用), 在新環境上按照清單完成軟體包安裝, 這是 juju 的玩法。
将所有軟體包安裝好并打包成一個二進制鏡像, 拷貝到新環境上部署運作, 這是 docker 的玩法。dockerfile 描述如何建立鏡像, 類似于軟體包清單。
docker 鏡像不止是預安裝軟體包, 還包含基礎作業系統環境, 統一的日志、資料路徑, 環境變量等标準化應用運作環境。這可難不倒 juju, juju 同樣基于一個标準鏡像建立 vm 或 lxc 容器, 再安裝軟體包, 同樣提供标準化的運作環境。這兩種方式各有優缺點, 在此不作深究。但就使用成本來說, docker 目前在國内外發展火熱, 技術和實踐經驗相對成熟, 更容易使用。
使用 docker 應用容器部署應用, docker 容器為應用提供了标準一緻且互相獨立的運作環境, 這樣應用使用相同的配置和路徑, 也可以在單個主控端上實作多執行個體部署。與 vm 的單機單部署模式相比, 應用容器要做的足夠輕, 消除 vm 的額外開銷, 并且完美支援微服務編排。
有些軟體包很好的實作了軟體包預設配置與應用自定義配置的分離, 如 tomcat, 隻需指定 catalina_base 目錄與 catalina_home 目錄分開, 将應用部署到 catalina_base 下, 即可實作應用自定義配置和 tomcat 軟體包預設配置分離, 兩者獨立維護, 互不影響。
許多軟體包沒有實作這樣的能力, docker 通過分層檔案系統解決這個問題, 同時可以避免每個軟體包都去考慮設計配置分離功能。
應用自定義配置在軟體包安裝層的上層, 運作容器時覆寫預設配置, 但在軟體包安裝層更新軟體包時看不到應用自定義配置, 不會受應用自定義配置影響。需要注意的是, 軟體包更新後是否相容舊的應用自定義配置, 是否需要更新自定義配置, 需要應用負責人關注和測試。
按照 docker 的分層設計思想, 越基礎越固定不變的東西越要放到底層, 越容易變化的東西越要放到上層, 是以應用依賴的軟體包和基礎配置要放到底層, 可以獨立為一個 base 鏡像, 應用本身和自定義配置放在上層。如果應用本身或配置更新更頻繁, 可将這兩者再分成兩層。
假設我們要修改一個應用配置, 一種方式是登陸一台機器修改, 測試 ok 後将修改同步到所有其他機器。這種方式很原始并且缺乏監管, 容易出錯。比如新擴容了 100 台機器每台都要更新一遍, 如果操作有遺漏, 哪些機器配置已經更新, 哪些機器還是舊的配置也缺乏監管。
按 docker 的玩法, 應該是先更新鏡像, 測試 ok 後分發鏡像到所有機器更新容器。docker 監管了所有容器部署的鏡像版本和容器狀态, 進而可以很友善的檢查哪些容器更新了, 哪些沒有更新。對于很少變化的靜态配置, 應該固化到鏡像中。
對于一些經常變化的配置, 重新打鏡像和更新容器成本太高, 應該設計成預定義的開關, 使用開關平台進行監控和管理, 或者使用 diamond 等配置管理平台管理。
docker 容器内的檔案系統伴随容器而生, 銷毀或更新容器時 (如更新鏡像或修改容器配置), 原有資料将會丢失。并且受分層檔案系統設計影響, 其性能可能更差(與存儲引擎實作有關)。
dockerfile 中使用 <code>volume</code> 指定容器中需要挂載為資料卷的目錄清單。
綜上所述, docker 化運維需要将應用拆分為 3 部分:
基礎環境, 應用所有依賴, 應用軟體包和靜态配置, 固化到鏡像。
需要動态修改的配置, 通過開關平台或 diamond 等配置平台進行管理。
需要持久化儲存或頻繁寫需求的配置或資料目錄, 挂載為資料卷。
部署運維時, 使用 docker 分發鏡像, 配置平台推送配置, 即可實作應用快速部署、遷移、更新、復原、擴縮容等運維操作。