:::

「布丁布丁吃什麼?」在GitHub上開放原始碼囉! / My Blog is now open source on GitHub!

布丁布丁吃布丁

「布丁布丁吃什麼?」在GitHub上開放原始碼囉! / My Blog is now open source on GitHub!

image

布丁布丁吃什麼?」這個Blog最大的特徵就在於網站上有著許多奇奇怪怪的小功能。從側邊欄上的「最近留言」、「最新文章」「留言板」,到文章本身的「自動摘要法」「圖片延遲載入」等各種小工具,都是Blogger沒有提供、我參考別人的寫法或自己撰寫而成的功能。

現在這些程式碼統一保存在GitHub上進行版本控制。對於改造Blogger有興趣的朋友、JavaScriptCSS有興趣的朋友,歡迎參考我的程式碼,彼此多多切磋交流吧。

Welcome to Pulipuli.blogspot.tw. My blog has many features which are not provided by Blogger, for examples, like “recent response list”, “recent post list”, “post auto digest”, etc.. Today, I released the code of these features on GitHub. You can use them freely. Enjoy it!

存放空間的遷移歷程 / History of Code Hosting

說真的,「布丁布丁吃什麼?」很早之前就是Open Source了。除了Blogger內建功能之外,大部分功能都是以JavaScript與CSS的程式碼來實作。這些程式碼本身都是必須讓你下載之後才能執行,換句話說,這些功能本身就是「開放」的程式碼了。

那麼這些程式碼是存在哪裡呢?這邊我就在簡單的回顧中記錄一下「布丁布丁吃什麼?」的這段歷史吧。

Google Page Creator

我印象中「布丁布丁吃?」時期一開始的時候,我是將程式碼擺放在Google Page Creator中。Page Creator是Google早期供人架站的空間。雖然它只有提供100MB的大小,在流量上也有諸多限制,但是擺放我這種小流量Blog使用的JavaScript與CSS程式碼已經很夠用了。

不過老實說它不太好用,沒有目錄功能(因為Page Creator是用來建立網頁、而不是網站),上傳介面也很難操作。幾年之後,Page Creator被關閉,成為歷史名詞。而原本在Page Creator上的程式碼則是被轉換到Google協作平台上繼續運作。

Google Sites協作平台

image

由於Google Page Creator被關閉,我的程式碼就順勢移到了Google協作平台上,叫做「布丁布丁吃?」wiki。協作平台搭上了當時流行的wiki風格,讓人容易在網頁上建立資料,也允許更複雜的網站架構。

協作平台是個穩定的架站空間,我一樣把它用來存放JavaScript與CSS程式碼。受惠於協作平台的功能,我可以將程式碼分門別類,每次上傳檔案也會記錄不同的版本。在「布丁布丁吃什麼?」介紹的功能中,有些是獨立出來讓讀者安裝使用的程式碼,這些程式碼就會放在協作平台中,跟「布丁布丁吃什麼?」專用程式碼分開保存。

可惜的是,協作平台的上傳功能依然很難用。點開網頁、選擇檔案、上傳的這幾個步驟雖然看起來很簡單,但是時常修改程式碼的話,這些步驟依然是相當地煩人啊!

Dropbox

image

「布丁布丁吃什麼?」的程式碼中,給讀者使用的程式碼是放在協作平台,而現在你所看到「布丁布丁吃什麼?」專用的JavaScript與CSS程式碼其實是架設在Dropbox的公開資料夾Public底下。

知名雲端硬碟Dropbox早在很久之前就提供了架站空間的功能,你可以把網頁程式碼放在公開資料夾上供他人瀏覽,也可以用DropPages之類的第三方應用輕易地架起專業網站。

雖然我的網頁內容寫在Blogger上,不過JavaScript與CSS卻也可以放在Dropbox中。我這次搭配Directory Junction整合了Aptana Studio 2 IDE與本機端XAMPP伺服器的運作環境。我不僅能在本機端開發與測試「布丁布丁吃什麼?」,也能夠用簡單地幾個步驟就能夠將JavaScript與CSS進行壓縮、上傳到Dropbox公開資料夾。

如果你對Dropbox有興趣的話,歡迎使用我的推薦連結來註冊Dropbox,順便幫我增加一點空間吧!

布丁邀請註冊Dropbox連結

GitHub

6a00d8341c767353ef016762f7c808970b-800wi

Dropbox提供了我的程式碼穩定的運作環境,而GitHub則是提供了查看我的程式碼的社交平台。

之前我開始研究起GitHub,這是因為最近看到幾篇新聞都在討論GitHub。GitHub是許多開放原始碼專案存放的保存庫,近年來也逐漸成為公司招聘程式設計師的管道。因為公司能在GitHub上看到每個人實際上寫的程式碼,而不是像LinkedIn只能看到幾行經歷。

雖然說光看程式碼也不見得夠看到實際上運作的平台,就像是「布丁布丁吃什麼?」的GitHub也是要搭配Blogger才能運作,不過光是為這個社群貢獻程式碼的精神,我覺得就具有令人值得去做的意義。

我想藉由「布丁布丁吃什麼?」的程式撰寫來練習GitHub與Git的用法,這也是「布丁布丁吃什麼?」作為讓我實驗程式碼的用途之一啊。

近期「布丁布丁吃什麼?」的調整 / Recent Changes in Pulipuli.blogspot.tw

image

除了用GitHub與Dropbox改進「布丁布丁吃什麼?」的功能調整流程之外,最近也做了幾個小地方的修改。

英文標題與摘要 / Writing Title and Abstract in English

image

作為博士生,英文寫作是必須要去面對的課題。我希望能夠在日常生活中就常常使用英文來寫作,所以現在就從寫Blog開始。我寫的英文應該會有很多錯誤,歡迎大家用留言回覆來幫我糾正一下喔!

至於為什麼只有標題跟摘要是英文,這是因為光是寫標題跟摘要就花了好多時間,等更能上手之後再來考慮全英文的Blog吧。不過我寫這Blog一部分就是為了給華人地區的讀者看,所以仍然會以中文版本為主喔!

QR Code

image

有人發現到了嗎?這是今天才剛出來的新功能喔!「布丁布丁吃什麼?」每篇全文文章最後都加上了QR Code的名片,讓讀者方便知道這篇文章的來源。

對我來說,因為我很常查閱「布丁布丁吃什麼?」的文章,有時候在電腦上看一看想要轉移到手機上的時候,在手機輸入網址總是太過麻煩。現在我只要在手機上用QR Code Scanner之類的App掃描一下QR Code,就能在手機上直接開啟文章內容喔!

image

在列印的時候,也會出現這個名片的樣子。就算將「布丁布丁吃什麼?」印成紙本,也能夠透過QR Code方便地回到網頁上喔。

這個功能是以jquery.qrcode.js為基礎,我自己建立了它的分支並進行改造,在加上適用於Blogger環境的包裝器(wrapper)來實作。如果有人也想要安裝QR Code到你的Blogger的話,請回覆在下面,我有時間會再另外寫一篇QR Code的安裝教學。


結語 / Conclusion

藉著調整Blog的契機,這篇介紹了「布丁布丁吃什麼?」的JavaScript與CSS原始碼存放空間選擇的歷程,目前是用以下規則來擺放程式碼:

然後聊了一下最近「布丁布丁吃什麼?」的變動,也順便宣傳自己加入的QR Code功能。

最後我想閒聊一下QR Code。我認為QR Code不僅僅只是讓人在廣告上開啟網頁而已,它可以是連結實體與數位(從印出紙本開啟Blog)、數位到數位(從螢幕掃描到手機),也可以藉由加入特殊參數讓它用於開啟指定的應用程式。而這個簡單的轉換,卻能夠連結不同時空的人與物。

想像一下,公車的乘客不需要在座椅上塗鴉了。他們可以掃描這台公車專屬的QR Code,然後在這台公車專屬的線上討論版聊天;圖書館的讀者不僅僅是在書上從別人的筆記來認識與這本書內容相關的事情,他能掃描QR Code來到這本書專屬網站上來取得相關資訊,更能在討論版上認識同樣閱讀這本書的愛書者。

QR Code只是簡單的技術,重點在於要如何應用。這也是我們作為研究者應該去思考的問題。共勉之。

(more...)

Symbolic Link Creator建立結合目錄

布丁布丁吃布丁

Symbolic Link Creator建立結合目錄

image 

Windows使用的NTFS檔案系統具備了結合目錄(Directory Junction)功能,可以建立一個連結目錄直接指向另一個目的目錄。連結目錄操作時就跟一般檔案操作一樣,實際上卻是操作目的目錄的資料。這篇是教你如何使用Symbolic Link Creator讓一個資料夾同時出現在Windows不同路徑上,他們的內容檔案共通,而且操作起來跟一般檔案總管內的操作一模一樣──就連其他軟體運作時不會感到差異。這可不是捷徑(Shortcut),而是結合目錄功能的優點喔!


結合目錄應用於雲端同步工具

在現在雲端空間的時代,我們可以用Dropbox來同步、備份電腦上的各種文件,這也包括了軟體的設定檔,例如IDE開發環境、遠端伺服器的連線設定。但是Dropbox之類的雲端空間通常會將同步範圍限定於特定的資料夾中,你要同步,就必須把檔案放入這個資料夾。對於必須安裝在特定路徑才能夠使用的軟體來說,設定檔不能放在Dropbox指定的資料夾,就難以享受雲端同步的好處。

Dropbox Folder Sync是利用建立結合目錄的方式,先將資料移到Dropbox資料夾,然後建立一個資料夾的結合目錄,擺放到原本的位置。這能讓原本位置的路徑仍能正常使用、實際的檔案內容又可以在Dropbox備份。但是Dropbox Folder Sync只能用於Dropbox,其他的軟體像是Google DriveSugarSyncbox之類的軟體就得另尋他法。

其實Dropbox Folder Sync也只是將指令junction弄成讓人簡單操作的GUI介面,不過可選擇的參數比較少。而Symbolic Link Creator也是一樣是利用指令列做成的GUI介面,但是你就可以任意建立符號連結到你要的地方了。
舉例來說:

Directory Junction跟Symbolic Link的差別

這一篇雖然介紹的是Directory Junction,但是用的工具卻是叫做Symbolic Link Creator,到底這兩者之間有什麼差別呢?
網路上也有人問過這個問題。最簡單的區別就是Directory Junction建立出來的連結點是一個「目錄」,而Symbolic Link則是建立一個「檔案」(類似捷徑的感覺)。另外,Directory Junction通常只能連結到本地端的資料夾,而不能透過網路上的芳鄰之類的網路技術連結到遠端資料夾。這大概就是他們最大的差別了。

下載Symbolic Link Creator

image

這是免安裝的工具,開啟之後就能夠直接使用了。

建立結合目錄資料夾

首先,我們要規劃連結資料夾(Link Folder)目的資料夾(Destination Folder)的路徑。

image 

在這個例子中,我想要在桌面上擺一個連結資料夾,路徑是「D:\Desktop\」底下,資料夾名字叫做「demo」。這個資料夾會連到目的資料夾,路徑為「D:\Desktop\Dropbox\demo」。

image 

打開Symbolic Link Creator,各別在以下幾個地方輸入我們的規劃設定:

  • Link Folder
    • Please select the place where you want your link:
      輸入連結資料夾所在路徑「D:\Desktop\」
    • Now give a name to the link:
      輸入連結資料夾名稱「demo」
  • Destination Folder
    • Please select the path to the real folder you want to link:
      輸入目的資料夾路徑「D:\Desktop\Dropbox\demo」
    • Select the type of link: 選擇「Directory Junction」

按下Create,符號連結很快就會建立完成。

image 

完成之後會跳出這個訊息。

image 

桌面上就會出現一個資料夾「demo」,內容就跟Dropbox底下的「demo」一樣。在裡面新增、修改資料,也同樣會影響到另一個資料夾喔!

移除結合目錄

你可以注意到桌面的「demo」資料夾跟一般資料夾不太一樣,有個類似捷徑的圖示,表示他是結合目錄。

image

如果不需要結合目錄,那就直接刪除掉桌面的「demo」資料夾就好。這個動作並不會影響到Dropbox底下的「demo」囉。


結語:寫備忘也學一些東西

因為我常常在不同電腦與手機之間工作,檔案同步對我來說非常重要。而且我也想要備份花了很多時間配置的軟體設定,Dropbox一向是很穩定的備份工具。所以最近常常使用Symbolic Link Creator來建立結合目錄。

不過每次使用Symbolic Link Creator的時候都會忘記怎麼設定,到底Link Folder要寫來源還是目的?type of link又要選哪一種好?為了怕下次又忘記,這次我乾脆寫在blog上就好了。(其實我Blogger大多數文章都是操作備忘錄,方便未來我忘記的時候再回頭查閱而已啊。)

這次在寫的時候也一併搞懂了Directory Junction跟Symbolic Link的差別,意外地又學到一些知識,真不錯啊。

(more...)

水果店老婆婆的香蕉

布丁布丁吃布丁

水果店老婆婆的香蕉

DSC_0549

今天我也一如往常地,拖著一身剛從實驗室離開的疲憊身子(以及一身做不完的工作),在半夜12點多的時候踏入了24小時營業的水果店。

超過12點之後,水果店的水果架會蓋上一層布,彷彿要打烊一般。通常只會有一位顧店的店員,以及我與零零星星的幾位顧客而已。

今天也跟以前一樣,半夜的水果店沒什麼人。然而不同的是,卻有一位老婆婆站在攤位旁吃著一根熟透的香蕉。

(她是店員的熟客嗎?正在試吃香蕉?)雖然有點好奇這位老婆婆的身分,不過我的注意力終究是被拿根香蕉吸引了。是的,熟得剛好的香蕉是很少出現在水果攤的。水果攤大多都擺的是稍微青澀的香蕉,以便顧客買一串回家慢慢吃。於是看到熟透的香蕉,讓我油然興起想吃香蕉的念頭。

「香蕉~香蕉~香蕉在那兒?」一邊喃喃自語的我,抱著期待地經過了老婆婆,走向擺香蕉的位置。可惜,攤位上剩下的幾串香蕉都還很青,不適合現買現吃。

好吧,我還有其他水果可以選呢!椪柑39元與19元、芭樂10元、7元與1元、蘋果一顆10元、小蕃茄29元、黑珍珠39元……到底要吃什麼好呢?

 

「你要吃香蕉嗎?」

 

正當我在猶豫的時候,背後有個聲音呼喚了我。

一轉頭,老婆婆站在我後面,似乎的確是對我講話。

「啊我喔,是啊,想吃香蕉呢。」我點了點頭。

老婆婆說道:「我這有一根熟到裂開的香蕉,你拿去吃吧。」

聽到這句話我十分開心,高興地回道:「是喔,真是太好了,我好喜歡熟的香蕉呢。」

老婆婆緩慢地從手上的袋子中摸索幾番,然後拿出一根旁邊裂開的香蕉。「拿去吧,」老婆婆好心地提醒我:「記得要把旁邊裂開的部份切掉喔。」

「好的!我想現在就吃,沒有刀可以切,不過應該沒關係吧?」」看到黃橙橙的香蕉,我迫不及待地開始剝起了皮。

「店員那邊有水果刀可以借。」老婆婆指指櫃檯。

「原來如此,謝謝喔。」

 

跟老婆婆道了聲謝,我從店員借了把水果刀,然後再旁邊處理水果的地方切起香蕉來。

嗯……到底要切多少呢?隨便吧,好像也沒熟到爛掉啦。

 

「這根也給你吃吧。」

咦?老婆婆突如其來地又拿了一根香蕉放到我的面前。

我有點驚訝地回道:「這怎麼好意思……」

「哇跨例馬西就儉ㄟ狼……我看你也是很節儉的人,」老婆婆用臺語講到一半,似乎以為我聽不懂,所以又換成了國語。

「我也是很省著吃,我們很像。我已經好幾年都沒收入了。」

對著老婆婆的語重心長,我一時間不知道該怎麼回應才好。

 

只見老婆婆點了點頭,補充了一句:「這根就給你明天吃,一天不要吃太多啊。」然後就轉身慢慢地離去。

「是,謝謝您。」我一手拿著播到一半的香蕉,一手拿著水果刀,目送老婆婆離開。

 

我到底該怎麼回應老婆婆才比較好……

我不是沒有錢,我錢包裡面也有幾千元……是要拿來繳學分費的就是。

比起我想吃香蕉這件事情,總覺得老婆婆應該更需要這根香蕉。

可是我還是傻傻地接受了老婆婆的好意,收下了兩根香蕉。

我到底該怎麼報答老婆婆,怎麼報答願意施捨給陌生人的這個社會呢?

 

在這邊,我只能還是謝謝老婆婆的心意。

DSC_0554

香蕉很好吃,我明天的早餐就靠它了。

(more...)

使用Minify壓縮JavaScript跟CSS範例

使用Minify壓縮JavaScript跟CSS範例

image

Minify是用來壓縮JavaScritp跟CSS的PHP 5應用程式。跟我之前介紹的YUI Compressor壓縮器功能類似,但是YUI Compressor是Java程式,沒有Minify原生整合PHP來得方便。Minify目前最新版本為2.1.5,你可以在GitHub找到它全部的原始碼。

Minify功能很多很複雜,但是它自己的使用手冊中卻沒有提到怎樣簡單地在PHP使用。這篇就是簡單地寫個範例,讓大家知道要怎麼用Minify來壓縮JavaScript跟CSS。


下載檔案

image

你可以在GitHub找到Minify的所有原始碼,請按下「ZIP」下載檔案。

壓縮範例

我這篇的用法中,JavaScript跟CSS都是以PHP變數的形式儲存再來進行壓縮。Minify主要的用法是壓縮既有的JavaScript與CSS檔案,但是我比較常將各個檔案整理、組合、排列,然後再壓縮,這也是這兩個範例的主要作法。

壓縮JavaScript
<?php

/**
* --------
* JavaScript Compressor
* --------
*/

$js = "
/**
* This is a demo script
*/
function test() {
var _test_ms = '1';
alert(_i);
}
"
;

require_once './min/lib/JSMinPlus.php';

$packed_js = JSMinPlus::minify($js);

echo $packed_js; //function test(){var _test_ms='1';alert(_i)}

?>

壓縮CSS
<?php

/**
* --------
* CSS Compressor
* --------
*/

$css = "
/**
* This is a demo css
*/
body hi {
font-size: 3em;
/* font-weight: bold; */
color: #666666;
}
"
;

require_once './min/lib/CSSmin.php';

$cssmin = new CSSmin();
$packed_css = $cssmin->run($css);

echo $packed_css; //body hi{font-size:3em;color:#666}

?>

注意:不是任何JavaScript都能壓縮

然而,Minify壓縮法跟YUI Compressor還是不一樣。如果JavaScript已經是壓縮好的程式,那麼Minify再壓縮之後通常就會發生錯誤。

另外,有些程式碼是專門寫好給YUI Compressor壓縮的,所以用Minify壓縮時就會發生錯誤。這時候要嘛就是找線上的YUI壓縮服務,要嘛就是自己裝個YUI Compressor來壓縮。


結語:原生的Minify比Java的YUI Compressor好用

我之前改用YUI Compressor壓縮的時候常常會發生錯誤,這是由於PHP並非多線程設計,一旦網站大量對PHP請求的時候,PHP就會傻傻地去呼叫YUI Compressor的Java程式,然後Java就會快速地吃光伺服器的CPU跟記憶體,最後伺服器當機。即使我之前用PHPLock跟設計快取機制,這個問題還是很難根治。

然而跟使用Java的YUI Compressor相比,Minify原生於PHP的運作效率並不差,甚至可以說更好。到目前為止運作都蠻順暢的。而大量請求網頁的時候仍會出錯,那也是PHP自身設定就能夠搞定,不用像是使用YUI Compressor的時候還要去研究Java的環境設定。

最後發個牢騷,我還是覺得Java太容易當機了,不論是這邊用Java跑YUI Compressor,還是Tomcat上運作DSpace,Java太容易吃光記憶體跟佔用大量CPU,這讓我感到非常困擾。(即使設定了Xms跟Xmx還是很容易當機!)即使如此,用Java開發Servlet網站服務的專案還是很多,大家到底是怎麼面對這種問題的啊?我很好奇!

(more...)

NetBeans儲存RSA key fingerprint

NetBeans儲存RSA key fingerprint

image

我編輯PHP專案的時候主要使用NetBeans.org這個IDE,之前不僅發現他內建了Git,也可以用SFTP上傳修改後的檔案,不需要另外在開TortoiseGit或是FileZilla,非常方便。

只是在SFTP上傳的時候每次都要對照RSA key fingerprint,它不會儲存在電腦中,每次都會跳出來詢問我是否要確定,這讓我有點困擾。後來找到NetBeans論壇上stephanmitchev的教學,終於成功設定,讓NetBeans儲存RSA key fingerprint。

以下用圖文來介紹作法。

1. 建立一個空檔案儲存RSA Key Fingerprint

image

首先我先在NetBeans的專案目錄底下新建一個空白檔案,叫做rsa.key。我用「新增 –> 文字文件」的功能來新增,檔名任意即可,檔案內容不需要填寫。

image

NetBeans專案目錄通常是在你程式碼目錄底下的「nbproject」目錄。

2. 開啟專案設定 Open Project Properties

image

開啟「File」 > 「Project Properties (專案名稱)」

3. 管理遠端設定 Manage Remote Connection

image

在Categories中進入「Run Configuration」,然後在Remote Connection右邊找到「Manage…」進入。

4. 設定Known Hosts File

image

在Known Hosts File那一欄位後面的Browse選擇剛剛新增的rsa.key。

5. 第一次測試,儲存RSA Key Fingerprint

image

按下下面的「Test Connection」,NetBeans會跳出Warning視窗,要你確認RSA key fingerprint。按下「Yes」,RSA key fingerprint就會儲存在rsa.key檔案中。

6. 第二次測試,不會再跳出詢問

image

第二次再按下「Test Connection」時已經不會跳出詢問視窗,這就是RSA key fingerprint已經儲存了。

這樣每次上傳就不會再詢問你囉。

(more...)

Acronis True Image Home 10 還原教學

布丁布丁吃布丁

Acronis True Image Home 10 還原教學

這是寫給家人看的,筆電的系統還原教學。


開機進入Acronis

1 DSC_0007 - 1

筆電開機。開機按鈕如上圖紅圈所示,按下三秒左右開機。

 

2 DSC_0008

看到畫面上出現以下訊息時,按下F11按鍵:

Starting Acronis Loader…

Press F11 for Acronis Startup Recovery Manager…

3 DSC_0009

選擇「Acronis True Image Home (完整版本)」進入。

4 DSC_0014

等待Acronis讀取。

5 DSC_0018

成功進入Acronis。


執行還原作業

5 DSC_0018 - 1

選擇上圖紅框所示的「還原」功能。

6 DSC_0020

歡迎使用「資料還原精靈」!按下一步。

7 DSC_0024

選擇備份存檔,選擇DOCUMENT (D:) 當中以「outty_D10_」開頭的檔案名稱,附檔名為tib的檔案。檔案名稱包含了日期,例如「outty_D10_20110510.tib」表示20110510製作的備份。請選擇距離現在最近的備份檔案。

下一步。

8 DSC_0027

選擇還原類型:還原磁碟或磁碟分割。

下一步。

9 DSC_0031

要還原的磁碟分割或磁碟:選擇NTFS (C:)

下一步。

10 DSC_0032

還原磁碟分割位置:選擇SYSTEM (C:)

下一步。

11 DSC_0036

選擇磁碟分割類型:啟動。

下一步。

12 DSC_0041

選擇磁碟分割大小。直接下一步。

13 DSC_0043

下一個選擇:否,我不要。

下一步。

14 DSC_0046

還原選項,直接下一步。

15 DSC_0048

作業清單。按下繼續。

16 DSC_0051

Acronis開始進行還原。

照之前的經驗來看,還原大約需要15分鐘。

還原完成後重新開機

image

還原完成之後,從左上角「作業」->「結束」,Acronis會重新啟動筆電。

2 DSC_0008

看到這個訊息時不要理它,放三秒鐘它就會自動略過。

17 DSC_0003

然後順利進入Windows XP之後,就會是當初備份時穩定的狀況了。

(more...)

虛擬機器轉移(V2V) : Windows 2003從VirtualBox到KVM

布丁布丁吃布丁

虛擬機器轉移(V2V) : Windows 2003從VirtualBox到KVM

image

跟前幾篇講實體機器虛擬化(Physical-to-Virtual,P2V)不同,這一篇要講的是虛擬機器VirtualBox 4.2.6)轉移到另一種虛擬機器Proxmox VE 1.9底下的KVM)的過程,亦即所謂的虛擬機器轉移(Virtual-to-Virtual,V2V,或是遷移migration)。這次轉移的客體作業系統(Guest OS)是Winodws 2003,儘管只是把VirtualBox上製作的VMDK虛擬機器硬碟映像檔換到KVM執行,但還是有很多細節需要注意。以下記錄大致上的過程供大家參考。


為什麼要做V2V?

目前我常用的免費虛擬機器技術有兩種:適合工作站使用的VirtualBox,以及適合伺服器用的KVM

我常常在自己的電腦用VirtualBox安裝作業系統來進行各種測試,VirtualBox可以調整的參數多、網路設定也很方便,操作起來很容易。另一方面,我會將開發到穩定狀態、不太需要常常修改的系統放置到Proxmox VE的KVM上,讓系統提供服務就好,我們平常就不太再去更動作業系統的基層設定。

從VirtualBox到KVM這之間的轉換,就需要V2V的協助。

V2V作法概述:利用共同支援vmdk硬碟格式

200px-Vmware.svg

多虧於VMware如此盛行,VMware制定的vmdk(Virtual Machine Disk,虛擬機器硬碟映像檔)幾乎成為了各家虛擬機器爭相支援的對象,這包括了VirtualBox與KVM。

image

因此簡單的想法,就是利用VirtualBox製作vmdk硬碟檔,再把它放到KVM環境中運作。

題外話,我寫這篇的時候才發現原來VirtualBox也支援建立了KVM主要用的虛擬機器硬碟格式QEMU增強硬碟,不過我想即使用QEMU來建立虛擬機器,轉移Windows 2003的時候依然會出現以下的問題。

Windows 2003的V2V步驟

經過了幾次失敗的嘗試之後,我參考了Alex寫的Converting Windows VMWare machines to KVM,將目前看來可行的作法整理如下。步驟中會用到兩個名詞:來源端是指VirtualBox虛擬機器,目的端則是指KVM虛擬機器。

1. 來源建立虛擬機器時用vmdk

image

就如前面所說,這篇V2V是利用共同支援的虛擬機器硬碟格式vmdk,所以建立VirtualBox虛擬機器時請選擇VMDK

image

硬碟大小其實只要符合作業系統最低需求即可,不過有趣的地方在於,似乎因為VMware建立vmdk預設的大小都是8GB,所以許多Virtual Appliance都是8GB。在這邊我們也參考一下傳統,設成8GB。

2. 來源端使用mergeide.reg

2013-02-11_142222

如果你的Windows 2003是裝在IDE控制器上,那麼第一個步驟就是使用mergeide.reg免空Box.net)。請下載這個檔案,然後在來源虛擬機器中執行(如上圖),調整虛擬機器的登錄檔即可。

mergeide.reg是來自於Alex教學中的一個登錄檔,但是連Alex也不知道原作者是誰。在此我也要感謝這位作者的提供,他的mergeide.reg真的幫了我們很大的忙。

以下是mergeide.reg的檔案內容:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\primary_ide_channel]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="atapi"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\secondary_ide_channel]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="atapi"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\*pnp0600]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="atapi"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\*azt0502]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="atapi"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\gendisk]
"ClassGUID"="{4D36E967-E325-11CE-BFC1-08002BE10318}"
"Service"="disk"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#cc_0101]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_0e11&dev_ae33]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_1039&dev_0601]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_1039&dev_5513]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_1042&dev_1000]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_105a&dev_4d33]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_1095&dev_0640]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_1095&dev_0646]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_1097&dev_0038]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_10ad&dev_0001]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_10ad&dev_0150]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_10b9&dev_5215]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_10b9&dev_5219]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_10b9&dev_5229]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="pciide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_1106&dev_0571]
"Service"="pciide"
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_8086&dev_1222]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="intelide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_8086&dev_1230]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="intelide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_8086&dev_2411]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="intelide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_8086&dev_2421]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="intelide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_8086&dev_7010]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="intelide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_8086&dev_7111]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="intelide"

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\pci#ven_8086&dev_7199]
"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}"
"Service"="intelide"

;Add driver for Atapi (requires atapi.sys in drivers directory)

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\atapi]
"ErrorControl"=dword:00000001
"Group"="SCSI miniport"
"Start"=dword:00000000
"Tag"=dword:00000019
"Type"=dword:00000001
"DisplayName"="Standard IDE/ESDI Hard Disk Controller"
"ImagePath"=hex(2):53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,44,00,\
52,00,49,00,56,00,45,00,52,00,53,00,5c,00,61,00,74,00,61,00,70,00,69,00,2e,\
00,73,00,79,00,73,00,00,00

;Add driver for intelide (requires intelide.sys in drivers directory)

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\IntelIde]
"ErrorControl"=dword:00000001
"Group"="System Bus Extender"
"Start"=dword:00000000
"Tag"=dword:00000004
"Type"=dword:00000001
"ImagePath"=hex(2):53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,44,00,\
52,00,49,00,56,00,45,00,52,00,53,00,5c,00,69,00,6e,00,74,00,65,00,6c,00,69,\
00,64,00,65,00,2e,00,73,00,79,00,73,00,00,00


;Add driver for pciide (requires pciide.sys and pciidex.sys in drivers directory)

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PCIIde]
"ErrorControl"=dword:00000001
"Group"="System Bus Extender"
"Start"=dword:00000000
"Tag"=dword:00000003
"Type"=dword:00000001
"ImagePath"=hex(2):53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,44,00,\
52,00,49,00,56,00,45,00,52,00,53,00,5c,00,70,00,63,00,69,00,69,00,64,00,65,\
00,2e,00,73,00,79,00,73,00,00,00

3. 來源端完全關機

image

接著要把來源端電腦完全關機。不能只是儲存機器狀態喔,必須是完全關機。

4. 目的端建立新的虛擬機器

image

本篇使用的目的端KVM是透過Proxmox VE 1.9來控管,這邊我們先建立一個新的虛擬機器。以下是需要注意的參數:

  • Type: Fullyvirtualized (KVM)
  • Image Format: vmdk
  • DIsk space (GB): 8 (同來源端)
  • Disk type: IDE (同來源端)
  • Memory (MB): 256 (同來源端)
  • Guest Type: Windows 2003

image

設置完成,請注意Proxmox VE自動配給的VMID,在此是158。

5. 來源端vmdk傳送到目的端

2013-02-11_145222

接下來就要把來源端的vmdk硬碟檔案傳送到目的端伺服器上。Proxmox VE在配置KVM虛擬機器時都有規定好的路徑,如果VMID為158,那麼158的虛擬機器硬碟檔案就放在以下路徑:

/var/lib/vz/images/158

請將來源端的vmdk上傳到該路徑底下吧。

6. 目的端替換硬碟

image

當vmdk上傳到目的端的指定路徑之後,我們切換到Hardware這一頁,你會發現剛剛上傳的vmdk已經在下面列表了。

image

接著我們先移除原本的硬碟,按下原本硬碟左邊的紅色向下鍵頭按鈕image,它會跳出DELETE選單。按下去之後,原本的硬碟會從虛擬機器上拔除,但是檔案還是在Proxmox VE裡面喔。

image

然後按下Hardware device list for VM 158左邊的紅色下向箭頭image,點下「Add a hard disk」。

image

Existing Disks選擇剛剛上傳的vmdk,然後按下add按鈕。

image

vmdk插上KVM的虛擬機器囉。

7. 目的端關閉KVM功能

image

切換到Options這一頁,然後在Disable KVM這選項後面打鉤,按下save儲存。(感謝來自neozeed的教學)

2013-02-11_161833

如果沒有做這個選項的話,目的端開機時會遇到「INTERNAL_POWER_ERROR」或其他各種問題的藍色當機畫面。

我找到現在仍不知道開關Disable KVM的意義何在。就連Griffon的Blog也是教說關掉KVM就好,目前也只能照做囉。

8. 目的端開機、檢查是否順利運作

image

回到Status,按下「Start」按鈕。

image

然後再按下Open VNC console,來看看虛擬機器現在的狀況。

image

順利的話,就進入Windows 2003囉。


結語:不要被藍白當機畫面打擊士氣了!

Image 11

這個藍白畫面是我在這次V2V過程中最常看到的景象,實在是非常無奈。我想到頭來還是Windows 2003綁定硬體,導致VirtualBox的IDE控制器轉換到KVM上的時候不合所導致的。出現這種藍白當機畫面,大多都是硬體上的問題。只是在不知道解法的時候總是會很無奈。希望這篇記錄的方法可以幫助大家在做V2V更加順利啊。

(more...)