Podman的使用 | Word Count: 4.4k | Reading Time: 19mins | Post Views:
容器镜像不像酒,越陈越香;而是更像奶酪,越陈越臭.
Podman是Pod Manager的缩写。Podman解决了Docker一直存在的某些问题,其中最重要的两点是:
Podman提供了增强的安全性
非root权限执行命令的能力
Pod是Kubernetes项目中普遍存在的一个概念,一个pod可以有一个或者多个容器,这些容器共享相同的命名空间和控制组。Podman项目组将Podman描述为“用于在Linux系统上开发、管理和运行OCI容器的无守护进程的容器引擎。容器既可以以特权模式运行,可以以非特权模式运行”。Podman的目标是可以在Linux上自然的运行容器,从而充分利用Linux平台的所有功能。
2025.02 山西·晋中·榆次
术语 容器 容器是在Linux系统上运行的一组进程.容器确保一个进程组不会干扰系统上的其他进程,恶意进程不能支配系统资源.容器通过以下方式进行隔离:
资源限制(cgroups)
一组进程可以使用的内存量
进程可使用的CPU核数
进程可使用的网络资源数量
安全限制
放弃Linux能力来限制root用户的权限
通过SELinux控制对文件系统的访问
只读访问内核文件系统
通过seccomp限制内核中可用的系统调用
通过用户命名空间将主机上的一组UID映射到另一组UID,从而允许访问有限特权环境
命名空间
网络命名空间
挂载命名空间
PID命名空间
镜像 容器镜像通过将所有软件捆绑到一个单元中的方式,解决了依赖管理问题,可以将所有软件库\可执行文件和配置文件一并交付.
容器镜像格式
包含应用程序所需的所有软件的目录树
描述rootfs内容的JSON文件
被称为manifest列表的JSON文件,用于将多个镜像连接在一起以支持不同的硬件架构
容器运行方式
镜像使用Linux tar工具将rootfs和JSON文件打包在一起,然后上传到容器镜像注册服务器
容器引擎会将JSON文件\引擎内置默认值和用户输入合并来创建新的容器OCI运行时贵方的JSON文件
容器运行时读取容器的JSON文件\内核cgroups\安全约束和命名空间,并最终启动容器的主进程
容器标准
OCI标准委员会
OCI镜像格式
OCI运行时规范
Podman
支持fork/exec模型,容器时命令的子进程
无守护进程,软件升级时不停止容器
支持kubernetes类pod和基于kubernetetes yaml启动容器
支持非特权容器
支持REST API
与systemd集成
自定义容器镜像注册服务器
支持多种传输方式
完全可定制
特权容器 1 2 3 4 5 6 7 8 9 10 11 12 # 关闭docker的安全限制,并挂载本地根目录 (base) [root@docker ~]# docker run -it --name hacker --privileged -v /:/host redhat/ubi8 chroot /host Unable to find image 'redhat/ubi8:latest' locally latest: Pulling from redhat/ubi8 c9235833a899: Pull complete Digest: sha256:2e863fb65e595839633113300a0c6709e9af81523a30001290068265c121a927 Status: Downloaded newer image for redhat/ubi8:latest sh-4.2# ls / bin boot data dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var sh-4.2# cd /root sh-4.2# ls Anaconda3-2023.09-0-Linux-x86_64.sh
如果普通用户拥有docker的权限,就可以获得”为所欲为”的权限,删除容器就可以抹除所有操作记录.
基础命令 参见:Podman使用入门
Pod Podman pod和Kubernetes pod一样,包含一个infra容器,或者被称为pause容器。该容器负责维持内核的命名空间和cgroups的状态,允许容器在pod内的创建与销毁。infra容器由一个名为conmon的容器监控进程来监控,而且pod中的每个容器都有属于自己的conmon。
conmon负责执行OCI运行时,将OCI规范文件的路径和容器层挂载点
conmon负责监控容器的生命周期
conmon负责处理用户到容器的连接
conmon负责生成pod的日志文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 # 创建一个空的pod,也就是一个网络命名空间,并将容器内部端口8080绑定到主机上的8080端口 $ mkdir html$ podman pod create -p 8080:8080 --name mypod --volume ./html:/var/www/html:z a086f23c67ae68ba79399d8dcb09217440e43f9079608607059bf8f929b97845 # 列出当前的pod $ podman pod ps POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS a086f23c67ae mypod Created About a minute ago be5b8119c711 1 # 可见实际只有pause容器,并无业务容器,端口也已经映射 $ podman ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES be5b8119c711 localhost/podman-pause:5.3.1-1732147200 reated 0.0.0.0:8080->8080/tcp a086f23c67ae-infra # 添加pod, Web程序的实际应用 $ podman create --pod mypod --name myapp ubi8/httpd-24 # 创建应用脚本 $ cat > ./html/time.sh <<EOF # !/bin/bash data() { echo "<html><head></head><h1>"; date; echo "Hello World</h1></body></html>" sleep 1 } while true ; do data > index.html done EOF $ chmod +x ./html/time.sh # 添加边车容器,将/var/www/html目录作为默认目录并运行打印时间戳脚本 $ podman create --pod mypod --name time --workdir /var/www/html ubi8 ./time.sh # 启动pod $ podman pod start mypod # 列出pod $ podman pod ps POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS c8a185241126 mypod Running 4 minutes ago b2e753fc5766 3 # 查看pod属性 $ podman pod inspect mypod [ { "Id": "c8a185241126ef5370ca62f32a2b87286dbc6fe29a6a1de6203f2cb790ffbb16", "Name": "mypod", "Created": "2025-02-05T21:18:04.411942531+08:00", "CreateCommand": [ "podman", "pod", "create", "-p", "8080:8080", "--name", "mypod", "--volume", "/root/html:/var/www/html:z" ], "ExitPolicy": "continue", "State": "Running", "Hostname": "", "CreateCgroup": true, …… # 检查 $ curl 192.168.24.10:8080 <html><head></head><h1> Wed Feb 5 13:31:26 UTC 2025 Hello World</h1></body></html> # 停止pod $ podman pod stop mypod # 删除pod $ podman pod rm mypod
设计 自定义和配置文件 存储位置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 配置文件位置 # root权限下系统podman配置存储文件位置 root@docker:~# podman info --format '{{ .Store.ConfigFile }}' /usr/share/containers/storage.conf # 普通用户配置存储文件位置 $ podman info --format '{{ .Store.ConfigFile }}' /home/sujx/.config/containers/storage.conf # 默认配置位置 root@docker:~# vim /usr/share/containers/storage.conf [storage] driver = "overlay" runroot = "/run/containers/storage" graphroot = "/var/lib/containers/storage"
通过修改graproot参数可以修改镜像和容器存储位置。Podman使用container/storage支持多种不同类型的分层文件,被称为写时复制(CoW)文件系统,Podman默认使用overlay驱动程序。
容器镜像注册服务器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 配置文件位置 root@docker:~# cat /etc/containers/registries.conf # 镜像注册服务器数组,按顺序依次拉取镜像 unqualified-search-registries = ["registry.fedoraproject.org", "registry.access.redhat.com", "docker.io", "quay.io"] # 配置docker hub代理,每个镜像注册服务器独立配置 [[registry]] prefix="docker.io" location="hub.1panel.dev" # 允许未加密http连接 insecure=true # 禁止镜像下载 blocked=true # 允许使用短命称 short-name-mode = "enforcing"
引擎配置 1 2 # 引擎配置文件位置 root@podman:~# vim /usr/share/containers/containers.conf
container.conf支持以下配置项:
[containers] 运行单个容器的配置
[engine] Podman的默认配置
[service_destinations] 远程服务配置
[secrets] 有关secrets插件驱动程序信息
[network] 网络特殊配置
系统配置 当你在非特权模式下运行Podman时,将使用 /etc/subuid和/etc/subgid 文件来制定容器的UID范围。Podman会读取这俩个文件以获取分配给你的用户账户UID和GID范围。然后Podma启动 /usr/bin/newuidmap 和 /usr/bin/newgidmap ,验证podman制定的UID和GID范围是否实际分配给你。某些情况下,需要手动修改这些文件以便添加UID。
与Systemd集成 Systemd是Linux事实上的init系统。Podman接受systemd的强大功能,Podman鼓励用户将systemd单元文件与Podman命令一起使用。
在容器中运行systemd 在容器中将systemd作为初始PID运行,然后允许systemd启动容器内的一个或多个服务。这种思路认为,容器化服务应该像在虚拟机中一样启动。这种方式允许在同一容器中运行多个服务,利用本地通信路径,加快将大型多服务应用程序转换为容器。另外,systemd在容器中的另一个巨大优势是init系统会处理僵尸程序的清理工作,这样当容器进程异常退出的适合,如果PID1不回收它们,它们就会悬挂并且永不消失。
Podman的设计旨在支持两种方法——微服务和多服务容器。Podman检查容器的cmd选项,然后为init系统启动systemd,接着它自动以systemd模式启动容器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 [sujx@docker ~]$ podman pull ubi9-init [sujx@docker ~]$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE registry.access.redhat.com/ubi9-init latest 2e10efedbde9 3 days ago 251 MB # 容器内程序启动是由init启动 [sujx@docker ~]$ podman inspect ubi9-init --format '{{ .Config.Cmd }}' [/sbin/init] # 常规容器的启动 # 以nginx为例 [sujx@docker ~]$ podman inspect nginx --format '{{ .Config.Cmd }}' [nginx -g daemon off;] # 以ubuntu为例 [sujx@docker ~]$ podman inspect ubuntu --format '{{ .Config.Cmd }}' [/bin/bash] # 如果无参数启动systemd容器,可以看到容器启动后是先启动systemd # 此时通过Ctrl-C是无法停止容器,只有通过其他终端来终止 [sujx@docker ~]$ podman run -ti ubi9-init systemd 252-46.el9_5.2 running in system mode (+PAM +AUDIT +SELINUX -APPARMOR +IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN -IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT -QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -BPF_FRAMEWORK +XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified) Detected virtualization container-other. Detected architecture x86-64. Welcome to Red Hat Enterprise Linux 9.5 (Plow)! Initializing machine ID from container UUID. Queued start job for default target Graphical Interface. [ OK ] Created slice Slice /system/modprobe. [ OK ] Started Dispatch Password Requests to Console Directory Watch. [ OK ] Started Forward Password Requests to Wall Directory Watch. [ OK ] Reached target Local File Systems. [ OK ] Reached target Network is Online. [ OK ] Reached target Path Units. [ OK ] Reached target Remote File Systems. [ OK ] Reached target Slice Units. [ OK ] Reached target Swaps. # podman通过systemd发生停止信号,杀死最近启动的容器 [sujx@docker ~]$ podman stop -l
容器化的systemd要求
在/run上挂载tmpfs
在/tmp上挂载tmpfs
将/var/log/journald作为tmpfs
container环境变量
STOPSIGNAL=SIGRTMIN+3 systemd接受这个信号才会彻底退出
systemd模式下的Podman容器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # 创建systemd容器,使用--systemd=always标志以systemd模式启动容器 [sujx@docker ~]$ podman create --rm --name SystemD -ti --systemd=always ubi9-init sh 592a5aaa4eeaedc901a38de957ff709d97e50ec8083e222ebeefbb11dba40120 # 停止参数 [sujx@docker ~]$ podman inspect SystemD --format '{{ .Config.StopSignal }}' SIGRTMIN+3 # 查看tmpfs挂载 [sujx@docker ~]$ podman start --attach SystemD sh-5.1# mount |grep -e /tmp -e /run | head -2 tmpfs on /run/secrets type tmpfs (rw,nosuid,nodev,relatime,size=394904k,nr_inodes=98726,mode=700,uid=1000,gid=1000,inode64) tmpfs on /run/.containerenv type tmpfs (rw,nosuid,nodev,relatime,size=394904k,nr_inodes=98726,mode=700,uid=1000,gid=1000,inode64) sh-5.1# printenv container oci # 创建一个httpd服务的容器Dockerfie cat >> /home/sujx/podman/Containerfile<EOF FROM ubi9-init RUN dnf -y install httpd; dnf -y clean all RUN systemctl enable --now httpd.service EOF # 生成容器 [sujx@docker ~]$ podman build -t my-systemd /home/sujx/podman # 拉起服务 [sujx@docker ~]$ podman run -d --rm -p 8080:80 -v ./html/:/var/www/html:Z my-systemd 8746e0bf313a4d3c84535623393567f148d4c3d762ce5683b53c679dc9510308 [sujx@docker ~]$ curl localhost:8080 <h1>Goodbye Workd!</h1>
使用journald进行日志记录 1 2 3 4 5 6 7 8 9 # podman默认使用journald来记录日志 [sujx@docker ~]$ podman info --format '{{ .Host.LogDriver }}' journald # 输出事件 [sujx@docker ~]$ podman run --rm --name test2 ubi9 echo "Check if logs persist" Check if logs persist # 使用主机journalctl来查看容器日志 [sujx@docker ~]$ journalctl -b |grep "Check if logs persist" Feb 20 21:54:37 docker test2[3249]: Check if logs persist
在系统启动时启动容器 重启容器 Podman通过在systemd单位文件中配置Podman的启动模式。如果容器崩溃或者系统重新启动,就可能需要配置相关参数。
选项
功能
启动时重启
no
容器退出时不重启容器
×
on-failure
当容器以非零状态退出时重启
×
always
容器退出时重启,无论其退出状态如何,重试次数无限
√
1 2 3 # 配置重启策略 [sujx@docker ~]$ podman run -d --restart=always --name Ubuntu ubuntu cb7a068d99b56107db3afe0b1955d5f210964ae97cecd01e1e85205346b92810
使用Podman作为系统服务 common进程也在systemd服务中运行,用以监视容器进程。systemd不知道容器的存在,它只指导运行在单元文件中的进程,包括容器进程。
Podman具有生成包含最佳默认值的单位文件的功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 # 创建容器 [sujx@docker ~]$ podman create -p 8080:80 --name my-Web nginx 24c372bff6a8cec5ce8f11eca604dd3d84987b17e6585f1d840bf10783991881 # 创建user权限的启动文件 [sujx@docker ~]$ mkdir -p $HOME/.config/systemd/user [sujx@docker ~]$ podman generate systemd my-Web > $HOME/.config/systemd/user/my-Web.service # 查看service单元文件 [sujx@docker ~]$ cat $HOME/.config/systemd/user/my-Web.service [Unit] Description=Podman container-684673ead27728b8946376cab1ebfc2472cf9f550bcefd1161934ce7d6acc125.service Documentation=man:podman-generate-systemd(1) Wants=network-online.target After=network-online.target RequiresMountsFor=/run/user/1000/containers [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=on-failure TimeoutStopSec=70 ExecStart=/usr/bin/podman start 684673ead27728b8946376cab1ebfc2472cf9f550bcefd1161934ce7d6acc125 ExecStop=/usr/bin/podman stop \ -t 10 684673ead27728b8946376cab1ebfc2472cf9f550bcefd1161934ce7d6acc125 ExecStopPost=/usr/bin/podman stop \ -t 10 684673ead27728b8946376cab1ebfc2472cf9f550bcefd1161934ce7d6acc125 PIDFile=/run/user/1000/containers/overlay-containers/684673ead27728b8946376cab1ebfc2472cf9f550bcefd1161934ce7d6acc125/userdata/conmon.pid Type=forking [Install] WantedBy=default.target # 启动服务 [sujx@docker ~]$ systemctl --user daemon-reload [sujx@docker ~]$ systemctl --user start my-Web.service [sujx@docker ~]$ systemctl --user status my-Web.service my-Web.service - Podman container-684673ead27728b8946376cab1ebfc2472cf9f550bcefd1161934ce7d6acc125.service Loaded: loaded (/home/sujx/.config/systemd/user/my-Web.service; disabled; preset: disabled) Drop-In: /usr/lib/systemd/user/service.d └─10-timeout-abort.conf Active: active (running) since Fri 2025-02-21 11:25:38 CST; 8s ago Docs: man:podman-generate-systemd(1) Process: 1460 ExecStart=/usr/bin/podman start 684673ead27728b8946376cab1ebfc2472cf9f550bcefd1161934ce7d6a> Main PID: 1484 (conmon) Tasks: 2 (limit: 4580) Memory: 17.6M (peak: 32.9M) CPU: 84ms CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/my-Web.service # 校验服务 [sujx@docker ~]$ curl localhost:8080 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> # 关闭服务 [sujx@docker ~]$ systemctl --user stop my-Web
分发systemctl单元文件 我们可以通过–new这个开关重新生成一个systemd单元文件,用于在其他系统中使用。这样服务在重启的时候,会拉取镜像和创建新的容器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 # 重新生成单元文件 [sujx@docker ~]$ podman generate systemd --new my-Web > $HOME/.config/systemd/user/my-Web.service # 单元文件中容器的EexcStart命令修改为podman run,而不是原来的podman start [sujx@docker user]$ cat my-Web.service [Unit] Description=Podman container-684673ead27728b8946376cab1ebfc2472cf9f550bcefd1161934ce7d6acc125.service Documentation=man:podman-generate-systemd(1) Wants=network-online.target After=network-online.target RequiresMountsFor=%t/containers [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=on-failure TimeoutStopSec=70 ExecStart=/usr/bin/podman run \ --cidfile=%t/%n.ctr-id \ --cgroups=no-conmon \ --rm \ --sdnotify=conmon \ -d \ --replace \ -p 8080:80 \ --name my-Web nginx ExecStop=/usr/bin/podman stop \ --ignore -t 10 \ --cidfile=%t/%n.ctr-id ExecStopPost=/usr/bin/podman rm \ -f \ --ignore -t 10 \ --cidfile=%t/%n.ctr-id Type=notify NotifyAccess=all [Install] WantedBy=default.target
自动更新容器 Podman可以管理自己的更新,每个节点会监视容器镜像注册服务器中是否出现新的镜像。当新的镜像出现时,节点会拉取镜像并重新创建容器。
这个功能的开启条件有两个:
容器必须在使用podman generate systemd –new 生成的systemd单元文件中运行
容器具有特殊的标签 –label “io.containers.autoupdate=registry/local”
1 2 3 4 5 6 7 8 9 10 11 # 创建带标签容器 [sujx@docker ~]$ podman create --label "io.container.autoupdate=regitstry" -p 8081:80 --name my-Http httpd # 创建单元文件 [sujx@docker ~]$ podman generate systemd my-Http --new >> $HOME/.config/systemd/user/my-Http.service # 启动服务 [sujx@docker ~]$ systemctl --user daemon-reload [sujx@docker ~]$ systemctl --user enable --now my-Http.service # 手动升级,自动拉取所有带标签的容器的新镜像并重启服务 [sujx@docker ~]$ podman autoupdate # 定时更新,每天检查一次 [sujx@docker ~]$ systemctl --user enable --now podman-auto-update.service
Podman服务 Podman项目支持RESTful API,可以使用podman system service命令创建监听服务应用于响应Podman的API调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 # 启动podman的restful API套接字服务 [sujx@docker ~]$ systemctl --user enable podman.socket [sujx@docker ~]$ systemctl --user start podman.socket [sujx@docker ~]$ ls $XDG_RUNTIME_DIR/podman/podman.sock /run/user/1000/podman/podman.sock # 使用curl探测podman的版本信息 [sujx@docker ~]$ curl -s --unix-socket $XDG_RUNTIME_DIR/podman/podman.sock http://d/v1.0.0/libpod/version |jq { "Platform": { "Name": "linux/amd64/fedora-40" }, "Components": [ { "Name": "Podman Engine", "Version": "5.3.1", "Details": { "APIVersion": "5.3.1", "Arch": "amd64", "BuildTime": "2024-11-21T08:00:00+08:00", "Experimental": "false", "GitCommit": "", "GoVersion": "go1.22.7", "KernelVersion": "6.12.15-100.fc40.x86_64", "MinAPIVersion": "4.0.0", "Os": "linux" } }, { "Name": "Conmon", "Version": "conmon version 2.1.12, commit: ", "Details": { "Package": "conmon-2.1.12-2.fc40.x86_64" } }, { "Name": "OCI Runtime (crun)", "Version": "crun version 1.19.1\ncommit: 3e32a70c93f5aa5fea69b50256cca7fd4aa23c80\nrundir: /run/user/1000/crun\nspec: 1.0.0\n+SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +LIBKRUN +WASM:wasmedge +YAJL", "Details": { "Package": "crun-1.19.1-1.fc40.x86_64" } } ], "Version": "5.3.1", "ApiVersion": "1.41", "MinAPIVersion": "1.24", "GitCommit": "", "GoVersion": "go1.22.7", "Os": "linux", "Arch": "amd64", "KernelVersion": "6.12.15-100.fc40.x86_64", "BuildTime": "2024-11-21T08:00:00+08:00" } # 使用curl连接podman的默认输出 # 查询本地镜像列表 [sujx@docker ~]$ curl -s --unix-socket $XDG_RUNTIME_DIR/podman/podman.sock http://d/v1.0.0/libpod/images/json |jq [ { "Id": "2e10efedbde980518ddeae0d6d42d6d503b1915e2b09edfe2d9ed93453ae4018", "ParentId": "", "RepoTags": [ "registry.access.redhat.com/ubi9-init:latest" ], "RepoDigests": [ "registry.access.redhat.com/ubi9-init@sha256:c80641132b5ba47ce8d806f48405f78085c508f4e6db7d619d208d9752cf53b1", "registry.access.redhat.com/ubi9-init@sha256:ea7611fcd37de2e2d1b79eac0255efa89eb1f7e82bfecf91739d56f9674f2fe2" ], "Created": 1739777526, "Size": 251470246, "SharedSize": 0, "VirtualSize": 251470246,
使用Python与Podman交互 我们可以是以哦那个docker-py与Podman服务进行交互
1 2 3 4 5 6 7 8 9 10 11 # 安装工具 [sujx@docker ~]$ dnf -y install podman-py # 编辑python脚本,podman-py默认链接Podman套接字 [sujx@docker ~]$ cat >./image.py<<EOF import podman client=podman.PodmanClient() print(client.images.list(all=True)) EOF # 执行测试 [sujx@docker ~]$ python3 image.py [<Image: 'registry.access.redhat.com/ubi9-init:latest'>, <Image: 'docker.io/library/nginx:latest'>, <Image: 'docker.io/library/ubuntu:latest'>, <Image: 'docker.io/library/httpd:latest'>, <Image: 'docker.io/library/busybox:latest'>]
参考
了解容器内部和外部的 root
无根容器的背后发生了什么
弄懂什么是REST API