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验证。
- 确认前端容器的1000:1000用户对
内容的提问来源于stack exchange,提问作者afidegnum
相关产品推荐
相关产品推荐

