研发工程师玩转Kubernetes——使用emptyDir在同一Pod不同容器间共享数据

文章详细描述了如何在Kubernetes中使用emptyDir实现同一Pod内不同容器之间的文件系统共享,并展示了如何通过设置Pod亲和性来确保同一Node上的Pod之间无法共享emptyDir。通过实例和代码展示了创建Deployment和验证效果的过程。

kubernets可以通过emptyDir实现在同一Pod的不同容器间共享文件系统。
在这里插入图片描述
正如它的名字,当Pod被创建时,emptyDir卷会被创建,这个时候它是一个空的文件夹;当Pod被删除时,emptyDir卷也会被永久删除。

同一Pod上不同容器之间共享

# bash
if [ -f /tempdir/lockfile ] && ! { set -C; 2>/dev/null >/tempdir/lockfile; }; then
    tail -f /tempdir/lockfile
else
    exec 3>/tempdir/lockfile
    if [ -n "$POD_NAME" ]; then
        pod_name=$POD_NAME
    else
        pod_name="unknown_pod"
    fi
    if [ -n "$CONTAINER_NAME" ]; then
        container_name=$CONTAINER_NAME
    else
        container_name="unknown_container"
    fi
    while true; do
        echo "$pod_name $container_name write something to lockfile" >&3
        sleep 5
    done
fi

我们使用上面这段脚本,会检测/tempdir/lockfile文件是否存在。如果不存在则创建这个文件,并获取Pod和Container名称,然后每隔5秒钟在/tempdir/lockfile写入一句话;如果存在,则不停打印新写入这个文件的内容。
然后使用下面的清单文件创建一个deployment

# emptydir_same_pod.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: emptydir-deployment
spec:
  selector:
    matchLabels:
      app: emptydir-container
  replicas: 1
  template:
    metadata:
      labels:
        app: emptydir-container
    spec:
      containers:
      - name: emptydir-container1
        image: busybox
        command: ["/bin/sh", "-c", "if [ -f /tempdir/lockfile ] && ! { set -C; 2>/dev/null >/tempdir/lockfile; }; then tail -f /tempdir/lockfile; else exec 3>/tempdir/lockfile; if [ -n \"$POD_NAME\" ]; then pod_name=$POD_NAME; else pod_name=\"unknown_pod\"; fi; if [ -n \"$CONTAINER_NAME\" ]; then container_name=$CONTAINER_NAME; else container_name=\"unknown_container\"; fi; while true; do echo \"$pod_name $container_name write something to lockfile\" >&3; sleep 5; done; fi;"]
        volumeMounts:
        - name: emptydir-volume
          mountPath: /tempdir
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: CONTAINER_NAME
          value: emptydir-container1
      - name: emptydir-container2
        image: busybox
        command: ["/bin/sh", "-c" ,"if [ -f /tempdir/lockfile ] && ! { set -C; 2>/dev/null >/tempdir/lockfile; }; then tail -f /tempdir/lockfile; else exec 3>/tempdir/lockfile; if [ -n \"$POD_NAME\" ]; then pod_name=$POD_NAME; else pod_name=\"unknown_pod\"; fi; if [ -n \"$CONTAINER_NAME\" ]; then container_name=$CONTAINER_NAME; else container_name=\"unknown_container\"; fi; while true; do echo \"$pod_name $container_name write something to lockfile\" >&3; sleep 5; done; fi;"]
        volumeMounts:
        - name: emptydir-volume
          mountPath: /tempdir
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: CONTAINER_NAME
          value: emptydir-container2
      volumes:
      - name: emptydir-volume
        emptyDir: 
          medium: Memory
          sizeLimit: 1Gi

这个Deployment会创建一个Pod,这个Pod会含有两个容器:emptydir-container1和emptydir-container2。
使用下面命令创建这个部署

kubectl create -f emptydir_same_pod.yaml 

deployment.apps/emptydir-deployment created

然后登录到容器中查看/tempdir/lockfile文件的内容

kubectl exec pods/emptydir-deployment-75c6545df5-slznj --container emptydir-container1 -it -- tail -f /tempdir/lockfile

emptydir-deployment-75c6545df5-slznj emptydir-container1 write something to lockfile
emptydir-deployment-75c6545df5-slznj emptydir-container1 write something to lockfile
emptydir-deployment-75c6545df5-slznj emptydir-container1 write something to lockfile
……

kubectl exec pods/emptydir-deployment-75c6545df5-slznj --container emptydir-container2 -it -- tail -f /tempdir/lockfile

emptydir-deployment-75c6545df5-slznj emptydir-container1 write something to lockfile
emptydir-deployment-75c6545df5-slznj emptydir-container1 write something to lockfile
emptydir-deployment-75c6545df5-slznj emptydir-container1 write something to lockfile
……

可以看到emptydir-container1容器在持续写入内容;emptydir-container2因为检测到/tempdir/lockfile文件存在,就不会写入文件。
通过下面指令可以看到emptydir-container2的输出

kubectl logs pods/emptydir-deployment-75c6545df5-slznj --container emptydir-container2

emptydir-deployment-75c6545df5-slznj emptydir-container1 write something to lockfile
emptydir-deployment-75c6545df5-slznj emptydir-container1 write something to lockfile
emptydir-deployment-75c6545df5-slznj emptydir-container1 write something to lockfile
……

同一个Node的不同Pod间不可以共享

我们应用Pod亲和性,让Deployment在同一个Node上部署相同的Pod。

# emptydir_same_node.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: emptydir-same-node-deployment
spec:
  selector:
    matchLabels:
      app: emptydir-container
  replicas: 2
  template:
    metadata:
      labels:
        app: emptydir-container
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - emptydir-container
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: emptydir-container
        image: busybox
        command: ["/bin/sh", "-c", "if [ -f /tempdir/lockfile ] && ! { set -C; 2>/dev/null >/tempdir/lockfile; }; then tail -f /tempdir/lockfile; else exec 3>/tempdir/lockfile; if [ -n \"$POD_NAME\" ]; then pod_name=$POD_NAME; else pod_name=\"unknown_pod\"; fi; if [ -n \"$CONTAINER_NAME\" ]; then container_name=$CONTAINER_NAME; else container_name=\"unknown_container\"; fi; while true; do echo \"$pod_name $container_name write something to lockfile\" >&3; sleep 5; done; fi;"]
        volumeMounts:
        - name: emptydir-volume
          mountPath: /tempdir
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: CONTAINER_NAME
          value: emptydir-container
      volumes:
      - name: emptydir-volume
        emptyDir: 
          medium: Memory
          sizeLimit: 1Gi

创建好这个部署后,我们可以通过下面指令确认它们被部署在同一个Node(ubuntuc)上。

kubectl get pods -o wide
NAME                                             READY   STATUS    RESTARTS   AGE   IP            NODE      NOMINATED NODE   READINESS GATES
emptydir-same-node-deployment-6b6cfbb769-vhj7k   1/1     Running   0          34s   10.1.43.199   ubuntuc   <none>           <none>
emptydir-same-node-deployment-6b6cfbb769-mgh8h   1/1     Running   0          34s   10.1.43.198   ubuntuc   <none>           <none>

然后查看每个Pod上/tempdir/lockfile文件的内容

kubectl exec pods/emptydir-same-node-deployment-6b6cfbb769-mgh8h --container emptydir-container -it -- tail -f /tempdir/lockfile

emptydir-same-node-deployment-6b6cfbb769-mgh8h emptydir-container write something to lockfile
emptydir-same-node-deployment-6b6cfbb769-mgh8h emptydir-container write something to lockfile
emptydir-same-node-deployment-6b6cfbb769-mgh8h emptydir-container write something to lockfile
……

kubectl exec pods/emptydir-same-node-deployment-6b6cfbb769-vhj7k --container emptydir-container -it -- tail -f /tempdir/lockfile

emptydir-same-node-deployment-6b6cfbb769-vhj7k emptydir-container write something to lockfile
emptydir-same-node-deployment-6b6cfbb769-vhj7k emptydir-container write something to lockfile
emptydir-same-node-deployment-6b6cfbb769-vhj7k emptydir-container write something to lockfile
……

可以看到它们打印出来的Pod名称不同,即可以证明:同一个Node上不同Pod创建的emptyDir是不同的。

参考资料

<think>我们正在讨论的是Kubernetes中的EmptyDir卷。问题:同一EmptyDir卷是否可以安全地挂载到Pod内多个容器不同路径? 根据引用[3]:“kubernetes通过定义存储卷来满足这个需求,它们不像pod这样的顶级资源,而是定义为pod的一部分,并和pod共享相同的生命周期。这意味着在pod启动时创建卷,并在删除pod时销毁卷。因此,在容器重启期,卷的内容不会变,新的容器可以识别前一个容器写入到卷中的所有文件。另外,如果一个pod包含多个容器,多个容器可以共享一个卷。” 所以,同一EmptyDir卷可以被挂载到同一Pod中的多个容器中。而且,由于这个卷是Pod级别的资源,所以多个容器挂载的是同一个存储卷实例。 但是,问题中问的是挂载到多个容器不同路径。这意味着,同一个卷(同一EmptyDir)被挂载到不同容器不同路径下。例如: - 容器A将卷挂载到路径 /path1 - 容器B将卷挂载到路径 /path2 由于是同一个卷,所以无论挂载到哪个路径,实际上都是访问同一个存储空。因此,容器A在/path1下写入的文件,在容器B的/path2下也能看到,反之亦然。 那么,这样是否安全?这取决于应用场景。 安全性分析: 1. **数据共享**:如果多个容器需要共享数据,那么这是安全的,并且正是EmptyDir的设计用途之一。例如,一个容器生成日志,另一个容器处理日志,它们可以通过共享EmptyDir卷来传递日志文件。 2. **并发访问**:如果多个容器同时对同一个文件进行读写,那么需要应用程序自己处理文件锁或并发控制,否则可能会出现数据损坏。这与在同一个主机上多个进程访问同一个文件没有区别。 3. **路径隔离**:虽然挂载点路径不同,但实际存储是共享的。因此,不同容器中的应用程序可能会覆盖或干扰彼此的文件,如果它们不知道对方的存在。因此,需要确保应用程序不会在同一个卷中写入相同的文件路径,或者有明确的文件命名规则以避免冲突。 4. **使用场景**:EmptyDir卷通常用于临时存储,比如缓存、临时文件、进程通信等。如果多个容器需要共享这些临时数据,那么共享同一EmptyDir卷是合适的。 结论:从Kubernetes的角度,同一EmptyDir卷挂载到多个容器不同路径是安全的,因为Kubernetes会确保每个PodEmptyDir卷是独立的,并且多个容器挂载同一个卷是设计支持的功能。但是,应用程序需要能够处理并发访问和文件冲突,以避免数据损坏。 引用[5]提到:“数据挂载卷(Volume)的使用已成为服务运行不可或缺的一部分,尤其是在涉及配置文件、缓存目录、日志输出、数据库存储等场景下,其初始化逻辑与持久化机制的正确性直接影响业务的稳定性与可维护性。” 因此,在共享卷时,要特别注意初始化逻辑和持久化机制的正确性。 因此,答案是:可以安全地挂载,但需要应用程序设计时考虑共享存储的并发访问和文件冲突问题。 引用[3]支持了多个容器共享一个卷的可行性。 现在,根据要求,生成相关问题。 §§相关问题§§ 1. 在Kubernetes中,同一EmptyDir卷被多个容器挂载时,如何避免文件访问冲突? 2. EmptyDir卷的生命周期是怎样的?它何时会被清理? 3. 除了EmptyDirKubernetes还有哪些类型的卷适合多容器共享?</think>### Kubernetes同一 EmptyDir 卷挂载到多个容器不同路径的安全性分析 在 Kubernetes 中,**同一EmptyDir 卷可以安全地挂载到 Pod 内多个容器不同路径**,这是 Kubernetes 原生支持的特性,其安全性取决于以下关键机制: #### ✅ 安全的核心原理 1. **卷共享机制** 同一EmptyDir 卷在 Pod 内被多个容器挂载时: - 所有容器访问的是**同一份物理存储空**(位于节点上的临时目录) - 不同容器通过各自挂载路径访问时,实际读写的是**相同存储内容** - 符合引用[3]的描述:*"如果一个pod包含多个容器,多个容器可以共享一个卷"*[^3] 2. **数据一致性保障** - 写入操作遵循 **POSIX 文件系统语义**,与本地磁盘行为一致 - 容器通过文件锁(`flock()`)可实现并发控制 - 示例配置: ```yaml volumes: - name: shared-cache # 定义共享EmptyDiremptyDir: {} containers: - name: container-a volumeMounts: - name: shared-cache mountPath: /container-a/cache # 容器A的挂载路径 - name: container-b volumeMounts: - name: shared-cache mountPath: /container-b/cache # 容器B的挂载路径 ``` 3. **生命周期绑定** 如引用[3]所述:*"卷定义为pod的一部分,并和pod共享相同的生命周期"*[^3],这保证了: - 卷在 Pod 启动时创建 - 所有容器停止后卷才销毁 - 容器重启不会丢失卷内数据 #### ⚠️ 需注意的风险场景 1. **文件路径冲突** 若不同容器向**相同文件路径**写入数据(如都尝试写 `/cache/temp.file`),会产生覆盖: ```mermaid graph LR A[容器A] -->|写入 /cache/temp.file| C[共享存储] B[容器B] -->|写入 /cache/temp.file| C C --> D[数据损坏] ``` **解决方案**:为各容器约定独立子目录(如 `/cache/container-a/`) 2. **并发写入竞争** 当多个容器同时写入同一文件时,需应用程序实现: - 文件锁定机制(如 `fcntl` 锁) - 原子写操作(如 `O_APPEND` 模式) 3. **存储介质限制** EmptyDir 使用节点本地存储,需注意: - 磁盘空不足会导致写入失败 - SSD/HDD 性能差异影响 IO 吞吐量 #### ✔️ 最佳实践建议 1. **路径隔离策略** ```yaml volumeMounts: - name: shared-vol mountPath: /cache/container-a # 容器A使用独立子目录 - name: shared-vol mountPath: /cache/container-b # 容器B使用独立子目录 ``` 2. **只读挂载控制** 对不需要写入的容器启用 `readOnly`: ```yaml volumeMounts: - name: shared-vol mountPath: /cache readOnly: true # 安全限制写入 ``` 3. **资源配额管理** 通过 `sizeLimit` 防止磁盘耗尽: ```yaml volumes: - name: shared-vol emptyDir: sizeLimit: 1Gi # 限制卷大小 ``` > **结论**:同一 EmptyDir 卷挂载到多个容器不同路径在 **Kubernetes 设计上是安全的**,实际安全性取决于应用程序是否正确处理文件并发访问和路径隔离。建议配合文件锁机制和子目录隔离使用[^3][^5]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

breaksoftware

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值