Cloud Run中Secret Reference被挂载为目录而非文件的问题求助
问题描述
使用Cloud Run结合Secret Manager挂载两个密钥为文件类型卷时,mtls的p12文件能正常挂载为文件,但Firebase的JSON密钥被挂载成了目录,导致Java应用抛出文件未找到异常(提示目标路径是目录)。
配置片段
Cloud Run YAML中的相关配置:
volumeMounts: - name: secret-2f1d5ec9-d681-4b0f-8a77-204c5f853330 readOnly: true mountPath: /root/key/mtls/client_auth.p12 - name: secret-29c1417a-d9fe-4c37-8cb0-562c97f3c827 readOnly: true mountPath: /root/key/firebase/myapp-d2a0f-firebase-adminsdk-irfes-a699971a4d.json volumes: - name: secret-2f1d5ec9-d681-4b0f-8a77-204c5f853330 secret: secretName: myapp_mtls_key items: - key: latest path: myapp_mtls_key - name: secret-29c1417a-d9fe-4c37-8cb0-562c97f3c827 secret: secretName: myapp_firebase_token items: - key: latest path: myapp_firebase_token
错误日志
java.io.FileNotFoundException: /root/key/firebase/myapp-d2a0f-firebase-adminsdk-irfes-a699971a4d.json (Is a directory) at java.base/java.io.FileInputStream.open0(Native Method) at java.base/java.io.FileInputStream.open(FileInputStream.java:216) at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157) at java.base/java.io.FileInputStream.<init>(FileInputStream.java:111) at com.myapp.gcp.GCPInit.init(GCPInit.java:39)
已在Docker容器内测试卷挂载逻辑,确认应用本身无问题,排除代码层面错误。
问题原因与解决方法
这个问题的核心是Cloud Run的Secret挂载逻辑:当指定mountPath为文件路径时,若未明确指定卷内的目标文件,Cloud Run会将mountPath创建为目录,再把Secret中的文件放入该目录下。
解决方法1:调整Secret卷的文件路径为目标文件名
修改Firebase密钥的volumes配置,将items.path设置为最终要生成的文件名,同时将mountPath改为目录路径:
# 修改后的volumeMounts volumeMounts: - name: secret-29c1417a-d9fe-4c37-8cb0-562c97f3c827 readOnly: true mountPath: /root/key/firebase/ # 修改后的volumes volumes: - name: secret-29c1417a-d9fe-4c37-8cb0-562c97f3c827 secret: secretName: myapp_firebase_token items: - key: latest path: myapp-d2a0f-firebase-adminsdk-irfes-a699971a4d.json
这样Secret中的内容会被直接挂载为/root/key/firebase/myapp-d2a0f-firebase-adminsdk-irfes-a699971a4d.json文件。
解决方法2:使用subPath指定卷内文件
如果希望保留原有mountPath的文件路径写法,需要在volumeMounts中添加subPath字段,指定Secret卷中对应的文件名(即items.path的值):
volumeMounts: - name: secret-29c1417a-d9fe-4c37-8cb0-562c97f3c827 readOnly: true mountPath: /root/key/firebase/myapp-d2a0f-firebase-adminsdk-irfes-a699971a4d.json subPath: myapp_firebase_token
subPath会告诉Cloud Run将卷内的myapp_firebase_token文件直接映射到指定的mountPath路径,而非创建目录。
关于mtls密钥正常的说明
mtls密钥能正常工作,大概率是因为容器镜像中已经存在/root/key/mtls/目录,Cloud Run在挂载时直接将Secret内容写入到指定的文件路径中;而Firebase的/root/key/firebase/目录不存在,触发了Cloud Run自动创建目录的逻辑,但未正确映射文件。
内容的提问来源于stack exchange,提问作者Ravi

