我有一个 K8S 部署,将卷作为原始块加载(通过volumeDevices):
apiVersion: apps/v1
kind: Deployment
...
spec:
replicas: 1
...
containers:
- name: somepod
image: ubuntu:latest
command: ["sh","-c", "--"]
args: ["mount /dev/block /data && while true; do sleep 1000000; done"]
securityContext:
privileged: true
volumeDevices:
- devicePath: /dev/block
name: vol
volumes:
- name: vol
persistentVolumeClaim:
claimName: vol
这按预期工作。
我想要实现的目标:
我想在容器中挂载 /dev/block ,而不必授予它特权访问权限(因此,无需 root)。
我可以完全控制基础映像,其默认用户是 1001,已添加到非 root 组。
当 k8s 将 /dev/block 添加到容器时,据我所知,它会为其分配一个随机组,例如 993:
brw-rw----. 1 root 993 259, 16 Dec 15 09:00 block
据我了解,这是我无法控制的(例如,我无法告诉 k8s 将其安装在已知组下)。
我尝试过的事情:
- 将文件系统格式化为 ext4,添加 /etc/fstab 行
/dev/block /data ext4 user,uid=1001,auto 0 0
- 添加
securityContext: fsGroup:1001
- 将文件系统格式化为 ntfs 添加 /etc/fstab 行
/dev/block /data ntfs user,uid=1001,auto 0 0
pmount
在容器中安装和使用。失败,因为我的用户不属于 /dev/block 组- 使用 postStart 挂钩(无用,因为它共享主运行时的相同权限)
- 使用特权 initContainer 将卷从 /dev/block 挂载到emptyDir /data。根据我的理解,initContainer 和容器应该共享emptyDir,但由于数据存在于已安装的卷上,因此这是行不通的。
我还没有尝试过的事情:
一个可能的失败点可能是我可能不正确的 /etc/fstab 设置,因为每当我尝试以用户身份挂载时,无论如何,我仍然会遇到 /dev/block 上的权限问题。
为什么我使用块卷:
我正在运行 EKS,并且希望在同一可用区的多个 Pod 之间共享“ReadWriteMany”中的数据。我研究过在 io2 中使用 EFS 卷而不是 EBS,但我有价格/延迟问题。
相关问题:
答案1
最终对我来说的解决方案是使用 AWS EC2 函数(由 Karpenter 导出),该函数允许为节点配置给定卷快照的副本。
我的 Karpenter 的 ec2 NodeClass 看起来像:
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
name: test
spec:
amiFamily: AL2
...
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
deleteOnTermination: true
volumeSize: 100Gi
volumeType: gp2
- deviceName: /dev/xvdc
ebs:
deleteOnTermination: true
snapshotID: snap-ID-NUMBER
volumeSize: 40Gi
volumeType: gp2
...
userData: |-
#!/bin/bash
set -x
...
mkdir -p /home/ec2-user/data/
mount -o defaults /dev/nvme2n1 /home/ec2-user/data/
...
这里进行了一些尝试和错误,但主要的收获是:
- AWS 提供从我提供的给定 snapshotID 复制的磁盘;
- 它被添加到 /dev/xvdc 下;在我的 AMI 中,这等于 /dev/nvme2n1,尽管不能保证所有 AMIS/Arch 都如此
- 我将文件系统挂载在 EC2 的用户数据中。
此外,为了确保数据更新,我运行 aws s3 同步作为 userData 的一部分。无需 Karpenter,只需使用 AWS EC2 的 api 即可复制相同的行为。