一、Pod 常用内置字段有哪些

Pod 里有一类非常实用的“内置字段”,经常用于动态注入运行信息。

1. metadata 相关

最常见的是:

  • metadata.name
  • metadata.namespace
  • metadata.uid
  • metadata.labels
  • metadata.annotations

这些字段通常用于:

  • 日志与监控标识
  • 多环境区分
  • Service 筛选和版本标记
  • 构建信息透传

2. spec 相关

例如:

  • spec.nodeName
  • spec.serviceAccountName

这类字段更偏运行和权限控制,例如:

  • 把 Pod 固定到某台节点
  • 指定访问 API Server 所使用的服务账号

3. status 相关

例如:

  • status.hostIP
  • status.hostIPs
  • status.podIP
  • status.podIPs

它们在日志采集、节点关联和双栈网络场景里都很实用。

二、如何给 Pod 配置环境变量

除了手工写死环境变量,Pod 还支持通过 fieldRef 动态注入自身信息。

示例:

apiVersion: v1
kind: Pod
metadata:
  name: pod-env
  labels:
    run: pod-env
    environment: test
  annotations:
    build-info: "commit=abc123"
    monitor/path: "/metrics"
spec:
  nodeName: k8s-node02
  serviceAccountName: pod-sa
  containers:
  - image: registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:1.14.2
    name: pod-env
    env:
    - name: ENV
      value: test
    - name: POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    - name: POD_NAMESPACE
      valueFrom:
        fieldRef:
          fieldPath: metadata.namespace
    - name: POD_NODE_NAME
      valueFrom:
        fieldRef:
          fieldPath: spec.nodeName
    - name: POD_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP
    - name: HOST_IP
      valueFrom:
        fieldRef:
          fieldPath: status.hostIP

先准备 ServiceAccount

kubectl create serviceaccount pod-sa

再应用 YAML:

kubectl apply -f pod-env.yaml

进入 Pod 验证:

kubectl exec pod-env -- env

这类能力本质上就是 Downward API:把 Pod 自己的元数据和运行态信息注入给容器。

三、镜像拉取策略为什么经常被忽略

Pod 常见的 imagePullPolicy 有三种:

  • Always
  • IfNotPresent
  • Never

默认行为通常是:

  • 如果镜像标签是 latest,往往倾向于 Always
  • 如果标签是明确版本,默认通常是 IfNotPresent

示例:

imagePullPolicy: Always

然后可以通过:

kubectl describe po nginx

查看实际拉取情况。

四、为什么“节点上明明有镜像”,Pod 还是拉不到

这类问题在 Kubernetes 里非常常见,通常有四种原因。

1. 镜像只在单个节点存在

如果镜像只导入到了某一台节点,而 Pod 被调度到了别的节点,就会出现“明明有镜像却拉不到”的现象。

2. Docker 和 Containerd 的镜像存储隔离

即使你用 docker load 导入成功,也不代表 kubelet 能用到这份镜像。因为很多 Kubernetes 集群实际用的是 Containerd:

  • Docker 镜像常在 /var/lib/docker
  • Containerd 镜像常在 /var/lib/containerd

所以常见处理方式是:

docker save myimage:tag > myimage.tar
ctr -n=k8s.io images import myimage.tar

3. Containerd 命名空间不对

Kubernetes 默认只会读取 k8s.io 命名空间里的镜像。

错误做法:

ctr images import image.tar

正确做法:

ctr -n=k8s.io images import image.tar

排查时可以对比:

ctr -n=k8s.io images ls
ctr -n=default images ls

4. Always 导致强制远程拉取

即使本地有镜像,只要策略是 Always,仍可能继续尝试从远端仓库拉取。如果私有仓库认证失败或网络不通,Pod 依然会报错。

这也是为什么很多生产环境更倾向于固定版本标签加 IfNotPresent

五、Pod 的重启策略怎么理解

Pod 的 restartPolicy 常见有三种:

  • Always
  • OnFailure
  • Never

含义分别是:

  • Always:默认策略,容器退出就尝试拉起
  • OnFailure:只有非 0 退出码才重启
  • Never:无论什么情况都不自动重启

示例:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:1.14.2
    command: ["sleep","4"]
    imagePullPolicy: Always
  restartPolicy: OnFailure

如果命令正常结束,Pod 往往会显示 Completed,而不会像 Always 那样循环重启。

六、重启策略和镜像拉取策略不要混淆

这两个词很像,但控制的完全不是一回事:

  • restartPolicy 决定“容器退出后要不要重启”
  • imagePullPolicy 决定“容器启动前要不要重新拉镜像”

一个控制运行时行为,一个控制拉取镜像行为。

七、这部分配置最常见的实战建议

如果把这一篇内容收敛成几条实战建议,大概就是:

  • 环境变量优先用 YAML 明确管理,不要大量写死在镜像里
  • 需要读取 Pod 自身信息时,优先考虑 fieldRef
  • 生产环境尽量使用明确镜像版本,不要滥用 latest
  • 使用 Containerd 的集群,导入镜像时注意 k8s.io 命名空间
  • 分清 restartPolicyimagePullPolicy,排障时不要混为一谈

这样做能避免很多“看起来像容器问题,实际是配置问题”的低级坑。