2025年了,要不要试试Podman?(转载自知乎)

原文链接:https://zhuanlan.zhihu.com/p/22886116297

自从卸载Docker Desktop后,我一直在使用Colima。过去这三年中,它一直稳定可靠。但随着时间推移,我也逐渐发现了一些问题:Colima依然依赖Docker作为容器引擎,而且它基于第三方的Lima虚拟化方案,显得有些冗余和陈旧。偶然间我看到了Podman,它充满着新鲜感:

  • 独立引擎:与Colima依赖Docker引擎不同,Podman采用了自己的开源容器引擎,完全脱离Docker生态。这对我来说是全新的尝试。
  • Daemonless:Podman的无守护进程设计节省了系统资源,性能更好。
  • 更简单的工具链:相比于Colima需要借助Lima来实现虚拟化,Podman使用自己的Podman Machine工具。
  • 兼容性:Podman与Docker CLI完全兼容,能够无缝接入现有工作流程。

说干就干。不过动手之前,我们先深入了解一下Podman与Colima在底层实现上的区别。

提示:本文阅读时长15分钟。

架构对比

首先,所有的容器方案,都是基于Linux,所以在macOS上需要运行虚拟机。最常见的虚拟机有QEMU、Apple原生的vz和applehv。vz是macOS原生的虚拟化技术Virtualization Framework。目前LimaDocker Desktop都默认使用vz。而applehv是Apple hypervisor,据说是vz的底层技术Podman使用applehv。

在虚拟机里运行容器引擎,Docker使用守护进程dockerd,通过容器运行时containerd调用更低级别容器运行时runc。Podman则直接调用自家的容器运行时crun(也支持runc),据说crun比runc快50%,对资源的要求也更低。这些容器运行时都符合OCI标准,所以都可以运行Docker镜像。

此外,还有专门管理虚拟机环境的工具,用来下载Linux镜像、启动虚拟机。Podman方案使用Podman Machine,而Colima方案依赖Lima。

还有命令行工具,Podman方案采用的是Podman Remote通过SSH调用虚拟机内的Podman。而Colima使用Docker CLI。Podman CLI特意模仿Docker CLI,所以迁移非常顺利。

综上所述,Colima方案通过Lima启动基于vz技术的虚拟机,在macOS上使用Docker CLI与虚拟机内的dockerd交互,由dockerd调用containerd和runc控制容器;而Podman方案则使用Podman Machine基于applehv启动虚拟机,用户通过Podman Remote调用虚拟机内的Podman,后者直接调用crun。

安装上手

首先是安装Podman:

$ brew install podman

安装好以后初始化虚拟机。这会下载Fedora CoreOS镜像运行Linux。

$ podman machine init

现在就可以看到创建的虚拟机:

$ podman machine list
NAME                     VM TYPE     CREATED     LAST UP            CPUS        MEMORY      DISK SIZE
podman-machine-default*  applehv     4 days ago  2 seconds ago  7           2GiB        100GiB

然后就是启动虚拟机:

$ podman machine start

然后就可以正常使用了:

$ podman run --rm hello-world
Resolved "hello-world" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Trying to pull quay.io/podman/hello:latest...
Getting image source signatures
Copying blob sha256:1ff9adeff4443b503b304e7aa4c37bb90762947125f4a522b370162a7492ff47
Copying config sha256:83fc7ce1224f5ed3885f6aaec0bb001c0bbb2a308e3250d7408804a720c72a32
Writing manifest to image destination
!... Hello Podman World ...!

         .--"--.
       / -     - \
      / (O)   (O) \
   ~~~| -=(,Y,)=- |
    .---. /`  \   |~~
 ~/  o  o \~~~~.----. ~~
  | =(X)= |~  / (O (O) \
   ~~~~~~~  ~| =(Y_)=-  |
  ~~~~    ~~~|   U      |~~

Project:   https://github.com/containers/podman
Website:   https://podman.io
Desktop:   https://podman-desktop.io
Documents: https://docs.podman.io
YouTube:   https://youtube.com/@Podman
X/Twitter: @Podman_io
Mastodon:  @Podman_io@fosstodon.org

哈哈哈哈这怎么和正版的不一样?这是什么小可爱?

不过先不用在意这些细节哈,我们继续。现在就可以使用Podman代替Docker了:

$ alias docker=podman

如果想要自动补全,可以安装docker-completion

$ brew install docker-completion

使用完后,就可以关闭虚拟机,节约资源:

$ podman machine stop

Podman的镜像

在pull或者run的时候,需要指定镜像名字。如果使用一个简单的名字,例如podman pull mysql(这种被称为unqualified image name)。Podman会先查找Short-Name Aliasing配置:

$ podman machine ssh cat /etc/containers/registries.conf.d/000-shortnames.conf
[aliases]
  ...
  # centos
  "centos" = "quay.io/centos/centos"
  # containers
  "hello-world" = "quay.io/podman/hello"
  # docker
  ...
  # Ubuntu
  "ubuntu" = "docker.io/library/ubuntu"
  ...

我们前面运行run hello-world的时候会看见小海豹,就是因为在别名里配置了"hello-world" = "quay.io/podman/hello",所以实际上运行的是quay.io/podman/hello镜像。

如果没有在别名配置里找到,Podman就会到配置的仓库里查找,默认配置的仓库就是Docker Hub():

$ podman machine ssh cat /etc/containers/registries.conf.d/999-podman-machine.conf
...
unqualified-search-registries=["docker.io"]

这个行为就和Docker一样了。

如果要运行正版的hello-world怎么办呢?可以使用镜像全名(fully-qualified image):

$ podman run --rm docker.io/library/hello-world
...
Hello from Docker!
...

PS:hello-world是Docker的官方镜像,所以Podman里对应的镜像全名就是docker.io/library/hello-world,参考Normalization of docker.io references。如果是非官方的镜像,例如在Docker Hub的镜像pytorch/pytorch,对应的Podman里的全名就是docker.io/pytorch/pytorch

搜索

还可以通过命令行方便的搜索镜像,不需要打开Docker Hub:

$ podman search mysql --filter=is-official
NAME                     DESCRIPTION
docker.io/library/mysql  MySQL is a widely used, open-source relation...

这里会到unqualified-search-registries配置的仓库里进行搜索。

还可以查询某个镜像的tag,注意这里需要使用全名:

$ podman search docker.io/library/mysql --list-tags --limit 10000 | grep -i lts
docker.io/library/mysql  lts
docker.io/library/mysql  lts-oracle
docker.io/library/mysql  lts-oraclelinux8
docker.io/library/mysql  lts-oraclelinux9

也可以指定在某个仓库里搜索,格式是[仓库名字]/[search term]

$ podman search quay.io/centos
NAME                                     DESCRIPTION
...
quay.io/centos/centos                    The official CentOS base containers.
...

host-gateway问题

使用过程中我也遇到了一些问题。在使用Open WebUI的时候,按照文档说明运行会报错:

$ podman run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main

报错信息:Error: failed to create new hosts file: unable to replace "host-gateway" of host entry "host.docker.internal:host-gateway": host containers internal IP address is empty.

看上去问题出现在--add-host=host.docker.internal:host-gateway。这个参数是什么意思呢?我查了资料,这个参数的含义如下:

  • 在Docker环境下,host.docker.internal是一个特殊的主机名,用于解析为宿主机在容器内部的访问地址。这样容器内的应用便可以通过该地址访问宿主机提供的服务。
  • host-gateway则是一个特殊的关键字,用于在容器启动时自动解析为宿主机的IP地址,以便动态设置host.docker.internal的值。

然而,Podman默认已经提供了host.docker.internal的解析,无需额外配置。所以解决方案是直接去掉 --add-host=host.docker.internal:host-gateway参数:

$ podman run -d -p 3000:8080 -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main

Docker Compose

Docker Compose是容器化开发中常用的功能,Podman也通过external compose provider支持这一功能。external compose provider包括podman-composedocker-compose两个选项。

一开始我想彻底摆脱Docker,所以使用podman-compose。不过在使用过程中遇到了一些问题,后来切换成docker-compose后问题就解决了。

Spring Boot Docker Compose Support可以让我们在运行测试或者本地服务时,不需要额外写代码就能自动启动容器。当我将Docker/Colima替换成Podman后,运行的时候Spring Boot Docker Compose Support就报错了:Cannot run program "docker": error=2, No such file or directory

这是因为Java使用ProcessBuilder执行外部命令时,并不会读取Shell中的别名(alias)。解决这个问题,可以创建一个符号链接:

$ ln -s `brew --prefix`/bin/podman `brew --prefix`/bin/docker

然而继续运行时,报了另外一个错误,显示podman compose --ansi never config --format=json执行出错。

经过分析发现,podman-composedocker-compose虽然在命令行上尽量保持一致,但在某些功能和参数实现上存在差异。例如,上述命令中--ansi never--format=json参数在podman-compose下未能正确处理,导致兼容性问题。最终,我还是安装了docker-compose来解决该问题:

$ brew install docker-compose

清理Colima

现在可以正常使用Podman来完成功能了。如果你和我一样有“强迫症”,那你肯定想彻底删除Colima。

首先记得迁移Docker的镜像和Volume。然后删除Colima和Docker:

$ brew services stop colima
$ colima delete
$ brew uninstall docker colima qemu

PS:这里看到brew services stop colima,不得不说,Podman还有个缺点,就是不能通过brew services自动启动,期望以后会改进。

Colima使用的配置文件和pid文件,在~/.colima目录下。同时Docker的配置文件在~/.docker目录下。

删除不需要的配置文件:

$ rm -rf ~/.colima ~/.docker

PS:另外可以顺便检查下还有哪些工具是不再使用的:

$ brew leaves

既然到这里了,我们也看看Podman用了哪些文件:

  • ~/.config/containers Podman的配置,包括和虚拟机的连接信息,例如podman-connections.json
  • ~/.local/share/containers 虚拟机运行文件目录

这就是我从Docker/Colima迁移到Podman的经验总结。期间为了弄清各种技术细节,我把Podman官网翻了个底朝天,终于弄明白了它的优势,还理清了各概念之间的关系。整个过程充满挑战,却也别有一番乐趣。

posted @ 2025-04-24 22:08  rebeca8  阅读(679)  评论(0)    收藏  举报