k8s 1.21 新 beta feature BoundServiceAccountToken 对 velero+restic 的影响
背景
自 k8s v1.21.0 开始, BoundServiceAccountTokenVolume 功能升级到 beta, 也就是说会默认 enable。这个功能属于比较冷门,其发展路线如下,
| Feature-state | k8s-version |
| ------------- | ----------- |
| alpha | v1.13 |
| beta | v1.21 |
| Stable GA | v1.22 |
当 BoundServiceAccountTokenVolume 特性被启用时,可以将 service account volume 迁移到一个 projected volume。Service account token 将在一小时后或者 Pod 被删除后过期。
引入的新问题
因此,如果在 velero 中使用 restic 对 pod 进行备份或迁移,source k8s version > 1.21,同时 target k8s version 低于 1.21 的话,可能会出现 restore 的 pod 不能正常启动。提示 error 如下,
kubelet Unable to attach or mount volumes: unmounted volumes=[kube-api-access-scw4k]
这时候解决方案是将 pod 删除,replica controller 会重新生成 pod 的配置,就可以正常启动了。
通过查看 velero 的 issue,发现已经有人遇到相同的问题,并且在 velero) 1.6.1 以及之后版本上 fix 了这个 issue。
那么这个 oundServiceAccountTokenVolume 在实际 pod 中是怎么存在的呢?以下是其一个具体例子
volumes:
- name: kube-api-access-l5vcn
projected:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
可以看到,Admission Controller 在 Pod 创建或者更新时,对 Pod 执行一些修改。此控制器激活时(默认处于激活状态),当 Pod 被创建或修改时,该控制器将执行如下动作
- 为 Pod 添加一个 volume (其中包含了访问 APIServer 的 token)
- 为 Pod 中的每一个容器添加一个 volumeSource,并挂载到路径 /var/run/secrets/kubernetes.io/serviceaccount
- 如果 Pod 未设置 ServiceAccount,将 ServiceAccount 设置为 kube-api-access-xxxxx
而低于 1.21 版本的 k8s 中,Pod 默认的 ServiceAccount 设置为 default-token-xxxx,并且是正常 volume 的形式挂载给 pod 使用的。
因此在 1.21 版本中,当使用 Restic copy volume 的时候,会尝试复制 kube-api-access-xxxxx 并挂给 pod 使用。这时候如果在低版本 k8s 中 restore data,就会触发这个 issue 了。