Podman Go 绑定是一组函数,允许开发者在其基于 Go 的应用程序内部执行 Podman 操作。这些 Go 绑定连接到 Podman 服务,该服务可在本地或远程机器上运行。您可以执行多种操作,包括拉取和列出镜像、启动、停止或检查容器。目前,Podman 存储库提供了针对镜像、容器、Pod、网络和清单等操作的绑定。
这些绑定要求 Podman 系统服务为指定用户运行。这可以通过 systemd 使用 systemctl 命令来完成,或者直接手动调用该服务。
启动Podman服务的命令会因运行该服务的用户不同而略有差异。对于有根(rootful)服务,可按如下方式启动该服务:
# systemctl start podman.socket
对于非特权用户(也称为无root权限用户),按如下方式启动服务:
$ systemctl start --user podman.socket
手动运行系统服务可能会很方便。这样做可以让你启用调试消息。
$ podman --log-level=debug system service -t0
若未为套接字指定具体路径,系统将提供默认路径。rootful 连接的套接字位置为 /run/podman/podman.sock,rootless 连接的套接字位置为 /run/user/USERID#/podman/podman.sock。有关 Podman 系统服务的更多信息,请参阅 man podman-system-service。
确保已安装所需依赖项,因为编译使用绑定库的 Go 程序时需要这些依赖项。
使用绑定库的第一步是建立与套接字的连接。如前所述,套接字的目标取决于其所有者。在此情况下,建立的是 rootful 连接。
import (
"context"
"fmt"
"os"
"github.com/containers/podman/v6/pkg/bindings"
)
func main() {
conn, err := bindings.NewConnection(context.Background(), "unix:///run/podman/podman.sock")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}从 bindings.NewConnection 函数返回的 conn 变量随后可用于后续的函数调用中,以与容器进行交互。
以下示例基于上文的连接示例展开,同样均为根连接。
注意:绑定方法的可选参数需通过 *Option 结构上的 With*() 方法设置。复合类型不会被复制,而是使用其地址。因此,在初始化 *Option 结构与调用绑定方法之间,不应修改底层字段。
以下示例将获取名为foorbar的容器的检查信息,然后打印该容器的ID。请注意用于获取大小的可选检查选项的使用。
import (
"context"
"fmt"
"os"
"github.com/containers/podman/v6/pkg/bindings"
"github.com/containers/podman/v6/pkg/bindings/containers"
)
func main() {
conn, err := bindings.NewConnection(context.Background(), "unix:///run/podman/podman.sock")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
inspectData, err := containers.Inspect(conn, "foobar", new(containers.InspectOptions).WithSize(true))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Print the container ID
fmt.Println(inspectData.ID)
}以下示例将镜像 quay.ioo/libpod/alpine_nginx 拉取到本地镜像仓库。
import (
"context"
"fmt"
"os"
"github.com/containers/podman/v6/pkg/bindings"
"github.com/containers/podman/v6/pkg/bindings/images"
)
func main() {
conn, err := bindings.NewConnection(context.Background(), "unix:///run/podman/podman.sock")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
_, err = images.Pull(conn, "quay.io/libpod/alpine_nginx", nil)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}以下示例拉取了 quay.io/libpod/alpine_nginx 镜像,然后基于该镜像创建名为 foobar 的容器,最后启动该容器。
import (
"context"
"fmt"
"os"
"github.com/containers/podman/v6/pkg/bindings"
"github.com/containers/podman/v6/pkg/bindings/containers"
"github.com/containers/podman/v6/pkg/bindings/images"
"github.com/containers/podman/v6/pkg/specgen"
)
func main() {
conn, err := bindings.NewConnection(context.Background(), "unix:///run/podman/podman.sock")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
_, err = images.Pull(conn, "quay.io/libpod/alpine_nginx", nil)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
s := specgen.NewSpecGenerator("quay.io/libpod/alpine_nginx", false)
s.Name = "foobar"
createResponse, err := containers.CreateWithSpec(conn, s, nil)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("Container created.")
if err := containers.Start(conn, createResponse.ID, nil); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("Container started.")
}要在开发环境中进行调试,你可以像这样在调试模式下启动 Podman 系统服务:
$ podman --log-level=debug system service -t 0
--log-level=debug 选项会回显所有记录的请求,有助于更精细地追踪执行路径。运行示例片段如下所示:
INFO[0000] podman filtering at log level debug
DEBU[0000] Called service.PersistentPreRunE(podman --log-level=debug system service -t0)
DEBU[0000] Ignoring libpod.conf EventsLogger setting "/home/lsm5/.config/containers/containers.conf". Use "journald" if you want to change this setting and remove libpod.conf files.
DEBU[0000] Reading configuration file "/usr/share/containers/containers.conf"
DEBU[0000] Merged system config "/usr/share/containers/containers.conf": {Editors note: the remainder of this line was removed due to Jekyll formatting errors.}
DEBU[0000] Using conmon: "/usr/bin/conmon"
DEBU[0000] Initializing boltdb state at /home/lsm5/.local/share/containers/storage/libpod/bolt_state.db
DEBU[0000] Overriding run root "/run/user/1000/containers" with "/run/user/1000" from database
DEBU[0000] Using graph driver overlay
DEBU[0000] Using graph root /home/lsm5/.local/share/containers/storage
DEBU[0000] Using run root /run/user/1000
DEBU[0000] Using static dir /home/lsm5/.local/share/containers/storage/libpod
DEBU[0000] Using tmp dir /run/user/1000/libpod/tmp
DEBU[0000] Using volume path /home/lsm5/.local/share/containers/storage/volumes
DEBU[0000] Set libpod namespace to ""
DEBU[0000] Not configuring container store
DEBU[0000] Initializing event backend file
DEBU[0000] using runtime "/usr/bin/runc"
DEBU[0000] using runtime "/usr/bin/crun"
WARN[0000] Error initializing configured OCI runtime kata: no valid executable found for OCI runtime kata: invalid argument
DEBU[0000] using runtime "/usr/bin/crun"
INFO[0000] Setting parallel job count to 25
INFO[0000] podman filtering at log level debug
DEBU[0000] Called service.PersistentPreRunE(podman --log-level=debug system service -t0)
DEBU[0000] Ignoring libpod.conf EventsLogger setting "/home/lsm5/.config/containers/containers.conf". Use "journald" if you want to change this setting and remove libpod.conf files.
DEBU[0000] Reading configuration file "/usr/share/containers/containers.conf"如果通过 systemd 套接字激活启动了 Podman 系统服务,可使用 journalctl 查看日志。示例运行后的日志如下所示:
$ journalctl --user --no-pager -u podman.socket -- Reboot -- Jul 22 13:50:40 nagato.nanadai.me systemd[1048]: Listening on Podman API Socket. $
$ journalctl --user --no-pager -u podman.service Jul 22 13:50:53 nagato.nanadai.me systemd[1048]: Starting Podman API Service... Jul 22 13:50:54 nagato.nanadai.me podman[1527]: time="2020-07-22T13:50:54-04:00" level=error msg="Error refreshing volume 38480630a8bdaa3e1a0ebd34c94038591b0d7ad994b37be5b4f2072bb6ef0879: error acquiring lock 0 for volume 38480630a8bdaa3e1a0ebd34c94038591b0d7ad994b37be5b4f2072bb6ef0879: file exists" Jul 22 13:50:54 nagato.nanadai.me podman[1527]: time="2020-07-22T13:50:54-04:00" level=error msg="Error refreshing volume 47d410af4d762a0cc456a89e58f759937146fa3be32b5e95a698a1d4069f4024: error acquiring lock 0 for volume 47d410af4d762a0cc456a89e58f759937146fa3be32b5e95a698a1d4069f4024: file exists" Jul 22 13:50:54 nagato.nanadai.me podman[1527]: time="2020-07-22T13:50:54-04:00" level=error msg="Error refreshing volume 86e73f082e344dad38c8792fb86b2017c4f133f2a8db87f239d1d28a78cf0868: error acquiring lock 0 for volume 86e73f082e344dad38c8792fb86b2017c4f133f2a8db87f239d1d28a78cf0868: file exists" Jul 22 13:50:54 nagato.nanadai.me podman[1527]: time="2020-07-22T13:50:54-04:00" level=error msg="Error refreshing volume 9a16ea764be490a5563e384d9074ab0495e4d9119be380c664037d6cf1215631: error acquiring lock 0 for volume 9a16ea764be490a5563e384d9074ab0495e4d9119be380c664037d6cf1215631: file exists" Jul 22 13:50:54 nagato.nanadai.me podman[1527]: time="2020-07-22T13:50:54-04:00" level=error msg="Error refreshing volume bfd6b2a97217f8655add13e0ad3f6b8e1c79bc1519b7a1e15361a107ccf57fc0: error acquiring lock 0 for volume bfd6b2a97217f8655add13e0ad3f6b8e1c79bc1519b7a1e15361a107ccf57fc0: file exists" Jul 22 13:50:54 nagato.nanadai.me podman[1527]: time="2020-07-22T13:50:54-04:00" level=error msg="Error refreshing volume f9b9f630982452ebcbed24bd229b142fbeecd5d4c85791fca440b21d56fef563: error acquiring lock 0 for volume f9b9f630982452ebcbed24bd229b142fbeecd5d4c85791fca440b21d56fef563: file exists" Jul 22 13:50:54 nagato.nanadai.me podman[1527]: Trying to pull registry.fedoraproject.org/fedora:latest... Jul 22 13:50:55 nagato.nanadai.me podman[1527]: Getting image source signatures Jul 22 13:50:55 nagato.nanadai.me podman[1527]: Copying blob sha256:dd9f43919ba05f05d4f783c31e83e5e776c4f5d29dd72b9ec5056b9576c10053 Jul 22 13:50:55 nagato.nanadai.me podman[1527]: Copying config sha256:00ff39a8bf19f810a7e641f7eb3ddc47635913a19c4996debd91fafb6b379069 Jul 22 13:50:55 nagato.nanadai.me podman[1527]: Writing manifest to image destination Jul 22 13:50:55 nagato.nanadai.me podman[1527]: Storing signatures Jul 22 13:50:55 nagato.nanadai.me systemd[1048]: podman.service: unit configures an IP firewall, but not running as root. Jul 22 13:50:55 nagato.nanadai.me systemd[1048]: (This warning is only shown for the first unit using IP firewalling.) Jul 22 13:51:15 nagato.nanadai.me systemd[1048]: podman.service: Succeeded. Jul 22 13:51:15 nagato.nanadai.me systemd[1048]: Finished Podman API Service. Jul 22 13:51:15 nagato.nanadai.me systemd[1048]: podman.service: Consumed 1.339s CPU time. $
您还可以通过使用类似 socat 的工具来验证传递的信息是否正确,该工具能够输出套接字所接收的内容。
在构建使用 Podman Go 绑定库的程序时,可通过向 go build 命令传递 “remote” 构建标签来缩减二进制文件体积。该标签会排除与本地 Podman 操作相关的代码,对于仅通过网络与 Podman 进行交互的应用程序而言,这些代码并非必需。