2020年2月21日 星期五

透過 RESTful API 管理一群 lxc 的 lxd

好啦, 如果需要完整的虛擬化, lxd 當然無法取代 kvm, 畢竟 lxd 只是容器 (container) 技術。 但如果只是想要玩玩不同的 distribution 的命令列, 那麼 lxd 就超合適的。 如 lxc 筆記 所說 (但換個比喻) 如果把 lxc 想成是車子的主體, 那麼 lxd 就是方向盤/排檔桿/剎車/儀表板等等 「使用者介面」。 凡是 「lxc-xxx」 長像的指令 (例如 lxc-ls、 lxc-create) 都屬於底層 lxc 套件, 是修車師傅專用的, 我們駕駛人一般不太去用它。 這篇介紹適用於駕駛人、 長得像 「lxc xxx」 的指令 (例如 lxc ls、 lxc launch)。

Ubuntu 的 lxd 文件 是很好的出發點。 它解釋: 可以說 lxd 是 「輕量級的容器 "hypervisor"」; lxd 跟 lxc 之間的關係, 有點像 libvirt 跟 qemu 之間的關係。 比較特別的是, lxd 提供遠端操作的介面。 再拿我先前的汽車比喻, 修正一下: 想像你一個人在控制室裡同時遙控遠端的十部 (半自動駕駛) 汽車, 每部汽車就是一個當地的 lxc, 而控制室裡的儀表板就是 lxd 的操作介面。 也大推 lxd 主要作者 Stéphane Graber 所寫 一系列文章 的第一篇觀念介紹文。

那麼, 接下來就先照著 ubuntu 文件 (及 Stéphane 系列第三篇) 做一小段吧。 當然, 我們的事業沒那麼龐大; lxc 跟 lxd 其實都只在本機執行。 以 sudo apt install lxd 安裝 lxd 之後, 要先執行一次 sudo lxd init 以初始化系統。 再把你的 user 加入 lxd 群組, 例如我打: sudo adduser ckhung lxd 登出再登入, 從此以後就不需要用 root 的身份; 凡人 ckhung 就可以用 lxc 指令。

lxc list   # 已建立了哪些 containers? (目前沒有)
lxc image list   # 本地已下載了哪些映像檔? (目前沒有)
lxc image list images:  # 網路上有哪些映像檔可以下載? 哇~ 好多!

因為每次查詢 (網路連線) 都有點慢, 而且輸出結果有點囉嗦, 所以我喜歡去掉一些欄位、 去掉分隔線、 把結果存檔: lxc image list images: -c lfds | grep -v '^[+-]*$' > ~/lxc-images.txt 當然, 隔一陣子, 這個資料就會過時, 需要再更新。 打開 ~/lxc-images.txt 看一下, 哇, 除了想當然爾的 debian/ubuntu/fedora/... 還有 kali 跟 openwrt 耶! 那就拿 kali 來作實驗好了:

lxc launch images:kali k1
lxc launch images:kali k2 

我們先從伺服器下載名為 「kali」 的映像檔, 以它建立名為 「k1」 的 container, 並且立即啟動。 同樣再以 kali 映像檔建立第二個 container, 名為 「k2」。 這次速度快多了, 因為本地已有映像檔。 用 lxc list 查看, 可以看到已有兩部 containers, 而且都已配有區網 ip 位址; 用 lxc image list 看到本地已有一個映像檔。

lxc exec k1 bash 進入 container, 在裡面查一下: cat /etc/os-releasedpkg -l 等等, 並且 apt update 確認一下網路順暢。 如果網路不通, 請參考 How To Set Up a Network Bridge for LXD Containers 。 因為 kali 是高手玩的, 我也不會用 (遮臉) 示範到此為止, 按 ^d 跳出。

如果要執行圖形介面的軟體, 請參考 lxc 筆記 的 X11 forwarding 那一節。 其他可能常用到的指令:

lxc info k1  # 查看 k1 的詳細訊息
lxc stop k1  # k1 關機
lxc start k1  # k1 開機
lxc delete k1  # 砍掉 k1! 起手無回!

再來是分享檔案: lxc config device add k2 share1 disk source=~ path=/mnt/hosthome 這句話會把 host 裡自己的家目錄 (/home/ckhung) 分享給 k2 這個 container, 成為 k2 裡面的一個名為 share1 的 disk 裝置, 並且自動掛載在 k2 的 /mnt/hosthome (會自動建立) 底下。 從此以後從 k2 裡面的這個目錄就可以 讀取 host 裡的檔案。

如果想要從 k2 裡面 寫入 host 所分享過來的目錄與檔案, 那就必須:

  1. 在 k2 裡面新增一個用戶, 例如 useradd -u 5971 -m -s /bin/bash snoopy 這裡故意指定奇怪數字作為 uid, 以便下一個指令看得更清楚。 也順便查一下新用戶的 gid: id snoopy
  2. 在 host 裡面指定: 把自己 (凡人 ckhung) 的 uid 與 gid 對應到 k2 裡面的 snoopy: echo -e "uid $(id -u) 5971\ngid $(id -g) 5971" | lxc config set k2 raw.idmap - (假設剛才查到的 snoopy 的 gid 跟 uid 一樣) 注意: 雙引號, 不是單引號! 這裡有差。
  3. (在 host 裡) 假設 id -u 的輸出是 1000 那麼請在 /etc/subuid 最後加一列 root:1000:1 這意思是允許 root 把 uid 1000 這一個用戶映射到 container 裡面的某用戶。 (注意: 原有的另一列 root:很大的數字:65536 不要刪掉!) 同樣地, 根據 id -g 的輸出也如法泡製在 /etc/subgid 最後加一列。 這是因為負責此事的 lxd 服務是以 root 的身份在執行的。 必須 systemctl restart lxd 才會生效。
  4. k2 關機、重開。 重新進入。 在 k2 裡面看到那些 host 所分享過來的檔案與目錄, 擁有人都是 snoopy, 可以寫入!

除錯過程可能會需要查看目前設定: lxc config device show k2 或刪除做錯的設定: lxc config device remove k2 share1 。 以上關於分享檔案, 主要參考 nixCraft Tribaal 兩篇優質教學文; 這個自問自答 也有一些參考價值。 用 echo 餵給 lxc config 的語法, 從 這個問答 學來。 可以直接編輯設定檔嗎? 根據 這個問答, 設定檔是 .db ; 但我甚至在同一目錄下也找不到設定檔。 (版本問題?) 粗略查看 原始碼, 看來就直接呼叫 newuidmap 跟 newgidmap 而已, 好像並沒有寫入什麼設定檔。 是可以從 /var/log/lxd/某容器/lxc.conf 裡面看到 「某容器」 當初創立時的所有參數設定; 但那只是歷史記錄, 並不反應目前的狀況, 更無法修改它以影響未來。 要查看目前的所有設定, 請用 lxc config show --expanded k2 ( 為什麼需要用 --expanded ?)

如果想掀開引擎蓋看看, 請用 root 的身份 (sudo bash) 進到 /var/lib/lxd 底下逛逛。 在 /var/lib/lxd/storage-pools/default/containers/ 底下會看到 k1 跟 k2 兩部 containers 的目錄, 包含各自的系統根目錄 (rootfs)。 在那裡下 du -s * 可以查看每部 container 佔用多少空間。 至於映像檔, 則是下載到 /var/lib/lxd/images/ 底下。 kali linux 映像檔的一些設定檔放在 7be3...1d33 裡面, 可以用 tar tJf 7be3...1d33 查看。 (要解壓縮的話用 tar xJf ... )。 而 7be3...1d33.rootfs 則是一個 squashfs 壓縮的唯讀檔案系統。 十六進位數字 7be3...1d33 是 kali linux 映像檔的 id, 它就像是身份證字號一樣, 當初是這樣產生的: cat 7be3* | sha256sum (兩個檔串在一起的 sha256sum) 而 lxc image list 所秀的 fingerprint 就是這個 id 的一小部分。

想要再多學一些 lxd 指令的話, 可以參考 Useful LXD commands LXD cheat sheet for beginners 。 不過我覺得進不同版本的 linux 裡面探索才更好玩啊~

1 則留言:

  1. 先前遺漏了~ 在 /etc/subuid 及 /etc/subgid 裡面新增 root:1000:1 (之類的) 那一句很重要!

    回覆刪除

因為垃圾留言太多,現在改為審核後才發佈,請耐心等候一兩天。