Azure Timer Function部署后无法上传文件至Blob存储报错求助
问题背景
- 基于5分钟周期Timer Trigger开发的Azure Function,预期实现定时向Blob存储上传目标文件的能力
- 代码在本地环境可正常完成文件下载、上传全流程,部署到Azure云端后执行失败
业务代码
主方法
device_client = IoTHubDeviceClient.create_from_connection_string(CONNECTION_STRING) PATH_TO_FILE = wget.download("link-of-something", out=os.getcwd()) device_client.connect() blob_name = os.path.basename(PATH_TO_FILE) storage_info = device_client.get_storage_info_for_blob(blob_name) store_blob(storage_info, PATH_TO_FILE) device_client.shutdown()
辅助上传方法
def store_blob(blob_info, file_name): try: sas_url = "https://{}/{}/{}{}".format( blob_info["hostName"], blob_info["containerName"], blob_info["blobName"], blob_info["sasToken"] ) print("\nUploading file: {} to Azure Storage as blob: {} in container {}\n".format(file_name, blob_info["blobName"], blob_info["containerName"])) # 上传指定文件 with BlobClient.from_blob_url(sas_url) as blob_client: with open(file_name, "rb") as f: result = blob_client.upload_blob(f, overwrite=True) return (True, result) except FileNotFoundError as ex: # 捕获文件未找到异常,添加HTTP状态码用于向IoT Hub返回通知 ex.status_code = 404 return (False, ex) except AzureError as ex: # 捕获上传操作可能引发的Azure相关错误 return (False, ex)
错误信息
精简后的错误堆栈如下:
Result: Failure Exception: OSError: [Errno 30] Read-only file system: './nasa_graphics_manual_nhb_1430-2_jan_1976.pdfjo243l48.tmp' Stack: File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/dispatcher.py", line 407, in _handle__invocation_request call_result = await self._loop.run_in_executor( File "/usr/local/lib/python3.9/concurrent/futures/thread.py", line 58, in run result = self.fn(*self.args, **self.kwargs) File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/dispatcher.py", line 649, in _run_sync_func return ExtensionManager.get_sync_invocation_wrapper(context, File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/extension.py", line 215, in _raw_invocation_wrapper result = function(**args) File "/home/site/wwwroot/azure-function-timer/__init__.py", line 134, in main PATH_TO_FILE = wget.download("https://www.nasa.gov/sites/default/files/atoms/files/nasa_graphics_manual_nhb_1430-2_jan_1976.pdf", out=os.getcwd()) # wget to get the filename and path File "/home/site/wwwroot/.python_packages/lib/site-packages/wget.py", line 506, in download (fd, tmpfile) = tempfile.mkstemp(".tmp", prefix=prefix, dir=".") File "/usr/local/lib/python3.9/tempfile.py", line 336, in mkstemp return _mkstemp_inner(dir, prefix, suffix, flags, output_type) File "/usr/local/lib/python3.9/tempfile.py", line 255, in _mkstemp_inner fd = _os.open(file, flags, 0o600)
错误定位:异常触发点为wget.download方法调用行,根因是尝试在当前工作目录创建临时文件时触发只读文件系统错误。
根因分析
Azure Function Linux运行环境默认对应用根目录(即os.getcwd()返回的/home/site/wwwroot路径)做只读挂载,只有系统临时目录/tmp具备写入权限。
本地运行时工作目录可写,因此wget创建临时文件、下载文件的流程可以正常执行;部署到云端后,wget尝试在只读的工作目录下生成下载用的.tmp临时文件,直接触发[Errno 30] Read-only file system错误。
修复方案
- 修改wget下载的输出路径,从原来的
os.getcwd()替换为系统临时目录,建议使用Python标准库tempfile的gettempdir()方法跨环境获取临时目录路径,兼容本地和云端运行场景:import tempfile # 替换原来的PATH_TO_FILE赋值逻辑 PATH_TO_FILE = wget.download("目标文件下载链接", out=tempfile.gettempdir()) - 该方案完全适配当前业务场景:
/tmp目录用于存放临时文件,文件不会持久化保留,函数执行完成后平台会自动回收空间,刚好满足下载后即时上传到Blob、不需要本地留存文件的需求,不需要额外调整Function配置。 - 如果后续有持久化写入文件的需求,可以在Function应用设置中添加配置项
WEBSITES_ENABLE_APP_SERVICE_STORAGE = true开启应用目录写入权限,但对于当前临时下载的场景,直接使用/tmp目录是性能最优、改动最小的方案。
内容的提问来源于stack exchange,提问作者Merrick
相关产品推荐
相关产品推荐

