You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker容器间Rust+Hyper Unix Socket通信错误排查求助

问题:前端容器无法通过共享Unix套接字访问Actix服务器

环境与问题概述

运行两个Docker容器:一个是Actix服务器,绑定到Unix域套接字/tmp/iso-uds.socket;另一个是前端Framesurge-Perseus应用。已为套接字创建共享卷,且通过其他容器用netcat测试可正常访问该套接字,但前端容器尝试通过共享卷获取数据时失败。

错误日志

Running `dist/target_engine/release/front`
451.5 Error: render function 'build_state' in template '' failed (cause: Server(None))
451.5
451.5 Caused by:
451.5   Hyper error: Hyper error: error trying to connect: No such file or directory (os error 2)
------
failed to solve: process "/bin/sh -c perseus deploy" did not complete successfully: exit code: 1

相关代码

客户端请求与状态构建代码

use hyper::{body::HttpBody, Client};
use hyperlocal::{UnixClientExt, Uri};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use tokio::io::{self, AsyncWrite as _};
use perseus::prelude::*;

use std::io::stdout;
use std::error::Error;

pub static SOCKET_ADDR: &str = "/tmp/iso-uds.socket";

#[cfg(engine)]
pub async fn client_request<T: DeserializeOwned>(path: String) -> Result<T, hyper::Error> {
    use crate::SOCKET_ADDR;
    use hyper::body::HttpBody;
    use hyperlocal::UnixClientExt;
    let url = hyperlocal::Uri::new(SOCKET_ADDR, &path).into();

    let client = hyper::Client::unix();

    let mut response = client.get(url).await?;
    let mut bytes = Vec::default();
    while let Some(next) = response.data().await {
        let chunk = next?;
        bytes.extend(chunk);
    }
    let bres = String::from_utf8(bytes).unwrap();
    let res: T = serde_json::from_str(&bres).expect("Could not deserialize input");

    Ok(res)
}

#[engine_only_fn]
async fn get_build_state(
    _info: StateGeneratorInfo<()>,
) -> Result<IndexPageState, BlamedError<httpreq::MyError>> {
    use crate::httpreq;
    let body = perseus::utils::cache_fallible_res(
        "index",
        || async {
            let path = "/views/news/3";
            let res = future::timeout(
                Duration::from_secs(5),
                httpreq::request_client::<Vec<ContentViews>>(path.to_string()),
            )
            .await?;
            Ok::<Vec<ContentViews>, httpreq::MyError>(res.expect("REASON"))
        },
        true,
    )
    .await?;

    Ok(IndexPageState { contents: body })
}

直接调用可正常运行的代码

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let path = "/views/news/3";
    let cnt = client_request::<Vec<ContentViews>>(path.to_string()).await?;
    println!("{:#?}", cnt);

    Ok(())
}

Docker Compose配置

version: "3"
services:
  front:
    build:
      context: .
    user: "1000:1000"
    volumes:
      - mysocket:/tmp:rw
      - ./static/:/app/static/
    ports:
      - 4401:4401
    expose:
      - "4401"
networks:
  default:
    name: mynet
    external: true
volumes:
  mysocket:
    external: true

问题分析与调试建议

  • 检查套接字文件的存在性与权限
    • 在前端容器的构建或运行阶段,添加命令ls -l /tmp/确认iso-uds.socket是否存在。
    • 确保Actix服务器创建套接字时设置了允许前端用户(1000:1000)读写的权限,比如在Actix代码中设置UnixListener的权限为0o777,或者让服务器用户与前端用户同组并设置权限为0o770。
  • 确认容器启动顺序与健康状态
    • 前端容器的perseus deploy命令必须在Actix服务器完全启动并创建好套接字后执行。可在docker-compose中给前端容器添加depends_on,并为Actix服务器配置健康检查(比如检查套接字文件存在,或提供HTTP健康端点),确保服务器就绪后再触发前端部署。
  • 排查构建阶段与运行阶段的差异
    • perseus deploy是在Docker构建阶段执行的,此时共享卷mysocket默认不会挂载。如果构建过程需要访问套接字,这种方式不可行,需调整为在运行时执行Perseus的渲染逻辑,或把Actix访问逻辑移到运行阶段。
  • 验证代码中的路径与日志
    • 在client_request函数中添加日志,打印当前尝试连接的套接字路径,以及/tmp目录的文件列表,确认路径无误且文件存在。
  • 检查用户权限匹配
    • 确认前端容器的1000:1000用户对/tmp目录和套接字文件有读写权限,可在容器内执行sudo -u 1000 ls -l /tmp/iso-uds.socket验证。

内容的提问来源于stack exchange,提问作者afidegnum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 03:25:05