日常经常需要使用容器,时常想要 docker 更轻量一些,比如不需要 daemon,不需要 root,普通用户就可以使用上。
然后被安利了 podman,使用了挺长时间了,以下是我的安利~

daemonless

如题,podman 不需要跑一个 daemon 来管理容器。
具体实现的话,大概是底层的 oci runtime 会在 XDG_RUNTIME_DIR 给每个容器一个独立的文件夹来存放一些状态信息,可以被 podman cli 读取和管理。

socket

podman 仍然提供了通过 socket 来管理的功能,这个 socket 需要单独跑一个 daemon,不过非常轻,类似提供 podman cli 的功能同时带有验证。

systemctl --user status podman.socket

systemctl --user enable --now podman.socket

rootless

与其把“权力”关进笼子里,不如一开始就分离需要“权力”的部分。
普通用户使用 podman 默认就是 rootless

配置文件: ~/.config/containers
容器存储: ~/.local/share/containers

storage driver

  • overlay(default)
    需要安装 fuse-overlayfs
  • btrfs
    推荐在 fstab 添加 user_subvol_rm_allowed 挂载选项,来源
  • zfs…

pasta User-Mode Networking

slirp4netns 的替代,拥有更好的性能,是现在 podman 5.x 默认的网络实现(rootless)

pasta (same binary as passt, different command) offers equivalent functionality, for network namespaces: traffic is forwarded using a tap interface inside the namespace, without the need to create further interfaces on the host, hence not requiring any capabilities or privileges.

Starting with Linux 3.8, unprivileged users can create network_namespaces(7) along with user_namespaces(7). However, unprivileged network namespaces had not been very useful, because creating veth(4) pairs across the host and network namespaces still requires the root privileges. (i.e. No internet connection)

slirp4netns allows connecting a network namespace to the Internet in a completely unprivileged way, by connecting a TAP device in a network namespace to the usermode TCP/IP stack (“slirp”).

host.containers.internal

通过 /etc/hosts 设置,在使用 pasta 的情况下是指向 169.254.1.2 的特殊地址,指向本机,通常用于访问其他容器暴露的端口或者 host 的服务。
但是无法访问监听 localhost 回环地址的服务,需要监听 0.0.0.0

性能测试

TODO

UID 映射

默认 --userns=host

KeyHost UserContainer User
auto$UIDnil (Host User UID is not mapped into container.)
host$UID0 (Default User account mapped to root user in container.)
keep-id$UID$UID (Map user account to same UID within container.)
keep-id:uid=200,gid=210$UID200:210 (Map user account to specified UID, GID value within container.)
nomap$UIDnil (Host User UID is not mapped into container.)

具体来说,对于 rootless container

$ cat /etc/subuid
<login name>:100000:65536
Container UIDHost UID
01000
1100000
2100001
1000100999

pod

podman 是支持 pod 的,不过没有 k8s 的许多企业化功能。

pod

  • 共享网络子空间
  • 共享硬件资源
  • 共享资源限制

kube

podman 支持用 Kubernetes YAML 来定义 pod。
同时有自己的 metadata 和 volume 写法,具体可以阅读文档。
博主个人是习惯把需要多个容器的服务用 pod 来写。

支持的 Kubernetes kinds

  • Pod
  • Deployment
  • PersistentVolumeClaim
  • ConfigMap
  • Secret
  • DaemonSet

这里给一个 yaml example:

apiVersion: v1
kind: Pod
metadata:
...
spec:
  containers:
  - name: container
    image: foobar
...

systemd unit

systemd units using Podman Quadlet
Quadlet 现在是 systemd generator
这是我最看重的功能,通过 systemd 来管理 podman container。

扫描的位置:
root: /etc/containers/systemd/
user: $XDG_CONFIG_HOME/containers/systemd/

.container

[Unit]
Description=A minimal container

[Container]
# Use the centos image
Image=quay.io/centos/centos:latest
# Use volume and network defined below
Volume=test.volume:/data
# In the container we just run sleep
Exec=sleep 60

[Service]
# Restart service when sleep finishes
Restart=always
# Extend Timeout to allow time to pull the image
TimeoutStartSec=900

[Install]
# Start by default on boot
WantedBy=multi-user.target default.target

.kube

配合上文的 kube pod yaml

[Unit]
Description=A kubernetes yaml based service
Before=local-fs.target

[Kube]
Yaml=%h/kube/test.yaml

[Install]
# Start by default on boot
WantedBy=multi-user.target default.target

auto-update

自动拉去新的 contianer image,然后重启 container,是一个 system service + timer。
需要容器开启 AutoUpdate(.container)/io.containers.autoupdate(.kube metadata) 选项

systemctl --user enable podman-auto-update.timer
podman auto-update

distrobox

Use any Linux distribution inside your terminal. Enable both backward and forward compatibility with software and freedom to use whatever distribution you’re more comfortable with.

Run any distribution as you need~