2019年1月6日 星期日

如何使用在Linux上建構iScsi的鏡像系統

如何使用在Linux上建構iSCSI的Copy On Write鏡像系統


iSCSI系統是一種SAN(Storage Area Network)的應用,在客戶端應用起來就跟普通的硬碟一般,可開機、可以做任何內接硬碟可以做到的事情。透過iSCSI SAN遠端開機,我們可以很簡單的在伺服器端管理系統,諸如系統還原、備份等等,若您的環境有很多台相同規格或不同規格的機器,透過網路硬碟開機,可以很簡單的管理這些機器。

本文的應用,是在伺服器端使用SSD來建置提供客戶端網路開機的硬碟鏡像,也就是使用一份較大空間的SSD於上面建置供多個不同的硬體開機的系統磁碟,客戶端可透過多種方法來遠端開機,但本文不會提及何種開機方式,只有講到如何使用鏡像系統,網路開機的文件請自行尋找。 為降低SSD磁碟空間的開銷,本文使用磁碟快照的技術來建置多個不同系統的系統磁碟,使用這個方法可以令這些不同磁碟的鏡像使用相同的檔案,藉以節省SSD空間的使用量。 


如上圖所示,客戶端的作業系統被安裝在原始鏡像系統,我們再從原始鏡像系統中使用Copy On Write(COW)技術製作衍生快照,客戶端是連接上衍生快照2與衍生快照3來當作系統磁碟開機,這種技術是要覆寫檔案時,才會把更動的部分寫在衍生快照區,當存取未更動的檔案時則使用原始鏡像中的檔案,這種方式可以大大的減低伺服器端的檔案系統開銷。

當然您可以使用標準的Linux作業系統來製作這種系統,為簡化建置,本文使用Synology的系統為範本來建立這樣的應用。先開啟SSH的功能,開啟的方法為:

  1. 打開控制台。
  2. 點選「終端機 & SNMP」。
  3. 啟動SSH功能。 
接下來可以使用Putty或任何SSH客戶端連進去,輸入任何一個已經創建的帳號登入SSH,再使用指令 

> sudo su

再輸入您登入的這個帳號的密碼,切換到 root 身份。


iSCSI設定

開啟選單 -> iSCSI Manager 點選 LUN 這個頁面,再點選新增。



請注意,這邊我們在 Thin Provisioning 不使用新的功能,它內建的功能沒辦法建立衍生鏡像,所以我們要用SSH自己操作。



這邊我們讓它順便幫我們建立iSCSI target並連結。




這邊直接下一步。



此時我們登入SSH,切換到root帳號後,檢視根目錄


# ls /
bin     dev           initrd  lib64       proc  sbin  tmpRoot  var.defaults
boot    etc           lib     lost+found  root  sys   usr      volume1
config  etc.defaults  lib32   mnt         run   tmp   var

 

 我們看到 volume1這個目錄,這個就是磁碟陣列的掛載點,再看看內部:

 # ls /volume1/
@appstore      @cloudsync  @eaDir  @iSCSI  @sharesnap  @tmp
@cloudstation  @database   homes   @S2S    tftp_root

 這些 @開頭的都是btrfs的掛載點,其中 iSCSI 這個目錄就是我們要操作的位置,以下的位置皆於此目錄中操作:

# cd /volume1/\@iSCSI/LUN/BLUN_THICK/
# ls
4d02abcf-690a-4e5a-bcfd-abe766a7652f


 /volume1/\@iSCSI/LUN/BLUN_THICK/ 就是我們的工作目錄,每當從圖形界面建立一個新的iSCSI LUN時,在這個目錄下就會新增加一個16進制長串文字的目錄,所以這個
4d02abcf-690a-4e5a-bcfd-abe766a7652f目錄就對應到前面於圖形界面中建立的LUN1,看看裡面的檔案:

# ls -l
total 134217728
-rw-r--r-- 1 root root 137438953472 Jan  6 17:37 LUN-1_00000
-rw-r--r-- 1 root root 549755813888 Jan  6 17:37 ROD
 

裡面只有兩個檔案,LUN-1_0000就是鏡像檔案,這時你可以在客戶端把這個磁碟掛載起來安裝作業系統,所有的操作都會儲存在這個檔案裡面,這邊不對這個部分多描述,我們只簡單的將他掛載起來,放一個檔案進去驗證。






這時我們要在客戶端與伺服器端斷開這個LUN以避免不小心編輯到,請注意,當這個檔案衍生出任何的鏡像以後,這個檔案就不應該被編輯,否則衍生的鏡像會壞掉。

關閉檔案總管視窗,並斷開客戶端的iSCSI連結,在伺服器端的iSCSI Manager中點選LUN頁面點選LUN1->動作 -> 編輯-> 連結 -> 將 Target - 1已連結前面的打勾去掉,這樣整個LUN1就完全從系統中斷開了。

接著我們要從LUN1鏡像出LUN2與LUN3。我們在伺服器端的iSCSI Manager的LUN頁面新建一個LUN2:




但此時先不和iSCSI target連結。



待建立完成後,我們回到終端機SSH上看新建立的LUN2於何處:

# ls /volume1/@iSCSI/LUN/BLUN_THICK
06d72394-fec9-4cf6-8820-5cd16f6aaa7a  4d02abcf-690a-4e5a-bcfd-abe766a7652f

這時我們看到多了一個06d72394-fec9-4cf6-8820-5cd16f6aaa7a的目錄,這個就是新的LUN2所在的位置,檢視目錄內容可以看到一個LUN-2_00000的檔案,這個就是新建的LUN2。

# cd  06d72394-fec9-4cf6-8820-5cd16f6aaa7a
# ls -l
total 134217728
-rw-r--r-- 1 root root 137438953472 Jan  6 20:53 LUN-2_00000
-rw-r--r-- 1 root root 549755813888 Jan  6 20:53 ROD


這時我們要用指令把LUN-1鏡像到這個LUN-2_00000檔案:

# rm LUN-2_00000
# cp --reflink=always ../4d02abcf-690a-4e5a-bcfd-abe766a7652f/LUN-1_00000 LUN-2_00000

上面這兩行指令是把原來的LUN-2_00000刪除,再從LUN-1鏡像到LUN-2來,--reflink=always就是使用Copy On Write(COW)的方式將檔案鏡像過來,在cp指令的說明中有這一段

When --reflink[=always] is specified, perform a lightweight copy, where the data blocks are copied only when modified.

接下來再用相同的方式建立LUN-3,從LUN-1鏡像到LUN-3。
建立完成後,可以用指令察看這些鏡像檔案

# btrfs subvolume list -a /volume1/
ID 257 gen 42503 top level 5 path <FS_TREE>/@syno
ID 259 gen 42480 top level 257 path @syno/@iSCSI
ID 263 gen 42196 top level 257 path @syno/homes
ID 449 gen 42190 top level 257 path @syno/@sharesnap
ID 450 gen 42190 top level 449 path <FS_TREE>/@syno/@sharesnap/homes
ID 451 gen 39813 top level 450 path <FS_TREE>/@syno/@sharesnap/homes/GMT+08-2019.01.01-04.00.29

...
ID 563 gen 42189 top level 450 path <FS_TREE>/@syno/@sharesnap/homes/GMT+08-2019.01.06-04.00.02
ID 564 gen 42455 top level 259 path <FS_TREE>/@syno/@iSCSI/LUN/BLUN_THICK/4d02abcf-690a-4e5a-bcfd-abe766a7652f
ID 574 gen 42494 top level 259 path <FS_TREE>/@syno/@iSCSI/LUN/BLUN_THICK/06d72394-fec9-4cf6-8820-5cd16f6aaa7a
ID 588 gen 42494 top level 259 path <FS_TREE>/@syno/@iSCSI/LUN/BLUN_THICK/de8f1294-ebd3-4715-88a1-931ea32fa36e


其中最後的三個項目就是我們所新建出來的鏡像。



完成後從iSCSI Manager中點選Target -> 新增



建立一個新的 iSCSI Target-2。

此處連結到現有的LUN-2,再用一樣的方法建立新的 iSCSI target-3,連結到LUN-3。


如此我們就有了3個target,如此當你從客戶端連接上Target-2或Target-3時,會發現剛剛複製進Target-1的檔案已經在Target-2的LUN2與Target-3的LUN3中。

要注意,因為這三個LUN其實是來自於同一個LUN-1,若您在同一台客戶端連接了任二個LUN,後面連接的LUN會被屏蔽。





如上圖,磁碟2是連接iSCSI target-2而取得的磁碟,連接後直接掛載上了系統,而磁碟3則是之後連接iSCSI target-3所取得的磁碟,顯示是有問題的離線磁碟,只要客戶端發現到連接的磁碟是來自於同一個鏡像,就會被屏蔽。反之若先連接iSCSI target-3取得磁碟,再連接iSCSI target-2取得第二個磁碟,第二個磁碟一樣會發生相同的狀況。

至此我們已經完成這個教學,我們可以在伺服器端用類似的方法為客戶端快速的建立系統磁碟,若客戶端需要做系統還原,只需從LUN-1中重新鏡像出系統磁碟供客戶端使用,鏡像中還能繼續生出鏡像,多種玩法大家自己去挖掘,祝你們大家好運!















2014年6月1日 星期日

Launch DroidSSh as service on CyanogenMod

       I am find the way that launch the sshd as service for long time, I hope the sshd will not been destroy while system low memory while launch as service, it need more exam. Even the CyanogenMod build in the sshd, but I'm bad luck ... it show me "Segmentation fault" or "void endpwent()(3) is not implemented on Android" on my two difference device, finally I found the easiest way for the goal.

The DroidSSH is always stable on my two device, it never complain any problem to me, it is a option of my goal and it is only success of my trying, ok let beginning.

1. Install the DroidSSH from Google Play and launch it, it will spend more time at first run, the others procedure you may setting your device with DroidSSH or your terminal emulation.

2. Create the directory /data/local/userinit.d
3. Create file /data/local/userinit.d/90sshd and edit it.
4. paste the contents bellow



# ================ start ===================
#!/system/bin/sh

umask 077
/data/data/berserker.android.apps.sshdroid/dropbear/dropbear -H /data/user -Y "PASSWORD" -S -p 22 -r /data/data/berserker.android.apps.sshdroid/dropbear/dropbear.key.rsa -d /data/data/berserker.android.apps.sshdroid/dropbear/dropbear.key.dss

#================= end ===================

 5. Change the permission and group

chmod 755 /data/local/userinit.d/90sshd
chgrp shell /data/local/userinit.d/90sshd


 Ok, it finish, reboot your device, it will start as service.


Note: 
1. -H mean the home directory of user.
2. -Y specify the password, you should change it.


My reference:

2014年5月26日 星期一

Port Jetty to android launch from dalvikvm


There is a project named i-Jetty that you can install from google play, and another droidSSH let you control your android device remote, the two app can make your old android device to become a server. In general, the android app will be release if system busy, low memory or in deep sleep, it mean you will lost SSH control if Http service busy from i-jetty, another reason why I port it to launch by native dalvikvm is no log in i-Jetty interface.

I download the source of Jetty-8.1.15 and import to android sdk to see what are not support by android system, that is what I found:

  • The following package not support by android.
    • javax.annotation: it parse annotation something like @ServletFilter(urlPatterns={"/myurl"} in your servlet code.
    • javax.naming:  see document
    • java.lang.management: see document
  •  The KeyStroe provider not support from dalvikvm launcher.
    • Neither JKS or BKS keystore provider exist: It support SSL connection object(which make HTTPS connection) need the provider.
    • I found the keystore.so in android system, it may a hint for you.



there is my package file, it not support HTTPS although the package are include, so don't use it in bank systems ...

2013年9月29日 星期日

The trouble of warp_content of TextView -- setHorizontallyScrolling, pinch zoom, finger scroll.

There is no API support from Android official for pinch zoom and finger scroll(2 dimension), I must make it by myself, ok, let's try it.

The first problem is ... 

The default behavior of TextView is adjust the text to fit the width of parent, and only vertical direction scroll support, it not meet my application, I need keep the format of text while setText(). on other words, the TextView shouldn't warp(new line) automatically, only warp while read the "new line" symbol.

There are what I found:
1. Place the TextView in the HorizontallyScrollView ( I hate unused heavy layout ).
2. Set the properties singleLine ( well ... there is really single line in there, god! ).
3. Set android:scrollHorizontally="true" ( Nothing happen ... damn ).
4. bra bra bra ....( it mean many many unused solution ).

I tried many many key word for search google ... it spend my 2 day lone ...

Then I see a function setHorizontallyScrolling(boolean) of TextView, I have no idea it is the same properties with android:scrollHorizontally at that moment, I tried it ... it WORK!

How deep Hole(trap) is ...
The conclusion is use TextView.setHorizontallyScrolling(true) then you can get the original format of text in TextView, forget others ...