在 macOS 中使用 Podman

米開朗基楊發表於2020-11-23

原文連結:https://fuckcloudnative.io/posts/use-podman-in-macos/

Podman 是一個無守護程式與 Docker 命令相容的下一代 Linux 容器工具,該專案由 RedHat 主導,其他的細節可以參考 Podman 使用指南,本文的重點不是這個。

Podman 一直以來只能跑在 Linux 系統上,macOSWindows 只能通過 CLI 遠端連線 Podman 的 API 來管理容器。事實上 Docker 也不支援 macOS 和 Windows,但 Docker 針對 Windows 和 macOS 推出了專門的客戶端,客戶端裡面整合了虛擬化相關的設定,通過巢狀一層虛擬化來支援 Docker。對於 Podman 來說,想要在 macOS 上執行也只能通過虛擬化來實現,網上也有不少方案,基本上都是通過 Virtualbox 來實現,都不太優雅。本文將介紹一種相對更優雅的方案,雖然不是很完美,但我已經盡力做到接近完美了。。

HyperKit 介紹

HyperKit 是一個具有 hyperisor 能力的輕量級虛擬化工具集,包含了基於 xhyve(The BSD Hypervisor)的完整 hypervisor。HyperKit 設計成上層元件諸如 VPNKitDataKit 的介面。xhyve 是 基於 bhyve 的 Mac OS X 移植版本,而 bhyve 又是 FreeBSD 下的虛擬化技術。。。

我們知道,Docker 在 Linux 上利用了 Linux 原生支援的容器方式實現資源和環境的隔離,直接利用宿主核心,效能接近原生。然而,在 macOS 上卻仍然需要虛擬化的技術。早期的 Docker 乾脆直接在開源的 VirtualBox 中構建虛擬機器,效能低下。後期的 Docker 基於輕量化的虛擬化框架 HyperKit 開發,據說效能得到很大提升。

本文將介紹如何通過 HyperKit 來使用 Podman。方法也很簡單,先通過 Hyperkit 建立一個輕量級虛擬機器,然後在虛擬機器中安裝 Podman,並開啟 remote API,最後在本地通過 CLI 連線虛擬機器中的 Podman。這和 macOS 中的 Docker 實現原理是一樣的,只不過 Podman 是沒有 Daemon 的,與 Docker 相比可以節省不少資源。

2. 安裝 HyperKit

你可以自己下載原始碼編譯 HyperKit,但我不建議這麼做,不同的 macOS 版本會遇到各種各樣的錯誤。我這裡推薦兩種超級簡單的方法:

  1. 直接通過安裝 Docker 來獲得 HyperKit,因為 Docker Desktop on Mac 就是基於 HyperKit 實現的,所以安裝 Docker Desktop on Mac 就能夠獲得完整的 HyperKit 執行環境。整個過程會非常順暢和簡單。安裝完 Docker 之後可以永遠不用開啟 Docker,直接使用 HyperKit 就好。或者你可以直接解除安裝 Docker,解除安裝之前先把 hyperkit 二進位制檔案備份出來,因為解除安裝 Docker 也會刪掉 hyperkit 二進位制檔案。

  2. 直接通過安裝 Multipass 來獲得 HyperKit。Multipass 是 Canonical 公司(Ubuntu)開發的基於不同作業系統內建原生 Hypervisor 實現的工作站。由於 Windows(Hyper-V),macOS(hyperkit)和 Linux(KVM)都原生支援 hypervisor,這樣通過 multipass shell 命令就能夠在一個 shell 中實現建立執行 Ubuntu 虛擬機器。在 macOS 平臺,預設的後端是 hyperkit,需要 macOS Yosemite (10.10.3) 以上版本並且需要安裝在 2010 以後生產的 Mac 裝置。安裝方法很簡單:

    $ brew cask install multipass
    

    安裝好了之後可以在 /Library/Application Support/com.canonical.multipass/bin/ 目錄下找到 hyperkit 二進位制檔案。

3. 建立虛擬機器

你可以直接通過 hyperkit 來建立虛擬機器,但引數比較複雜,有興趣的自己研究吧。我推薦直接通過 multipass 來建立,命令特別簡單:

$ multipass launch -c 2 -d 10G -m 2G -n podman
  • -n : 指定啟動例項名字
  • -c : 分配 CPU 數量
  • -d : 設定磁碟容量
  • -m : 設定記憶體容量

第一次啟動虛擬機器的時候會去拉去映象,國內網速可能會很慢。

檢視已經啟動的虛擬機器:

$ multipass list
Name                    State             IPv4             Image
podman                  Running           192.168.64.2     Ubuntu 20.04 LTS

進入虛擬機器:

$ multipass shell podman
Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-52-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun Nov  8 19:30:29 CST 2020

  System load:  0.0                Processes:               119
  Usage of /:   13.4% of 11.46GB   Users logged in:         0
  Memory usage: 11%                IPv4 address for enp0s2: 192.168.64.2
  Swap usage:   0%


0 updates can be installed immediately.
0 of these updates are security updates.


Last login: Sun Nov  8 17:38:31 2020 from 192.168.64.1
ubuntu@podman:~$

4. 安裝 Podman

在虛擬機器中安裝 Podman:

ubuntu@podman:~$ . /etc/os-release
ubuntu@podman:~$ echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" | ubuntu@podman:~$ sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
ubuntu@podman:~$ curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key | sudo apt-key add -
ubuntu@podman:~$ sudo apt-get update
ubuntu@podman:~$ sudo apt-get -y upgrade
ubuntu@podman:~$ sudo apt-get -y install podman

5. 建立 Podman Socket

Podman 依賴於 systemd 的 socket activation 特性。假設 Daemon B 依賴於 Daemon A,那麼它就必須等到 Daemon A 完成啟動後才能啟動。socket activation的思想就是:Daemon B 啟動時其實並不需要 Daemon A 真正執行起來,它只需要 Daemon A 建立的 socket 處於 listen 狀態就 OK 了。而這個 socket 不必由 Daemon A 建立, 而是由 systemd 在系統初始化時就建立。當 Daemon B 發起啟動時發起連線,systemd 再將 Daemon A 啟動,當 Daemon A 啟動後,再將 socket 歸還給 Daemon A。

Podman 會通過 podman.socket 先建立一個處於監聽狀態的 socket 檔案 /run/podman/podman.sock,當有程式向該 socket 發起連線時,systemd 會啟動同名的 service:podman.service,以接管該 socket。先看看 podman.socket 和 podman.service 長啥樣:

ubuntu@podman:~$ sudo systemctl cat podman.socket
# /lib/systemd/system/podman.socket
[Unit]
Description=Podman API Socket
Documentation=man:podman-system-service(1)

[Socket]
ListenStream=%t/podman/podman.sock
SocketMode=0660

[Install]
WantedBy=sockets.target

ubuntu@podman:~$ sudo systemctl cat podman.service
# /lib/systemd/system/podman.service
[Unit]
Description=Podman API Service
Requires=podman.socket
After=podman.socket
Documentation=man:podman-system-service(1)
StartLimitIntervalSec=0

[Service]
Type=notify
KillMode=process
ExecStart=/usr/bin/podman system service

設定開機自啟 podman.socket,並立即啟動:

ubuntu@podman:~$ sudo systemctl enable podman.socket --now

確認 socket 是否正處於監聽狀態:

ubuntu@podman:~$ podman --remote info
host:
  arch: amd64
  buildahVersion: 1.16.1
  cgroupManager: systemd
  cgroupVersion: v1
  conmon:
    package: 'conmon: /usr/libexec/podman/conmon'
    path: /usr/libexec/podman/conmon
    version: 'conmon version 2.0.20, commit: '
  cpus: 2
  ...

3. 客戶端 CLI 設定

接下來所有的設定,如不作特殊說明,都在 macOS 本地終端執行。

Podman 遠端連線依賴 SSH,所以需要設定免密登入,先生成祕鑰檔案:

$ ssh-keygen -t rsa   # 一路回車到底

然後將本地的公鑰 ~/.ssh/id_rsa.pub 追加到虛擬機器的 /root/.ssh/authorized_keys 檔案中。

安裝 Podman CLI:

$ brew install podman

新增遠端連線:

$ podman system connection add ubuntu --identity ~/.ssh/id_rsa ssh://root@192.168.64.2/run/podman/podman.sock

檢視已經建立的連線:

$ podman system connection list
Name     Identity                 URI
podman*  /Users/Ryan/.ssh/id_rsa  ssh://root@192.168.64.2:22/run/podman/podman.sock

由於這是第一個連線,所以被直接設定為預設連線(podman 後面加了 *)。

測試遠端連線是否可用:

$ podman ps
CONTAINER ID  IMAGE   COMMAND  CREATED  STATUS  PORTS   NAMES

$ podman pull nginx:alpine
Trying to pull docker.io/library/nginx:alpine...
Getting image source signatures
Copying blob sha256:188c0c94c7c576fff0792aca7ec73d67a2f7f4cb3a6e53a84559337260b36964
Copying blob sha256:9dd8e8e549988a3e2c521f27f805b7a03d909d185bb01cdb4a4029e5a6702919
Copying blob sha256:85defa007a8b33f817a5113210cca4aca6681b721d4b44dc94928c265959d7d5
Copying blob sha256:f2dc206a393cd74df3fea6d4c1d3cefe209979e8dbcceb4893ec9eadcc10bc14
Copying blob sha256:0ca72de6f95718a4bd36e45f03fffa98e53819be7e75cb8cd1bcb0705b845939
Copying config sha256:e5dcd7aa4b5e5d2df8152b9e58aba32a05edd9b269816f5d8b7ced535743d16c
Writing manifest to image destination
Storing signatures
e5dcd7aa4b5e5d2df8152b9e58aba32a05edd9b269816f5d8b7ced535743d16c

$ podman image ls
REPOSITORY                TAG     IMAGE ID      CREATED      SIZE
docker.io/library/nginx   alpine  e5dcd7aa4b5e  2 days ago   23.3 MB

現在我們就可以直接在本地用 podman 愉快地玩耍了!

如果你建立了多個連線,可用使用 --connection 引數指定遠端連線,或者使用 podman system connection default <NAME> 來設定預設的遠端連線。

最後,我們來看看 hyperkit 的記憶體佔用:

實體記憶體只佔用了 921M,如果你覺得這個記憶體佔用很多,不妨去對比下 Docker Desktop 的記憶體佔用。

總結

本文介紹了在 macOS 中使用 podman 的方法,通過 HyperKit 建立 Ubuntu 虛擬機器執行 Podman,並建立 Podman Socket,然後客戶端通過 SSH 連線服務端的 Socket,以實現通過遠端連線來管理容器。


Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12離線安裝包釋出地址http://store.lameleg.com ,歡迎體驗。 使用了最新的sealos v3.3.6版本。 作了主機名解析配置優化,lvscare 掛載/lib/module解決開機啟動ipvs載入問題, 修復lvscare社群netlink與3.10核心不相容問題,sealos生成百年證書等特性。更多特性 https://github.com/fanux/sealos 。歡迎掃描下方的二維碼加入釘釘群 ,釘釘群已經整合sealos的機器人實時可以看到sealos的動態。

相關文章