复制后的字节内容可以完全一致,但应用需要的扩展属性已经缺失。

扩展属性属于 inode,也受命名空间约束

扩展属性在普通文件内容流之外,为文件系统对象附加有名字的字节值。应用可以使用 user 命名空间存放小型元数据,其他命名空间则具有内核、安全模块或特权相关语义。它是否可靠,取决于文件系统、访问规则和传输工具。只有工作流程按明确契约保留并解释标签,元数据才能成为下游判断的有效依据。 坏掉的样子 属性值不一定是文本,可以包含空字符或任意二进制数据。把它当作以零结尾的字符串,或者假定固定编码,可能破坏原值。空属性和缺失属性也不是同一状态;如果都返回空字符串,就会隐藏元数据到底被刻意设为空,还是在传输中丢失。使用前需要明确编码与缺失语义,而不是依赖显示工具碰巧如何呈现。 同一文件系统内重命名保留对象及属性,复制内容通常却创建另一个 inode。复制工具决定尝试保留哪些元数据,因此文件哈希相同不能证明扩展属性相同。流程可能成功传递每一个内容字节,却遗漏下游需要的分类、来源或应用版本标签。内容校验通过,只能证明它实际覆盖的内容范围。 命名空间名称不会自动建立应用授权规则。设置 user.classification 为 private,不会让本来可读的文件变得保密。user 属性服从适用的文件访问权限,安全属性则有另外的文档语义与策略。把应用标签当作已经强制执行的访问控制,可能在标签看起来完好的同时暴露内容,因此需要检查实际读写行为。 快速验证 把脚本保存为 xattrs.py,在临时目录支持用户扩展属性的一次性 Linux 容器中,以 root 运行 python3 xattrs.py。实测使用 Linux 6.12.76、Python 3.11.2 和 ext4 卷。root 准备样本,再通过一个普通数字身份启动子进程,不会创建账号: from pathlib import Path from tempfile import TemporaryDirectory import errno,os,shutil,subprocess,sys def fails(code,operation): try:operation() except OSError as error:assert error.errno==code,error else:raise AssertionError('expected attribute error') with TemporaryDirectory(prefix='xbcatm-xattr-') as directory: root=Path(directory);root.chmod(0o755);path=root/'data';path.write_bytes(b'public fixture');path.chmod(0o644) os.setxattr(path,'user.review',b'binary\0value\xff',os.XATTR_CREATE) assert os.getxattr(path,'user.review')==b'binary\0value\xff' fails(errno.EEXIST,lambda:os.setxattr(path,'user.review',b'other',os.XATTR_CREATE)) fails(errno.ENODATA,lambda:os.setxattr(path,'user.missing',b'value',os.XATTR_REPLACE)) os.setxattr(path,'user.empty',b'');assert os.getxattr(path,'user.empty')==b'' os.removexattr(path,'user.empty');fails(errno.ENODATA,lambda:os.getxattr(path,'user.empty')) print('attribute values are bytes; empty differs from missing; CREATE and REPLACE enforce their preconditions') alias=root/'alias';os.link(path,alias) os.setxattr(alias,'user.review',b'shared',os.XATTR_REPLACE) assert os.getxattr(path,'user.review')==b'shared' moved=root/'moved';path.rename(moved);assert os.getxattr(moved,'user.review')==b'shared' plain=root/'plain';preserved=root/'preserved';shutil.copyfile(moved,plain);shutil.copy2(moved,preserved) fails(errno.ENODATA,lambda:os.getxattr(plain,'user.review')) assert os.getxattr(preserved,'user.review')==b'shared' assert plain.read_bytes()==preserved.read_bytes()==moved.read_bytes() print('hard links and same-filesystem rename retain inode attributes; copyfile omits them, copy2 preserves this supported user attribute') os.setxattr(moved,'user.classification',b'private') probe=r''' from pathlib import Path import errno,os,sys path=Path(sys.argv[1]);assert path.read_bytes()==b'public fixture' assert os.getxattr(path,'user.classification')==b'private' try:os.setxattr(path,'user.classification',b'changed') except OSError as error:assert error.errno==errno.EACCES else:raise AssertionError('another identity changed a read-only user attribute') ''' result=subprocess.run([sys.executable,'-c',probe,str(moved)],user=61001,group=61001,extra_groups=[],capture_output=True,text=True,timeout=5) assert result.returncode==0,result.stderr fails(errno.E2BIG,lambda:os.setxattr(moved,'user.too_large',b'x'*65537)) print('a user.classification label does not enforce confidentiality; file permissions block the other identity from changing it; oversized value returns E2BIG') 样本保存同时包含空字符和非 UTF-8 字节的值,并取回完全相同的字节。用 XATTR_CREATE 再次创建相同键,得到 EEXIST;用 XATTR_REPLACE 修改缺失键,得到 ENODATA。这些标志明确表达前提,而不是把所有写入都变成不检查原状态的覆盖。错误结果也是契约的一部分,需要由调用方实际处理。 ...

十二月 14, 2027 · 1 分钟 · XB Field Notes
顶层 annotation 更新既有 ReplicaSet,模板 annotation 则产生新的 Pod。

Annotation 携带可被消费者解释的元数据

Annotation 为 Kubernetes 对象附加非识别性元数据,可以记录来源、负责人说明,或供工具消费的配置。标准标签选择器不会按 annotation 值筛选对象,但这并不意味着 annotation 没有作用。控制器、准入组件或发布工具都可能解释约定的键并改变行为。判断元数据修改的影响之前,应先确认具体消费者,不能仅凭字段名称认定它只是无害备注。 不参与选择,不等于没有校验 Annotation 的键和值都必须是字符串。键遵循限定名称格式,可以包含可选的 DNS 风格前缀和名称部分;一个对象的 annotation 键和值合计大小不能超过 256 KiB。因此,它不是不受限制的任意类型 JSON 存储。如果某个工具把 JSON 序列化后放进字符串,额外的格式与解释规则仍然由这个工具负责,而不是自动成为 Kubernetes 的通用语义。 自动化写入的键应使用负责组织控制的前缀。普通负责人说明与某个控制器专用参数,即使都位于同一张映射中,也具有不同含义。应记录哪个组件负责写入、哪个组件负责读取每个操作性键。来自另一种控制器、看起来很熟悉的 annotation,不能在没有核对契约时就当作可移植配置使用。 标签与 annotation 的选择角色也不同。标准选择器可以匹配标签表达式,而描述性的 annotation 通常需要另外读取和解释。这不意味着每一个任意标签都拥有专门存储索引,更不意味着 annotation 无法影响协调过程。字段选择应依据消费者的 API,而不是机械遵循“机器只读标签、人只读备注”的错误分工。 坏掉的样子 字段所在的位置会改变效果。修改 Deployment 顶层 metadata,与修改 spec.template 里面的 metadata,是不同操作。即使容器镜像和选择器标签没有改变,Pod 模板变化仍可能触发滚动更新。反过来,只写在 Deployment 对象上的 annotation,也不会自动变成 Pod 模板里的变化。审阅补丁时应明确完整字段路径,不能只比较键名。 ...

三月 10, 2027 · 3 分钟 · XB Field Notes