# 如何<br>在外接式儲存裝置中<br>安裝可保留作業狀態的 Ubuntu 作業系統
<https://hackmd.io/@brlin/portable-ubuntu-howto>
:::warning
尚未完成,歡迎[分身伐樹](https://hackmd.io/HX9sDBeiTXuYX7k2viEEwA)
:::
---
[![Powered by HackMD](https://i.imgur.com/YznA3wX.png)](https://hackmd.io)
「感恩HackMD!讚嘆HackMD!」
這是一個基於Markdown的HackMD簡報
---
<a href='https://creativecommons.org/licenses/by-sa/4.0/' target='_blank'><img src='https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/by-sa.svg' style='width: 50%; height:auto' /></a><br>歡迎於授權範圍內自由使用本作品
[點此查看本簡報的來源碼](https://hackmd.io/HX9sDBeiTXuYX7k2viEEwA)
---
## 免責聲明
* 以下全為個人經驗整理,不保證正確性
* 對任何第三方的論述全為主觀論點,僅供參考且不應當作事實看待
---
## 基本知識
---
### <ruby>快閃記憶體<rp>(</rp><rt>flash memory</rt><rp>)</rp></ruby>儲存裝置的<br>可用性問題
* 快閃記憶體的原理是透過電壓變更將電荷<span style='color:red' >**束縛入**</span>/<span style='color: green'>**釋放出**</span>半導體電路組成的晶格(cell)來儲存資料
* 每次的寫入操作都會破壞晶格束縛電荷能力,故快閃記憶體寫入次數有限,**寫多了就會壞掉**
* **請避免在其中保存重要資料**,壞了不保證能救回來
---
### <ruby>快閃記憶體<rp>(</rp><rt>flash memory</rt><rp>)</rp></ruby>儲存裝置的<br>~~效~~笑能問題
* 快閃記憶體隨身碟的讀寫效能主要由其使用的**記憶體顆粒**與**記憶體控制器能力**決定
* 說什麼 USB3.0(5000Mbps) 比 USB2.0(480Mbps) 快十倍的都是在**講幹話**
* 效能依據分為連續讀取、連續寫入、隨機讀取、隨機寫入、每秒讀寫操作數、讀寫延遲等
* 但是絕大多數都不會印在包裝上,
<small>因為要 <span style='color: red'>co</span><span style='color: orange'>st</span><span style='color: yellow'>d</span><span style='color: green'>o</span><span style='color: blue'>w</span><span style='color: purple'>n</span> 騙你以為你買到好東西</small>
---
### <ruby>快閃記憶體<rp>(</rp><rt>flash memory</rt><rp>)</rp></ruby>儲存裝置的<br>分區對齊問題
* 記憶體分頁(page)是快閃記憶體能夠讀寫的最小單位(大小 2KiB~32KiB 不等)
* 分頁寫入資料了之後必須經過抹除(erase)才能再寫入新的資料,抹除區塊(erase block)是快閃記憶體*理論上*能夠抹除的最小單位(大小 128KiB~2MiB 不等)
* 多個抹除區塊組合為一個抹除區段(erase segment),這是*實務上*控制器抹除的最小單位(大小通常為 4MiB)
---
### <ruby>快閃記憶體<rp>(</rp><rt>flash memory</rt><rp>)</rp></ruby>儲存裝置的<br>分區對齊問題
* 分頁、抹除區塊、抹除區段的大小可以用讀寫測試的方式猜出來
* 取最小公倍數作為分區邊界起點較不會有不對齊造成的問題(4MiB是個安全值)
---
## 產品選購參考
強烈主觀意見,僅供參考
---
### <del>爛爛的</del>便宜貨
<img src='https://i.imgur.com/XBGlfn2.jpg' style='height: 500px' />
---
### 老實<del>但是還是一樣爛爛</del>的便宜貨
<img src='https://i.imgur.com/OHySBjM.jpg' style='height: 500px' />
---
### 國防布<br><small>(包裝上完全看不出來,碰運氣)</small>
---
### <del>好的</del>好野人
<img src='https://i.imgur.com/afilHw0.jpg' style='height: 330px' /><img src='https://i.imgur.com/g9r5YD8.png' style='height: 330px' />
---
### 不過CP值都比不上
![固態硬碟+外接硬碟盒](https://i.imgur.com/A3zT20h.png)
---
## 目標
* 支援舊式PC韌體(唸作BIOS)開機程序
* 支援新式PC韌體(唸作UEFI)開機程序
* 支援 UEFI SecureBoot
---
## 免責聲明
* 很多電腦製造商韌體設計很爛,開不了請找他們算帳
* 不保證你的隨身碟可以繼續長長久久的用下去
* **絕對不幫忙救資料**,這邊有幾家資料救援公司~~好便宜的~~
---
## 需要什麼工具
* 一台電腦
* 一個Debian系的GNU+Linux作業系統散佈版本
* 網際網路存取能力
* 一個外接式USB匯流排儲存裝置
* 快閃記憶體隨身碟
* 快閃記憶體固態硬碟 + 外接硬碟盒
* 傳統磁盤轉動式硬碟 + 外接硬碟盒
---
## Ubiquity 作業系統安裝程式
* 很殘念地不支援UEFI規範內的可移除式磁碟開機程序,跳過
---
## 安裝媒體 Live 系統 + Persistence
還在學QAQ
---
## Debootstrap<del>土法煉鋼</del>
* 能夠在Debian系系統下佈署另一個Debian系系統的工具
* 直接用它在隨身碟中建一個Ubuntu作業系統出來
---
## 桌面環境選擇
* 都已經要到處插別人電腦了還是選輕量的吧
* XFCE
* LXDE
* MATE
---
## 儲存空間分區<br><small>Partitioning</small>
* Microsoft Windows只支援存取可移除式磁碟的第一分區
* Microsoft Windows的安裝程式只支援FAT、NTFS與ExFAT等(如果還有)檔案系統的安裝媒體
* UEFI規範只保證主板韌體一定支援FAT檔案系統(其他的檔案系統要看有沒有驅動)
* 有解,如Rufus開發者開發的[UEFI:NTFS](https://github.com/pbatard/uefi-ntfs)驅動
---
### 檔案系統選用
* 有日誌(journaling)的檔案系統會增加讀寫負擔,不建議使用
* 針對Flash儲存裝置設計的檔案系統較佳,但有系統、bootloader支援度的問題
* Flash-Friendly File System(F2FS)
* [什麼是Flash Translation Layer(FTL)?](http://anemospring.blogspot.tw/2010/06/ftl-scheme-flash-translation-layer.html)
---
### 檔案系統選用
![](https://i.imgur.com/8vDgpX2.png)
---
### 分區參考1(EXT2)
```
# parted /dev/sdX --script unit MiB print
型號:JetFlash Transcend 64GB (scsi)
磁碟 /dev/sdX:60160MiB
磁區大小 (邏輯/物理):512B/512B # 假的
分割區:msdos
磁碟旗標: # 不需要 boot 旗標,會需要的你的主板韌體有問題
編號 起始點 結束點 大小 類型 檔案系統 旗標
1 4.00MiB 5120MiB 5116MiB primary fat32 lba
2 5120MiB 60160MiB 55040MiB primary ext2
```
---
### 分區參考2(F2FS)
```
# parted /dev/sdX --script unit MiB print
型號:JetFlash Transcend 64GB (scsi)
磁碟 /dev/sdX:60160MiB
磁區大小 (邏輯/物理):512B/512B
分割區:msdos
磁碟旗標:
編號 起始點 結束點 大小 類型 檔案系統 旗標
1 4.00MiB 5004MiB 5000MiB primary fat32
2 5004MiB 6004MiB 1000MiB primary ext2
3 6004MiB 60160MiB 54156MiB primary
```
---
## 檔案系統初始化
* FAT檔案系統的標籤長度最多11個位元組
* EXT檔案系統的標籤長度最多16個位元組
---
## Debootstrap安裝基本系統
```
$ sudo mkdir --parents /mnt/debootstrap/rootfs
$ cd /mnt/debootstrap
$ sudo mount /dev/sdX3 rootfs
# debootstrap [OPTION]... <suite> <target> [<mirror> [<script>]]
$ sudo debootstrap xenial rootfs http://tw.archive.ubuntu.com/ubuntu
```
---
## 把其他檔案系統掛載在正確的位置
```bash
$ sudo mount /dev/sdX2 rootfs/boot
$ sudo mkdir rootfs/boot/efi
$ sudo mount /dev/sdX1 rootfs/boot/efi
```
---
## 變更根目錄(chroot)以取得該系統的 Root Shell
* 程序太麻煩了,直接偷用 ArchLinux 的 arch-chroot 腳本吧
```bash
$ sudo arch-chroot rootfs
```
---
## 自訂主機名稱
由於是異機可用系統所以沒「主機」名稱可設,選個自己好記的吧:
```bash
$ sudo printf 'MY-USB\n' >/etc/hostname
```
主機名稱→網路地址映射設定也要新增對應的項目:
```bash
$ sudo printf '127.0.1.1\tMY-USB\n' >>/etc/hosts
```
```
$ sudo hostname -f /etc/hostname
$ bash
```
---
### 參考資料
* hostname(5) 的使用手冊頁面(manpage)
* hosts(5) 的使用手冊頁面
* hostname(1) 的使用手冊頁面
---
## <small>WORKAROUND</small><br>修正 APT 軟體來源清單
Debootstrap 預設給的軟體來源清單是不完整的,弄一個相對完整的給它
```bash
$ sudo apt install nano # 或是你慣用的純文字文件編輯器
$ sudo cp --force /usr/share/doc/apt/examples/sources.list /etc/apt/sources.list
$ sudo apt edit-sources # 注意目前 Ubuntu 16.04 提供的範本使用的是 14.04(trusty) 的軟體來源,請手動修正
```
* [Repositories - Community Help Wiki](https://help.ubuntu.com/community/Repositories#Managing_Repositories)
---
## 全系統升級
由於使用的 suite 是 xenial 而非 xenial-updates 故需要如此
```bash
$ sudo apt update # 更新本地軟體來源快取資料
$ sudo apt full-upgrade
```
---
## 初始化語系設定
```
$ sudo dpkg-reconfigure locales
# 勾選 `zh_TW UTF-8 UTF-8`、`zh_HK UTF-8 UTF-8` 跟 `zh_CN UTF-8 UTF-8`
# 預設語系選 zh_TW.UTF-8
$ sudo update-locale LANGUAGE=zh_TW:zh_HK:zh:en
```
---
## 安裝 Linux 作業系統核心
基本系統預設是沒有作業系統核心的(因為某些情境其實不需要)
```bash
$ sudo apt install linux-signed-generic
# 安裝舊式PC開機支援的 GRUB 的提問,選擇根裝置(/dev/sdX)而非底下的分區裝置(/dev/sdXN)
```
這邊直接安裝簽好 SecureBoot 的版本(-signed)
---
## 安裝 GRUB 開機載入程式<br>(舊式PC開機支援)
一樣,基本系統預設是沒有開機載入程式(bootloader)的(因為某些情境不需要),**這個步驟實際上已在上個步驟進行**
```bash
$ sudo apt install grub-pc-bin grub2-common
$ sudo grub-install --verbose /dev/sdX
```
* 故意不裝 grub-pc 軟體包,因為會跟等一下安裝的 grub-efi-amd64-signed 軟體包衝突
* 有 30KiB 附近大小的 core.img 程式被寫進**MBR跟第一分區間的間隙**
---
## 停用 GRUB 其他系統開機選單自動產生
```
$ sudo chmod a-x /etc/grub.d/30_os-prober
$ sudo update-grub
```
---
## 新式PC開機支援<br><small>(含Secureboot簽章)</small>
```bash
$ sudo apt install grub-efi-amd64-signed shim-signed grub-efi-ia32-bin
$ sudo grub-install --target=x86_64-efi --uefi-secure-boot --removable --verbose
$ sudo grub-install --target=i386-efi --removable --verbose
$ sudo sh -c 'mkdir --parents /boot/.disk && touch /boot/.disk/info' # 讓有簽章的 GRUB 能找到 /boot 分區的 workaround
```
* grub-efi-ia32-bin 提供 Intel 32位元處理器架構的UEFI韌體(但沒有Secureboot簽章)
* 目前預設只支援內接磁碟開機方式,外接式的要自己修
---
## 新式PC開機支援<br><small>(含Secureboot簽章)</small>
```
/boot/efi
└── EFI
├── BOOT
│ ├── BOOTIA32.EFI # 沒有簽章的 Intel 32位元處理器架構 GRUB 開機載入程式
│ ├── BOOTX64.EFI # 有簽 Microsoft 簽章的 Intel 64位元處理器架構 SHIM 開機載入程式,可驗證 Canonical 簽章
│ ├── grub.cfg # 實際上這個不會被讀到
│ ├── grub.efi # 跟 BOOTIA32.EFI 一樣,因軟體缺陷冗餘生出來的檔案?
│ ├── grubx64.efi # 有簽 Canonical 簽章的 GRUB 開機載入程式
│ └── mmx64.efi # 自簽章需要
└── ubuntu # 完全用不到但因為 GRUB 的軟體缺陷會自動安裝
├── fw
├── fwupx64.efi
├── grub.cfg
├── grubx64.efi
├── mmx64.efi
└── shimx64.efi
```
---
## <small>WORKAROUND</small><br>修正 GRUB 沒有將 root 核心參數設定為 UUID 的問題
* 由於 GNU GRUB 的軟體缺陷,可被Linux作業系統核心識別 UUID 的 F2FS 根目錄系統被判定為無法識別而汰退為保存對異機使用不友善的相對路徑(如 /dev/sdX3),此問題修正前需要手動解決才不會開機時無法掛載根目錄檔案系統
```bash
# sudo mkdir /etc/default/grub.d
$ sudo nano /etc/default/grub.d/10-local-force-to-use-uuid-for-rootfs-device-specification.cfg
# 在 GRUB_CMDLINE_LINUX_DEFAULT 的值後面加上 `root=UUID=〈根目錄檔案系統的UUID,查閱 `blkid` 命令的輸出〉` 其會覆越掉前面自動插入的 root 核心參數設定
$ sudo update-grub # 重新產生開機選單
```
---
## <small>WORKAROUND</small><br>強制作業系統核心以文字模式啟動
在部份的硬體配置下早期的開機訊息將無法顯示在螢幕上,此法可以迴避此問題
```
printf "# Force boot in text mode to avoid blank screen during early boot stages.\nGRUB_GFXPAYLOAD_LINUX=text\n" > /etc/default/grub.d/10-local-force-text-mode.cfg
```
---
## 撰寫檔案系統掛載設定<br>(/etc/fstab)
參閱 fstab(5) 的 manpage 使用手冊頁面
```bash
$ sudoedit /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
```
---
## 撰寫檔案系統掛載設定<br>(/etc/fstab)
* file system 欄位建議使用 UUID
* FAT 檔案系統的 type 為 `vfat`,且 options 須填入 `utf8=1` 以支援 Unicode 檔名
* options 如果沒有已知的就填 defaults
* dump 欄位都設定 0
* pass 欄位根目錄檔案系統設定為 1,其他的設定為 2
---
## 安裝 F2FS 的使用者空間工具以讓 F2FS 檔案系統在開機時可以被檢查
```bash
$ sudo apt install f2fs-tools
# 檢查有沒有包入initramfs
$ lsinitramfs /boot/initrd* | grep 'fsck\.f2fs'
sbin/fsck.f2fs
```
---
## 將 F2FS 檔案系統驅動核心模組打包入作業系統初始化時期運行記憶體檔案系統(initramfs)中
這樣系統才能成功掛載根目錄檔案系統
:::warning
注意:理論上應該要自動包入才對,可能是個軟體缺陷
:::
---
## 將 F2FS 檔案系統驅動核心模組打包入作業系統初始化時期運行記憶體檔案系統(initramfs)中
```bash
$ printf '# F2FS根目錄檔案系統掛載支援\nf2fs\n\n' \
| sudo tee --append /etc/initramfs-tools/modules
# F2FS根目錄檔案系統掛載支援
f2fs
$ update-initramfs -k all -uv
# 檢查有沒有包入核心模組
$ lsinitramfs /boot/initrd* | grep 'f2fs\.ko'
```
---
## <small>WORKAROUND</small><br>迴避F2FS沒有依賴crc32模組的問題<br><small><a href='https://bugzilla.kernel.org/show_bug.cgi?id=187471' target='_blank'>Linux作業系統核心第187471號軟體缺陷</a></small>
```bash
$ printf '# WORKAROUND: 迴避F2FS沒有依賴crc32模組的問題\n# https://bugzilla.kernel.org/show_bug.cgi?id=187471\ncrypto-crc32\n\n' \
| sudo tee --append /etc/initramfs-tools/modules
# WORKAROUND: 迴避F2FS沒有依賴crc32模組的問題
# https://bugzilla.kernel.org/show_bug.cgi?id=187471
crypto-crc32
$ update-initramfs -k all -uv
```
---
## (選用)加快F2FS乾淨檔案系統的檢查速度
如果開機的時候一直卡在呼叫 fsck.f2fs 的話可以將 `fastboot` 參數加入 Linux 作業系統核心參數列中
```bash
$ sudoedit /etc/fstab
# 在 / 項目的掛載選項中加入 `fastboot`
```
---
## 新增一般使用者帳號
記得給他 sudo 的使用權限
```bash
$ sudo adduser _user_name_
$ sudo gpasswd --add _user_name_ sudo
```
---
## 安裝 Xubuntu 桌面版
```
# apt install xubuntu-desktop
```
:::info
注意:如果設定軟體途中在 blueman 軟體包發生錯誤,此為 blueman 軟體包打包的已知缺陷:[#878814 - fails to install in a chroot - Debian Bug report logs](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=878814)
:::
---
## 搞定收工!
```
# exit
$ sudo umount --recursive rootfs
$ udisksctl power-off --block-device /dev/sdX
# 可以拔儲存裝置了
```
---
## 參考資料<br><small>快閃記憶體基本知識方面</small>
* [LiveUsbPendrivePersistent - Ubuntu Wiki](https://wiki.ubuntu.com/LiveUsbPendrivePersistent "LiveUsbPendrivePersistent - Ubuntu Wiki")
* [Optimizing Linux with cheap flash drives [LWN.net]](https://lwn.net/Articles/428584/)
* [F2FS: A New File System for Flash Storage | USENIX](https://www.usenix.org/conference/fast15/technical-sessions/presentation/lee)
* [Understanding Flash: Blocks, Pages and Program / Erases | flashdba](https://flashdba.com/2014/06/20/understanding-flash-blocks-pages-and-program-erases/)
---
## 參考資料<br><small>開機相關</small>
* [UEFI/SecureBoot - Ubuntu Wiki](https://wiki.ubuntu.com/UEFI/SecureBoot)
* [GNU GRUB Manual 2.02](https://www.gnu.org/software/grub/manual/grub/grub.html)
* [Ubuntu 簽署了 Secureboot 的 GRUB 開機程式開機原理分析 - HackMD](https://hackmd.io/69I-NAe_SRGPc_qxJia7dg?view)
---
## 參考資料<br><small>系統設定</small>
* [Repositories - Community Help Wiki](https://help.ubuntu.com/community/Repositories#Managing_Repositories)
* hostname(5) 使用手冊頁面
* hosts(5) 使用手冊頁面
---
## 參考資料<br><small>其他</small>
* update-grub-gfxpayload(8) 使用手冊頁面:
```
‘GRUB_GFXPAYLOAD_LINUX’
Set to ‘text’ to force the Linux kernel to boot in normal text mode, ‘keep’ to preserve the graphics mode set using ‘GRUB_GFXMODE’, ‘widthxheight’\[‘xdepth’\] to set a particular graphics mode, or a sequence of these separated by commas or semicolons to try several modes in sequence. See [gfxpayload](https://www.gnu.org/software/grub/manual/grub/grub.html#gfxpayload).
Depending on your kernel, your distribution, your graphics card, and the phase of the moon, note that using this option may cause GNU/Linux to suffer from various display problems, particularly during the early part of the boot sequence. If you have problems, set this option to ‘text’ and GRUB will tell Linux to boot in normal text mode.
```
{"metaMigratedAt":"2023-06-14T15:55:29.260Z","metaMigratedFrom":"Content","breaks":"true","title":"如何在外接式儲存裝置中安裝可保留作業狀態的 Ubuntu 作業系統","description":"https://hackmd.io/@brlin/portable-ubuntu","contributors":"[{\"id\":\"62aab908-4afa-4059-813c-f855a82c2b1d\",\"add\":740,\"del\":421}]"}