@@ -310,12 +310,9 @@ def _start(self) -> None:
310310 Raises:
311311 ContainerRunError: 容器启动失败。
312312 """
313- try :
314- # ── 1. 创建 Podman 客户端 ──
313+ def _create_client () -> None :
314+ """ 创建 Podman 客户端的内部辅助函数。"""
315315 if self .host_path is not None :
316- # 有宿主机路径:走跨平台路径转换流程
317- # Windows 下 PodmanSSHClient 返回的是包装对象,需调用 .client()
318- # Linux/macOS 下 _get_podman_context 直接返回 PodmanClient
319316 self ._pctx = _get_podman_context (
320317 self .host_path , ** self .client_kwargs
321318 )
@@ -325,14 +322,12 @@ def _start(self) -> None:
325322 else self ._pctx .ctx
326323 )
327324 else :
328- # 无宿主机路径:直接创建 PodmanClient,不做路径转换
329325 from podman import PodmanClient
330-
331326 self ._client = PodmanClient (** self .client_kwargs )
332327
333- # ── 2. 构建挂载列表 ──
328+ def _build_mounts () -> list [dict [str , Any ]]:
329+ """构建挂载列表的内部辅助函数。"""
334330 mounts : list [dict [str , Any ]] = []
335- # bind 挂载:将宿主机目录映射到容器内
336331 if self .host_path is not None and self .target is not None :
337332 mounts .append (
338333 {
@@ -341,36 +336,30 @@ def _start(self) -> None:
341336 "target" : self .target ,
342337 },
343338 )
344- # 命名卷挂载:Podman 管理的持久化存储卷
345339 for vol_src , vol_target in self .volumes .items ():
346340 mounts .append (
347341 {"type" : "volume" , "source" : vol_src , "target" : vol_target }
348342 )
343+ return mounts
349344
350- # ── 3. 清理同名旧容器 ──
351- # 仅在显式指定容器名时才清理,避免误删自动命名的容器
345+ def _cleanup_old_container () -> None :
346+ """清理同名旧容器的内部辅助函数。"""
352347 if self .name is not None :
353348 try :
354349 old = self ._client .containers .get (self .name )
355350 old .remove (force = True )
356351 except Exception :
357352 pass
358353
359- # ── 4. 仅建连接模式 ──
360- # start_container=False 时跳过容器创建,仅管理客户端生命周期
361- if not self .start_container :
362- return
363-
364- # ── 5. 构建容器运行参数并启动 ──
365- # 固定参数:所有容器都必须的配置
354+ def _build_run_params (mounts : list [dict [str , Any ]]) -> dict [str , Any ]:
355+ """构建容器运行参数的内部辅助函数。"""
366356 run_params : dict [str , Any ] = {
367357 "image" : self .image ,
368358 "command" : self .command or ["sleep" , "infinity" ],
369359 "tty" : True ,
370360 "stdin_open" : True ,
371361 "detach" : True ,
372362 }
373- # 条件参数:仅在显式设置时才传入,避免覆盖 SDK 默认行为
374363 if self .name is not None :
375364 run_params ["name" ] = self .name
376365 if mounts :
@@ -379,13 +368,46 @@ def _start(self) -> None:
379368 run_params ["working_dir" ] = self .working_dir
380369 if self .network_mode is not None :
381370 run_params ["network_mode" ] = self .network_mode
382- # 用户自定义参数最后合并,允许覆盖以上所有参数
383371 run_params .update (self .run_kwargs )
372+ return run_params
373+
374+ def _try_start_container (use_host_network : bool = False ) -> bool :
375+ """尝试启动容器,返回是否成功。
384376
385- self ._container = self ._client .containers .run (** run_params )
386- except Exception as exc :
387- self ._cleanup ()
388- raise ContainerRunError (f"容器启动失败: { exc } " ) from exc
377+ Args:
378+ use_host_network: 是否使用 host 网络模式(用于 pasta 错误时重试)
379+
380+ Returns:
381+ True 表示启动成功,False 表示遇到 pasta 相关错误需要重试
382+ """
383+ try :
384+ _create_client ()
385+ mounts = _build_mounts ()
386+ _cleanup_old_container ()
387+
388+ if not self .start_container :
389+ return True
390+
391+ run_params = _build_run_params (mounts )
392+
393+ if use_host_network and "network_mode" not in run_params :
394+ run_params ["network_mode" ] = "host"
395+
396+ self ._container = self ._client .containers .run (** run_params )
397+ return True
398+ except Exception as exc :
399+ self ._cleanup ()
400+ exc_str = str (exc )
401+ if "pasta" in exc_str .lower () and not use_host_network :
402+ return False
403+ raise ContainerRunError (f"容器启动失败: { exc } " ) from exc
404+
405+ # 首次尝试启动
406+ if _try_start_container ():
407+ return
408+
409+ # 遇到 pasta 错误,重试使用 host 网络模式
410+ _try_start_container (use_host_network = True )
389411
390412 def _cleanup (self ) -> None :
391413 """清理资源:容器 → 客户端 → SSH 隧道。
0 commit comments