Podman Pod PS 过滤器完全指南:`--filter` 九大过滤键的语法、原理与实战

Podman Pod PS 过滤器完全指南:`--filter` 九大过滤键的语法、原理与实战 Podman Pod PS 过滤器完全指南--filter九大过滤键的语法、原理与实战【免费下载链接】podmanPodman: A tool for managing OCI containers and pods.项目地址: https://gitcode.com/gh_mirrors/po/podman本文以 Podman 仓库中podman pod ps命令的过滤器官方选项文档 filter.pod-ps.md 为核心骨架结合 pkg/domain/filters/pods.go 的过滤器实现源码与 test/e2e/pod_ps_test.go 的端到端测试用例系统讲解podman pod ps --filter的全部过滤键filter key、取值语法、正则与时间戳规则以及底层过滤函数的真实调用逻辑。读完本文你将能够在日常排障、批量管理、脚本化输出中精准筛选任意 Pod。一、podman pod ps --filter是什么podman pod ps别名podman pod ls/podman pod list用于列出主机上所有的 Pod 及其名称、ID 与当前状态。当 Pod 数量众多时--filter短选项-f用于只输出满足条件的 Pod。命令入口定义在 cmd/podman/pods/ps.go其中过滤器参数的声明方式为filterFlagName : filter flags.StringArrayVarP(inputFilters, filterFlagName, f, []string{}, Filter output based on conditions given)注意两点它是一个StringArray 类型的可重复参数因此每写一个过滤条件就要使用一次--filter而不是用逗号把多个条件拼在一个--filter里多个--filter之间是AND与逻辑Pod 必须同时满足所有条件才会被列出。官方文档给出的标准示例podman pod ps --filter labeltest --filter until10m参数解析的底层逻辑ps.go的pods()函数在收到用户输入后会先做一次格式校验把每个--filter参数从第一个处拆分为键与值fname, filter, hasFilter : strings.Cut(f, ) if !hasFilter { return fmt.Errorf(filter input must be in the form of filtervalue: %s is invalid, f) } psInput.Filters[fname] append(psInput.Filters[fname], filter)也就是说filtervalue的写法是强制要求的。如果输入了没有的过滤串例如直接写running命令会直接报错filter input must be in the form of filtervalue。随后本地本地/远程架构下均有对应实现的PodPs会把过滤键交给 GeneratePodFilterFunc 生成一个个返回布尔值的谓词函数最后通过ic.Libpod.Pods(filters...)让 libpod 层基于这些谓词过滤 Pod 列表。因此一个--filter就是一组谓词所有谓词都必须返回 truePod 才会出现在结果中。二、九大过滤键总览文档中列出的全部过滤键如下表描述以当前仓库 filter.pod-ps.md 为准Filter 键说明ctr-ids按 Pod 内容器 ID 过滤默认前缀匹配支持正则ctr-names按 Pod 内容器名称过滤支持正则ctr-number按 Pod 内容器数量过滤ctr-status按 Pod 内容器状态过滤id按 Pod ID 过滤默认前缀匹配支持正则label按标签过滤labelkey/labelkeyvaluelabel!反向过滤name按 Pod 名称过滤支持正则network按网络名称或网络完整 ID 过滤status按 Pod 状态过滤until按 Pod 创建时间过滤早于给定时间戳的 Pod需要特别说明的是表中的ctr-ids、ctr-names、id、name四个键都接受正则表达式作为过滤值而label是一个复合键其变体label!负向标签过滤与label一起组成了完整的标签筛选能力。三、按 Pod 身份过滤id与nameid按 Pod ID 过滤# 前缀匹配默认只要 Pod ID 以给定前缀开头即命中 podman pod ps --filter idabc123 # 正则匹配例如要求 ID 以给定串结尾 podman pod ps --filter idabc123$底层实现位于GeneratePodFilterFunc的id分支直接对p.ID()应用通用 ID 过滤器case id: return func(p *libpod.Pod) bool { return filters.FilterID(p.ID(), filterValues) }, nil在 test/e2e/pod_ps_test.go 中有对应的端到端用例podman pod ps id filter flag先pod create创建 Pod再用--filter idpodid验证输出只包含该 Pod。name按 Pod 名称过滤case name: return func(p *libpod.Pod) bool { return util.StringMatchRegexSlice(p.Name(), filterValues) }, nil测试podman pod ps filter name regexp演示了正则的两种用法podman pod ps -q --no-trunc --filter namemypod podman pod ps -q --no-trunc --filter namemypod$其中namemypod$利用$锚定名称结尾等价于精确匹配名为mypod的 Pod也兼容mypod为其他名称前缀的情况被排除。由于是正则匹配正则表达式中的特殊字符如[、(等如需字面匹配应进行转义。四、按 Pod 内容器过滤ctr-ids、ctr-names、ctr-number、ctr-status这一类过滤键关注的是Pod 内部的容器维度常用于找出哪个 Pod 包含了某个容器 / 处于某种容器状态。ctr-ids按容器 ID 过滤case ctr-ids: return func(p *libpod.Pod) bool { ctrIds, err : p.AllContainersByID() if err ! nil { return false } for _, id : range ctrIds { if filters.FilterID(id, filterValues) { return true } } return false }, nil只要 Pod 内任意一个容器的 ID 与过滤值匹配默认前缀匹配支持正则该 Pod 即被命中。端到端测试演示了前缀匹配与正则的组合用法podman pod ps -q --no-trunc --filter ctr-ids完整容器ID # 前缀 正则结尾锚定 podman pod ps -q --no-trunc --filter ctr-ids前40位 --filter ctr-ids完整ID$这里多次传入ctr-ids时逻辑是值集合内命中任意一个即算该键成立OR而不同键之间仍是 AND。ctr-names按容器名称过滤case ctr-names: return func(p *libpod.Pod) bool { ctrs, err : p.AllContainers() if err ! nil { return false } for _, ctr : range ctrs { return util.StringMatchRegexSlice(ctr.Name(), filterValues) } return false }, nil按 Pod 内容器名称做正则匹配。测试中的用法podman pod ps -q --no-trunc --filter ctr-namestest1 # 与容器状态条件组合AND 逻辑 podman pod ps -q --no-trunc --filter ctr-namestest --filter ctr-statusrunningctr-number按容器数量过滤case ctr-number: return func(p *libpod.Pod) bool { ctrIds, err : p.AllContainersByID() if err ! nil { return false } for _, filterValue : range filterValues { fVint, err2 : strconv.Atoi(filterValue) if err2 ! nil { return false } if len(ctrIds) fVint { return true } } return false }, nil值必须是十进制整数内部用strconv.Atoi解析解析失败则该 Pod 直接不命中命中条件是Pod 内容器总数 该数值。测试用例# 恰好包含 1 个容器的 Pod podman pod ps -q --no-trunc --filter ctr-number1 # 同时给出多个数值命中任一数值即可 podman pod ps -q --no-trunc --filter ctr-number1 --filter ctr-number0注意ctr-number统计的是AllContainersByID()返回的全部容器含 infra 容器因此一个刚创建的空 Pod 通常也会被算作包含 1 个infra容器实际使用时请以podman pod ps --ctr-ids的输出核对。ctr-status按容器状态过滤文档明确规定ctr-status只接受以下六个值created、running、paused、stopped、exited、unknown。非法值会在生成过滤函数时直接返回错误%s is not a valid status。底层实现pkg/domain/filters/pods.go做了两个状态归一化映射实际容器状态过滤时使用的字符串ContainerStateConfiguredcreatedContainerStateStoppedexited其余状态状态原名过滤值stopped在比较时等价替换为exited也就是说文档中列的stopped与exited实际指向同一组容器状态二者可以互换使用。命中条件是Pod 内任意一个容器的归一化后的状态等于任一过滤值。测试验证podman pod ps -q --no-trunc --filter ctr-statusrunning podman pod ps -q --no-trunc --filter ctr-statusexited podman pod ps -q --no-trunc --filter ctr-statuscreated # 多个状态值 OR 关系 podman pod ps -q --no-trunc --filter ctr-statusexited --filter ctr-statusrunning五、按标签过滤label与反向label!label是使用频率最高的过滤键之一文档说明了它的两种格式labelkey或labelkeyvalue保留具有指定标签或指定键值对的容器Podlabel!key或label!keyvalue保留不具有指定标签或指定键值对的容器Pod。# 拥有 app 标签无论值的 Pod podman pod ps --filter labelapp # 拥有 appmyapp 键值对的 Pod podman pod ps --filter labelappmyapp # 不拥有 app 标签的 Pod podman pod ps --filter label!app # 组合多个标签条件 podman pod ps --filter labelapp --filter labelenvprod底层实现分别调用filters.MatchLabelFilters(filterValues, labels)与filters.MatchNegatedLabelFilters(filterValues, labels)case label: return func(p *libpod.Pod) bool { labels : p.Labels() return filters.MatchLabelFilters(filterValues, labels) }, nil case label!: return func(p *libpod.Pod) bool { labels : p.Labels() return filters.MatchNegatedLabelFilters(filterValues, labels) }, nil端到端测试podman pod ps filter labels验证了labelapp与labelappmyapp的行为labelapp只要求键存在值任意labelappmyapp则要求键值对完全匹配。反向过滤label!的语义是排除而非要求不存在于任何标签中在组合多个过滤条件时需要注意label!条件与其他条件之间仍是 AND 逻辑即 Pod 必须既满足正向条件、又满足负向条件。六、按网络过滤networknetwork过滤键接受网络名称或网络完整 ID。其实现会先把过滤值解析为网络名通过r.Network().NetworkInspect(val)查询若网络不存在则跳过该值再检查 Pod 的 infra 容器的网络列表中是否包含任一目标网络case network: var inputNetNames []string for _, val : range filterValues { net, err : r.Network().NetworkInspect(val) ... inputNetNames append(inputNetNames, net.Name) } return func(p *libpod.Pod) bool { infra, err : p.InfraContainer() if err ! nil { return false } networks, err : infra.Networks() if err ! nil || len(networks) 0 { return false } for _, net : range networks { if slices.Contains(inputNetNames, net) { return true } } return false }, nil由此可以总结三个重要的行为细节没有 infra 容器或没有任何网络的 Pod 永远不会命中实现中直接return false过滤值既可以是网络名也可以是网络完整 ID内部会通过NetworkInspect换算成网络名再比较该过滤键依赖 libpod 运行时来查询网络信息因此仅在本机本地模式下可用远程/隧道模式下此键的行为会有所限制。测试示例podman network create mynet podman pod create --network mynet podman pod ps --no-trunc --filter networkmynet七、按 Pod 状态过滤statusstatus过滤的是Pod 自身的聚合状态。文档规定合法值只有stopped、running、paused、exited、dead、created、degraded。非法值在生成过滤函数时直接报错%s is not a valid pod status。case status: for _, filterValue : range filterValues { if !slices.Contains([]string{stopped, running, paused, exited, dead, created, degraded}, filterValue) { return nil, fmt.Errorf(%s is not a valid pod status, filterValue) } } return func(p *libpod.Pod) bool { status, err : p.GetPodStatus() if err ! nil { return false } return slices.Contains(filterValues, strings.ToLower(status)) }, nil这里Pod 状态与容器状态是两回事。Pod 的聚合状态由 libpod/pod_status.go 的createPodStatusResults根据 Pod 内所有容器的状态推导而来规则如下没有容器 →created所有容器都running→running有容器 running 但并非全部 →degraded所有容器都paused→paused所有容器都stopped/exited→exited有容器 stopped 但并非全部 →stopped存在异常状态如 error→errored其余情况 →created。podman pod ps --filter statusrunning podman pod ps --filter statusdegraded podman pod ps --filter statusexited这解释了status的取值为何比ctr-status多出degraded、dead、stopped等聚合语义degraded表示Pod 中部分容器运行、部分未运行的中间态是排查 Pod 部分故障时最常用的过滤值。八、按创建时间过滤untiluntil过滤创建时间早于给定时间点的 Pod接受三种格式Unix 时间戳如--filter until5000000000日期格式时间戳RFC3339 等可解析的日期时间字符串Go duration 相对时间如10m、1h30m相对当前机器时间向前推算。# 相对时间10 分钟前创建的 Pod podman pod ps --filter until10m # Unix 时间戳早于 2000 年 1 月 1 日创建的 Pod podman pod ps --filter until946684800实现逻辑位于until分支通过filters.ComputeUntilTimestamp(filterValues)把过滤值统一换算成绝对时间戳再与 Pod 的创建时间比较case until: return func(p *libpod.Pod) bool { until, err : filters.ComputeUntilTimestamp(filterValues) if err ! nil { return false } if p.CreatedTime().Before(until) { return true } return false }, nil对应测试用例podman pod ps --filter until# 先创建 Pod再用一个很小的 Unix 时间戳50过滤不命中 podman pod ps --filter until50 # 用一个很大的未来时间戳5000000000过滤命中 podman pod ps --filter until5000000000注意duration 字符串如10m的解析依赖 Go 的time.ParseDuration语法支持ns、us/µs、ms、s、m、h等单位组合由于是相对机器当前时间计算同一命令在不同时刻执行结果可能不同。九、组合使用与实战场景由于多个--filter之间是 AND 逻辑而同一键的多个值是 OR 逻辑可以组合出非常精确的查询。以下是基于文档与测试用例整理的可直接运行的实战命令# 1. 找到运行中且包含名为 test1 容器的 Pod podman pod ps -q --no-trunc --filter ctr-namestest1 --filter ctr-statusrunning # 2. 找出 10 分钟前创建、带 appmyapp 标签、当前处于 degraded 状态的 Pod podman pod ps --filter labelappmyapp --filter until10m --filter statusdegraded # 3. 排除带 envdev 标签的 Pod podman pod ps --filter label!envdev # 4. 找出连接在 mynet 网络上的 Pod podman pod ps --no-trunc --filter networkmynet # 5. 只输出 ID便于脚本循环处理 for pid in $(podman pod ps -q --filter statusrunning); do podman pod inspect $pid done与podman ps容器过滤器命名空间的对比podman pod ps --filter的键与podman ps --filter容器的键相互独立容器侧有exited、created、running等Pod 侧新增了ctr-ids、ctr-names、ctr-number、ctr-status四个下钻到容器层面的键以及network键。Pod 侧的status值degraded是容器侧没有的聚合语义。常见报错与排查现象原因解决filter input must be in the form of filtervalue--filter后缺少写成--filter keyvaluexxx is not a valid status/not a valid pod status传入了文档之外的取值核对ctr-status六值与status七值xxx is an invalid filter过滤键拼写错误或不支持核对上表九大键含label!正则不生效未按正则语法书写确认使用了id、name、ctr-ids、ctr-names四类支持正则的键十、源码速查想要深入验证文中结论可直接阅读以下仓库文件过滤器官方文档docs/source/markdown/options/filter.pod-ps.md本文骨架--filter同时被podman pod ps引用CLI 入口与参数解析cmd/podman/pods/ps.go--filter、-f声明、strings.Cut解析、输出格式过滤器谓词生成核心pkg/domain/filters/pods.go九大键 label!的实现与状态白名单Pod 聚合状态推导libpod/pod_status.gostatus键取值degraded/exited等的来源Pod 列表领域对象pkg/domain/entities/pods.goPodPSOptions.Filters map[string][]string端到端测试test/e2e/pod_ps_test.go覆盖id/name/until/label/network/ctr-*全部过滤键的验证用例需要提醒的是--filter选项文档由多个命令共享生成机制podman pod ps的过滤器行为以本文所述为准若使用远程tunnel模式部分依赖本机 libpod 运行时的过滤键如network可能无法完整生效请在本地节点执行验证。【免费下载链接】podmanPodman: A tool for managing OCI containers and pods.项目地址: https://gitcode.com/gh_mirrors/po/podman创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考