3540 字
18 分鐘
【DevOps】在 Windows 安裝 WSL2 和 Podman

  程式寫好後,打包與部署也是一段繁雜的操作流程,這就是現代 DevOps 重要的一環;來學一點現代的解方——容器化(Containerization)。

Why?#

  先講一些基礎概念和我為何選擇、需要這些工具:

Why 容器化(Containerization)?#

  • 新技術的推出總是因為想解決舊技術的一些問題——以一個前後端分離的 web app 舉例,容器化技術想解決的舊問題大致如下:
    1. 部署一個 web app 的多個服務需要一台 VM,從裝 Linux 作業系統開始,然後前端需要 web server 如 Apache 或 nginx、後端需要程式語言的執行環境如 Java 或 Node.js 等等、還需要裝資料庫,都裝好後依序設環境變數,流程繁雜。
    2. 如果有第二個 web app 想要部署?再開一台 VM 比較穩定、但耗更多資源;和之前的 web app 共用一台 VM 也不是不行,不過就會互相影響,比如其中一個 app 把記憶體或硬碟佔滿導致 VM 掛掉、兩個 app 一起死。
    3. 開發過程在開發電腦的環境裡測試沒問題,但是上到生產環境 VM 裡有些不曉得哪裡的執行環境設定不太一樣、導致跑起來出問題,除錯麻煩……
  • 容器化技術能夠解決以上這些問題,原理……簡單講是把虛擬化的層級從傳統 VM 的作業系統層級往上一層,每個環境不需要各自有一個完整的作業系統、而是多個 container 共用一個作業系統核心。
    1. 一個 web app 的多個服務各打包為一個 image,透過 compose.yaml 這類腳本一併處理打包為多個 image 與執行多個 container,方便自動化處理、省下人工操作的麻煩與高錯誤率。
      • 前端可以把 web server 和前端 build 好的結果包成一個 container,後端也可以把執行環境和 build 出的結果包成一個 container,再一個資料庫的 container,就能跑起前後端分離的 web app 了。
    2. 多個 container 是獨立的,不過能透過 port 溝通、所以後端 container 還是能用傳統的方式連接到資料庫 container。
    3. 開發電腦上也用一樣的 image 建立 container 測試執行,就與生產環境 VM 裡幾乎相同了。

Image 與 Container#

  • Image:譯作「映像檔」,是已打包好、但靜態躺著未被執行的程式模板;有點像是 OOP 概念裡的 class。
  • Container:譯作「容器」,是照著程式模板執行起來的實例;有點像是 OOP 概念裡基於 class 創建的 instance。
    • Container 使用的資料會存放在 Volume,類似於電腦的硬碟、拔掉換一顆資料就全部不見;管理 Container 的工具通常可以一併管理其 Volume。

Why WSL2?#

  • WSL,全稱「Windows Subsystem for Linux」,是 Windows 官方內建的 Linux 核心
  • 比跑在 VirtualBox VM 裡的 Linux 更原生支援、且可以和平常使用的 Windows 作業系統同時運行
  • 有分 WSL 和 WSL2,前者的概念比較像把 Linux 指令翻譯成 Windows 作業系統聽得懂的指令去執行,後者就真的是 VM 了,也因此後者支援 Linux 的功能較為完整
  • 稍早說明容器化時有提到可在同個 VM 裡透過容器管理工具執行 container,不過目前的容器管理工具僅支援在 Linux 作業系統上執行……所以要想在 Windows 上執行,就要靠 WSL2 了!

Why Podman?#

  • 容器化技術現已有開放標準「OCI(Open Container Initiative)」,所以各家可以根據標準做自己的實現產品、打包出的 image 可以共用
  • 較早推出、目前也最普及的容器管理工具是 Docker,學習資源也較多;相較之下 Podman 又是新技術了,相比的優勢大概有以下幾點:
    1. Docker 的本體是開源的,但 Windows 上需要一併使用的 Docker Desktop 不是開源,只是非營利下可免費使用;Podman 和 Podman Desktop 則皆為開源。
    2. Docker 執行時需要 root 權限,Podman 則不需要,隔離權限以提高安全性。
    3. Podman 作為市場挑戰者(?),設計基本指令時用法幾乎都和 Docker 一模一樣,在兩者之間轉換的重新學習成本很低。
  • 考量到 Podman 有其優勢,又因為 OCI 和指令用法相同、未來如果一些情境必須用 Docker 也不難轉換,所以我決定直接從 Podman 學起。

Why Podman Desktop?#

  • 雖然確實可以只在 WSL2 VM 裡裝 Podman,但那樣的話在 Windows 作業系統這邊就沒辦法用了
  • Podman Desktop 就是為了能在 Windows 作業系統這邊執行而設計的工具,而且還有 GUI、方便檢視和操作

Podman、Podman Desktop 與 Podman Machine#

  • 待會安裝過程可能會對這三者有點迷糊,可以先知道一點概念、再去實際操作安裝步驟、再回來讀一次,就會比較瞭解這兩者了
  • Podman 需要在一個 Linux 作業系統裡執行;雖然確實可以只在 WSL2 VM 裡裝 Podman,但那樣的話在 Windows 作業系統這邊就沒辦法用了。
  • Podman Desktop 就是為了能在 Windows 作業系統這邊執行而設計的工具,而且還有 GUI、方便檢視和操作
  • Podman Desktop 的實現方式是透過 WSL2 建立一個專屬的 Linux VM 給 Podman 用、也就是 Podman machine
  • 所以 Podman Desktop、Podman machine、Podman 是三個不同的服務,Podman 依賴 Podman machine、Podman Desktop 則用於管理 Podman machine 與其裡面的 Podman
    • 如果沒有設好一連串的自動啟動,想要用 Podman 時要記得先啟動 Podman machine、才能用 Podman。
    • 如果 Podman 沒開、就先開 Podman Desktop,會發現[Containers]等頁籤畫面都顯示「No Container Engine」,就是指你還沒開 Podman machine。
    • 進階情境下甚至可以在一個 Windows 的 WSL2 裡有多個 Podman machine
    • 不過預設設定是登入 Windows 就會自動啟動 Podman Desktop、啟動 Podman Desktop 就會自動啟動安裝時一併裝好的 Podman machine,就不會遇到這些問題了。

步驟#

啟用 WSL#

  1. 確保已開啟虛擬化:工作管理員 >[效能]頁籤 >[CPU]頁籤 > 右下角「模擬」顯示「已啟用」
    • 如果沒啟用怎麼辦?似乎是要進 BIOS 改設定……我沒碰到,就暫不深入研究了。
  2. 安裝 WSL:在 CLI 執行 wsl --install,下載與安裝、看到提示後重新啟動電腦
  3. 重啟後安裝 Ubuntu
    • 「Ubuntu」是 WSL 預設安裝的 Linux distribution
    • 應是會自動安裝 Ubuntu、跳出 Terminal 視窗提示創建使用者帳號
    • 可能由於某些因素沒有自動安裝……
      1. 先執行 wsl -l -v 確認 WSL 已正常安裝(應會跳出 Windows 子系統 Linux 版 沒有已安裝的發佈。
      2. 執行 wsl --install -d Ubuntu
  4. 創建使用者帳號
    • 提示訊息像是 Create a default Unix user account:,依序輸入要設的使用者名稱與密碼
    • 打密碼的時候畫面上完全不會有任何反應、係屬正常現象,Linux 都是這樣設計的、請安心繼續打字 XD
    • 這個使用者不是 root,不過系統會自動把這個使用者加入 sudo group、未來可以打 sudo 輸入這個使用者的密碼、暫時取得 root 權限做操作
  • 退出 WSL、回到原本的 shell:exit
  • 列出正在運行的 WSL VM:wsl -l -v
  • 關掉 WSL:wsl --shutdown
    • 閒置時還是會佔資源,如果在意可以手動關掉

安裝 Podman Desktop 與 Podman#

  1. 官網 下載安裝檔
  2. 執行安裝檔、選一下要僅安裝給此使用者還是所有使用者……然後就可以點[完成]了 OuO
  3. 進入 Get started 引導——「Choose the extensions to include」有三個選項、選擇要安裝的部分
    • Podman:本體、包含 CLI 和 Podman machine,當然要勾選
    • kubectl CLI:Kubernetes 的控制工具,我大概暫時還用不到、先略過,反正按照提示說明、以後都可以再啟用
    • Compose:多容器管理工具,開發 web app 會常用、這次順便裝起來
  4. 選好 extensions 後回到主畫面,跟著引導依序安裝 Podman 和 Compose

安裝 Podman#

  1. 顯示「We could not find Podman. Let’s install it!」,就順著引導去安裝
  2. 要選擇「Virtualization Provider for the Podman machine」,在這裡我就選擇剛裝好的「WSL v2」
  3. 「Autostart Podman engine when launching Podman Desktop」:我就選擇 Enabled
  • 這是 CLI

創建 Podman machine#

  1. 顯示「We could not find any Podman machine. Let’s create one!」,順著引導按右下角的[Next]
  2. 「Create a Podman machine」頁面,有一些選項可選,可以都保持預設就好、繼續[Create]
    • 一般情況下 Machine with root priviledges 可以關閉,這就是之前提到 Podman 可以在無 root 權限執行的優勢
  • 這是一個 VM,如果之前 Virtualization Provider 選擇「WSL v2」,就是 WSL 裡面的一個 Linux instance,名稱就是自己設定的 Name
    • 在檔案總管左下方[Linux]頁籤,可以看到目前所有的 Linux instance、有稍早安裝的 Ubuntu 和剛剛創建的 Podman machine……原來兩者其實是獨立不相干的 😅
  • podman machine 開頭的 CLI 指令就是針對這台 Podman machine,podman 開頭的指令才是 Podman CLI

安裝 Compose#

  1. 第一頁有個 Note 提示:If you would like to use docker compose up or docker-compose with Podman, enable Docker Compatibility.,先記在腦袋裡、下一步會去處理它。
  2. 接著就一路[Next]到底

根據個人偏好改一些設定……#

  偏好設定都在左下角[Settings]> 左方[Preference]頁籤

  • Appearance > Zoom Level:介面縮放,從 0 調到 1,眼睛舒服多了 😆
  • Docker Compatibility > Enabled:啟用後在 CLI 打 docker 會自動導向使用 podman,就像設 alias 的概念
    • 如果這台電腦上只有裝 Podman、沒裝 Docker,那就啟用它吧、打錯沒煩惱 XD
    • 前一步說記在腦袋裡的提示就是這個
  • Start on login > Start:登入 Windows 時是否自動啟動 Podman Desktop 、並接著自動啟動 Podman Machine
    • 如果沒開,開機後直接在 CLI 打 podman 指令是無效的;要自己先啟動 Podman Desktop 或執行 podman machine start 後才能用。

嘗試執行第一個 container:nginx#

  1. 先準備一個目錄的靜態網頁檔案、並 cd 到該目錄,待會用來透過 nginx serve
  2. 創建並啟動 container:run
    Terminal window
    podman run -d `
    --name test-nginx `
    -p 3001:80 `
    -v "${PWD}:/usr/share/nginx/html:ro" `
    nginx:1.29.7-alpine
    • -d:detached,背景執行、不佔用 terminal
    • -p 3001:80:port 映射(mapping),冒號前面是本機、冒號後面是容器內,意思是把傳遞給本機 3001 port 的 request 轉發進容器裡的 80 port、也就是 nginx 在監聽的 port
      • 本機 port 可以隨自己喜好挑、只要不要和其他正在執行的服務衝突就好
    • -v "${PWD}:/usr/share/nginx/html:ro":掛載 volume,值以冒號分隔
      • 第一個欄位:volume 資料位置,有兩種模式:
        1. Bind Mount:寫本機的絕對路徑,檔案就存放在本機的這個位置
          • ${PWD} 是目前目錄的變數;變數只能在雙引號內使用,若在單引號內、變數不會解析出來。
          • 順帶一提,${PWD} 是 Powershell 的語法,cmd 和 bash 會有所不同。
        2. Named Volume:寫名稱,由 Podman 管理,相同的名稱就指向相同的 volume
      • 第二個欄位是 container 內的位置,表示把本機於第一個欄位填寫的位置綁定到 container 裡的這裡
      • 第三個欄位非必填,ro 表示 Read-Only、在這個 nginx 的使用情境適合加上。
    • nginx:1.29.7-alpine:指定用哪個 image 創建這個 container;這裡輸入的 tag 可以去 Docker Hub 上面找,熱門工具幾乎都有官方出的 image
      • nginx 舉例,tag 裡還有好幾個後綴,舉兩個現階段用得到的說明一下:
        • (無後綴的普通版):通常基於 Debian、常見的 Linux distribution,有基礎的預裝 bash 工具如 grep
        • alpine:基於 Alpine、是另一個 Linux distribution,主打安全、輕量級和極簡,不過相較於普通版,可能不支援一些開發時常用的額外功能,且由於缺少某些 C 語言擴充套件、某些使用情境會有相容性問題;一般推薦開發時用普通版、到生產環境且不會撞到相容性問題再用此版本。
  3. 執行 podman ps 看這個 test-nginx container 是否正在執行,如果是、開瀏覽器去 localhost:3001 應該就看得到網頁了
    • podman ps -a 才能看到所有 container、包含目前非執行中的
    • 是否正在執行要看 STATUS 欄位,正在執行會顯示 Up <啟動至今過了多久>、非執行中會顯示 Exited <多久前停止>
  4. 啟動和停止 container:podman start test-nginxpodman stop test-nginx
    • 未來就不用再執行 run 了,只有創建 container 時才會用到,且 run 時設定的 port 等資訊都已經寫死在裡面了。

後記閒聊#

  我在寫文章時會刁鑽一些用字遣詞(?),比如該用「占用」還是「佔用」;這次遇到一個大問題是該用「nginx(全小寫)」、「NGINX(全大寫)」還是「Nginx(首字母大寫)」?

  • nginx 官網 上是全小寫、且不因在句首或標題而首字母轉大寫
  • 但在公司和產品方面,F5 公司的產品介紹 是全大寫;IThome 的相關新聞 也是用全大寫
  • 維基百科 是固定首字母大寫,不過右邊資訊卡上又是全大寫?
  • 多篇網路上的技術部落格分享是固定首字母大寫,如 古古的後端筆記
  • 發現了這則不太確定來源的論壇回文:How exactly is NGINX spelled?,看起來回文者的 Email 是屬於 nginx.org 網域、代表是內部人員;不過這是 2012 年的回文了、2019 年 F5 收購 NGINX, Inc.。

  最後我的決定是指軟體工具時用「nginx(全小寫)」,品牌商標之類的情境再用「NGINX(全大寫)」——不過可能沒什麼機會用到就是了。

  順帶一提,唸法是「Engine X」,這點就沒爭議了。

參考資料#

延伸閱讀#