Tag: kubernetes

3 notes found.

用 tar 的 -(stdin/stdout)配合 | 管道,把目录内容从一端流式送到另一端,全程不落临时文件。比逐文件拷贝更快、更稳,还保留目录结构与权限。

基本形态

# 左侧:tar 打包写到 stdout;右侧:从 stdin 解包到目标目录
tar cf - -C /src dir \
  | tar xf - -C /dst
  • c 创建归档、f - 输出到 -(stdout);x 解包、f --(stdin)读取归档
  • -C dir 先切换目录再操作,避免把绝对/相对路径的前缀带进归档

跨主机/跨进程传送

管道两侧不必是同一进程,常见于 kubectl exec、ssh、curl 等场景:

# 从远端 Pod 拉目录到本地,剥离前两级路径
kubectl exec -n platform "$POD" -- tar cf - /app/config \
  | tar xf - --strip-components=2 -C /home/laborant/config

# 等价写法:左侧把 /app 设为根,归档内只剩 config/ 一级前缀,右侧只需 strip 1
kubectl exec -n platform "$POD" -- tar cf - -C /app config \
  | tar xf - --strip-components=1 -C /home/laborant/config
  • --strip-components=N:去掉每个成员路径最前面的 N 个分量(本例去掉 app/config 两级)
  • exec 不加 -t(TTY),避免换行转换污染二进制流
  • -C 目标目录须先存在,否则报 Cannot open,先 mkdir -p

变体

  • 压缩(网络慢):左侧 tar czf -,右侧 tar xzf -(gzip)
  • 本地备份tar cf - dir | tar xf - 等价 cp -a,但保留更完整属性

注意

  • 两端都需安装 tar(busybox/distroless 容器可能没有)
  • --strip-components 由 GNU tar / bsdtar 提供,macOS / Linux 均有
  • 非 root 解包时文件 owner 变成当前用户(root 下才默认保留)

当 Kubernetes 将 ConfigMap 挂载为 volume 时,pod 内的文件其实是 symlink,直接 kubectl cp 会跳过所有文件导致拷不出内容。用 kubectl exec + tar 管道即可复制真实文件。

问题

# 这样拷贝会失败:目录内全是 symlink,无 .conf 文件落地
kubectl cp platform/${POD}:/app/config/ /home/laborant/config/

warning: skipping symlink: "/home/laborant/config/server.conf" -> "..data/server.conf"
# ...
# kubectl cp 退出码为 0 却什么都没拷出来

原因:kubectl cp 内部用 tar 流式传输,但没传 --dereference。挂载路径下的条目全是 symlink,tar 视其为符号链接而跳过。kubectl cp 即使失败也返回 0,必须 ls 验证结果。

解决方案

在 pod 内部 tar 打包(内核 VFS 透明解析 symlink),再管道给本地 tar 解包:

# 左侧在 pod 内打包并写 stdout,右侧本地解包并剥离前两级路径
kubectl exec -n platform "$POD" -- tar cf - /app/config \
  | tar xf - --strip-components=2 -C /home/laborant/config
  • --strip-components=2:去掉 app/config 两级前缀,只留裸文件名
  • tar xf -:从 stdin 读取归档,-C 指定解包目录
ls /home/laborant/config/
# database.conf  feature-flags.conf  logging.conf  server.conf

通用注意点与变体

  • exec 不要加 -t(TTY):TTY 会对输出做换行转换,污染二进制归档流;无 TTY 的 exec 才是干净的 stdin/stdout 回传
  • -C 目标目录必须先存在tar 不会自动创建目录,会报 Cannot open 之类错误,先 mkdir -p /home/laborant/config
  • 等价写法:左侧 tar cf - -C /app config 时归档成员只有 config/... 一级前缀,右侧只需 --strip-components=1;与”绝对路径 + strip 2”语义等价,任选一种保持一致
  • 压缩变体:网络较慢时左侧 tar czf -(gzip 压缩),右侧 tar xzf - 解压
  • 依赖:Pod 内需装有 tar(busybox/distroless 镜像可能没有,报 exec: tar: not found);本地的 --strip-components 由 GNU tar / bsdtar 提供,macOS / Linux 均有
  • 权限:非 root 解包时文件 owner 会变成当前用户(tar 仅在 root 下默认保留 owner),通常无碍

获取运行中的 pod 名

POD=$(kubectl get pod -n platform \
  -l app=config-service \
  -o jsonpath='{.items[0].metadata.name}')
原子更新机制:两层级联导致 kubectl cp 失效

ConfigMap 以 volume 挂载时,目录结构是两层间接:

/app/config/
├── ..2026_08_19_10_19_29.2041564214/   ← 真实目录,存真实字节
├── ..data -> ..2026_08_19_10_19_29.2041564214   ← 指向真实目录
└── server.conf -> ..data/server.conf    ← 每个文件都是 symlink
  • 权限串首字符 l 表示 symlink(lrwxrwxrwx
  • kubelet 更新 ConfigMap 时写入新时间戳目录,再通过一次原子 rename() 重指 ..data,保证运行中的 pod 立即看到新内容且不出现新旧混合
  • tar 默认不跟随 symlink,kubectl cp 因此全部跳过

kubectl create ingress--rule 语法里,tls 是挂在某条 rule 上的,它的 host 会直接复用该 rule 的 host,命令行层面没有单独指定 tls hosts 的选项

kubectl create ingress snake-ingress -o snake \
  --rule="a.com/=snake:80,tls=snake" \
  --dry-run=client -o yaml

生成结果一定是:

spec:
  rules:
  - host: a.com
    http:
      paths:
      - path: /
        pathType: Exact
        backend:
          service:
            name: snake
            port:
              number: 80
  tls:
  - hosts:
    - a.com
    secretName: snake

rules[].hosttls[].hosts 必然一致,无法让两者不同。

可行的两种办法

  1. 手动改生成的 YAML(最直接):用 --dry-run=client -o yaml 生成后直接编辑 spec.tls[0].hosts,改成你想要的域名(如通配符证书 *.a.com 或额外域名),与 rules[].host 脱钩即可。

  2. 用多条 --rule 聚合多个 host

    kubectl create ingress snake-ingress -o snake \
      --rule="a.com/=snake:80,tls=snake" \
      --rule="b.com/=snake:80,tls=snake" \
      --dry-run=client -o yaml

    这样 tls[0].hosts 会变成 [a.com, b.com],但本质上只是各 rule host 的并集——并不能做到”某条 rule 的 host 不出现在 tls.hosts 里”这种脱钩效果。

如果你的目标是”http 规则匹配 a.com,但证书 SAN 是别的域名(如通配符证书)“,最干净的做法就是方案 1:生成模板后手工改 tls.hostsapply