問題: 在某臺機器上運行正常的環(huán)境, 換到另外一臺機器就gp, 或需要很繁瑣的從頭配置,
浪費從幾小時到幾天不等的時間.
原因, 則通常包括環(huán)境的各個部分散落在不同角落, 不是少了這個就是少了那個, 或不同機器上版本不一樣;
還包括在配置中使用硬編碼的絕對路徑, 依賴全局環(huán)境變量或?qū)傩缘?
機器環(huán)境雖然各有各的不同, 但依然有可能創(chuàng)建一個"環(huán)境無關(guān)的環(huán)境"
1. 使用相對路徑代替絕對路徑
關(guān)鍵是如何獲得當前路徑, 如何確定根路徑, 如何確保目錄結(jié)構(gòu)
-
Windows和Unix都有內(nèi)置的環(huán)境變量來表示當前路徑, 分別是
%cd% 和 $PWD
-
Windows批處理腳本中, 還可以使用
%~dp0% 獲得腳本所在路徑; 而在Unix Bash 腳本中, 則可以使用 `pwd`,
即獲得 pwd 命令的輸出
-
如果總是需要引用某個根路徑的話, 則可以使用環(huán)境變量來定義根路徑(參見后面的環(huán)境變量).
其實相對路徑配合固定的目錄結(jié)構(gòu), 大大削減了對顯式定義根路徑的需求
-
那么如何保證目錄結(jié)構(gòu)是固定的呢? 自然是使用配置管理系統(tǒng)
2. 使用配置管理系統(tǒng)(版本控制系統(tǒng))
配置管理系統(tǒng)不只是放源代碼的, 只要有配置管理需求或配置管理能帶來好處, 或需要有唯一的官方來源,
都可以使用配置管理系統(tǒng)來管理; 環(huán)境的配置文件, 環(huán)境本身, 都可以置入配置管理之下. 有些公司的版本控制系統(tǒng)只放源代碼, 連測試代碼都分開另放.
-
強制使用配置管理可解決固定的目錄結(jié)構(gòu)的問題
-
使用配置管理還可以解決丟三落四的問題
-
自然也可以解決所用工具版本不一致的問題
這里有幾個常見的問題:
-
大型的系統(tǒng)軟件如何處理, 比如 JDK, VC++編譯器等, 是否也需要置入版本控制;
這個基本不用, 如果對其特定的版本有需求, 可在腳本中加入檢查其版本的邏輯, 不滿足則提示并退出即可
-
依賴的大量二進制庫如何處理; 如果有必要可使用依賴管理工具如 Maven, Ivy 等,
而用于存放依賴的本地倉庫依然應該置入配置管理, 哪怕不用其版本控制功能, 而只是利用其官方來源/備份存檔等好處
-
必須放在特定位置的文件如何處理, 比如某個文件必須放在/etc目錄下;
這個文件還是可以放在配置管理下的目錄中, 而在/etc下創(chuàng)建符號鏈接來指向它; 并提供腳本來干這件事.
3. 環(huán)境變量
必要時使用環(huán)境變量來引用環(huán)境. 全局的環(huán)境變量可用作缺省值,
在腳本中覆蓋它(基本上, 這是"用戶自定義屬性"的一個實例).
4. 缺省值 + 用戶自定義屬性
這是創(chuàng)建"環(huán)境無關(guān)的環(huán)境"的核心機制. 無論如何, 環(huán)境要在不同機器上部署, 總會需要修改某些配置,
以適應宿主機器. 然而前面我們提到, 所有配置都已置入版本控制. 如果我們直接修改, 則每個環(huán)境中都會存在未提交的本地修改. 這是我們不希望看到的,
因為當我們升級配置并更新到所有部署時, 可能會產(chǎn)生沖突. 這里其實是兩個層面的問題:
- 提供一種機制, 當環(huán)境與缺省配置不一致時, 允許用戶修改
- 用戶修改的文件應避免與官方文件更新的沖突
先說第一個.
缺省值當然可以直接定義在腳本或配置文件中.
而多數(shù)常用的腳本和配置系統(tǒng)都提供了用戶定義屬性覆蓋缺省值的機制. 比如:
-
Windows批處理: set
path=my_extra_path;%path%
-
Bash: export PATH=my_extra_path:$PATH
-
Ant:
<property file="user.properties"/>
<!-- user.properties 中可定義任何后面引用到的屬性, 以覆蓋其缺省值-->
<property name="src.dir"
path="${basedir}" /> <!-- 定義"src.dir"的缺省值-->
-
CruiseControl:
<property name="src.dir"
value="." /> <!-- 定義"src.dir"的缺省值-->
<property file="user.properties"/>
<!-- user.properties 中可定義任何后面引用到的屬性, 以覆蓋其缺省值-->
-
注意Ant的屬性是只讀的, 先入為主. CruiseControl的屬性則是后發(fā)制人.
再說第二個.
有一個很簡單的解決辦法, 就是把用戶自定義屬性置入單獨的文件,
并且不要把它提交到版本控制系統(tǒng)中(一個理由是這一部分相對整個組織來說, 不存在也不需要唯一的官方來源)
前面例子中的 user.properties 就是一個用戶自定義屬性文件,
只存在每個用戶自己的機器上, 不在配置庫中. 在Windows和Bash腳本中也可以類似處理
-
Windows: call
user_env.bat
-
Bash: source ./user_env.sh
或 . ./user_env.sh
隨之而來的一個問題是, 這個用戶相關(guān)的文件應該放在何處. 這里其實約定好就可以了, 比如當前路徑,
根路徑, 甚至user的home路徑都可以
參考借鑒
-
至此, 這套東西在不同的機器上部署時, 只要從版本控制系統(tǒng)中check out出來即可使用了.
更進一步, 還可以提供腳本, 即生成器, 自動探測用戶的環(huán)境, 來生成全套配置, 類似Rails生成應用框架那樣.
-
其實, 這是一個規(guī)范性或標準性的問題. Neal Ford 在<<Productive
Programmer: 卓有成效的程序員>>中, 用一章的篇幅詳述了各種解決方案, 包括配置管理, 符號鏈接等, 除此之外,
他還建議可以/應該使用虛擬機來統(tǒng)一項目組的開發(fā)環(huán)境等. 參見<<Productive Programmer: 卓有成效的程序員>>第五章.
-
另請參閱<<CruiseControl
Enterprise 最佳實踐 (3) : Configuring CruiseControl the CruiseControl way>>,
是創(chuàng)建環(huán)境無關(guān)的持續(xù)集成環(huán)境的實例